diff --git a/.DS_Store b/.DS_Store index 6f08f39..63bada6 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Example/.DS_Store b/Example/.DS_Store index 0907b18..0847205 100644 Binary files a/Example/.DS_Store and b/Example/.DS_Store differ diff --git a/Example/Geofirestore.xcodeproj/project.pbxproj b/Example/Geofirestore.xcodeproj/project.pbxproj index 6e0a282..d9a839a 100644 --- a/Example/Geofirestore.xcodeproj/project.pbxproj +++ b/Example/Geofirestore.xcodeproj/project.pbxproj @@ -324,7 +324,8 @@ "${PODS_ROOT}/Target Support Files/Pods-Geofirestore_Example/Pods-Geofirestore_Example-frameworks.sh", "${BUILT_PRODUCTS_DIR}/BoringSSL-GRPC/openssl_grpc.framework", "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework", - "${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework", + "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework", + "${BUILT_PRODUCTS_DIR}/abseil/absl.framework", "${BUILT_PRODUCTS_DIR}/gRPC-C++/grpcpp.framework", "${BUILT_PRODUCTS_DIR}/gRPC-Core/grpc.framework", "${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework", @@ -334,7 +335,8 @@ outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl_grpc.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/absl.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/grpcpp.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/grpc.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework", diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 61a84fd..d0f1194 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,112 +1,287 @@ PODS: - - BoringSSL-GRPC (0.0.2): - - BoringSSL-GRPC/Implementation (= 0.0.2) - - BoringSSL-GRPC/Interface (= 0.0.2) - - BoringSSL-GRPC/Implementation (0.0.2): - - BoringSSL-GRPC/Interface (= 0.0.2) - - BoringSSL-GRPC/Interface (0.0.2) - - Firebase (5.20.2): - - Firebase/Core (= 5.20.2) - - Firebase/Core (5.20.2): + - abseil/algorithm (0.20190808): + - abseil/algorithm/algorithm (= 0.20190808) + - abseil/algorithm/container (= 0.20190808) + - abseil/algorithm/algorithm (0.20190808) + - abseil/algorithm/container (0.20190808): + - abseil/algorithm/algorithm + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/base (0.20190808): + - abseil/base/atomic_hook (= 0.20190808) + - abseil/base/base (= 0.20190808) + - abseil/base/base_internal (= 0.20190808) + - abseil/base/bits (= 0.20190808) + - abseil/base/config (= 0.20190808) + - abseil/base/core_headers (= 0.20190808) + - abseil/base/dynamic_annotations (= 0.20190808) + - abseil/base/endian (= 0.20190808) + - abseil/base/log_severity (= 0.20190808) + - abseil/base/malloc_internal (= 0.20190808) + - abseil/base/pretty_function (= 0.20190808) + - abseil/base/spinlock_wait (= 0.20190808) + - abseil/base/throw_delegate (= 0.20190808) + - abseil/base/atomic_hook (0.20190808) + - abseil/base/base (0.20190808): + - abseil/base/atomic_hook + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/base/dynamic_annotations + - abseil/base/log_severity + - abseil/base/spinlock_wait + - abseil/meta/type_traits + - abseil/base/base_internal (0.20190808): + - abseil/meta/type_traits + - abseil/base/bits (0.20190808): + - abseil/base/core_headers + - abseil/base/config (0.20190808) + - abseil/base/core_headers (0.20190808): + - abseil/base/config + - abseil/base/dynamic_annotations (0.20190808) + - abseil/base/endian (0.20190808): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/log_severity (0.20190808): + - abseil/base/core_headers + - abseil/base/malloc_internal (0.20190808): + - abseil/base/base + - abseil/base/config + - abseil/base/core_headers + - abseil/base/dynamic_annotations + - abseil/base/spinlock_wait + - abseil/base/pretty_function (0.20190808) + - abseil/base/spinlock_wait (0.20190808): + - abseil/base/core_headers + - abseil/base/throw_delegate (0.20190808): + - abseil/base/base + - abseil/base/config + - abseil/memory (0.20190808): + - abseil/memory/memory (= 0.20190808) + - abseil/memory/memory (0.20190808): + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/meta (0.20190808): + - abseil/meta/type_traits (= 0.20190808) + - abseil/meta/type_traits (0.20190808): + - abseil/base/config + - abseil/numeric/int128 (0.20190808): + - abseil/base/config + - abseil/base/core_headers + - abseil/strings/internal (0.20190808): + - abseil/base/core_headers + - abseil/base/endian + - abseil/meta/type_traits + - abseil/strings/strings (0.20190808): + - abseil/base/base + - abseil/base/bits + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian + - abseil/base/throw_delegate + - abseil/memory/memory + - abseil/meta/type_traits + - abseil/numeric/int128 + - abseil/strings/internal + - abseil/time (0.20190808): + - abseil/time/internal (= 0.20190808) + - abseil/time/time (= 0.20190808) + - abseil/time/internal (0.20190808): + - abseil/time/internal/cctz (= 0.20190808) + - abseil/time/internal/cctz (0.20190808): + - abseil/time/internal/cctz/civil_time (= 0.20190808) + - abseil/time/internal/cctz/includes (= 0.20190808) + - abseil/time/internal/cctz/time_zone (= 0.20190808) + - abseil/time/internal/cctz/civil_time (0.20190808) + - abseil/time/internal/cctz/includes (0.20190808) + - abseil/time/internal/cctz/time_zone (0.20190808): + - abseil/time/internal/cctz/civil_time + - abseil/time/time (0.20190808): + - abseil/base/base + - abseil/base/core_headers + - abseil/numeric/int128 + - abseil/strings/strings + - abseil/time/internal/cctz/civil_time + - abseil/time/internal/cctz/time_zone + - abseil/types (0.20190808): + - abseil/types/any (= 0.20190808) + - abseil/types/bad_any_cast (= 0.20190808) + - abseil/types/bad_any_cast_impl (= 0.20190808) + - abseil/types/bad_optional_access (= 0.20190808) + - abseil/types/bad_variant_access (= 0.20190808) + - abseil/types/compare (= 0.20190808) + - abseil/types/optional (= 0.20190808) + - abseil/types/span (= 0.20190808) + - abseil/types/variant (= 0.20190808) + - abseil/types/any (0.20190808): + - abseil/base/config + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/types/bad_any_cast + - abseil/utility/utility + - abseil/types/bad_any_cast (0.20190808): + - abseil/base/config + - abseil/types/bad_any_cast_impl + - abseil/types/bad_any_cast_impl (0.20190808): + - abseil/base/base + - abseil/base/config + - abseil/types/bad_optional_access (0.20190808): + - abseil/base/base + - abseil/base/config + - abseil/types/bad_variant_access (0.20190808): + - abseil/base/base + - abseil/base/config + - abseil/types/compare (0.20190808): + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/types/optional (0.20190808): + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/memory/memory + - abseil/meta/type_traits + - abseil/types/bad_optional_access + - abseil/utility/utility + - abseil/types/span (0.20190808): + - abseil/algorithm/algorithm + - abseil/base/core_headers + - abseil/base/throw_delegate + - abseil/meta/type_traits + - abseil/types/variant (0.20190808): + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/types/bad_variant_access + - abseil/utility/utility + - abseil/utility/utility (0.20190808): + - abseil/base/base_internal + - abseil/base/config + - abseil/meta/type_traits + - BoringSSL-GRPC (0.0.3): + - BoringSSL-GRPC/Implementation (= 0.0.3) + - BoringSSL-GRPC/Interface (= 0.0.3) + - BoringSSL-GRPC/Implementation (0.0.3): + - BoringSSL-GRPC/Interface (= 0.0.3) + - BoringSSL-GRPC/Interface (0.0.3) + - Firebase (6.17.0): + - Firebase/Core (= 6.17.0) + - Firebase/Core (6.17.0): - Firebase/CoreOnly - - FirebaseAnalytics (= 5.8.1) - - Firebase/CoreOnly (5.20.2): - - FirebaseCore (= 5.4.1) - - Firebase/Database (5.20.2): + - FirebaseAnalytics (= 6.2.2) + - Firebase/CoreOnly (6.17.0): + - FirebaseCore (= 6.6.2) + - Firebase/Database (6.17.0): - Firebase/CoreOnly - - FirebaseDatabase (= 5.1.1) - - FirebaseAnalytics (5.8.1): - - FirebaseCore (~> 5.4) - - FirebaseInstanceID (~> 3.8) - - GoogleAppMeasurement (= 5.8.1) - - GoogleUtilities/AppDelegateSwizzler (~> 5.2) - - GoogleUtilities/MethodSwizzler (~> 5.2) - - GoogleUtilities/Network (~> 5.2) - - "GoogleUtilities/NSData+zlib (~> 5.2)" - - nanopb (~> 0.3) + - FirebaseDatabase (~> 6.1.4) + - FirebaseAnalytics (6.2.2): + - FirebaseCore (~> 6.6) + - FirebaseInstanceID (~> 4.3) + - GoogleAppMeasurement (= 6.2.2) + - GoogleUtilities/AppDelegateSwizzler (~> 6.0) + - GoogleUtilities/MethodSwizzler (~> 6.0) + - GoogleUtilities/Network (~> 6.0) + - "GoogleUtilities/NSData+zlib (~> 6.0)" + - nanopb (= 0.3.9011) - FirebaseAuthInterop (1.0.0) - - FirebaseCore (5.4.1): - - GoogleUtilities/Environment (~> 5.2) - - GoogleUtilities/Logger (~> 5.2) - - FirebaseDatabase (5.1.1): - - FirebaseAuthInterop (~> 1.0) - - FirebaseCore (~> 5.2) - - leveldb-library (~> 1.18) - - FirebaseFirestore (1.2.1): - - FirebaseAuthInterop (~> 1.0) - - FirebaseCore (~> 5.2) - - FirebaseFirestore/abseil-cpp (= 1.2.1) - - "gRPC-C++ (= 0.0.6)" - - leveldb-library (~> 1.20) + - FirebaseCore (6.6.2): + - FirebaseCoreDiagnostics (~> 1.2) + - FirebaseCoreDiagnosticsInterop (~> 1.2) + - GoogleUtilities/Environment (~> 6.5) + - GoogleUtilities/Logger (~> 6.5) + - FirebaseCoreDiagnostics (1.2.0): + - FirebaseCoreDiagnosticsInterop (~> 1.2) + - GoogleDataTransportCCTSupport (~> 1.3) + - GoogleUtilities/Environment (~> 6.5) + - GoogleUtilities/Logger (~> 6.5) - nanopb (~> 0.3.901) - - Protobuf (~> 3.1) - - FirebaseFirestore/abseil-cpp (1.2.1): + - FirebaseCoreDiagnosticsInterop (1.2.0) + - FirebaseDatabase (6.1.4): - FirebaseAuthInterop (~> 1.0) - - FirebaseCore (~> 5.2) - - "gRPC-C++ (= 0.0.6)" - - leveldb-library (~> 1.20) + - FirebaseCore (~> 6.0) + - leveldb-library (~> 1.22) + - FirebaseFirestore (1.10.2): + - abseil/algorithm (= 0.20190808) + - abseil/base (= 0.20190808) + - abseil/memory (= 0.20190808) + - abseil/meta (= 0.20190808) + - abseil/strings/strings (= 0.20190808) + - abseil/time (= 0.20190808) + - abseil/types (= 0.20190808) + - FirebaseAuthInterop (~> 1.0) + - FirebaseCore (~> 6.2) + - "gRPC-C++ (= 0.0.9)" + - leveldb-library (~> 1.22) - nanopb (~> 0.3.901) - - Protobuf (~> 3.1) - - FirebaseInstanceID (3.8.1): - - FirebaseCore (~> 5.2) - - GoogleUtilities/Environment (~> 5.2) - - GoogleUtilities/UserDefaults (~> 5.2) - - GeoFire (3.0.0): - - Firebase/Database (~> 5.0) - - Geofirestore (1.0.0): + - FirebaseInstallations (1.1.0): + - FirebaseCore (~> 6.6) + - GoogleUtilities/UserDefaults (~> 6.5) + - PromisesObjC (~> 1.2) + - FirebaseInstanceID (4.3.1): + - FirebaseCore (~> 6.6) + - FirebaseInstallations (~> 1.0) + - GoogleUtilities/Environment (~> 6.5) + - GoogleUtilities/UserDefaults (~> 6.5) + - GeoFire (4.0.1): + - Firebase/Database (~> 6.0) + - Geofirestore (1.0.1): - Firebase - FirebaseCore - FirebaseFirestore - GeoFire - - GoogleAppMeasurement (5.8.1): - - GoogleUtilities/AppDelegateSwizzler (~> 5.2) - - GoogleUtilities/MethodSwizzler (~> 5.2) - - GoogleUtilities/Network (~> 5.2) - - "GoogleUtilities/NSData+zlib (~> 5.2)" - - nanopb (~> 0.3) - - GoogleUtilities/AppDelegateSwizzler (5.8.0): + - GoogleAppMeasurement (6.2.2): + - GoogleUtilities/AppDelegateSwizzler (~> 6.0) + - GoogleUtilities/MethodSwizzler (~> 6.0) + - GoogleUtilities/Network (~> 6.0) + - "GoogleUtilities/NSData+zlib (~> 6.0)" + - nanopb (= 0.3.9011) + - GoogleDataTransport (4.0.0) + - GoogleDataTransportCCTSupport (1.4.0): + - GoogleDataTransport (~> 4.0) + - nanopb (~> 0.3.901) + - GoogleUtilities/AppDelegateSwizzler (6.5.1): - GoogleUtilities/Environment - GoogleUtilities/Logger - GoogleUtilities/Network - - GoogleUtilities/Environment (5.8.0) - - GoogleUtilities/Logger (5.8.0): + - GoogleUtilities/Environment (6.5.1) + - GoogleUtilities/Logger (6.5.1): - GoogleUtilities/Environment - - GoogleUtilities/MethodSwizzler (5.8.0): + - GoogleUtilities/MethodSwizzler (6.5.1): - GoogleUtilities/Logger - - GoogleUtilities/Network (5.8.0): + - GoogleUtilities/Network (6.5.1): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (5.8.0)" - - GoogleUtilities/Reachability (5.8.0): + - "GoogleUtilities/NSData+zlib (6.5.1)" + - GoogleUtilities/Reachability (6.5.1): - GoogleUtilities/Logger - - GoogleUtilities/UserDefaults (5.8.0): + - GoogleUtilities/UserDefaults (6.5.1): - GoogleUtilities/Logger - - "gRPC-C++ (0.0.6)": - - "gRPC-C++/Implementation (= 0.0.6)" - - "gRPC-C++/Interface (= 0.0.6)" - - "gRPC-C++/Implementation (0.0.6)": - - "gRPC-C++/Interface (= 0.0.6)" - - gRPC-Core (= 1.17.0) + - "gRPC-C++ (0.0.9)": + - "gRPC-C++/Implementation (= 0.0.9)" + - "gRPC-C++/Interface (= 0.0.9)" + - "gRPC-C++/Implementation (0.0.9)": + - "gRPC-C++/Interface (= 0.0.9)" + - gRPC-Core (= 1.21.0) - nanopb (~> 0.3) - - "gRPC-C++/Interface (0.0.6)" - - gRPC-Core (1.17.0): - - gRPC-Core/Implementation (= 1.17.0) - - gRPC-Core/Interface (= 1.17.0) - - gRPC-Core/Implementation (1.17.0): - - BoringSSL-GRPC (= 0.0.2) - - gRPC-Core/Interface (= 1.17.0) + - "gRPC-C++/Interface (0.0.9)" + - gRPC-Core (1.21.0): + - gRPC-Core/Implementation (= 1.21.0) + - gRPC-Core/Interface (= 1.21.0) + - gRPC-Core/Implementation (1.21.0): + - BoringSSL-GRPC (= 0.0.3) + - gRPC-Core/Interface (= 1.21.0) - nanopb (~> 0.3) - - gRPC-Core/Interface (1.17.0) - - leveldb-library (1.20) - - nanopb (0.3.901): - - nanopb/decode (= 0.3.901) - - nanopb/encode (= 0.3.901) - - nanopb/decode (0.3.901) - - nanopb/encode (0.3.901) - - Nimble (8.0.2) - - Protobuf (3.9.0) - - Quick (2.1.0) + - gRPC-Core/Interface (1.21.0) + - leveldb-library (1.22) + - nanopb (0.3.9011): + - nanopb/decode (= 0.3.9011) + - nanopb/encode (= 0.3.9011) + - nanopb/decode (0.3.9011) + - nanopb/encode (0.3.9011) + - Nimble (8.0.5) + - PromisesObjC (1.2.8) + - Quick (2.2.0) DEPENDENCIES: - Geofirestore (from `../`) @@ -114,24 +289,30 @@ DEPENDENCIES: - Quick SPEC REPOS: - https://github.com/cocoapods/specs.git: + trunk: + - abseil - BoringSSL-GRPC - Firebase - FirebaseAnalytics - FirebaseAuthInterop - FirebaseCore + - FirebaseCoreDiagnostics + - FirebaseCoreDiagnosticsInterop - FirebaseDatabase - FirebaseFirestore + - FirebaseInstallations - FirebaseInstanceID - GeoFire - GoogleAppMeasurement + - GoogleDataTransport + - GoogleDataTransportCCTSupport - GoogleUtilities - "gRPC-C++" - gRPC-Core - leveldb-library - nanopb - Nimble - - Protobuf + - PromisesObjC - Quick EXTERNAL SOURCES: @@ -139,26 +320,32 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - BoringSSL-GRPC: 2a230d9cd93e7ce39916044f645cebb31f37dde6 - Firebase: 0c8cf33f266410c61ab3e2265cfa412200351d9c - FirebaseAnalytics: ece1aa57a4f43c64d53a648b5a5e05151aae947b + abseil: 18063d773f5366ff8736a050fe035a28f635fd27 + BoringSSL-GRPC: db8764df3204ccea016e1c8dd15d9a9ad63ff318 + Firebase: 2672e5636b42f977177716317e68346ae5e9de25 + FirebaseAnalytics: cf95d3aab897612783020fbd98401d5366f135ee FirebaseAuthInterop: 0ffa57668be100582bb7643d4fcb7615496c41fc - FirebaseCore: f1a9a8be1aee4bf71a2fc0f4096df6788bdfda61 - FirebaseDatabase: 2c15b0ea6f2c6eb5e57413f9d6340f1e50b81ae3 - FirebaseFirestore: faca891c0f0d1d6c10c793473e2f6a29d75014b5 - FirebaseInstanceID: a122b0c258720cf250551bb2bedf48c699f80d90 - GeoFire: e3ae6f4be3f2466c3467ef6c1c203db3af935c59 - Geofirestore: 0bfa94b5568614151c384cfa834bdb4c3636eaf0 - GoogleAppMeasurement: ffe513e90551844a739e7bcbb1d2aca1c28a4338 - GoogleUtilities: 04fce34bcd5620c1ee76fb79172105c74a4df335 - "gRPC-C++": e76441995900ac90e9bd98644ab4733f12521edf - gRPC-Core: 4028031ed2c5267cca0d846c876d8046b1ecb9b6 - leveldb-library: 08cba283675b7ed2d99629a4bc5fd052cd2bb6a5 - nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48 - Nimble: 622629381bda1dd5678162f21f1368cec7cbba60 - Protobuf: 1097ca58584c8d9be81bfbf2c5ff5975648dd87a - Quick: 4be43f6634acfa727dd106bdf3929ce125ffa79d + FirebaseCore: a1dd9dd6355a8356dd30a8f076839e242285a81c + FirebaseCoreDiagnostics: 5e78803ab276bc5b50340e3c539c06c3de35c649 + FirebaseCoreDiagnosticsInterop: 296e2c5f5314500a850ad0b83e9e7c10b011a850 + FirebaseDatabase: 0144e0706a4761f1b0e8679572eba8095ddb59be + FirebaseFirestore: 2ee644acccde18e49b2fb5d434c709b1f1171b13 + FirebaseInstallations: 575cd32f2aec0feeb0e44f5d0110a09e5e60b47b + FirebaseInstanceID: 031d7d0c8e7b5c030bbeb4d2a690550375e83fec + GeoFire: 67b5276c561434b4e4c7ea567c2c4d64e711339c + Geofirestore: 46c079cf1ceeb03e77e7b2e4a3e65530527b6f95 + GoogleAppMeasurement: d0560d915abf15e692e8538ba1d58442217b6aff + GoogleDataTransport: 47fe3b8e1673e5187dfd615656a3c5034f150d69 + GoogleDataTransportCCTSupport: 36f69887fd212db6d7ef4dd45ba44523717a434e + GoogleUtilities: 06eb53bb579efe7099152735900dd04bf09e7275 + "gRPC-C++": 9dfe7b44821e7b3e44aacad2af29d2c21f7cde83 + gRPC-Core: c9aef9a261a1247e881b18059b84d597293c9947 + leveldb-library: 55d93ee664b4007aac644a782d11da33fba316f7 + nanopb: 18003b5e52dab79db540fe93fe9579f399bd1ccd + Nimble: 4ab1aeb9b45553c75b9687196b0fa0713170a332 + PromisesObjC: c119f3cd559f50b7ae681fa59dc1acd19173b7e6 + Quick: 7fb19e13be07b5dfb3b90d4f9824c855a11af40e PODFILE CHECKSUM: 1f888529919bed58b4ce0420c841b0a5d00f4be8 -COCOAPODS: 1.7.5 +COCOAPODS: 1.8.4 diff --git a/Example/Pods/Firebase/.cocoapods.yml b/Example/Pods/Firebase/.cocoapods.yml deleted file mode 100755 index 57e7572..0000000 --- a/Example/Pods/Firebase/.cocoapods.yml +++ /dev/null @@ -1,5 +0,0 @@ -try: - install: - pre: - - git clone https://github.com/firebase/quickstart-ios - diff --git a/Example/Pods/Firebase/CHANGELOG.md b/Example/Pods/Firebase/CoreOnly/CHANGELOG.md similarity index 96% rename from Example/Pods/Firebase/CHANGELOG.md rename to Example/Pods/Firebase/CoreOnly/CHANGELOG.md index d1550c6..98849d3 100755 --- a/Example/Pods/Firebase/CHANGELOG.md +++ b/Example/Pods/Firebase/CoreOnly/CHANGELOG.md @@ -1,4 +1,4 @@ -Please go to https://firebase.google.com/support/release-notes/ios#0.0.0 +Please go to https://firebase.google.com/support/release-notes/ios to view the Firebase iOS release notes. You can find information about prior changes to the Firebase pod and Firebase diff --git a/Example/Pods/Firebase/CoreOnly/NOTICES b/Example/Pods/Firebase/CoreOnly/NOTICES new file mode 100644 index 0000000..1617eeb --- /dev/null +++ b/Example/Pods/Firebase/CoreOnly/NOTICES @@ -0,0 +1,11310 @@ +APLevelDB +Created by Adam Preble on 1/23/12. +Copyright (c) 2012 Adam Preble. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +Portions of APLevelDB are based on LevelDB-ObjC: + https:github.com/hoisie/LevelDB-ObjC +Specifically the SliceFromString/StringFromSlice macros, and the structure of +the enumeration methods. License for those potions follows: + +Copyright (c) 2011 Pave Labs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Abseil + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://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. + + +Boost +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +BoringSSL +BoringSSL is a fork of OpenSSL. As such, large parts of it fall under OpenSSL +licensing. Files that are completely new have a Google copyright and an ISC +license. This license is reproduced at the bottom of this file. + +Contributors to BoringSSL are required to follow the CLA rules for Chromium: +https://cla.developers.google.com/clas + +Files in third_party/ have their own licenses, as described therein. The MIT +license, for third_party/fiat, which, unlike other third_party directories, is +compiled into non-test libraries, is included below. + +The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the +OpenSSL License and the original SSLeay license apply to the toolkit. See below +for the actual license texts. Actually both licenses are BSD-style Open Source +licenses. In case of any license issues related to OpenSSL please contact +openssl-core@openssl.org. + +The following are Google-internal bug numbers where explicit permission from +some authors is recorded for use of their work. (This is purely for our own +record keeping.) + 27287199 + 27287880 + 27287883 + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + + +ISC license used for completely new code in BoringSSL: + +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + + +The code in third_party/fiat carries the MIT license: + +Copyright (c) 2015-2016 the fiat-crypto authors (see +https://github.com/mit-plv/fiat-crypto/blob/master/AUTHORS). + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +Licenses for support code +------------------------- + +Parts of the TLS test suite are under the Go license. This code is not included +in BoringSSL (i.e. libcrypto and libssl) when compiled, however, so +distributing code linked against BoringSSL does not trigger this license: + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +BoringSSL uses the Chromium test infrastructure to run a continuous build, +trybots etc. The scripts which manage this, and the script for generating build +metadata, are under the Chromium license. Distributing code linked against +BoringSSL does not trigger this license. + +Copyright 2015 The Chromium Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Brotli +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Chrome Certificate Verifier +// Copyright 2015 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Closure Compiler + 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 + +Closure Library + 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 + +Crunchy Crypt + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Darts-clone +# The BSD 2-clause license + +Copyright (c) 2008-2014, Susumu Yata +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Dimsum + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Drishti +Copyright 2019 The Drishti Authors. All rights reserved. + + 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 2017, The Drishti Authors. + + 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. + +DrishtiOSS + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Edge TPU + 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 2018 Google LLC + + 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. + +Eigen 3 +Eigen 3.3.90 +The corresponding source for this library is available at +https://eigen.googlesource.com/mirror/ + +Eigen is primarily MPL2 licensed. See COPYING.MPL2 and these links: + http://www.mozilla.org/MPL/2.0/ + http://www.mozilla.org/MPL/2.0/FAQ.html + +Some files contain third-party code under BSD, whence +the other COPYING.* files here. + +If you want to guarantee that the Eigen code that you are #including +is licensed under the MPL2 and possibly more permissive licenses (like +BSD), #define this preprocessor symbol: EIGEN_MPL2_ONLY +For example, with most compilers, you could add this to your project + CXXFLAGS: -DEIGEN_MPL2_ONLY +This will cause a compilation error to be generated if you #include +any code that is covered by more restrictive licences than MPL2. + +---------------------------------------------------------------------- +Following applies to: +./test/sparseqr.cpp +./test/half_float.cpp +./test/zerosized.cpp +./test/nesting_ops.cpp +./test/sizeoverflow.cpp +./test/swap.cpp +./test/product_mmtr.cpp +./test/stdvector_overload.cpp +./test/product_symm.cpp +./test/sparse_block.cpp +./test/eigen2support.cpp +./test/upperbidiagonalization.cpp +./test/numext.cpp +./test/adjoint.cpp +./test/AnnoyingScalar.h +./test/mpl2only.cpp +./test/stddeque.cpp +./test/householder.cpp +./test/product_small.cpp +./test/product_syrk.cpp +./test/inplace_decomposition.cpp +./test/vectorwiseop.cpp +./test/meta.cpp +./test/stdvector.cpp +./test/sparseLM.cpp +./test/diagonalmatrices.cpp +./test/stdlist_overload.cpp +./test/block.cpp +./test/cholmod_support.cpp +./test/basicstuff.cpp +./test/triangular.cpp +./test/product.h +./test/vectorization_logic.cpp +./test/dontalign.cpp +./test/first_aligned.cpp +./test/mapped_matrix.cpp +./test/umfpack_support.cpp +./test/product_selfadjoint.cpp +./test/smallvectors.cpp +./test/corners.cpp +./test/product_trsolve.cpp +./test/determinant.cpp +./test/stdlist.cpp +./test/unalignedcount.cpp +./test/qr.cpp +./test/svd_common.h +./test/ref.cpp +./test/symbolic_index.cpp +./test/geo_transformations.cpp +./test/geo_eulerangles.cpp +./test/eigensolver_selfadjoint.cpp +./test/stddeque_overload.cpp +./test/jacobisvd.cpp +./test/nullary.cpp +./test/inverse.cpp +./test/integer_types.cpp +./test/metis_support.cpp +./test/exceptions.cpp +./test/packetmath.cpp +./test/schur_complex.cpp +./test/type_alias.cpp +./test/unalignedassert.cpp +./test/geo_quaternion.cpp +./test/lu.cpp +./test/qr_fullpivoting.cpp +./test/denseLM.cpp +./test/linearstructure.cpp +./test/rand.cpp +./test/conservative_resize.cpp +./test/eigensolver_generalized_real.cpp +./test/pastix_support.cpp +./test/sparse_solver.h +./test/num_dimensions.cpp +./test/simplicial_cholesky.cpp +./test/hessenberg.cpp +./test/array_reverse.cpp +./test/special_numbers.cpp +./test/array_for_matrix.cpp +./test/product_large.cpp +./test/resize.cpp +./test/sparse_solvers.cpp +./test/selfadjoint.cpp +./test/schur_real.cpp +./test/sparse_basic.cpp +./test/conjugate_gradient.cpp +./test/real_qz.cpp +./test/bandmatrix.cpp +./test/dense_storage.cpp +./test/permutationmatrices.cpp +./test/array_cwise.cpp +./test/qr_colpivoting.cpp +./test/array_replicate.cpp +./test/rvalue_types.cpp +./test/stable_norm.cpp +./test/geo_homogeneous.cpp +./test/main.h +./test/eigensolver_complex.cpp +./test/product_trmm.cpp +./test/bicgstab.cpp +./test/redux.cpp +./test/klu_support.cpp +./test/geo_alignedbox.cpp +./test/is_same_dense.cpp +./test/sparse_permutations.cpp +./test/sparse_vector.cpp +./test/diagonal.cpp +./test/sparse.h +./test/mapstride.cpp +./test/visitor.cpp +./test/geo_hyperplane.cpp +./test/bdcsvd.cpp +./test/product_trmv.cpp +./test/nestbyvalue.cpp +./test/array_of_string.cpp +./test/superlu_support.cpp +./test/sizeof.cpp +./test/boostmultiprec.cpp +./test/commainitializer.cpp +./test/constructor.cpp +./test/mixingtypes.cpp +./test/miscmatrices.cpp +./test/mapstaticmethods.cpp +./test/product_notemporary.cpp +./test/initializer_list_construction.cpp +./test/incomplete_cholesky.cpp +./test/geo_parametrizedline.cpp +./test/indexed_view.cpp +./test/qtvector.cpp +./test/sparselu.cpp +./test/sparse_product.cpp +./test/dynalloc.cpp +./test/fastmath.cpp +./test/prec_inverse_4x4.cpp +./test/umeyama.cpp +./test/reshape.cpp +./test/product_extra.cpp +./test/jacobi.cpp +./test/sparse_ref.cpp +./test/nomalloc.cpp +./test/spqr_support.cpp +./test/lscg.cpp +./test/cholesky.cpp +./test/eigensolver_generic.cpp +./test/geo_orthomethods.cpp +./test/svd_fill.h +./test/stl_iterators.cpp +./Eigen/src/MetisSupport/MetisSupport.h +./Eigen/src/CholmodSupport/CholmodSupport.h +./Eigen/src/QR/CompleteOrthogonalDecomposition.h +./Eigen/src/QR/FullPivHouseholderQR.h +./Eigen/src/QR/HouseholderQR.h +./Eigen/src/QR/ColPivHouseholderQR.h +./Eigen/src/plugins/CommonCwiseUnaryOps.h +./Eigen/src/plugins/BlockMethods.h +./Eigen/src/plugins/CommonCwiseBinaryOps.h +./Eigen/src/plugins/MatrixCwiseUnaryOps.h +./Eigen/src/plugins/IndexedViewMethods.h +./Eigen/src/plugins/MatrixCwiseBinaryOps.h +./Eigen/src/SVD/UpperBidiagonalization.h +./Eigen/src/SVD/SVDBase.h +./Eigen/src/SVD/BDCSVD.h +./Eigen/src/SVD/JacobiSVD.h +./Eigen/src/SparseLU/SparseLU_relax_snode.h +./Eigen/src/SparseLU/SparseLU_column_dfs.h +./Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h +./Eigen/src/SparseLU/SparseLU_pivotL.h +./Eigen/src/SparseLU/SparseLU.h +./Eigen/src/SparseLU/SparseLU_pruneL.h +./Eigen/src/SparseLU/SparseLU_copy_to_ucol.h +./Eigen/src/SparseLU/SparseLU_heap_relax_snode.h +./Eigen/src/SparseLU/SparseLU_kernel_bmod.h +./Eigen/src/SparseLU/SparseLU_panel_dfs.h +./Eigen/src/SparseLU/SparseLU_panel_bmod.h +./Eigen/src/SparseLU/SparseLU_Structs.h +./Eigen/src/SparseLU/SparseLUImpl.h +./Eigen/src/SparseLU/SparseLU_Memory.h +./Eigen/src/SparseLU/SparseLU_column_bmod.h +./Eigen/src/SparseLU/SparseLU_gemm_kernel.h +./Eigen/src/SparseLU/SparseLU_Utils.h +./Eigen/src/OrderingMethods/Eigen_Colamd.h +./Eigen/src/OrderingMethods/Ordering.h +./Eigen/src/OrderingMethods/Amd.h +./Eigen/src/UmfPackSupport/UmfPackSupport.h +./Eigen/src/Geometry/Umeyama.h +./Eigen/src/Geometry/Transform.h +./Eigen/src/Geometry/OrthoMethods.h +./Eigen/src/Geometry/Hyperplane.h +./Eigen/src/Geometry/Homogeneous.h +./Eigen/src/Geometry/RotationBase.h +./Eigen/src/Geometry/EulerAngles.h +./Eigen/src/Geometry/Translation.h +./Eigen/src/Geometry/Rotation2D.h +./Eigen/src/Geometry/Scaling.h +./Eigen/src/Geometry/AlignedBox.h +./Eigen/src/Geometry/ParametrizedLine.h +./Eigen/src/Geometry/Quaternion.h +./Eigen/src/Geometry/AngleAxis.h +./Eigen/src/Geometry/arch/Geometry_SSE.h +./Eigen/src/KLUSupport/KLUSupport.h +./Eigen/src/misc/Kernel.h +./Eigen/src/misc/RealSvd2x2.h +./Eigen/src/misc/Image.h +./Eigen/src/StlSupport/details.h +./Eigen/src/StlSupport/StdList.h +./Eigen/src/StlSupport/StdDeque.h +./Eigen/src/StlSupport/StdVector.h +./Eigen/src/SparseQR/SparseQR.h +./Eigen/src/SuperLUSupport/SuperLUSupport.h +./Eigen/src/Householder/Householder.h +./Eigen/src/Householder/HouseholderSequence.h +./Eigen/src/Householder/BlockHouseholder.h +./Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +./Eigen/src/Eigenvalues/EigenSolver.h +./Eigen/src/Eigenvalues/GeneralizedEigenSolver.h +./Eigen/src/Eigenvalues/Tridiagonalization.h +./Eigen/src/Eigenvalues/HessenbergDecomposition.h +./Eigen/src/Eigenvalues/RealQZ.h +./Eigen/src/Eigenvalues/RealSchur.h +./Eigen/src/Eigenvalues/ComplexSchur.h +./Eigen/src/Eigenvalues/ComplexEigenSolver.h +./Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h +./Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h +./Eigen/src/SparseCholesky/SimplicialCholesky.h +./Eigen/src/SparseCholesky/SimplicialCholesky_impl.h +./Eigen/src/Cholesky/LLT.h +./Eigen/src/Cholesky/LDLT.h +./Eigen/src/Jacobi/Jacobi.h +./Eigen/src/PaStiXSupport/PaStiXSupport.h +./Eigen/src/SPQRSupport/SuiteSparseQRSupport.h +./Eigen/src/LU/Determinant.h +./Eigen/src/LU/InverseImpl.h +./Eigen/src/LU/PartialPivLU.h +./Eigen/src/LU/arch/Inverse_SSE.h +./Eigen/src/LU/FullPivLU.h +./Eigen/src/Core/Map.h +./Eigen/src/Core/VectorwiseOp.h +./Eigen/src/Core/VectorBlock.h +./Eigen/src/Core/Array.h +./Eigen/src/Core/Assign.h +./Eigen/src/Core/Dot.h +./Eigen/src/Core/NestByValue.h +./Eigen/src/Core/CoreEvaluators.h +./Eigen/src/Core/ReturnByValue.h +./Eigen/src/Core/SelfCwiseBinaryOp.h +./Eigen/src/Core/GlobalFunctions.h +./Eigen/src/Core/Transpositions.h +./Eigen/src/Core/Fuzzy.h +./Eigen/src/Core/NoAlias.h +./Eigen/src/Core/CwiseNullaryOp.h +./Eigen/src/Core/NumTraits.h +./Eigen/src/Core/IndexedView.h +./Eigen/src/Core/ArrayWrapper.h +./Eigen/src/Core/util/SymbolicIndex.h +./Eigen/src/Core/util/BlasUtil.h +./Eigen/src/Core/util/Constants.h +./Eigen/src/Core/util/IntegralConstant.h +./Eigen/src/Core/util/ReshapedHelper.h +./Eigen/src/Core/util/StaticAssert.h +./Eigen/src/Core/util/IndexedViewHelper.h +./Eigen/src/Core/util/ConfigureVectorization.h +./Eigen/src/Core/util/ForwardDeclarations.h +./Eigen/src/Core/util/Meta.h +./Eigen/src/Core/util/XprHelper.h +./Eigen/src/Core/util/Macros.h +./Eigen/src/Core/util/Memory.h +./Eigen/src/Core/Product.h +./Eigen/src/Core/Replicate.h +./Eigen/src/Core/ArrayBase.h +./Eigen/src/Core/functors/NullaryFunctors.h +./Eigen/src/Core/functors/StlFunctors.h +./Eigen/src/Core/functors/AssignmentFunctors.h +./Eigen/src/Core/functors/UnaryFunctors.h +./Eigen/src/Core/functors/TernaryFunctors.h +./Eigen/src/Core/functors/BinaryFunctors.h +./Eigen/src/Core/Redux.h +./Eigen/src/Core/EigenBase.h +./Eigen/src/Core/SolverBase.h +./Eigen/src/Core/ProductEvaluators.h +./Eigen/src/Core/Block.h +./Eigen/src/Core/SolveTriangular.h +./Eigen/src/Core/ArithmeticSequence.h +./Eigen/src/Core/MatrixBase.h +./Eigen/src/Core/PlainObjectBase.h +./Eigen/src/Core/Transpose.h +./Eigen/src/Core/IO.h +./Eigen/src/Core/MathFunctions.h +./Eigen/src/Core/Stride.h +./Eigen/src/Core/MathFunctionsImpl.h +./Eigen/src/Core/StableNorm.h +./Eigen/src/Core/DiagonalProduct.h +./Eigen/src/Core/products/GeneralMatrixMatrix.h +./Eigen/src/Core/products/GeneralMatrixVector.h +./Eigen/src/Core/products/SelfadjointMatrixVector.h +./Eigen/src/Core/products/GeneralBlockPanelKernel.h +./Eigen/src/Core/products/TriangularSolverMatrix.h +./Eigen/src/Core/products/SelfadjointMatrixMatrix.h +./Eigen/src/Core/products/Parallelizer.h +./Eigen/src/Core/products/SelfadjointRank2Update.h +./Eigen/src/Core/products/TriangularMatrixMatrix.h +./Eigen/src/Core/products/TriangularMatrixVector.h +./Eigen/src/Core/products/SelfadjointProduct.h +./Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +./Eigen/src/Core/products/TriangularSolverVector.h +./Eigen/src/Core/CwiseUnaryView.h +./Eigen/src/Core/CommaInitializer.h +./Eigen/src/Core/DenseStorage.h +./Eigen/src/Core/DenseBase.h +./Eigen/src/Core/PartialReduxEvaluator.h +./Eigen/src/Core/CoreIterators.h +./Eigen/src/Core/PermutationMatrix.h +./Eigen/src/Core/CwiseTernaryOp.h +./Eigen/src/Core/Reverse.h +./Eigen/src/Core/Reshaped.h +./Eigen/src/Core/Inverse.h +./Eigen/src/Core/TriangularMatrix.h +./Eigen/src/Core/BooleanRedux.h +./Eigen/src/Core/ForceAlignedAccess.h +./Eigen/src/Core/Ref.h +./Eigen/src/Core/StlIterators.h +./Eigen/src/Core/BandMatrix.h +./Eigen/src/Core/ConditionEstimator.h +./Eigen/src/Core/Diagonal.h +./Eigen/src/Core/DiagonalMatrix.h +./Eigen/src/Core/AssignEvaluator.h +./Eigen/src/Core/CwiseBinaryOp.h +./Eigen/src/Core/Visitor.h +./Eigen/src/Core/GenericPacketMath.h +./Eigen/src/Core/SelfAdjointView.h +./Eigen/src/Core/Random.h +./Eigen/src/Core/Solve.h +./Eigen/src/Core/arch/AltiVec/MathFunctions.h +./Eigen/src/Core/arch/AltiVec/PacketMath.h +./Eigen/src/Core/arch/AltiVec/Complex.h +./Eigen/src/Core/arch/MSA/MathFunctions.h +./Eigen/src/Core/arch/MSA/Complex.h +./Eigen/src/Core/arch/MSA/PacketMath.h +./Eigen/src/Core/arch/GPU/Half.h +./Eigen/src/Core/arch/GPU/PacketMathHalf.h +./Eigen/src/Core/arch/GPU/MathFunctions.h +./Eigen/src/Core/arch/GPU/PacketMath.h +./Eigen/src/Core/arch/GPU/TypeCasting.h +./Eigen/src/Core/arch/NEON/MathFunctions.h +./Eigen/src/Core/arch/NEON/Complex.h +./Eigen/src/Core/arch/NEON/PacketMath.h +./Eigen/src/Core/arch/NEON/TypeCasting.h +./Eigen/src/Core/arch/AVX/MathFunctions.h +./Eigen/src/Core/arch/AVX/TypeCasting.h +./Eigen/src/Core/arch/AVX/Complex.h +./Eigen/src/Core/arch/AVX/PacketMath.h +./Eigen/src/Core/arch/SYCL/InteropHeaders.h +./Eigen/src/Core/arch/SYCL/PacketMath.h +./Eigen/src/Core/arch/SYCL/TypeCasting.h +./Eigen/src/Core/arch/SYCL/MathFunctions.h +./Eigen/src/Core/arch/Default/GenericPacketMathFunctions.h +./Eigen/src/Core/arch/Default/ConjHelper.h +./Eigen/src/Core/arch/Default/Settings.h +./Eigen/src/Core/arch/AVX512/MathFunctions.h +./Eigen/src/Core/arch/AVX512/PacketMath.h +./Eigen/src/Core/arch/AVX512/Complex.h +./Eigen/src/Core/arch/SSE/PacketMath.h +./Eigen/src/Core/arch/SSE/Complex.h +./Eigen/src/Core/arch/SSE/TypeCasting.h +./Eigen/src/Core/arch/SSE/MathFunctions.h +./Eigen/src/Core/arch/ZVector/MathFunctions.h +./Eigen/src/Core/arch/ZVector/PacketMath.h +./Eigen/src/Core/arch/ZVector/Complex.h +./Eigen/src/Core/arch/CUDA/Complex.h +./Eigen/src/Core/Swap.h +./Eigen/src/Core/MapBase.h +./Eigen/src/Core/GeneralProduct.h +./Eigen/src/Core/Matrix.h +./Eigen/src/Core/Select.h +./Eigen/src/Core/CwiseUnaryOp.h +./Eigen/src/Core/DenseCoeffsBase.h +./Eigen/src/SparseCore/SparseCwiseUnaryOp.h +./Eigen/src/SparseCore/TriangularSolver.h +./Eigen/src/SparseCore/SparseView.h +./Eigen/src/SparseCore/SparseSolverBase.h +./Eigen/src/SparseCore/SparseTranspose.h +./Eigen/src/SparseCore/SparseDenseProduct.h +./Eigen/src/SparseCore/SparseMap.h +./Eigen/src/SparseCore/SparseProduct.h +./Eigen/src/SparseCore/SparseUtil.h +./Eigen/src/SparseCore/SparsePermutation.h +./Eigen/src/SparseCore/SparseTriangularView.h +./Eigen/src/SparseCore/SparseSelfAdjointView.h +./Eigen/src/SparseCore/SparseMatrixBase.h +./Eigen/src/SparseCore/AmbiVector.h +./Eigen/src/SparseCore/SparseAssign.h +./Eigen/src/SparseCore/SparseRedux.h +./Eigen/src/SparseCore/SparseDot.h +./Eigen/src/SparseCore/SparseCwiseBinaryOp.h +./Eigen/src/SparseCore/SparseCompressedBase.h +./Eigen/src/SparseCore/SparseSparseProductWithPruning.h +./Eigen/src/SparseCore/SparseColEtree.h +./Eigen/src/SparseCore/SparseRef.h +./Eigen/src/SparseCore/CompressedStorage.h +./Eigen/src/SparseCore/MappedSparseMatrix.h +./Eigen/src/SparseCore/SparseDiagonalProduct.h +./Eigen/src/SparseCore/SparseFuzzy.h +./Eigen/src/SparseCore/ConservativeSparseSparseProduct.h +./Eigen/src/SparseCore/SparseMatrix.h +./Eigen/src/SparseCore/SparseVector.h +./Eigen/src/SparseCore/SparseBlock.h +./Eigen/src/IterativeLinearSolvers/SolveWithGuess.h +./Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h +./Eigen/src/IterativeLinearSolvers/BiCGSTAB.h +./Eigen/src/IterativeLinearSolvers/ConjugateGradient.h +./Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h +./Eigen/src/IterativeLinearSolvers/IncompleteCholesky.h +./Eigen/src/IterativeLinearSolvers/IncompleteLUT.h +./Eigen/src/IterativeLinearSolvers/LeastSquareConjugateGradient.h +./unsupported/Eigen/src/Eigenvalues/ArpackSelfAdjointEigenSolver.h +./unsupported/Eigen/src/SpecialFunctions/arch/GPU/GpuSpecialFunctions.h +./unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsHalf.h +./unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsImpl.h +./unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsFunctors.h +./unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsArrayAPI.h +./unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsPacketMath.h +./unsupported/Eigen/src/Polynomials/Companion.h +./unsupported/Eigen/src/Polynomials/PolynomialUtils.h +./unsupported/Eigen/src/Polynomials/PolynomialSolver.h +./unsupported/Eigen/src/Splines/Spline.h +./unsupported/Eigen/src/Splines/SplineFwd.h +./unsupported/Eigen/src/Splines/SplineFitting.h +./unsupported/Eigen/src/BVH/KdBVH.h +./unsupported/Eigen/src/BVH/BVAlgorithms.h +./unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h +./unsupported/Eigen/src/AutoDiff/AutoDiffVector.h +./unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h +./unsupported/Eigen/src/MatrixFunctions/MatrixSquareRoot.h +./unsupported/Eigen/src/MatrixFunctions/MatrixPower.h +./unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h +./unsupported/Eigen/src/MatrixFunctions/MatrixLogarithm.h +./unsupported/Eigen/src/MatrixFunctions/StemFunction.h +./unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h +./unsupported/Eigen/src/Skyline/SkylineStorage.h +./unsupported/Eigen/src/Skyline/SkylineMatrixBase.h +./unsupported/Eigen/src/Skyline/SkylineMatrix.h +./unsupported/Eigen/src/Skyline/SkylineInplaceLU.h +./unsupported/Eigen/src/Skyline/SkylineProduct.h +./unsupported/Eigen/src/Skyline/SkylineUtil.h +./unsupported/Eigen/src/FFT/ei_kissfft_impl.h +./unsupported/Eigen/src/FFT/ei_fftw_impl.h +./unsupported/Eigen/src/LevenbergMarquardt/LevenbergMarquardt.h +./unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +./unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +./unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h +./unsupported/Eigen/src/NumericalDiff/NumericalDiff.h +./unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h +./unsupported/Eigen/src/IterativeSolvers/MINRES.h +./unsupported/Eigen/src/IterativeSolvers/DGMRES.h +./unsupported/Eigen/src/IterativeSolvers/Scaling.h +./unsupported/Eigen/src/IterativeSolvers/GMRES.h +./unsupported/Eigen/src/MoreVectorization/MathFunctions.h +./unsupported/Eigen/src/EulerAngles/EulerAngles.h +./unsupported/Eigen/src/EulerAngles/EulerSystem.h +./unsupported/Eigen/src/SparseExtra/BlockOfDynamicSparseMatrix.h +./unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h +./unsupported/Eigen/src/SparseExtra/BlockSparseMatrix.h +./unsupported/Eigen/src/SparseExtra/RandomSetter.h +./unsupported/Eigen/src/SparseExtra/MatrixMarketIterator.h +./unsupported/Eigen/src/SparseExtra/MarketIO.h +./unsupported/Eigen/CXX11/src/TensorSymmetry/StaticSymmetry.h +./unsupported/Eigen/CXX11/src/TensorSymmetry/Symmetry.h +./unsupported/Eigen/CXX11/src/TensorSymmetry/DynamicSymmetry.h +./unsupported/Eigen/CXX11/src/TensorSymmetry/util/TemplateGroupTheory.h +./unsupported/Eigen/CXX11/src/util/EmulateCXX11Meta.h +./unsupported/Eigen/CXX11/src/util/CXX11Meta.h +./unsupported/Eigen/CXX11/src/util/MaxSizeVector.h +./unsupported/Eigen/CXX11/src/util/EmulateArray.h +./unsupported/Eigen/CXX11/src/util/CXX11Workarounds.h +./unsupported/Eigen/CXX11/src/ThreadPool/ThreadYield.h +./unsupported/Eigen/CXX11/src/ThreadPool/NonBlockingThreadPool.h +./unsupported/Eigen/CXX11/src/ThreadPool/RunQueue.h +./unsupported/Eigen/CXX11/src/ThreadPool/ThreadCancel.h +./unsupported/Eigen/CXX11/src/ThreadPool/ThreadPoolInterface.h +./unsupported/Eigen/CXX11/src/ThreadPool/ThreadLocal.h +./unsupported/Eigen/CXX11/src/ThreadPool/Barrier.h +./unsupported/Eigen/CXX11/src/ThreadPool/EventCount.h +./unsupported/Eigen/CXX11/src/ThreadPool/ThreadEnvironment.h +./unsupported/Eigen/CXX11/src/Tensor/TensorRef.h +./unsupported/Eigen/CXX11/src/Tensor/TensorFixedSize.h +./unsupported/Eigen/CXX11/src/Tensor/TensorSyclRun.h +./unsupported/Eigen/CXX11/src/Tensor/TensorSyclTuple.h +./unsupported/Eigen/CXX11/src/Tensor/TensorTraits.h +./unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h +./unsupported/Eigen/CXX11/src/Tensor/TensorTrace.h +./unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h +./unsupported/Eigen/CXX11/src/Tensor/TensorReductionGpu.h +./unsupported/Eigen/CXX11/src/Tensor/TensorContractionThreadPool.h +./unsupported/Eigen/CXX11/src/Tensor/TensorSyclPlaceHolderExpr.h +./unsupported/Eigen/CXX11/src/Tensor/TensorSyclExprConstructor.h +./unsupported/Eigen/CXX11/src/Tensor/TensorIntDiv.h +./unsupported/Eigen/CXX11/src/Tensor/TensorExecutor.h +./unsupported/Eigen/CXX11/src/Tensor/TensorSyclConvertToDeviceExpression.h +./unsupported/Eigen/CXX11/src/Tensor/Tensor.h +./unsupported/Eigen/CXX11/src/Tensor/TensorDeviceGpu.h +./unsupported/Eigen/CXX11/src/Tensor/TensorPatch.h +./unsupported/Eigen/CXX11/src/Tensor/TensorMorphing.h +./unsupported/Eigen/CXX11/src/Tensor/TensorInflation.h +./unsupported/Eigen/CXX11/src/Tensor/TensorStriding.h +./unsupported/Eigen/CXX11/src/Tensor/TensorScan.h +./unsupported/Eigen/CXX11/src/Tensor/TensorChipping.h +./unsupported/Eigen/CXX11/src/Tensor/TensorCustomOp.h +./unsupported/Eigen/CXX11/src/Tensor/TensorDeviceSycl.h +./unsupported/Eigen/CXX11/src/Tensor/TensorGenerator.h +./unsupported/Eigen/CXX11/src/Tensor/TensorReductionSycl.h +./unsupported/Eigen/CXX11/src/Tensor/TensorArgMaxSycl.h +./unsupported/Eigen/CXX11/src/Tensor/TensorConvolution.h +./unsupported/Eigen/CXX11/src/Tensor/TensorBase.h +./unsupported/Eigen/CXX11/src/Tensor/TensorDimensions.h +./unsupported/Eigen/CXX11/src/Tensor/TensorReduction.h +./unsupported/Eigen/CXX11/src/Tensor/TensorPadding.h +./unsupported/Eigen/CXX11/src/Tensor/TensorUInt128.h +./unsupported/Eigen/CXX11/src/Tensor/TensorArgMax.h +./unsupported/Eigen/CXX11/src/Tensor/TensorMeta.h +./unsupported/Eigen/CXX11/src/Tensor/TensorExpr.h +./unsupported/Eigen/CXX11/src/Tensor/TensorIO.h +./unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h +./unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h +./unsupported/Eigen/CXX11/src/Tensor/TensorReverse.h +./unsupported/Eigen/CXX11/src/Tensor/TensorShuffling.h +./unsupported/Eigen/CXX11/src/Tensor/TensorConvolutionSycl.h +./unsupported/Eigen/CXX11/src/Tensor/TensorSyclFunctors.h +./unsupported/Eigen/CXX11/src/Tensor/TensorMap.h +./unsupported/Eigen/CXX11/src/Tensor/TensorSycl.h +./unsupported/Eigen/CXX11/src/Tensor/TensorSyclExtractFunctors.h +./unsupported/Eigen/CXX11/src/Tensor/TensorSyclExtractAccessor.h +./unsupported/Eigen/CXX11/src/Tensor/TensorEvaluator.h +./unsupported/Eigen/CXX11/src/Tensor/TensorConcatenation.h +./unsupported/Eigen/CXX11/src/Tensor/TensorGpuHipCudaDefines.h +./unsupported/Eigen/CXX11/src/Tensor/TensorInitializer.h +./unsupported/Eigen/CXX11/src/Tensor/TensorBlock.h +./unsupported/Eigen/CXX11/src/Tensor/TensorIndexList.h +./unsupported/Eigen/CXX11/src/Tensor/TensorGpuHipCudaUndefines.h +./unsupported/Eigen/CXX11/src/Tensor/TensorContractionMapper.h +./unsupported/Eigen/CXX11/src/Tensor/TensorCostModel.h +./unsupported/Eigen/CXX11/src/Tensor/TensorForcedEval.h +./unsupported/Eigen/CXX11/src/Tensor/TensorGlobalFunctions.h +./unsupported/Eigen/CXX11/src/Tensor/TensorContractionSycl.h +./unsupported/Eigen/CXX11/src/Tensor/TensorImagePatch.h +./unsupported/Eigen/CXX11/src/Tensor/TensorContractionBlocking.h +./unsupported/Eigen/CXX11/src/Tensor/TensorMacros.h +./unsupported/Eigen/CXX11/src/Tensor/TensorDevice.h +./unsupported/Eigen/CXX11/src/Tensor/TensorBroadcasting.h +./unsupported/Eigen/CXX11/src/Tensor/TensorSyclLeafCount.h +./unsupported/Eigen/CXX11/src/Tensor/TensorRandom.h +./unsupported/Eigen/CXX11/src/Tensor/TensorFFT.h +./unsupported/Eigen/CXX11/src/Tensor/TensorFunctors.h +./unsupported/Eigen/CXX11/src/Tensor/TensorContractionGpu.h +./unsupported/Eigen/CXX11/src/Tensor/TensorForwardDeclarations.h +./unsupported/Eigen/CXX11/src/Tensor/TensorDimensionList.h +./unsupported/Eigen/CXX11/src/Tensor/TensorConversion.h +./unsupported/Eigen/CXX11/src/Tensor/TensorEvalTo.h +./unsupported/Eigen/CXX11/src/Tensor/TensorAssign.h +./unsupported/Eigen/CXX11/src/Tensor/TensorLayoutSwap.h +./unsupported/Eigen/CXX11/src/FixedPoint/MatMatProduct.h +./unsupported/Eigen/CXX11/src/FixedPoint/MatMatProductNEON.h +./unsupported/Eigen/CXX11/src/FixedPoint/MatVecProduct.h +./unsupported/Eigen/CXX11/src/FixedPoint/FixedPointTypes.h +./unsupported/Eigen/CXX11/src/FixedPoint/MatMatProductAVX2.h +./unsupported/bench/bench_svd.cpp +./unsupported/test/cxx11_tensor_image_patch_sycl.cpp +./unsupported/test/cxx11_tensor_expr.cpp +./unsupported/test/FFTW.cpp +./unsupported/test/cxx11_tensor_reverse_sycl.cpp +./unsupported/test/cxx11_tensor_comparisons.cpp +./unsupported/test/cxx11_tensor_intdiv.cpp +./unsupported/test/autodiff.cpp +./unsupported/test/cxx11_tensor_executor.cpp +./unsupported/test/cxx11_tensor_reduction.cpp +./unsupported/test/cxx11_tensor_device_sycl.cpp +./unsupported/test/minres.cpp +./unsupported/test/cxx11_tensor_striding.cpp +./unsupported/test/cxx11_tensor_chipping.cpp +./unsupported/test/cxx11_tensor_convolution_sycl.cpp +./unsupported/test/openglsupport.cpp +./unsupported/test/cxx11_tensor_ifft.cpp +./unsupported/test/polynomialutils.cpp +./unsupported/test/cxx11_tensor_block_access.cpp +./unsupported/test/cxx11_tensor_block_eval.cpp +./unsupported/test/cxx11_tensor_block_io.cpp +./unsupported/test/cxx11_tensor_morphing.cpp +./unsupported/test/cxx11_tensor_casts.cpp +./unsupported/test/cxx11_tensor_shuffling_sycl.cpp +./unsupported/test/cxx11_tensor_morphing_sycl.cpp +./unsupported/test/forward_adolc.cpp +./unsupported/test/cxx11_tensor_layout_swap.cpp +./unsupported/test/cxx11_tensor_move.cpp +./unsupported/test/EulerAngles.cpp +./unsupported/test/cxx11_tensor_trace.cpp +./unsupported/test/alignedvector3.cpp +./unsupported/test/cxx11_tensor_lvalue.cpp +./unsupported/test/cxx11_tensor_argmax.cpp +./unsupported/test/cxx11_tensor_broadcast_sycl.cpp +./unsupported/test/autodiff_scalar.cpp +./unsupported/test/sparse_extra.cpp +./unsupported/test/cxx11_tensor_of_strings.cpp +./unsupported/test/cxx11_tensor_empty.cpp +./unsupported/test/cxx11_tensor_patch.cpp +./unsupported/test/cxx11_tensor_sycl.cpp +./unsupported/test/cxx11_tensor_forced_eval_sycl.cpp +./unsupported/test/cxx11_tensor_inflation_sycl.cpp +./unsupported/test/BVH.cpp +./unsupported/test/cxx11_tensor_generator.cpp +./unsupported/test/cxx11_meta.cpp +./unsupported/test/matrix_functions.h +./unsupported/test/kronecker_product.cpp +./unsupported/test/matrix_function.cpp +./unsupported/test/cxx11_tensor_thread_pool.cpp +./unsupported/test/cxx11_non_blocking_thread_pool.cpp +./unsupported/test/cxx11_tensor_fft.cpp +./unsupported/test/cxx11_tensor_assign.cpp +./unsupported/test/cxx11_tensor_simple.cpp +./unsupported/test/cxx11_tensor_of_complex.cpp +./unsupported/test/cxx11_tensor_inflation.cpp +./unsupported/test/cxx11_tensor_map.cpp +./unsupported/test/cxx11_tensor_shuffling.cpp +./unsupported/test/cxx11_tensor_padding.cpp +./unsupported/test/cxx11_tensor_argmax_sycl.cpp +./unsupported/test/matrix_square_root.cpp +./unsupported/test/dgmres.cpp +./unsupported/test/cxx11_tensor_custom_op_sycl.cpp +./unsupported/test/cxx11_tensor_reduction_sycl.cpp +./unsupported/test/cxx11_runqueue.cpp +./unsupported/test/cxx11_tensor_const.cpp +./unsupported/test/matrix_power.cpp +./unsupported/test/cxx11_tensor_contraction.cpp +./unsupported/test/cxx11_tensor_random.cpp +./unsupported/test/cxx11_tensor_volume_patch_sycl.cpp +./unsupported/test/cxx11_tensor_contract_sycl.cpp +./unsupported/test/cxx11_tensor_math.cpp +./unsupported/test/splines.cpp +./unsupported/test/cxx11_tensor_ref.cpp +./unsupported/test/cxx11_tensor_concatenation_sycl.cpp +./unsupported/test/gmres.cpp +./unsupported/test/cxx11_tensor_fixed_size.cpp +./unsupported/test/cxx11_tensor_custom_op.cpp +./unsupported/test/cxx11_tensor_generator_sycl.cpp +./unsupported/test/cxx11_tensor_uint128.cpp +./unsupported/test/cxx11_tensor_builtins_sycl.cpp +./unsupported/test/polynomialsolver.cpp +./unsupported/test/cxx11_tensor_concatenation.cpp +./unsupported/test/cxx11_tensor_broadcasting.cpp +./unsupported/test/cxx11_tensor_convolution.cpp +./unsupported/test/cxx11_tensor_forced_eval.cpp +./unsupported/test/levenberg_marquardt.cpp +./unsupported/test/cxx11_tensor_reverse.cpp +./unsupported/test/cxx11_tensor_notification.cpp +./unsupported/test/cxx11_tensor_patch_sycl.cpp +./unsupported/test/cxx11_tensor_image_patch.cpp +./unsupported/test/cxx11_tensor_scan.cpp +./unsupported/test/cxx11_tensor_padding_sycl.cpp +./unsupported/test/cxx11_tensor_index_list.cpp +./unsupported/test/cxx11_tensor_io.cpp +./unsupported/test/cxx11_tensor_mixed_indices.cpp +./unsupported/test/cxx11_tensor_striding_sycl.cpp +./unsupported/test/cxx11_tensor_of_const_values.cpp +./unsupported/test/cxx11_tensor_symmetry.cpp +./unsupported/test/cxx11_tensor_custom_index.cpp +./unsupported/test/cxx11_tensor_chipping_sycl.cpp +./unsupported/test/cxx11_tensor_roundings.cpp +./unsupported/test/matrix_exponential.cpp +./unsupported/test/cxx11_eventcount.cpp +./unsupported/test/special_functions.cpp +./unsupported/test/cxx11_tensor_dimension.cpp +./unsupported/test/cxx11_tensor_layout_swap_sycl.cpp +./lapack/eigenvalues.cpp +./lapack/single.cpp +./lapack/svd.cpp +./lapack/complex_single.cpp +./lapack/lu.cpp +./lapack/double.cpp +./lapack/complex_double.cpp +./lapack/cholesky.cpp +./lapack/lapack_common.h +./blas/level2_impl.h +./blas/PackedTriangularMatrixVector.h +./blas/level3_impl.h +./blas/complex_double.cpp +./blas/common.h +./blas/GeneralRank1Update.h +./blas/double.cpp +./blas/complex_single.cpp +./blas/Rank2Update.h +./blas/level1_impl.h +./blas/level2_real_impl.h +./blas/level1_real_impl.h +./blas/single.cpp +./blas/PackedSelfadjointProduct.h +./blas/BandTriangularSolver.h +./blas/level2_cplx_impl.h +./blas/PackedTriangularSolverVector.h +./blas/level1_cplx_impl.h +./bench/analyze-blocking-sizes.cpp +./bench/BenchTimer.h +./bench/spbench/spbenchsolver.h +./bench/spbench/spbenchstyle.h +./bench/benchFFT.cpp +./bench/eig33.cpp +./bench/benchmark-blocking-sizes.cpp +./demos/opengl/quaternion_demo.cpp +./demos/opengl/camera.h +./demos/opengl/gpuhelper.cpp +./demos/opengl/gpuhelper.h +./demos/opengl/icosphere.cpp +./demos/opengl/quaternion_demo.h +./demos/opengl/trackball.h +./demos/opengl/icosphere.h +./demos/opengl/camera.cpp +./demos/opengl/trackball.cpp +./demos/mix_eigen_and_c/binary_library.h +./demos/mix_eigen_and_c/binary_library.cpp +./demos/mandelbrot/mandelbrot.cpp +./demos/mandelbrot/mandelbrot.h + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + +---------------------------------------------------------------------- +Following applies to: +./doc/UsingIntelMKL.dox +./doc/UsingIntelMKL.dox +./Eigen/src/Eigenvalues/ComplexSchur_MKL.h +./Eigen/src/Eigenvalues/ComplexSchur_MKL.h +./Eigen/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h +./Eigen/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h +./Eigen/src/Eigenvalues/RealSchur_MKL.h +./Eigen/src/Eigenvalues/RealSchur_MKL.h +./Eigen/src/LU/arch/Inverse_SSE.h +./Eigen/src/LU/arch/Inverse_SSE.h +./Eigen/src/LU/PartialPivLU_MKL.h +./Eigen/src/LU/PartialPivLU_MKL.h +./Eigen/src/QR/HouseholderQR_MKL.h +./Eigen/src/QR/HouseholderQR_MKL.h +./Eigen/src/QR/ColPivHouseholderQR_MKL.h +./Eigen/src/QR/ColPivHouseholderQR_MKL.h +./Eigen/src/SVD/JacobiSVD_MKL.h +./Eigen/src/SVD/JacobiSVD_MKL.h +./Eigen/src/PardisoSupport/PardisoSupport.h +./Eigen/src/PardisoSupport/PardisoSupport.h +./Eigen/src/Core/Assign_MKL.h +./Eigen/src/Core/Assign_MKL.h +./Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h +./Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h +./Eigen/src/Core/products/GeneralMatrixVector_MKL.h +./Eigen/src/Core/products/GeneralMatrixVector_MKL.h +./Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h +./Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h +./Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h +./Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h +./Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h +./Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h +./Eigen/src/Core/products/TriangularMatrixVector_MKL.h +./Eigen/src/Core/products/TriangularMatrixVector_MKL.h +./Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h +./Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h +./Eigen/src/Core/products/TriangularSolverMatrix_MKL.h +./Eigen/src/Core/products/TriangularSolverMatrix_MKL.h +./Eigen/src/Core/util/MKL_support.h +./Eigen/src/Core/util/MKL_support.h +./Eigen/src/Cholesky/LLT_MKL.h +./Eigen/src/Cholesky/LLT_MKL.h + +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. * + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. * Neither the name of Intel Corporation nor the + names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +---------------------------------------------------------------------- +Following applies to: +./unsupported/Eigen/src/LevenbergMarquardt/LevenbergMarquardt.h +./unsupported/Eigen/src/LevenbergMarquardt/LMcovar.h +./unsupported/Eigen/src/LevenbergMarquardt/LMonestep.h +./unsupported/Eigen/src/LevenbergMarquardt/LMpar.h +./unsupported/Eigen/src/LevenbergMarquardt/LMqrsolv.h + +Minpack Copyright Notice (1999) University of Chicago. All rights +reserved + +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the +following conditions are met: + +1. Redistributions of source code must retain the above +copyright notice, this list of conditions and the following +disclaimer. + +2. Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following +disclaimer in the documentation and/or other materials +provided with the distribution. + +3. The end-user documentation included with the +redistribution, if any, must include the following +acknowledgment: + + "This product includes software developed by the + University of Chicago, as Operator of Argonne National + Laboratory. + +Alternately, this acknowledgment may appear in the software +itself, if and wherever such third-party acknowledgments +normally appear. + +4. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" +WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE +UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND +THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE +OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY +OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR +USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF +THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) +DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION +UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL +BE CORRECTED. + +5. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT +HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF +ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, +INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF +ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF +PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER +SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT +(INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE, +EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE +POSSIBILITY OF SUCH LOSS OR DAMAGES. + + +Copyright (c) 1992-2013 The University of Tennessee and The University + of Tennessee Research Foundation. All rights + reserved. +Copyright (c) 2000-2013 The University of California Berkeley. All + rights reserved. +Copyright (c) 2006-2013 The University of Colorado Denver. All rights + reserved. + +Following applies to: +./lapack/*.c + +$COPYRIGHT$ + +Additional copyrights may follow + +$HEADER$ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer listed + in this license in the documentation and/or other materials + provided with the distribution. + +- Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +The copyright holders provide no reassurances that the source code +provided does not infringe any patent, copyright, or any other +intellectual property rights of third parties. The copyright holders +disclaim any liability to any recipient for claims brought against +recipient by any third party for infringement of that parties +intellectual property rights. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +FImmutableSortedDictionary +Copyright (c) 2012 Mads Hartmann Jensen + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +FP16 +The MIT License (MIT) + +Copyright (c) 2017 Facebook Inc. +Copyright (c) 2017 Georgia Institute of Technology + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Firebase for iOS + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +Firebase for iOS + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +Firebase for iOS + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +FlatBuffers + + 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 2014 Google 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. + +GDAL + +GDAL/OGR Licensing +================== + +This file attempts to include all licenses that apply within the GDAL/OGR +source tree, in particular any that are supposed to be exposed to the end user +for credit requirements for instance. The contents of this file can be +displayed from GDAL commandline utilities using the --license commandline +switch. + + +GDAL/OGR General +---------------- + +In general GDAL/OGR is licensed under an MIT/X style license with the +following terms: + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + +gdal/frmts/gtiff/tif_float.c +---------------------------- + +Copyright (c) 2002, Industrial Light & Magic, a division of Lucas +Digital Ltd. LLC + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: +* Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. +* Neither the name of Industrial Light & Magic nor the names of +its contributors may be used to endorse or promote products derived +from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +gdal/frmts/hdf4/hdf-eos/* +------------------------ + + Copyright (C) 1996 Hughes and Applied Research Corporation + + Permission to use, modify, and distribute this software and its documentation + for any purpose without fee is hereby granted, provided that the above + copyright notice appear in all copies and that both that copyright notice and + this permission notice appear in supporting documentation. + + +gdal/frmts/pcraster/libcsf +-------------------------- + +Copyright (c) 1997-2003, Utrecht University +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +* Neither the name of Utrecht University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +GTMHTTPServer.m +Based a little on HTTPServer, part of the CocoaHTTPServer sample code found at +https://opensource.apple.com/source/HTTPServer/HTTPServer-11/CocoaHTTPServer/ +License for the CocoaHTTPServer sample code: + +Software License Agreement (BSD License) + +Copyright (c) 2011, Deusty, LLC +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Neither the name of Deusty nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of Deusty, LLC. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +GULAppEnvironmentUtil.m +The following copyright from Landon J. Fuller applies to the isAppEncrypted function. + +Copyright (c) 2017 Landon J. Fuller +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software +and associated documentation files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Comment from iPhone Dev Wiki +Crack Prevention: +App Store binaries are signed by both their developer and Apple. This encrypts the binary so +that decryption keys are needed in order to make the binary readable. When iOS executes the +binary, the decryption keys are used to decrypt the binary into a readable state where it is +then loaded into memory and executed. iOS can tell the encryption status of a binary via the +cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If cryptid is a non-zero +value then the binary is encrypted. + +'Cracking' works by letting the kernel decrypt the binary then siphoning the decrypted data into +a new binary file, resigning, and repackaging. This will only work on jailbroken devices as +codesignature validation has been removed. Resigning takes place because while the codesignature +doesn't have to be valid thanks to the jailbreak, it does have to be in place unless you have +AppSync or similar to disable codesignature checks. + +More information at Landon Fuller's blog + +Google APIs Client Library for Objective-C for REST + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Google Runtime Environment + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. +^L + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. +^L + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. +^L + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. +^L + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. +^L + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. +^L + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. +^L + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS +^L + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + + +Google Toolbox for Mac + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Google Utilities + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +Halide +Copyright (c) 2012 MIT CSAIL + +Developed by: + + The Halide team + MIT CSAIL + http://halide-lang.org + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +HighwayHash + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +ICU4C +COPYRIGHT AND PERMISSION NOTICE (ICU 58 and later) + +Copyright © 1991-2019 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in https://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that either +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, or +(b) this copyright and permission notice appear in associated +Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. + +--------------------- + +Third-Party Software Licenses + +This section contains third-party software notices and/or additional +terms for licensed third-party software components included within ICU +libraries. + +1. ICU License - ICU 1.8.1 to ICU 57.1 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1995-2016 International Business Machines Corporation and others +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY +SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER +RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +All trademarks and registered trademarks mentioned herein are the +property of their respective owners. + +2. Chinese/Japanese Word Break Dictionary Data (cjdict.txt) + + # The Google Chrome software developed by Google is licensed under + # the BSD license. Other software included in this distribution is + # provided under other licenses, as set forth below. + # + # The BSD License + # http://opensource.org/licenses/bsd-license.php + # Copyright (C) 2006-2008, Google Inc. + # + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions are met: + # + # Redistributions of source code must retain the above copyright notice, + # this list of conditions and the following disclaimer. + # Redistributions in binary form must reproduce the above + # copyright notice, this list of conditions and the following + # disclaimer in the documentation and/or other materials provided with + # the distribution. + # Neither the name of Google Inc. nor the names of its + # contributors may be used to endorse or promote products derived from + # this software without specific prior written permission. + # + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + # + # + # The word list in cjdict.txt are generated by combining three word lists + # listed below with further processing for compound word breaking. The + # frequency is generated with an iterative training against Google web + # corpora. + # + # * Libtabe (Chinese) + # - https://sourceforge.net/project/?group_id=1519 + # - Its license terms and conditions are shown below. + # + # * IPADIC (Japanese) + # - http://chasen.aist-nara.ac.jp/chasen/distribution.html + # - Its license terms and conditions are shown below. + # + # ---------COPYING.libtabe ---- BEGIN-------------------- + # + # /* + # * Copyright (c) 1999 TaBE Project. + # * Copyright (c) 1999 Pai-Hsiang Hsiao. + # * All rights reserved. + # * + # * Redistribution and use in source and binary forms, with or without + # * modification, are permitted provided that the following conditions + # * are met: + # * + # * . Redistributions of source code must retain the above copyright + # * notice, this list of conditions and the following disclaimer. + # * . Redistributions in binary form must reproduce the above copyright + # * notice, this list of conditions and the following disclaimer in + # * the documentation and/or other materials provided with the + # * distribution. + # * . Neither the name of the TaBE Project nor the names of its + # * contributors may be used to endorse or promote products derived + # * from this software without specific prior written permission. + # * + # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # * OF THE POSSIBILITY OF SUCH DAMAGE. + # */ + # + # /* + # * Copyright (c) 1999 Computer Systems and Communication Lab, + # * Institute of Information Science, Academia + # * Sinica. All rights reserved. + # * + # * Redistribution and use in source and binary forms, with or without + # * modification, are permitted provided that the following conditions + # * are met: + # * + # * . Redistributions of source code must retain the above copyright + # * notice, this list of conditions and the following disclaimer. + # * . Redistributions in binary form must reproduce the above copyright + # * notice, this list of conditions and the following disclaimer in + # * the documentation and/or other materials provided with the + # * distribution. + # * . Neither the name of the Computer Systems and Communication Lab + # * nor the names of its contributors may be used to endorse or + # * promote products derived from this software without specific + # * prior written permission. + # * + # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # * OF THE POSSIBILITY OF SUCH DAMAGE. + # */ + # + # Copyright 1996 Chih-Hao Tsai @ Beckman Institute, + # University of Illinois + # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4 + # + # ---------------COPYING.libtabe-----END-------------------------------- + # + # + # ---------------COPYING.ipadic-----BEGIN------------------------------- + # + # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science + # and Technology. All Rights Reserved. + # + # Use, reproduction, and distribution of this software is permitted. + # Any copy of this software, whether in its original form or modified, + # must include both the above copyright notice and the following + # paragraphs. + # + # Nara Institute of Science and Technology (NAIST), + # the copyright holders, disclaims all warranties with regard to this + # software, including all implied warranties of merchantability and + # fitness, in no event shall NAIST be liable for + # any special, indirect or consequential damages or any damages + # whatsoever resulting from loss of use, data or profits, whether in an + # action of contract, negligence or other tortuous action, arising out + # of or in connection with the use or performance of this software. + # + # A large portion of the dictionary entries + # originate from ICOT Free Software. The following conditions for ICOT + # Free Software applies to the current dictionary as well. + # + # Each User may also freely distribute the Program, whether in its + # original form or modified, to any third party or parties, PROVIDED + # that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear + # on, or be attached to, the Program, which is distributed substantially + # in the same form as set out herein and that such intended + # distribution, if actually made, will neither violate or otherwise + # contravene any of the laws and regulations of the countries having + # jurisdiction over the User or the intended distribution itself. + # + # NO WARRANTY + # + # The program was produced on an experimental basis in the course of the + # research and development conducted during the project and is provided + # to users as so produced on an experimental basis. Accordingly, the + # program is provided without any warranty whatsoever, whether express, + # implied, statutory or otherwise. The term "warranty" used herein + # includes, but is not limited to, any warranty of the quality, + # performance, merchantability and fitness for a particular purpose of + # the program and the nonexistence of any infringement or violation of + # any right of any third party. + # + # Each user of the program will agree and understand, and be deemed to + # have agreed and understood, that there is no warranty whatsoever for + # the program and, accordingly, the entire risk arising from or + # otherwise connected with the program is assumed by the user. + # + # Therefore, neither ICOT, the copyright holder, or any other + # organization that participated in or was otherwise related to the + # development of the program and their respective officials, directors, + # officers and other employees shall be held liable for any and all + # damages, including, without limitation, general, special, incidental + # and consequential damages, arising out of or otherwise in connection + # with the use or inability to use the program or any product, material + # or result produced or otherwise obtained by using the program, + # regardless of whether they have been advised of, or otherwise had + # knowledge of, the possibility of such damages at any time during the + # project or thereafter. Each user will be deemed to have agreed to the + # foregoing by his or her commencement of use of the program. The term + # "use" as used herein includes, but is not limited to, the use, + # modification, copying and distribution of the program and the + # production of secondary products from the program. + # + # In the case where the program, whether in its original form or + # modified, was distributed or delivered to or received by a user from + # any person, organization or entity other than ICOT, unless it makes or + # grants independently of ICOT any specific warranty to the user in + # writing, such person, organization or entity, will also be exempted + # from and not be held liable to the user for any such damages as noted + # above as far as the program is concerned. + # + # ---------------COPYING.ipadic-----END---------------------------------- + +3. Lao Word Break Dictionary Data (laodict.txt) + + # Copyright (c) 2013 International Business Machines Corporation + # and others. All Rights Reserved. + # + # Project: http://code.google.com/p/lao-dictionary/ + # Dictionary: http://lao-dictionary.googlecode.com/git/Lao-Dictionary.txt + # License: http://lao-dictionary.googlecode.com/git/Lao-Dictionary-LICENSE.txt + # (copied below) + # + # This file is derived from the above dictionary, with slight + # modifications. + # ---------------------------------------------------------------------- + # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell. + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, + # are permitted provided that the following conditions are met: + # + # + # Redistributions of source code must retain the above copyright notice, this + # list of conditions and the following disclaimer. Redistributions in + # binary form must reproduce the above copyright notice, this list of + # conditions and the following disclaimer in the documentation and/or + # other materials provided with the distribution. + # + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # OF THE POSSIBILITY OF SUCH DAMAGE. + # -------------------------------------------------------------------------- + +4. Burmese Word Break Dictionary Data (burmesedict.txt) + + # Copyright (c) 2014 International Business Machines Corporation + # and others. All Rights Reserved. + # + # This list is part of a project hosted at: + # github.com/kanyawtech/myanmar-karen-word-lists + # + # -------------------------------------------------------------------------- + # Copyright (c) 2013, LeRoy Benjamin Sharon + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: Redistributions of source code must retain the above + # copyright notice, this list of conditions and the following + # disclaimer. Redistributions in binary form must reproduce the + # above copyright notice, this list of conditions and the following + # disclaimer in the documentation and/or other materials provided + # with the distribution. + # + # Neither the name Myanmar Karen Word Lists, nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + # SUCH DAMAGE. + # -------------------------------------------------------------------------- + +5. Time Zone Database + + ICU uses the public domain data and code derived from Time Zone +Database for its time zone support. The ownership of the TZ database +is explained in BCP 175: Procedure for Maintaining the Time Zone +Database section 7. + + # 7. Database Ownership + # + # The TZ database itself is not an IETF Contribution or an IETF + # document. Rather it is a pre-existing and regularly updated work + # that is in the public domain, and is intended to remain in the + # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do + # not apply to the TZ Database or contributions that individuals make + # to it. Should any claims be made and substantiated against the TZ + # Database, the organization that is providing the IANA + # Considerations defined in this RFC, under the memorandum of + # understanding with the IETF, currently ICANN, may act in accordance + # with all competent court orders. No ownership claims will be made + # by ICANN or the IETF Trust on the database or the code. Any person + # making a contribution to the database or code waives all rights to + # future claims in that contribution or in the TZ Database. + +6. Google double-conversion + +Copyright 2006-2011, the V8 project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Khronos OpenGL headers +OpenGL Licenses + +Component Location Primary Author License +---------------------------------------------------------------------------- +standard headers gl/ The Khronos Group, MIT, SGI, and + Brian Paul, Apache 2.0 + Silicon Graphics + +EGL utilities util/ Google Apache 2.0 + +------------------------------------- + +Copyright The Khronos Group Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and/or associated documentation files (the +"Materials"), to deal in the Materials without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Materials, and to +permit persons to whom the Materials are furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Materials. + +THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + + +SGI FREE SOFTWARE LICENSE B +(Version 2.0, Sept. 18, 2008) + +Copyright (C) [dates of first publication] Silicon Graphics, Inc. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice including the dates of first publication and either +this permission notice or a reference to http://oss.sgi.com/projects/FreeB/ +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON +GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Silicon Graphics, Inc. shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Silicon +Graphics, Inc. + + + 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. + +LAPACK +Copyright (c) 1992-2011 The University of Tennessee and The University + of Tennessee Research Foundation. All rights + reserved. +Copyright (c) 2000-2011 The University of California Berkeley. All + rights reserved. +Copyright (c) 2006-2012 The University of Colorado Denver. All rights + reserved. + +$COPYRIGHT$ + +Additional copyrights may follow + +$HEADER$ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer listed + in this license in the documentation and/or other materials + provided with the distribution. + +- Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +The copyright holders provide no reassurances that the source code +provided does not infringe any patent, copyright, or any other +intellectual property rights of third parties. The copyright holders +disclaim any liability to any recipient for claims brought against +recipient by any third party for infringement of that parties +intellectual property rights. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Leptonica +/*====================================================================* + - Copyright (C) 2001 Leptonica. All rights reserved. + - + - Redistribution and use in source and binary forms, with or without + - modification, are permitted provided that the following conditions + - are met: + - 1. Redistributions of source code must retain the above copyright + - notice, this list of conditions and the following disclaimer. + - 2. Redistributions in binary form must reproduce the above + - copyright notice, this list of conditions and the following + - disclaimer in the documentation and/or other materials + - provided with the distribution. + - + - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY + - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *====================================================================*/ + + +Libxml2 +Libxml2, an XML C Parser + +Except where otherwise noted in the source code (e.g. the files hash.c, +list.c and the trio files, which are covered by a similar licence but +with different Copyright notices) all the files are: + + Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +-------------------------------------------------------------------- + +Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND +CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + +Author: breese@users.sourceforge.net + +(taken from hash.c) + +-------------------------------------------------------------------- + + Copyright (C) 2000 Gary Pennington and Daniel Veillard. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND +CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + +Author: Gary.Pennington@uk.sun.com + +(taken from list.c) + +-------------------------------------------------------------------- + +Copyright (C) 1998 Bjorn Reese and Daniel Stenberg. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND +CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + +(taken from trio.h and trio.c) + +-------------------------------------------------------------------- + +Copyright (C) 2001 Bjorn Reese + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND +CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + +(taken from triodef.h, trionan.h, and trionan.c) + +-------------------------------------------------------------------- + +Copyright (C) 2000 Bjorn Reese and Daniel Stenberg. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND +CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + +(taken from triop.h) + +-------------------------------------------------------------------- + +Copyright (C) 2001 Bjorn Reese and Daniel Stenberg. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND +CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + +(taken from triostr.h and triostr.c) + +************************************************************************* + +http://ctrio.sourceforge.net/ + +************************************************************************* + +Little CMS +Little CMS +Copyright (c) 1998-2011 Marti Maria Saguer + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +MARISA v0.2.0 +Copyright (c) 2010-2012, Susumu Yata +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of the nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +NCurses +Copyright (c) 1998-2017,2018 Free Software Foundation, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, distribute with modifications, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name(s) of the above copyright +holders shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without prior written +authorization. + + +Nano Protocol Buffers +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. + +Nanopb +Copyright (c) 2011 Petteri Aimonen + +This software is provided 'as-is', without any express or +implied warranty. In no event will the authors be held liable +for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source + distribution. + +Ooura FFT +Copyright(C) 1997,2001 Takuya OOURA (email: ooura@kurims.kyoto-u.ac.jp). +You may use, copy, modify this code for any purpose and +without fee. You may distribute this ORIGINAL package. + +OpenBLAS +Copyright (c) 2011-2014, The OpenBLAS Project +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. Neither the name of the OpenBLAS project nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +OpenCV +IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + +By downloading, copying, installing or using the software you agree to this license. +If you do not agree to this license, do not download, install, +copy or use the software. + + + Intel License Agreement + For Open Source Computer Vision Library + +Copyright (C) 2000, 2001, Intel Corporation, all rights reserved. +Copyright (C) 2013, OpenCV Foundation, all rights reserved. +Third party copyrights are property of their respective owners. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistribution's of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistribution's in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * The name of Intel Corporation may not be used to endorse or promote products + derived from this software without specific prior written permission. + +This software is provided by the copyright holders and contributors "as is" and +any express or implied warranties, including, but not limited to, the implied +warranties of merchantability and fitness for a particular purpose are disclaimed. +In no event shall the Intel Corporation or contributors be liable for any direct, +indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or services; +loss of use, data, or profits; or business interruption) however caused +and on any theory of liability, whether in contract, strict liability, +or tort (including negligence or otherwise) arising in any way out of +the use of this software, even if advised of the possibility of such damage. + +OpenCVX +By downloading, copying, installing or using the software you agree to this license. +If you do not agree to this license, do not download, install, +copy or use the software. + + + License Agreement + For Open Source Computer Vision Library + (3-clause BSD License) + +Copyright (C) 2000-2016, Intel Corporation, all rights reserved. +Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. +Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved. +Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved. +Copyright (C) 2015-2016, Itseez Inc., all rights reserved. +Third party copyrights are property of their respective owners. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the names of the copyright holders nor the names of the contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +This software is provided by the copyright holders and contributors "as is" and +any express or implied warranties, including, but not limited to, the implied +warranties of merchantability and fitness for a particular purpose are disclaimed. +In no event shall copyright holders or contributors be liable for any direct, +indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or services; +loss of use, data, or profits; or business interruption) however caused +and on any theory of liability, whether in contract, strict liability, +or tort (including negligence or otherwise) arising in any way out of +the use of this software, even if advised of the possibility of such damage. + +OpenCensus + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +PCRE +PCRE LICENCE +------------ + +PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + +Release 8 of PCRE is distributed under the terms of the "BSD" licence, as +specified below. The documentation for PCRE, supplied in the "doc" +directory, is distributed under the same terms as the software itself. The data +in the testdata directory is not copyrighted and is in the public domain. + +The basic library functions are written in C and are freestanding. Also +included in the distribution is a set of C++ wrapper functions, and a +just-in-time compiler that can be used to optimize pattern matching. These +are both optional features that can be omitted when the library is built. + + +THE BASIC LIBRARY FUNCTIONS +--------------------------- + +Written by: Philip Hazel +Email local part: ph10 +Email domain: cam.ac.uk + +University of Cambridge Computing Service, +Cambridge, England. + +Copyright (c) 1997-2017 University of Cambridge +All rights reserved. + + +PCRE JUST-IN-TIME COMPILATION SUPPORT +------------------------------------- + +Written by: Zoltan Herczeg +Email local part: hzmester +Emain domain: freemail.hu + +Copyright(c) 2010-2017 Zoltan Herczeg +All rights reserved. + + +STACK-LESS JUST-IN-TIME COMPILER +-------------------------------- + +Written by: Zoltan Herczeg +Email local part: hzmester +Emain domain: freemail.hu + +Copyright(c) 2009-2017 Zoltan Herczeg +All rights reserved. + + +THE C++ WRAPPER FUNCTIONS +------------------------- + +Contributed by: Google Inc. + +Copyright (c) 2007-2012, Google Inc. +All rights reserved. + + +THE "BSD" LICENCE +----------------- + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the name of Google + Inc. nor the names of their contributors may be used to endorse or + promote products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +End + +PNG +COPYRIGHT NOTICE, DISCLAIMER, and LICENSE +========================================= + +PNG Reference Library License version 2 +--------------------------------------- + + * Copyright (c) 1995-2019 The PNG Reference Library Authors. + * Copyright (c) 2018-2019 Cosmin Truta. + * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. + * Copyright (c) 1996-1997 Andreas Dilger. + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + +The software is supplied "as is", without warranty of any kind, +express or implied, including, without limitation, the warranties +of merchantability, fitness for a particular purpose, title, and +non-infringement. In no event shall the Copyright owners, or +anyone distributing the software, be liable for any damages or +other liability, whether in contract, tort or otherwise, arising +from, out of, or in connection with the software, or the use or +other dealings in the software, even if advised of the possibility +of such damage. + +Permission is hereby granted to use, copy, modify, and distribute +this software, or portions hereof, for any purpose, without fee, +subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you + use this software in a product, an acknowledgment in the product + documentation would be appreciated, but is not required. + + 2. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + + +PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35) +----------------------------------------------------------------------- + +libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are +Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are +derived from libpng-1.0.6, and are distributed according to the same +disclaimer and license as libpng-1.0.6 with the following individuals +added to the list of Contributing Authors: + + Simon-Pierre Cadieux + Eric S. Raymond + Mans Rullgard + Cosmin Truta + Gilles Vollant + James Yu + Mandar Sahastrabuddhe + Google Inc. + Vadim Barkov + +and with the following additions to the disclaimer: + + There is no warranty against interference with your enjoyment of + the library or against infringement. There is no warranty that our + efforts or the library will fulfill any of your particular purposes + or needs. This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and effort is + with the user. + +Some files in the "contrib" directory and some configure-generated +files that are distributed with libpng have other copyright owners, and +are released under other open source licenses. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from +libpng-0.96, and are distributed according to the same disclaimer and +license as libpng-0.96, with the following individuals added to the +list of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, +and are distributed according to the same disclaimer and license as +libpng-0.88, with the following individuals added to the list of +Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +Some files in the "scripts" directory have other copyright owners, +but are released under this license. + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing +Authors and Group 42, Inc. disclaim all warranties, expressed or +implied, including, without limitation, the warranties of +merchantability and of fitness for any purpose. The Contributing +Authors and Group 42, Inc. assume no liability for direct, indirect, +incidental, special, exemplary, or consequential damages, which may +result from the use of the PNG Reference Library, even if advised of +the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + + 1. The origin of this source code must not be misrepresented. + + 2. Altered versions must be plainly marked as such and must not + be misrepresented as being the original source. + + 3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, +without fee, and encourage the use of this source code as a component +to supporting the PNG file format in commercial products. If you use +this source code in a product, acknowledgment is not required but would +be appreciated. + +Protocol Buffers +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. + +RE2 +// Copyright (c) 2009 The RE2 Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Skia +// Copyright (c) 2011 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------------------- + +SocketRocket +Copyright 2012 Square 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. + +$OpenBSD: base64.c,v 1.5 2006/10/21 09:55:03 otto Exp $ + +Copyright (c) 1996 by Internet Software Consortium. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS +ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE +CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +Portions Copyright (c) 1995 by International Business Machines, Inc. + +International Business Machines, Inc. (hereinafter called IBM) grants +permission under its copyrights to use, copy, modify, and distribute this +Software with or without fee, provided that the above copyright notice and +all paragraphs of this notice appear in all copies, and that the name of IBM +not be used in connection with the marketing of any product incorporating +the Software or modifications thereof, without specific, written prior +permission. + +To the extent it has a right to do so, IBM grants an immunity from suit +under its patents, if any, for the use, sale or manufacture of products to +the extent that such products are used for performing Domain Name System +dynamic updates in TCP/IP networks by means of the Software. No immunity is +granted for any product per se or for any other function of any product. + +THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, +DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING +OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN +IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + +TCMalloc + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://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. + +TensorFlow +Copyright 2019 The TensorFlow Authors. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +UTF +UTF-8 Library + +The authors of this software are Rob Pike and Ken Thompson. + Copyright (c) 1998-2002 by Lucent Technologies. +Permission to use, copy, modify, and distribute this software for any +purpose without fee is hereby granted, provided that this entire notice +is included in all copies of any software which is or includes a copy +or modification of this software and in all copies of the supporting +documentation for such software. +THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED +WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY +REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY +OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + +Unsmear + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Web Tracing Framework C++ Bindings +Copyright 2012, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Zippy +Copyright 2011, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=== + +Some of the benchmark data in util/zippy/testdata is licensed differently: + + - fireworks.jpeg is Copyright 2013 Steinar H. Gunderson, and + is licensed under the Creative Commons Attribution 3.0 license + (CC-BY-3.0). See https://creativecommons.org/licenses/by/3.0/ + for more information. + + - kppkn.gtb is taken from the Gaviota chess tablebase set, and + is licensed under the MIT License. See + https://sites.google.com/site/gaviotachessengine/Home/endgame-tablebases-1 + for more information. + + - paper-100k.pdf is an excerpt (bytes 92160 to 194560) from the paper + “Combinatorial Modeling of Chromatin Features Quantitatively Predicts DNA + Replication Timing in _Drosophila_” by Federico Comoglio and Renato Paro, + which is licensed under the CC-BY license. See + http://www.ploscompbiol.org/static/license for more ifnormation. + + - alice29.txt, asyoulik.txt, plrabn12.txt and lcet10.txt are from Project + Gutenberg. The first three have expired copyrights and are in the public + domain; the latter does not have expired copyright, but is still in the + public domain according to the license information + (http://www.gutenberg.org/ebooks/53). + +Zstandard +BSD License + +For Zstandard software + +Copyright (c) 2016-present, Facebook, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +bzip2 + +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2010 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@bzip.org +bzip2/libbzip2 version 1.0.6 of 6 September 2010 + +-------------------------------------------------------------------------- + +c-ares +# c-ares license + +Copyright (c) 2007 - 2018, Daniel Stenberg with many contributors, see AUTHORS +file. + +Copyright 1998 by the Massachusetts Institute of Technology. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, provided that +the above copyright notice appear in all copies and that both that copyright +notice and this permission notice appear in supporting documentation, and that +the name of M.I.T. not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. +M.I.T. makes no representations about the suitability of this software for any +purpose. It is provided "as is" without express or implied warranty. + +double-conversion +Copyright 2006-2011, the V8 project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +firmware +SOLDERPAD HARDWARE LICENSE version 0.51 +This license is based closely on the Apache License Version 2.0, but is not +approved or endorsed by the Apache Foundation. A copy of the non-modified Apache +License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0. + +As this license is not currently OSI or FSF approved, the Licensor permits any +Work licensed under this License, at the option of the Licensee, to be treated +as licensed under the Apache License Version 2.0 (which is so approved). + +This License is licensed under the terms of this License and in particular +clause 7 below (Disclaimer of Warranties) applies in relation to its use. + +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 Rights owner or entity authorized by the Rights 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. + +“Rights” means copyright and any similar right including design right (whether +registered or unregistered), semiconductor topography (mask) rights and database +rights (but excluding Patents and Trademarks). + +“Source” form shall mean the preferred form for making modifications, including +but not limited to source code, net lists, board layouts, CAD files, +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, the instantiation of a hardware design and conversions +to other media types, including intermediate forms such as bytecodes, FPGA +bitstreams, artwork and semiconductor topographies (mask works). + +“Work” shall mean the work of authorship, whether in Source form or other Object +form, made available under the License, as indicated by a Rights 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) or physically connect to or interoperate with the interfaces of, the Work +and Derivative Works thereof. + +“Contribution” shall mean any design or 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 Rights owner or by an individual or Legal Entity +authorized to submit on behalf of the Rights 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 Rights 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 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 license under the Rights to reproduce, +prepare Derivative Works of, publicly display, publicly perform, sublicense, and +distribute the Work and such Derivative Works in Source or Object form and do +anything in relation to the Work as if the Rights did not exist. + +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: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and + +You must cause any modified files to carry prominent notices stating that You +changed the files; and + +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 + +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 +gRPC + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +gemmlowp + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +giflib +The GIFLIB distribution is Copyright (c) 1997 Eric S. Raymond + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +google_front_end +Google-owned, no external contributions. +gtm_session_fetcher + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +half +The MIT License + +Copyright (c) 2012-2017 Christian Rau + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +intrinsics + +LICENSE file has been created for compliance purposes. Not included in original distribution. +License notice found in NEONvsSEE_6.h files. + +---------------------------------------------------------------------------------------------------------------- +//created by Victoria Zhislina, the Senior Application Engineer, Intel Corporation, victoria.zhislina@intel.com + +//*** Copyright (C) 2012-2014 Intel Corporation. All rights reserved. + +//IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + +//By downloading, copying, installing or using the software you agree to this license. +//If you do not agree to this license, do not download, install, copy or use the software. + +// License Agreement +//Redistribution and use in source and binary forms, with or without modification, +//are permitted provided that the following conditions are met: + +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. + +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. + +//This software is provided by the copyright holders and contributors "as is" and +//any express or implied warranties, including, but not limited to, the implied +//warranties of merchantability and fitness for a particular purpose are disclaimed. +//In no event shall the Intel Corporation or contributors be liable for any direct, +//indirect, incidental, special, exemplary, or consequential damages +//(including, but not limited to, procurement of substitute goods or services; +//loss of use, data, or profits; or business interruption) however caused +//and on any theory of liability, whether in contract, strict liability, +//or tort (including negligence or otherwise) arising in any way out of +//the use of this software, even if advised of the possibility of such damage. + +//***************************************************************************************** +// This file is intended to simplify ARM->IA32 porting +// It makes the correspondence between ARM NEON intrinsics (as defined in "arm_neon.h") +// and x86 SSE(up to SSE4.2) intrinsic functions as defined in headers files below +//MMX instruction set is not used due to non availability on x64 systems, +//performance overhead and the necessity to use the EMMS instruction (_mm_empty())for mmx-x87 floating point switching +//***************************************************************************************** + +leveldb +Copyright (c) 2011 The LevelDB Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +libgeotiff + + libgeotiff Licensing + ==================== + +All the source code in this toolkit are either in the public domain, or under +an X style license. In any event it is all considered to be free to use +for any purpose (including commercial software). No credit is required +though some of the code requires that the specific source code modules +retain their existing copyright statements. The CSV files, and other tables +derived from the EPSG coordinate system database are also free to use. In +particular, no part of this code is "copyleft", nor does it imply any +requirement for users to disclose this or their own source code. + +All components not carrying their own copyright message, but distributed +with libgeotiff should be considered to be under the same license as +Niles' code. + +--------- + +Code by Frank Warmerdam has this copyright notice (directly copied from +X Consortium licence): + + * Copyright (c) 1999, Frank Warmerdam + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + +----------- + +Code by Niles Ritter is under this licence: + + * Written By: Niles D. Ritter. + * + * copyright (c) 1995 Niles D. Ritter + * + * Permission granted to use this software, so long as this copyright + * notice accompanies any products derived therefrom. + +----------- + +The EPSG Tables (from which the CSV files, and .inc files are derived) +carried this statement on use of the data (from the EPSG web site): + +Use of the Data + +The user assumes the entire risk as to the accuracy and the use of this +data. The data may be used, copied and distributed subject to the following +conditions: + +1. INFORMATION PROVIDED IN THIS DOCUMENT IS PROVIDED "AS IS" + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +2. The data may be included in any commercial package provided that any + commerciality is based on value added by the provider and not on a value + ascribed to the EPSG dataset which is made available at no charge. The + ownership of the EPSG dataset [OGP] must be acknowledged. + + +3. Subsets of information may be extracted from the dataset. Users are + advised that coordinate reference system and coordinate transformation + descriptions are incomplete unless all elements detailed as essential + in OGP Surveying and Positioning Guidance Note 7-1 annex F are included. + +4. Essential elements should preferably be reproduced as described in the + dataset. Modification of parameter values is permitted as described in + the table below to allow change to the content of the information provided + that numeric equivalence is achieved. Numeric equivalence refers to the + results of geodetic calculations in which the parameters are used, for + example (i) conversion of ellipsoid defining parameters, or (ii) conversion + of parameters between one and two standard parallel projection methods, + or (iii) conversion of parameters between 7-parameter geocentric + transformation methods. + + (EPSG provides a table at this point with some details) + +5. No data that has been modified other than as permitted in these terms + and conditions shall be described as or attributed to the EPSG dataset. + +---------- + +The cmake/*.cmake macros are under the following BSD license. This does +not affect produced binaries or the library. + +-- + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +libjpeg +libjpeg + +(extracted from src/README) + +LEGAL ISSUES +============ + +In plain English: + +1. We don't promise that this software works. (But if you find any bugs, + please let us know!) +2. You can use this software for whatever you want. You don't have to pay us. +3. You may not pretend that you wrote this software. If you use it in a + program, you must acknowledge somewhere in your documentation that + you've used the IJG code. + +In legalese: + +The authors make NO WARRANTY or representation, either express or implied, +with respect to this software, its quality, accuracy, merchantability, or +fitness for a particular purpose. This software is provided "AS IS", and you, +its user, assume the entire risk as to its quality and accuracy. + +This software is copyright (C) 1991-1998, Thomas G. Lane. +All Rights Reserved except as specified below. + +Permission is hereby granted to use, copy, modify, and distribute this +software (or portions thereof) for any purpose, without fee, subject to these +conditions: +(1) If any part of the source code for this software is distributed, then this +README file must be included, with this copyright and no-warranty notice +unaltered; and any additions, deletions, or changes to the original files +must be clearly indicated in accompanying documentation. +(2) If only executable code is distributed, then the accompanying +documentation must state that "this software is based in part on the work of +the Independent JPEG Group". +(3) Permission for use of this software is granted only if the user accepts +full responsibility for any undesirable consequences; the authors accept +NO LIABILITY for damages of any kind. + +These conditions apply to any software derived from or based on the IJG code, +not just to the unmodified library. If you use our work, you ought to +acknowledge us. + +Permission is NOT granted for the use of any IJG author's name or company name +in advertising or publicity relating to this software or products derived from +it. This software may be referred to only as "the Independent JPEG Group's +software". + +We specifically permit and encourage the use of this software as the basis of +commercial products, provided that all warranty or liability claims are +assumed by the product vendor. + + +ansi2knr.c is included in this distribution by permission of L. Peter Deutsch, +sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA. +ansi2knr.c is NOT covered by the above copyright and conditions, but instead +by the usual distribution terms of the Free Software Foundation; principally, +that you must include source code if you redistribute it. (See the file +ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part +of any program generated from the IJG code, this does not limit you more than +the foregoing paragraphs do. + +The Unix configuration script "configure" was produced with GNU Autoconf. +It is copyright by the Free Software Foundation but is freely distributable. +The same holds for its supporting scripts (config.guess, config.sub, +ltconfig, ltmain.sh). Another support script, install-sh, is copyright +by M.I.T. but is also freely distributable. + +It appears that the arithmetic coding option of the JPEG spec is covered by +patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot +legally be used without obtaining one or more licenses. For this reason, +support for arithmetic coding has been removed from the free JPEG software. +(Since arithmetic coding provides only a marginal gain over the unpatented +Huffman mode, it is unlikely that very many implementations will support it.) +So far as we are aware, there are no patent restrictions on the remaining +code. + +The IJG distribution formerly included code to read and write GIF files. +To avoid entanglement with the Unisys LZW patent, GIF reading support has +been removed altogether, and the GIF writer has been simplified to produce +"uncompressed GIFs". This technique does not use the LZW algorithm; the +resulting GIF files are larger than usual, but are readable by all standard +GIF decoders. + +We are required to state that + "The Graphics Interchange Format(c) is the Copyright property of + CompuServe Incorporated. GIF(sm) is a Service Mark property of + CompuServe Incorporated." + +libjpeg-turbo +For a summary of these license terms, see LICENSE.md. + +libjpeg-turbo license +--------------------- + This license covers the TurboJPEG API library and associated programs. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +- Neither the name of the libjpeg-turbo Project nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + +libjpeg license, Independent JPEG Group +--------------------------------------- + This license applies to the libjpeg API library and associated programs + (any code inherited from libjpeg, and any modifications to that code.) + +The authors make NO WARRANTY or representation, either express or implied, +with respect to this software, its quality, accuracy, merchantability, or +fitness for a particular purpose. This software is provided "AS IS", and you, +its user, assume the entire risk as to its quality and accuracy. + +This software is copyright (C) 1991-2016, Thomas G. Lane, Guido Vollbeding. +All Rights Reserved except as specified below. + +Permission is hereby granted to use, copy, modify, and distribute this +software (or portions thereof) for any purpose, without fee, subject to these +conditions: +(1) If any part of the source code for this software is distributed, then this +README file must be included, with this copyright and no-warranty notice +unaltered; and any additions, deletions, or changes to the original files +must be clearly indicated in accompanying documentation. +(2) If only executable code is distributed, then the accompanying +documentation must state that "this software is based in part on the work of +the Independent JPEG Group". +(3) Permission for use of this software is granted only if the user accepts +full responsibility for any undesirable consequences; the authors accept +NO LIABILITY for damages of any kind. + +These conditions apply to any software derived from or based on the IJG code, +not just to the unmodified library. If you use our work, you ought to +acknowledge us. + +Permission is NOT granted for the use of any IJG author's name or company name +in advertising or publicity relating to this software or products derived from +it. This software may be referred to only as "the Independent JPEG Group's +software". + +We specifically permit and encourage the use of this software as the basis of +commercial products, provided that all warranty or liability claims are +assumed by the product vendor. + + +The Unix configuration script "configure" was produced with GNU Autoconf. +It is copyright by the Free Software Foundation but is freely distributable. +The same holds for its supporting scripts (config.guess, config.sub, +ltmain.sh). Another support script, install-sh, is copyright by X Consortium +but is also freely distributable. + +The IJG distribution formerly included code to read and write GIF files. +To avoid entanglement with the Unisys LZW patent (now expired), GIF reading +support has been removed altogether, and the GIF writer has been simplified +to produce "uncompressed GIFs". This technique does not use the LZW +algorithm; the resulting GIF files are larger than usual, but are readable +by all standard GIF decoders. + +We are required to state that + "The Graphics Interchange Format(c) is the Copyright property of + CompuServe Incorporated. GIF(sm) is a Service Mark property of + CompuServe Incorporated." + + +zlib License +------------ + This license is a subset of the other two, and it covers the libjpeg-turbo + SIMD extensions. + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +libunwind +Copyright (c) 2002 Hewlett-Packard Co. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +libwebp +Copyright (c) 2010, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Google nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +libyuv +Copyright 2011 The LibYuv Project Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Google nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +libzip +Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner + +The authors can be contacted at + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +For AES encryption support, files under the following license are used: + +--------------------------------------------------------------------------- +Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. +All rights reserved. + +LICENSE TERMS + +The free distribution and use of this software in both source and binary +form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + +ALTERNATIVELY, provided that this notice is retained in full, this product +may be distributed under the terms of the GNU General Public License (GPL), +in which case the provisions of the GPL apply INSTEAD OF those given above. + +DISCLAIMER + +This software is provided 'as is' with no explicit or implied warranties +in respect of its properties, including, but not limited to, correctness +and/or fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 18th November 2008 + +llvm +lua +Lua License +----------- + +Lua is licensed under the terms of the MIT license reproduced below. +This means that Lua is free software and can be used for both academic +and commercial purposes at absolutely no cost. + +For details and rationale, see http://www.lua.org/license.html . + +=============================================================================== + +Copyright (C) 1994-2012 Lua.org, PUC-Rio. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +=============================================================================== + +(end of COPYRIGHT) + +minizip +zlib + +(extracted from README, except for match.S) + +Copyright notice: + + (C) 1995-2004 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + +(extracted from match.S, for match.S only) + + Copyright (C) 1998, 2007 Brian Raiter + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + +mobstore +Copyright 2017 The TensorFlow Authors. All rights reserved. + + 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 2017, The TensorFlow Authors. + + 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. + +neon_mathfun + Copyright (C) 2007 Julien Pommier + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + +nsync + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +riscv_isa_sim +Copyright (c) 2010-2017, The Regents of the University of California +(Regents). All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the Regents nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING +OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED +HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +sentencepiece + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- + +Copyright (c) 2008-2011, Susumu Yata All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. - Redistributions in binary +form must reproduce the above copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other materials provided with +the distribution. - Neither the name of the nor the names of +its contributors may be used to endorse or promote products derived from this +software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------- + +This is the esaxx copyright. + +Copyright (c) 2010 Daisuke Okanohara All Rights Reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- + + +Copyright 2008 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. + +sequence_lock + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +sse_mathfun + Copyright (C) 2007 Julien Pommier + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + +ssziparchive +Copyright (c) 2010-2011 Sam Soffes + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +systemc +*********** + Summary +*********** + +You can use and distribute this code however you want. +You have a full copyright license and a decent patent license. + +1. You have to reproduce the entire license if you distribute any binaries that + contain any portion of this library. +2. You have to make modifications conspicuous + (Mark modified files with "Copyright 20xx Google Inc.") +3. You have to make the source code of this library available for anyone to whom + you distribute a binary that contains any portion of this library. + +==================== + +SystemC Open Source License Agreement +(Download, Use and Contribution License Agreement Version 3.3) + +PLEASE READ THIS LICENSE AGREEMENT CAREFULLY BEFORE CLICKING ON THE "ACCEPT" +BUTTON, AS BY CLICKING ON THE "ACCEPT" BUTTON YOU ACKNOWLEDGE THAT YOU +HAVE READ, UNDERSTOOD AND AGREE TO BE BOUND BY THIS LICENSE AGREEMENT AND +ALL OF ITS TERMS AND CONDITIONS. + +Accellera Systems Initiative + +The purpose of the following license agreement (the "Agreement") is to encourage interoperability and +development of a C++ modeling language known as "SystemC" for system simulation and design (the +"Purpose"). The SystemC software and other items licensed hereunder are licensed, without fee of any kind, +for use pursuant to the terms and conditions set forth in this Agreement. + +License Agreement + +THE CONTRIBUTORS ARE WILLING TO LICENSE THEIR RESPECTIVE CONTRIBUTIONS TO YOU ONLY +ON THE CONDITION THAT YOU ACCEPT ALL OF THE TERMS OF THIS LICENSE AGREEMENT. IF YOU +DO NOT AGREE TO ALL OF THE TERMS OF THIS LICENSE AGREEMENT, THEN NO RIGHTS ARE +GRANTED TO YOU HEREUNDER TO USE ANY CONTRIBUTIONS. NOTWITHSTANDING ANYTHING TO +CONTRARY, ANY USE, REPRODUCTION OR DISTRIBUTION OF ANY CONTRIBUTION CONSTITUTES +YOUR ACCEPTANCE OF THIS AGREEMENT. + +1. Definitions + +1.1 “Agreement” means this contract. +1.2 “Accellera” means Accellera Systems Initiative, a California nonprofit mutual benefit corporation. +1.3 “Accellera Documentation” means the SystemC language reference manual and any other materials +assigned to Accellera pursuant to the Copyright Agreement. +1.4 “Accellera Release” means a Contribution or combination of Contributions which is developed or +created through the Accellera working group process, and the final work approved for release by a Accellera +working group, approved for release by the Accellera steering group and approved for release by the board of +directors of Accellera. Examples of Accellera Releases include Accellera libraries and Accellera +specifications. Accellera Documentation shall be deemed to be included in the definition of Accellera +Release. +1.5 “Code Contribution” means any Contribution in the form of Source Code. +1.6 “Contribution” means any work of authorship that is deposited or contributed in accordance with +Section 3 in furtherance of the Purpose including, without limitation, libraries, programs, specifications +and User Documentation and Modifications. Without limiting the generality of the foregoing, a list of all +Contributions which were deposited or contributed on or before July 13, 2006 is set forth on Exhibit A +attached hereto and incorporated herein by reference, all of which are considered Contributions pursuant to +this Agreement. A list of all Contributions is available upon written request to Accellera and can also be +found on the Website. For purposes of clarification, all contributions licensed pursuant to that certain +SystemC Open Source License Agreement (Software Download and Use License Agreement Version 2.4) +shall constitute, and be treated as, Contributions pursuant to this Agreement. +1.7 “Copyright Agreement” means any LRM and Copyright Contribution Agreement entered into +between Accellera and the signatory thereto at any time prior to or after the date hereof. +1.8 “ Contribution Questionnaire” means the questionnaire attached hereto as Exhibit C. +1.9 “Contributor” means any person or entity that makes a Contribution pursuant to Section 3. For +purposes of clarification, any person or entity depositing or contributing, as part or all of a Contribution, a +Contribution which has previously been so deposited or contributed is not the Contributor of such re- +deposited Contribution for the purposes of this Agreement. A list of all Contributors is available upon written +request to Accellera and can also be found on the Website. +1.10 “Contributor's Necessary Patent Claims” means those claims of all patents owned or licensable by +Contributor throughout the world that: (1) Contributor has the right to license (within the scope set forth +herein) without the obligation to pay royalties or other consideration to third parties; and (2) are necessarily +and directly infringed solely by the portion of a computer program that either implements, or is compiled +from, either an unmodified Contribution or an Accellera Release. For clarity, Contributor’s Necessary Patent +Claims shall not include any claim directed towards a data structure, method, algorithm, process, technique, +circuit representation, or circuit implementation that is not completely and entirely described either in such +Contributor’s Contribution or in an Accellera Release. Further, a Contributor’s Necessary Patent Claims shall +not include any claim based upon the combination of any Contribution or an Accellera Release with other +works of authorship, to the extent that the Contributor’s Necessary Patent Claims are infringed as a result of +such combination. +1.11 “Copyright Rights” means worldwide statutory and common law rights associated solely with works +of authorship including copyrights, copyright applications, copyright registrations, and “moral rights”. For +purposes of clarification, patents are not included in Copyright Rights. +1.12 “Derivative” or “Derivative work” means a work based upon one or more preexisting works, such +as a translation, condensation, or any other form in which a work may be recast, transformed, or +adapted. A work consisting of editorial revisions, annotations, elaborations, or other modifications, which, +as a whole, represent an original work of authorship, is a “derivative work”. +1.13 “Distribute” means making a Distribution. +1.14 “Distribution” means any distribution, sublicensing or other transfer of a Contribution to any third +party. +1.15 “Documentation” means, collectively, all User Documentation and Accellera Documentation. +1.16 “Marks” means, collectively, the registered and unregistered marks and logos that Accellera has +licensed or otherwise authorized Recipient to use. All marks and logos are listed on Exhibit D, which list +may be amended from time to time by Accellera to add or delete any marks or logos. +1.17 “Modification” means any additions or deletions to any Contribution. +1.18 “Recipient” means any person or entity which receives any Contribution under this Agreement. For +legal entities, “Recipient” includes any entity that controls, is controlled by, or is under common control with +Recipient. For purposes of this Section 1.18, “control” means beneficial ownership of fifty percent (50%) or +more of the outstanding shares or similar interest of such entity entitled to vote for election of the board of +directors or similar managing authority. +1.19 “Source Code” means human readable text in an electronic form suitable for modification that +describe the functions and data structures, including C, C++, and other language modules, plus any associated +interface definition files, scripts used to control compilation and installation of a computer program, or a list +of source code differential comparisons. +1.20 “User Documentation” means all user guides, user manuals and other similar materials related to any +Contribution or an Accellera Release. +1.21 “Website” means Accellera’s internet website located at http://www.accellera.org. + +2. GRANT OF RIGHTS + +2.1 Subject to the terms of this Agreement, each Contributor hereby grants to each Recipient a non- +exclusive, worldwide, royalty-free license under such Contributor's Copyright Rights to do the following: +(a) Use, reproduce, prepare Derivative works of, publicly display, publicly perform and Distribute any +Contributions of such Contributor and Derivative works thereof; and +(b) Use the know-how, information and knowledge embedded in the Contribution, without any +obligation to keep the foregoing confidential so long as the Recipient does not otherwise violate this +Agreement. +2.2 Accellera hereby grants to each Recipient a non-exclusive, worldwide, royalty- free license under +Accellera's Copyright Rights to use, reproduce, prepare Derivative works of, publicly display, publicly +perform and distribute the Accellera Documentation and any Derivative works thereof, subject to the terms +and conditions of this Agreement. +2.3 Subject to the terms of this Agreement, each Contributor hereby grants to each Recipient, a worldwide, +royalty-free, non-exclusive license under such Contributor's Necessary Patent Claims to make, have made, +use, sell, offer for sale, or import: (a) such Contributor's Contributions; (b) those portions of a computer +program that either implements, or is compiled from, the Contributor’s unmodified Contribution; and (c) +those portions of a computer program that implement, or are compiled from, an Accellera Release. +2.4 Each Contributor represents that, to its knowledge, it has sufficient rights in and to each of its +Contributions to grant the licenses set forth in Sections 2.1 and 2.3. Accellera represents that, to its +knowledge, it has sufficient rights in the Accellera Documentation to grant the license set forth in Section +2.2. +2.5 Except as expressly stated in Sections 2.1, 2.2 and 2.3, Recipient receives no rights or licenses to the +intellectual property of any Contributor or Accellera under this Agreement, whether expressly, by implication, +estoppel or otherwise. All rights in and to any Contribution not expressly granted under this Agreement are +reserved. +2.6 Except as specifically set forth in any Copyright Agreement, Contributor shall ensure that transfers or +assignments of all or any part of its right, title, and interest in and to any Contributions contributed or +deposited by Contributor hereunder, including all Copyright Rights and patent rights embodied therein, +shall be subject to the rights expressly granted in this Agreement including, without limitation, the licenses +granted in Sections 2.1 and 2.3. Recipient shall not remove or alter any proprietary notices contained in +the Contributions licensed to Recipient hereunder and shall reproduce and include such notices on any copies +of the Contributions made by Recipient in any media. +2.7 License to Marks. +(a) Accellera shall retain all right, title and interest in and to the Marks worldwide, subject to the +limited license granted to Recipient in this Section 2.7. Accellera hereby grants Recipient a non- +exclusive, royalty-free, limited license to use the Marks solely in connection with its exercise of +the rights granted pursuant to this Agreement and to indicate that the products being marketed by +Recipient are compatible with, and meet the standards of, Accellera Releases. All uses of the Marks +shall be in accordance with Accellera’s trademark usage policy set forth in Exhibit D. +(b) Recipient shall assist Accellera to the extent reasonably necessary to protect and maintain the +Marks worldwide, including, but not limited to, giving prompt notice to Accellera of any known or +potential infringement of the Marks, and cooperating with Accellera in preparing and executing any +documents necessary to register the Marks, or as may be required by the laws or rules of any country +or jurisdiction. In its sole discretion, Accellera may commence, prosecute or defend any action or +claim concerning the Marks. Accellera shall have the right to control any such litigation, and +Recipient shall fully cooperate with Accellera in any such litigation. Accellera shall reimburse +Recipient for the reasonable costs associated with providing such assistance, except to the extent that +such costs result from Recipient’s breach of this Section 2.7. Recipient shall not commence any action +regarding the Marks without Accellera’s prior written consent. +(c) All goodwill with respect to the Marks shall accrue for the sole benefit of Accellera. +Recipient shall maintain the quality of any products, associated packaging, collateral and marketing +materials on which it uses any of the Marks in a manner consistent with all terms, conditions and +requirements set forth in this Section 2.7 and at a level that meets or exceeds Recipient’s overall +reputation for quality and that is at least commensurate with industry standards. +2.8 RECIPIENT UNDERSTANDS THAT ALTHOUGH EACH CONTRIBUTOR AND ACCELLERA GRANTS +THE LICENSES SET FORTH HEREIN, NO ASSURANCES ARE PROVIDED BY ANY CONTRIBUTOR OR +ACCELLERA THAT ANY ACCELLERA RELEASE OR ANY CONTRIBUTION, EITHER ALONE OR IN +COMBINATION WITH ANY OTHER CONTRIBUTION, DOES NOT INFRINGE THE PATENT OR OTHER +INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY. MOREOVER, NO ASSURANCES ARE +MADE THAT ANY CONTRIBUTION OF ONE CONTRIBUTOR DOES NOT INFRINGE THE INTELLECTUAL +PROPERTY RIGHTS OF ANOTHER CONTRIBUTOR. EACH CONTRIBUTOR AND ACCELLERA DISCLAIM +ANY LIABILITY TO RECIPIENT FOR CLAIMS BROUGHT BY ANY OTHER ENTITY BASED ON +INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR OTHERWISE. In addition, as a condition to +exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to +secure any other intellectual property rights needed, if any. For example, if a third party patent license is +required to allow Recipient to distribute a computer program, then it is Recipient's responsibility to acquire +that license before Distributing such computer program. + +3. DESCRIPTION AND DEPOSIT OF CONTRIBUTIONS + +3.1 To the extent Recipient wishes to become a Contributor by making a Contribution, such +Contributor shall: +(a) (i) Deposit such Contribution at the Website according to the Contribution instructions found at +such Website, or (ii) disclose such Contribution at a meeting of any working group of Accellera; +(b) (i) Describe such Contribution in reasonable detail on Exhibit B (including the additions or +changes such Contributor made to create the Contribution and the date of any such changes or +additions), (ii) completing a Contribution Questionnaire with respect to such Contribution, and (iii) +delivering both documents to the Secretary of Accellera. All Contributions made after the date +hereof shall be effectuated by Contributor (x) amending Exhibit B and delivering such amended +Exhibit B to the Secretary of Accellera, which amended exhibit shall automatically replace the existing +Exhibit B, (y) completing a Contribution Questionnaire with respect to such Contribution, and (z) +delivering both documents to the Secretary of Accellera; +(c) Cause such Contribution to contain a file documenting such Contributor's name and contact +information, additions or changes such Contributor made to create the Contribution, and the date of +any such changes or additions; and +(d) Cause such Contribution to include in each file a prominent statement substantially similar to the +following: “Any code contained in this Contribution is derived, directly or indirectly, from the +SystemC source code. Copyright© 1996-[current year here] by all Contributors. All Rights reserved. +The contents of this file are subject to the restrictions and limitations set forth in the SystemC Open +Source License Version 3.1 (the “License”). You may not use this file except in compliance with such +restrictions and limitations. You may obtain instructions on how to receive a copy of the License at +http://www.accellera.org/. Software distributed by Contributors under the License is distributed +exclusively on an “AS IS” basis, WITHOUT WARRANTY OF ANY KIND, either express or +implied. See the License for the specific language governing rights and limitations under the License.” +3.2 Accellera may from time to time publish policies and procedures regarding the contribution or +depositing of Contributions as well as establish additional details regarding the contribution process. Without +limiting the foregoing, Accellera or the administrators of the Website shall have the right to remove any +Contribution from the Website at any time. + +4. REQUIREMENTS OF DISTRIBUTION + +4.1 A Recipient may choose to Distribute any Contribution or any compilation of multiple Contributions +(except for any Code Contributions) under its own license agreement provided that: +(a) Recipient complies with the terms and conditions of this Agreement; +(b) As between Recipient and any other Contributor, Recipient assumes all warranties and conditions, +express and implied, and all liability for damages arising out of its Distribution; and +(c) Recipient makes available to recipients of such Distribution then Source Code for such +Distributions, and informs them on how to obtain it in a reasonable manner on or through a medium +customarily used for software exchange. +4.2 If a Recipient chooses to Distribute any Code Contribution or compilations of Code Contributions +then: +(a) Such Code Contribution must be Distributed under this Agreement; and +(b) A copy of this Agreement must be included with each copy of such Code Contribution. +4.3 Each Recipient must include the following in a conspicuous location in the Code Contribution so +Distributed: “Copyright© 1996-[current year here], by all Contributors. All rights reserved.” +4.4 In addition, each Recipient that creates and Distributes or otherwise transfers a Modification whether +or not such Modification has been deposited pursuant to Section 3 must identify the originator of such +Modification in a manner that reasonably allows third parties to identify the originator of the Modification. +4.5 A Recipient may choose to Distribute the Accellera Documentation under its own license agreement, +provided that Recipient complies with the terms and conditions of this Agreement. Each Recipient must +include the following in a conspicuous location in the Accellera Documentation so Distributed or transferred: +“Copyright© 1996-[current year here], by Accellera Systems Initiative. All rights reserved.” +In addition, each Recipient that creates and Distributes a modification or Derivative work of the Accellera +Documentation, whether or not such modification or Derivative work has been contributed pursuant to a +Copyright Agreement must identify the originator of such modification or Derivative work in a manner that +reasonably allows third parties to identify the originator of the modification or derivative work. + +5. INDEMNIFICATION + +Any Recipient which Distributes any Contribution and/or Accellera Release (a “Distributor”) may accept +certain responsibilities with respect to end users, business partners and the like. While this license is +intended to facilitate the commercial use of Contributions Accellera Documentation and Accellera +Releases, a Distributor shall Distribute such Contributions, Accellera Documentation and Accellera Releases +in a manner which does not create potential liability for the Contributors. Therefore each Distributor hereby +agrees to defend and indemnify every Contributor (“Indemnified Contributor”) against any losses, +damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought +by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such +Distributor, including but not limited to the terms and conditions under which Distributor offered such +Contributions, Accellera Documentation and/or Accellera Releases in connection with its Distribution thereof. +The obligations in this Section 5 do not apply to any claims or Losses relating to any actual or alleged +intellectual property infringement of any Contribution, Accellera Documentation or Accellera Release. In +order to qualify, an Indemnified Contributor must: (a) promptly notify the Distributor in writing of such +claim, and (b) allow the Distributor to control, and cooperate with the Distributor in, the defense and any +related settlement negotiations. The Indemnified Contributor may participate in the defense of any such claim +at its own expense. +For example, a Recipient might include a Contribution in a commercial product offering, Product X. That +Recipient is then a Distributor. If that Distributor then makes performance claims, or offers warranties, +support, or indemnity or any other license terms related to Product X, those performance claims, offers and +other terms are such Distributor's responsibility alone. Under this Section 5, the Distributor would have to +defend claims against the Contributors related to those performance claims, offers, and other terms, and if a +court requires any Contributor to pay any damages as a result, the Distributor must pay those damages. + +6. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, ALL CONTRIBUTIONS, ACCELLERA +DOCUMENTATION AND ACCELLERA RELEASES ARE PROVIDED EXCLUSIVELY 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. EACH RECIPIENT IS SOLELY +RESPONSIBLE FOR DETERMINING THE APPROPRIATENESS OF ITS USE AND DISTRIBUTION OF ANY +CONTRIBUTION, ACCELLERA DOCUMENTATION AND ACCELLERA RELEASE AND ASSUMES ALL +RISKS ASSOCIATED WITH ITS EXERCISE OF RIGHTS UNDER THIS AGREEMENT, INCLUDING BUT NOT +LIMITED TO THE RISKS AND COSTS OF PROGRAM ERRORS, COMPLIANCE WITH APPLICABLE LAWS, +DAMAGE TO OR LOSS OF DATA, PROGRAMS OR EQUIPMENT, AND UNAVAILABILITY OR +INTERRUPTION OF OPERATIONS. THIS DISCLAIMER OR WARRANTY CONSTITUTES AN ESSENTIAL +PART OF THIS AGREEMENT. NO USE OF ANY CONTRIBUTION, ACCELLERA DOCUMENTATION OR +ACCELLERA RELEASE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +7. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NONE OF THE RECIPIENTS, CONTRIBUTORS +OR ACCELLERA SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OR DISTRIBUTION OF ANY CONTRIBUTION, ACCELLERA DOCUMENTATION OR ACCELLERA +RELEASE OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +8. U.S. GOVERNMENT USE + +If Recipient is licensing any computer program on behalf of any unit or agency of the United States +Government, then such computer program is commercial computer software, and, pursuant to FAR 12.212 or +DFARS 227.7202 and their successors, as applicable, shall be licensed to the Government under the terms and +conditions of this Agreement. + +9. PATENT CLAIMS + +If Recipient institutes patent litigation against any entity (including a cross-claim, counterclaim or declaratory +judgment claim in a lawsuit) alleging that any Contribution, Accellera Release or combination of +Contributions (excluding combinations of any Contribution with other software or hardware) infringes such +Recipient's patent(s), then the rights granted to Recipient by each Contributor under Section 2 shall terminate +as of the date such litigation is filed. + +10. TERMINATION + +All Recipient's rights under this Agreement shall terminate if Recipient fails to comply with any of the +material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time +after becoming aware of such noncompliance. If such occurs, Recipient shall cease all use and Distribution of +any Contributions of any other Contributor, Accellera Documentation and Accellera Releases based upon the +rights granted to Recipient under this Agreement as soon as reasonably practicable. However, +Recipient's obligations under this Agreement and any licenses granted by Recipient relating to any +Contributions shall survive such termination. + +11. LICENSE VERSIONS + +Accellera may publish new versions (including revisions) of this Agreement from time to time. Each +new version of the Agreement will be given a distinguishing version number. Any Contribution, Accellera +Documentation or Accellera Release may always be Distributed subject to the version of the Agreement under +which it was received. In addition, after a new version of the Agreement is published, Contributor may elect +to Distribute any Contribution, Accellera Documentation or Accellera Release under the new version. No +one other than Accellera, acting by a vote of at least seventy five percent (75%) of the members of its Board +of Directors, has the right to modify this Agreement; provided that Exhibit B and Exhibit C may be amended +as specifically set forth in Section 3.1(b), and Exhibit D may be amended as specifically set forth in Section +1.13. + +12. ELECTRONIC ACCEPTANCE + +This Agreement may be executed either electronically or on paper. If this Agreement is executed +electronically, by clicking on the “Accept” button, Recipient warrants that it agrees to all of the terms of this +Agreement, that Recipient is authorized to enter into this Agreement, and that this Agreement is legally +binding upon Recipient. If Recipient does not agree to be bound by this Agreement, then Recipient shall +click the “Decline” button and Recipient shall not receive any rights from the Contributors nor shall +Recipient download any Contributions, Accellera Documentation or Accellera Releases. + +13. GENERAL + +This Agreement represents the complete agreement concerning the subject matter hereof and supersedes all +prior agreements or representations, oral or written, regarding the subject matter hereof. If any provision of +this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or +enforceability of the remainder of the terms of this Agreement, and without further action by the parties +hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and +enforceable. This Agreement shall be executed in multiple counterparts (either electronically and/or on paper), +each of which shall be deemed to be an original, but all of which shall be one and the same Agreement. A +facsimile or other copy of the Agreement shall have the same force and effect as an originally executed copy +thereof. +This Agreement is governed by the laws of California, without reference to conflict of laws principles. Each +party waives its rights to a jury trial in any resulting litigation. Any litigation relating to this Agreement shall +be subject to the jurisdiction of the Federal Courts of the Northern District of California, with venue lying in +Santa Clara County, California, or the Santa Clara County Superior Court. The application of the United +Nations Convention on Contracts for the International Sale of Goods is expressly excluded. The provisions of +this Agreement shall be construed fairly in accordance with its terms and no rules of construction for or +against either party shall be applied in the interpreting this Agreement. Recipient shall not use any +Contribution, Accellera Documentation or Accellera Release in violation of local and other applicable laws +including, but not limited to, the export control laws of the United States. + + + +IN WITNESS WHEREOF, duly authorized representatives of the parties have executed and delivered this +Agreement as of the later of the dates set forth below. + +RECIPIENT: +By: +Name: +Its: +Date: +ACCELLERA SYSTEMS INITIATIVE: +By: +Name: +Its: +Date: + +EXHIBIT A +List of Contributions as of July 13, 2006 + +Number Contribution +1. Updated TLM Proposal +2. TLM Extensions +3. Abstract titled "Transaction Level Modeling in SystemC" +4. Code and related material entitled "SCE-API Example - Standard Co-emulation APO v1.8 Spec and Routed + Example" +5. Code and related material entitled "Simplebus v2.2 Example for SystemC v2.0. +6. Code and related material entitled "SystemC Generic Transaction Level Communication Channel." +7. Review of TLM API code and related documents. +8. SystemC Verification Library version 1.0; versions 1.1, 1.2, 2.0, 2.0.1 of the SystemC modeling language as + released by Accellera and which are, or were, available for download on the website prior to the + agreement; version 2.1 (beta 11) of the SystemC modeling language to be released and made available by + Open SystemC Initiative for download on the website. +9. Code and related material entitled "System Design with SystemC Examples." +10. Presentation document titled "Towards a SystemC Transaction Level Modeling Standard," dated June + 2004; presentation document titled "TLM Extensions," dated April 2004; presentation document titled + "Updated TLM Proposal," dated March 29, 2004; abstract titled "Transaction Level Modeling in System C." +11. Code and related material entitled "MP3 Decoder Example plus Performance Benchmark." +12. SystemC October 12 Library. +13. Source code modifications to the SystemC Library embodied in the October 12, 2004 kit + (system_2_z_lib.oct_12_2004.tgz). + Source code modifications to the SystemC Regression Test Suite embodied in the October 12, 2004 kit + (systemc_2_1_tests.oct_12_2004.tgz). +14. Synthesizable Subset 1.0. +15. TLM Contribution (Presentation documents; abstract; code; proposal dated 3/24/04). +16. Updated version of TLM kit +17. Code and related material “2.1 Beta Regression Tests” +18. Code and related material “OSCI SystemC 2.1 Beta” +19. SystemC 2.1 +20. Assorted recommendations for enhancements, bug fixes and improved cross-platform support, including + project files for Microsoft Visual C++ versions 6.0 and 7.1 that are contained within the files systemc- + 2.1.05may05.tgz and systemc_tests-2.105may05.tgz. +21. Minor modifications incorporated in SystemC 2.1 open source implementation dated July 14, 2005 to + permit port to Microsoft VC++ Version 7. +22. Numerous modifications incorporated in SystemC 2.1 open source implementation dated July 14, 2005. +23. A collection of interfaces and implementations in SystemC for analysis objects. + A collection of interfaces and implementations in SystemC for configuring components in a design. +24. Modifications to the most recent version of SCV which allow it to run under the SystemC-2.1v1 kit. +25. Set of header files intended to be included in the SystemC TLM Modeling library code. The API provides + for 1 interfaces: (a) “Atom at once (Variously called BA, PVT, CC) in which a single atom is transported at + once. +26. Modifications included in SystemC 2.2 library labeled “systemc-2.2.04feb06.tgz;” + Modifications included in SystemC 2.2 test suites labeled “systemc_tests-2.2.04feb06.tgz.” +27. Modifications to the SystemC 2.2 library to enable the port to gcc version 4; + Addition of compliance_1666 tests to the SystemC 2.2 regression test suite. +28. OSCI_TL3_2006_03_01.zip, including any updates of any of the foregoing, and + OSCI_SCML_Memory_and_Bitfield_2006_03_01.zip, including any updates of any of the foregoing. +29. C++/SystemC Code for Mentor’s SMI System PVT channel implementation; An example of a protocol + specific SystemC PVT channel implementation; Design examples using the above channel models; A + white-paper describing the channel implementations. + +EXHIBIT B +Form of Description of Contributions + +A. Description of Contributions +1. +2. + +The undersigned hereby makes the Contributions described above +pursuant to the term, conditions and limitations of the SystemC +License. +By: +Name: +Its: +Date: +Address: +Tel: +Fax: +Email: + +EXHIBIT C +Contribution Questionnaire +Contribution Number (see Exhibit B): +Date: +1. Is Contributor a member of Accellera Systems Initiative? +□ Yes +□ No +If Contributor is a member of Accellera Systems Initiative, please indicate Contributor’s membership status +and complete questions 2 or 3 (as applicable): +□ Corporate Member +□ Associate Member +If Contributor is not a member of Accellera Systems Initiative, please skip questions 2 and 3 and go to +question 4. + +2. If Contributor is a Corporate Member or Associate Member of Accellera Systems Initiative, please indicate the +name, title, and contact information for the person making this Contribution on behalf of such Corporate Member +or Associate Member: +Name: +Title: +Address: +Phone: +Fax: +Email: + +3. If Contributor is not a member of Accellera Systems Initiative, then please complete the following: +If the Contributor is a natural person, please indicate the name and address of Contributor’s employer +and the title of the position held at such employer: +Name of Employer: +Title with such Employer: +Address: +Phone: +Fax: +Email: +If Contributor is an entity (corporation, limited liability company, partnership), then please indicate the +name, title, and contact information for the person making this Contribution on behalf of such Contributor. +Entity Name: +Name: +Title: +Address: +Phone: +Fax: +Email: + +EXHIBIT D + +Trademark Usage Policy + +I. LIST OF MARKS +1. Open SystemC +2. Open SystemC Initiative +3. OSCI +4. SystemC +5. SystemC Initiative +6. All logos that incorporate the foregoing word marks + +II. PROPER USE OF MARKS +Trademarks and service marks function as adjectives and generally should not be used as nouns or verbs. +Accordingly, as often as possible, the Marks should be used as adjectives immediately preceding the generic +noun that refers to the service in question. For example: +The SystemC® software +The OSCI® LRM +No Possessives or Plurals. Since they are not nouns, the Marks should never be used in the possessive or +plural forms. For example, it is not appropriate to write “SystemC’s software.” +No Use as Verbs or as Puns. The Marks should never be used as verbs or as puns. + +III. PROPER ATTRIBUTION +Trademark ownership is attributed in two ways, with the use of a symbol (TM, SM, ®) after the mark and with a +legal legend, usually found at the end of a document following the copyright notice. Following are Accellera’s +rules for symbols and legends to attribute the Marks: +Symbols: +Which Symbol Do I Use? +The Marks generally function as trademarks rather than service marks. Unless you are specifically directed +otherwise, please use the ® symbol after the Marks. +Where Do I Place the ® Symbol? +The ® symbol is placed immediately after the mark, either in superscript or subscript. +When Do I Use the Symbol? +The ® symbol is to be used after the Marks in the following instances: +Most Prominent Uses: A ® symbol is required after prominent uses of the Marks, e.g., in the headlines and +large print text of web pages, advertisements, other promotional materials and press releases, except where +space limitations or specific style considerations prevent compliance with this requirement. +First Use in Text: A ® symbol is required after the first use of each Mark in text, e.g. advertising copy or the +body of press releases, even though the symbol may have already appeared in the headline or after another +prominent use of the mark in the same document. +All Logos: The ® symbol must appear after all logos incorporating the Marks. + +IV. LEGENDS +All Marks that appear on a web page or in a press release, advertisement or other written material (whether in +print or electronic form) must be attributed in an appropriate legend. The legend may be presented in +“mouseprint” but must be large enough to be read easily. Legends generally appear at the end of a document or +the bottom of a web page but may be placed elsewhere, e.g. the inside covers of documentation. +The Accellera Systems Initiative Legend: The following legend should be used in all materials in which any +of the Marks appear: +[Insert the Marks] are trademarks or registered trademarks of Accellera Systems Initiative, Inc. in the United +States and other countries and are used with permission. + +V. MARKS NEVER COMBINED +The Marks should never be combined with the marks of any business other than Accellera. The Marks should +always appear visually separate from any other marks appearing in the same materials such that each mark +creates a distinct commercial impression. It would, for instance, not be appropriate to superimpose the logo of +another business over any Accellera logo. + +VI. LOGOS +Logos incorporating the Marks can only be used in the format provided to you by Accellera for incorporation +into your materials or web pages. The logos provided to you by Accellera cannot be modified in any way +without Accellera’s prior written approval. Logos copied from Accellera web pages or other materials may not +to be used. Please contact info@accellera.org to obtain electronic files containing the Accellera logos and to +ask any question regarding the logos. + +tiff +Copyright (c) 1988-1997 Sam Leffler +Copyright (c) 1991-1997 Silicon Graphics, Inc. + +Permission to use, copy, modify, distribute, and sell this software and +its documentation for any purpose is hereby granted without fee, provided +that (i) the above copyright notices and this permission notice appear in +all copies of the software and related documentation, and (ii) the names of +Sam Leffler and Silicon Graphics may not be used in any advertising or +publicity relating to the software without the specific, prior written +permission of Sam Leffler and Silicon Graphics. + +THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR +ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF +LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +OF THIS SOFTWARE. + +upb + +Copyright (c) 2009-2011, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Google Inc. nor the names of any other + contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL GOOGLE INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +zlib +(extracted from README, except for match.S) + +Copyright notice: + + (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. + +(extracted from match.S, for match.S only) + +Copyright (C) 1998, 2007 Brian Raiter + +This software is provided 'as-is', without any express or implied +warranty. In no event will the author be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. diff --git a/Example/Pods/Firebase/CoreOnly/README.md b/Example/Pods/Firebase/CoreOnly/README.md new file mode 100755 index 0000000..a245f5d --- /dev/null +++ b/Example/Pods/Firebase/CoreOnly/README.md @@ -0,0 +1,81 @@ +# Firebase APIs for iOS + +Simplify your iOS development, grow your user base, and monetize more +effectively with Firebase services. + +Much more information can be found at [https://firebase.google.com](https://firebase.google.com). + +## Install a Firebase SDK using CocoaPods + +Firebase distributes several iOS specific APIs and SDKs via CocoaPods. +You can install the CocoaPods tool on OS X by running the following command from +the terminal. Detailed information is available in the [Getting Started +guide](https://guides.cocoapods.org/using/getting-started.html#getting-started). + +``` +$ sudo gem install cocoapods +``` + +## Add a Firebase SDK to your iOS app + +CocoaPods is used to install and manage dependencies in existing Xcode projects. + +1. Create an Xcode project, and save it to your local machine. +2. Create a file named `Podfile` in your project directory. This file defines + your project's dependencies, and is commonly referred to as a Podspec. +3. Open `Podfile`, and add your dependencies. A simple Podspec is shown here: + + ``` + platform :ios, '8.0' + pod 'Firebase' + ``` + +4. Save the file. + +5. Open a terminal and `cd` to the directory containing the Podfile. + + ``` + $ cd /project/ + ``` + +6. Run the `pod install` command. This will install the SDKs specified in the + Podspec, along with any dependencies they may have. + + ``` + $ pod install + ``` + +7. Open your app's `.xcworkspace` file to launch Xcode. Use this file for all + development on your app. + +8. You can also install other Firebase SDKs by adding the subspecs in the + Podfile. + + ``` + pod 'Firebase/AdMob' + pod 'Firebase/Analytics' + pod 'Firebase/Auth' + pod 'Firebase/Database' + pod 'Firebase/DynamicLinks' + pod 'Firebase/Firestore' + pod 'Firebase/Functions' + pod 'Firebase/InAppMessaging' + pod 'Firebase/InAppMessagingDisplay' + pod 'Firebase/Messaging' + pod 'Firebase/MLCommon' + pod 'Firebase/MLModelInterpreter' + pod 'Firebase/MLNLLanguageID' + pod 'Firebase/MLNLSmartReply' + pod 'Firebase/MLNLTranslate' + pod 'Firebase/MLNaturalLanguage' + pod 'Firebase/MLVision' + pod 'Firebase/MLVisionAutoML' + pod 'Firebase/MLVisionBarcodeModel' + pod 'Firebase/MLVisionFaceModel' + pod 'Firebase/MLVisionLabelModel' + pod 'Firebase/MLVisionObjectDetection' + pod 'Firebase/MLVisionTextModel' + pod 'Firebase/Performance' + pod 'Firebase/RemoteConfig' + pod 'Firebase/Storage' + ``` diff --git a/Example/Pods/Firebase/CoreOnly/Sources/Firebase.h b/Example/Pods/Firebase/CoreOnly/Sources/Firebase.h index aa0af40..e5049ca 100755 --- a/Example/Pods/Firebase/CoreOnly/Sources/Firebase.h +++ b/Example/Pods/Firebase/CoreOnly/Sources/Firebase.h @@ -1,3 +1,17 @@ +// Copyright 2019 Google +// +// 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. + #import #if !defined(__has_include) @@ -6,20 +20,14 @@ #else #if __has_include() #import - #else - #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING - #warning "FirebaseAnalytics.framework is not included in your target. Please add \ -`Firebase/Core` to your Podfile or add FirebaseAnalytics.framework to your project to ensure \ -Firebase services work as intended." - #endif // #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING #endif #if __has_include() #import #endif - #if __has_include() - #import + #if __has_include() + #import #endif #if __has_include() @@ -28,6 +36,13 @@ Firebase services work as intended." #if __has_include() #import + #if !__has_include() + #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING + #warning "FirebaseAnalytics.framework is not included in your target. Please add \ +`Firebase/Analytics` to your Podfile or add FirebaseAnalytics.framework to your project to ensure \ +Firebase Dynamic Links works as intended." + #endif // #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING + #endif #endif #if __has_include() @@ -40,18 +55,32 @@ Firebase services work as intended." #if __has_include() #import + #if !__has_include() + #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING + #warning "FirebaseAnalytics.framework is not included in your target. Please add \ +`Firebase/Analytics` to your Podfile or add FirebaseAnalytics.framework to your project to ensure \ +Firebase In App Messaging works as intended." + #endif // #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING + #endif #endif #if __has_include() #import #endif - #if __has_include() - #import - #endif - #if __has_include() #import + #if !__has_include() + #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING + #warning "FirebaseAnalytics.framework is not included in your target. Please add \ +`Firebase/Analytics` to your Podfile or add FirebaseAnalytics.framework to your project to ensure \ +Firebase Messaging works as intended." + #endif // #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING + #endif +#endif + + #if __has_include() + #import #endif #if __has_include() @@ -66,6 +95,10 @@ Firebase services work as intended." #import #endif + #if __has_include() + #import + #endif + #if __has_include() #import #endif @@ -74,6 +107,10 @@ Firebase services work as intended." #import #endif + #if __has_include() + #import + #endif + #if __has_include() #import #endif @@ -86,16 +123,34 @@ Firebase services work as intended." #import #endif + #if __has_include() + #import + #endif + #if __has_include() #import #endif #if __has_include() #import + #if !__has_include() + #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING + #warning "FirebaseAnalytics.framework is not included in your target. Please add \ +`Firebase/Analytics` to your Podfile or add FirebaseAnalytics.framework to your project to ensure \ +Firebase Performance works as intended." + #endif // #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING + #endif #endif #if __has_include() #import + #if !__has_include() + #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING + #warning "FirebaseAnalytics.framework is not included in your target. Please add \ +`Firebase/Analytics` to your Podfile or add FirebaseAnalytics.framework to your project to ensure \ +Firebase Remote Config works as intended." + #endif // #ifndef FIREBASE_ANALYTICS_SUPPRESS_WARNING + #endif #endif #if __has_include() diff --git a/Example/Pods/GoogleUtilities/LICENSE b/Example/Pods/Firebase/LICENSE similarity index 100% rename from Example/Pods/GoogleUtilities/LICENSE rename to Example/Pods/Firebase/LICENSE diff --git a/Example/Pods/Firebase/NOTICES b/Example/Pods/Firebase/NOTICES deleted file mode 100755 index ad93dba..0000000 --- a/Example/Pods/Firebase/NOTICES +++ /dev/null @@ -1,375 +0,0 @@ -Google LevelDB -Copyright (c) 2011 The LevelDB Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation andor other materials provided with the distribution. - -Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - --- - -Square Socket Rocket -Copyright 2012 Square 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. - --- - -APLevelDB -Created by Adam Preble on 12312. -Copyright (c) 2012 Adam Preble. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, andor sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -Portions of APLevelDB are based on LevelDB-ObjC: -https://github.com/hoisie/LevelDB-ObjC -Specifically the SliceFromString/StringFromSlice macros, and the structure of -the enumeration methods. License for those potions follows: -Copyright (c) 2011 Pave Labs -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - --- - -sqlite3 -2001 September 15 - -The author disclaims copyright to this source code. In place of -a legal notice, here is a blessing: - - May you do good and not evil. - May you find forgiveness for yourself and forgive others. - May you share freely, never taking more than you give. - - -This header file defines the interface that the SQLite library -presents to client programs. If a C-function, structure, datatype, -or constant definition does not appear in this file, then it is -not a published API of SQLite, is subject to change without -notice, and should not be referenced by programs that use SQLite. - -Some of the definitions that are in this file are marked as -"experimental". Experimental interfaces are normally new -features recently added to SQLite. We do not anticipate changes -to experimental interfaces but reserve the right to make minor changes -if experience from use "in the wild" suggest such changes are prudent. - -The official C-language API documentation for SQLite is derived -from comments in this file. This file is the authoritative source -on how SQLite interfaces are suppose to operate. - -The name of this file under configuration management is "sqlite.h.in". -The makefile makes some minor changes to this file (such as inserting -the version number) and changes its name to "sqlite3.h" as -part of the build process. - --- - -sysutsname.h -Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - -This file contains Original Code andor Modifications of Original Code -as defined in and that are subject to the Apple Public Source License -Version 2.0 (the 'License'). You may not use this file except in -compliance with the License. The rights granted to you under the License -may not be used to create, or enable the creation or redistribution of, -unlawful or unlicensed copies of an Apple operating system, or to -circumvent, violate, or enable the circumvention or violation of, any -terms of an Apple operating system software license agreement. - -Please obtain a copy of the License at -http://www.opensource.apple.com/apsl and read it before using this file. - -The Original Code and all software distributed under the License are -distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER -EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, -INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. -Please see the License for the specific language governing rights and -limitations under the License. - -Copyright 1993,1995 NeXT Computer Inc. All Rights Reserved -Copyright (c) 1994 The Regents of the University of California. All rights reserved. -This code is derived from software contributed to Berkeley by -Chuck Karish of Mindcraft, Inc. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation andor other materials provided with the distribution. -3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: -* This product includes software developed by the University of -* California, Berkeley and its contributors. -4. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - --- - -GTMNSData+zlib.h -Copyright 2007-2008 Google 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. - --- - -GTMDefines.h -Copyright 2008 Google 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. - --- - -ProtocolBuffer -Copyright 2008 Cyrus Najmabadi -Copyright 2011 Google 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. - --- - -GTMDefines.h -Copyright 2008 Google 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. - --- - -fbase64.c - -Copyright (c) 1996 by Internet Software Consortium. -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. -THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS -ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE -CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL -DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -Portions Copyright (c) 1995 by International Business Machines, Inc. -International Business Machines, Inc. (hereinafter called IBM) grants -permission under its copyrights to use, copy, modify, and distribute this -Software with or without fee, provided that the above copyright notice and -all paragraphs of this notice appear in all copies, and that the name of IBM -not be used in connection with the marketing of any product incorporating -the Software or modifications thereof, without specific, written prior -permission. -To the extent it has a right to do so, IBM grants an immunity from suit -under its patents, if any, for the use, sale or manufacture of products to -the extent that such products are used for performing Domain Name System -dynamic updates in TCP/IP networks by means of the Software. No immunity is -granted for any product per se or for any other function of any product. -THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, -DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING -OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN -IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. - -OPENBSD ORIGINAL: lib/libc/net/base64.c */ - --- - -FIRAppEnvironmentUtil.m - -The following copyright from Landon J. Fuller applies to the isAppEncrypted function. -Copyright (c) 2017 Landon J. Fuller -All rights reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING -BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Comment from iPhone Dev Wiki -Crack Prevention: -App Store binaries are signed by both their developer and Apple. This encrypts the binary so -that decryption keys are needed in order to make the binary readable. When iOS executes the -binary, the decryption keys are used to decrypt the binary into a readable state where it is -then loaded into memory and executed. iOS can tell the encryption status of a binary via the -cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If cryptid is a non-zero -value then the binary is encrypted. -'Cracking' works by letting the kernel decrypt the binary then siphoning the decrypted data into -a new binary file, resigning, and repackaging. This will only work on jailbroken devices as -codesignature validation has been removed. Resigning takes place because while the codesignature -doesn't have to be valid thanks to the jailbreak, it does have to be in place unless you have -AppSync or similar to disable codesignature checks. -More information at Landon Fuller's blog - --- - -tflite - -Copyright 2017 The TensorFlow Authors. 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. - --- - -FirebaseCore - -Copyright 2017 Google. - -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. - --- - -google_api_objectivec_client_for_rest - -Copyright 2011 Google 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. - --- - -ocmock - -Copyright (c) 2006-2016 Erik Doernenburg and contributors - -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/Example/Pods/Firebase/README.md b/Example/Pods/Firebase/README.md old mode 100755 new mode 100644 index a7ebe74..8c6e952 --- a/Example/Pods/Firebase/README.md +++ b/Example/Pods/Firebase/README.md @@ -1,90 +1,267 @@ -# Firebase APIs for iOS +# Firebase iOS Open Source Development + [![Actions Status][gh-core-badge]][gh-actions] + [![Actions Status][gh-dynamiclinks-badge]][gh-actions] + [![Actions Status][gh-datatransport-badge]][gh-actions] + [![Actions Status][gh-storage-badge]][gh-actions] + [![Actions Status][gh-zip-badge]][gh-actions] + [![Travis](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk) -Simplify your iOS development, grow your user base, and monetize more -effectively with Firebase services. +This repository contains a subset of the Firebase iOS SDK source. It currently +includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase, +FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging, +FirebaseInAppMessagingDisplay, FirebaseMessaging, FirebaseRemoteConfig, and +FirebaseStorage. -Much more information can be found at [https://firebase.google.com](https://firebase.google.com). +The repository also includes GoogleUtilities source. The +[GoogleUtilities](GoogleUtilities/README.md) pod is +a set of utilities used by Firebase and other Google products. -## Install a Firebase SDK using CocoaPods +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found at +[https://firebase.google.com](https://firebase.google.com). -Firebase distributes several iOS specific APIs and SDKs via CocoaPods. -You can install the CocoaPods tool on OS X by running the following command from -the terminal. Detailed information is available in the [Getting Started -guide](https://guides.cocoapods.org/using/getting-started.html#getting-started). +## Installation + +See the three subsections for details about three different installation methods. +1. [Standard pod install](README.md#standard-pod-install) +1. [Installing from the GitHub repo](README.md#installing-from-github) +1. [Experimental Carthage](README.md#carthage-ios-only) + +### Standard pod install + +Go to +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Installing from GitHub + +For releases starting with 5.0.0, the source for each release is also deployed +to CocoaPods master and available via standard +[CocoaPods Podfile syntax](https://guides.cocoapods.org/syntax/podfile.html#pod). + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See +[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All of the official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +``` +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +``` + +To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do: ``` -$ sudo gem install cocoapods +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' ``` -## Try out an SDK +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution are at +[Carthage](Carthage.md). + +### Rome + +Instructions for installing binary frameworks via +[Rome](https://github.com/CocoaPods/Rome) are at [Rome](Rome.md). + +## Development -You can try any of the SDKs with `pod try`. Run the following command and select -the SDK you are interested in when prompted: +To develop Firebase software in this repository, ensure that you have at least +the following software: + + * Xcode 10.1 (or later) + * CocoaPods 1.7.2 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self contained Xcode project. See +[Firestore/README.md](Firestore/README.md). + +### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +### Adding a New Firebase Pod + +See [AddNewPod.md](AddNewPod.md). + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/style.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/style.sh) +before creating a PR. + +Travis will verify that any code changes are done in a style compliant way. Install +`clang-format` and `swiftformat`. +These commands will get the right versions: ``` -$ pod try Firebase +brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/e3496d9/Formula/clang-format.rb +brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/7963c3d/Formula/swiftformat.rb ``` -Note that some SDKs may require credentials. More information is available in -the SDK-specific documentation at [https://firebase.google.com/docs/](https://firebase.google.com/docs/). - -## Add a Firebase SDK to your iOS app - -CocoaPods is used to install and manage dependencies in existing Xcode projects. - -1. Create an Xcode project, and save it to your local machine. -2. Create a file named `Podfile` in your project directory. This file defines - your project's dependencies, and is commonly referred to as a Podspec. -3. Open `Podfile`, and add your dependencies. A simple Podspec is shown here: - - ``` - platform :ios, '8.0' - pod 'Firebase' - ``` - -4. Save the file. - -5. Open a terminal and `cd` to the directory containing the Podfile. - - ``` - $ cd /project/ - ``` - -6. Run the `pod install` command. This will install the SDKs specified in the - Podspec, along with any dependencies they may have. - - ``` - $ pod install - ``` - -7. Open your app's `.xcworkspace` file to launch Xcode. Use this file for all - development on your app. - -8. You can also install other Firebase SDKs by adding the subspecs in the - Podfile. - - ``` - pod 'Firebase/AdMob' - pod 'Firebase/Analytics' - pod 'Firebase/Auth' - pod 'Firebase/Database' - pod 'Firebase/DynamicLinks' - pod 'Firebase/Firestore' - pod 'Firebase/Functions' - pod 'Firebase/InAppMessaging' - pod 'Firebase/InAppMessagingDisplay' - pod 'Firebase/Messaging' - pod 'Firebase/MLCommon' - pod 'Firebase/MLModelInterpreter' - pod 'Firebase/MLNLLanguageID' - pod 'Firebase/MLNLSmartReply' - pod 'Firebase/MLNaturalLanguage' - pod 'Firebase/MLVision' - pod 'Firebase/MLVisionBarcodeModel' - pod 'Firebase/MLVisionFaceModel' - pod 'Firebase/MLVisionLabelModel' - pod 'Firebase/MLVisionTextModel' - pod 'Firebase/Performance' - pod 'Firebase/RemoteConfig' - pod 'Firebase/Storage' - ``` +Note: if you already have a newer version of these installed you may need to +`brew switch` to this version. + +To update this section, find the versions of clang-format and swiftformat.rb to +match the versions in the CI failure logs +[here](https://github.com/Homebrew/homebrew-core/tree/master/Formula). + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +#### Viewing Code Coverage + +First, make sure that [xcov](https://github.com/nakiostudio/xcov) is installed with `gem install xcov`. + +After running the `AllUnitTests_iOS` scheme in Xcode, execute +`xcov --workspace Firebase.xcworkspace --scheme AllUnitTests_iOS --output_directory xcov_output` +at Example/ in the terminal. This will aggregate the coverage, and you can run `open xcov_output/index.html` to see the results. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need valid +`GoogleService-Info.plist` files for those samples. The Firebase Xcode project contains dummy plist +files without real values, but can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g. `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and replace the appropriate dummy plist file +(e.g. in [Example/Database/App/](Example/Database/App/)); + +Some sample apps like Firebase Messaging ([Example/Messaging/App](Example/Messaging/App)) require +special Apple capabilities, and you will have to change the sample app to use a unique bundle +identifier that you can control in your own Apple Developer account. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +If you're doing specific Firebase Auth development, see +[the Auth Sample README](Example/Auth/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +To run the Database Integration tests, make your database authentication rules +[public](https://firebase.google.com/docs/database/security/quickstart). + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[FIRStorageIntegrationTests.m](Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to actually test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account, and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications, and will not receive push notifications. +In order to receive push notifications, you'll have to follow the steps above and run the app on a +physical device. + +## Community Supported Efforts + +We've seen an amazing amount of interest and contributions to improve the Firebase SDKs, and we are +very grateful! We'd like to empower as many developers as we can to be able to use Firebase and +participate in the Firebase community. + +### tvOS, macOS, and Catalyst +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and work on +tvOS, macOS, and Catalyst. + +For tvOS, checkout the [Sample](Example/tvOSSample). + +Keep in mind that macOS, Catalyst and tvOS are not officially supported by Firebase, and this +repository is actively developed primarily for iOS. While we can catch basic unit test issues with +Travis, there may be some changes where the SDK no longer works as expected on macOS or tvOS. If you +encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the app +has communicated with our servers". This relies on Analytics and will not work on macOS/tvOS/Catalyst. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +To install, add a subset of the following to the Podfile: + +``` +pod 'Firebase/ABTesting' +pod 'Firebase/Auth' +pod 'Firebase/Crashlytics' +pod 'Firebase/Database' +pod 'Firebase/Firestore' +pod 'Firebase/Functions' +pod 'Firebase/Messaging' +pod 'Firebase/RemoteConfig' +pod 'Firebase/Storage' +``` + +#### Additional Catalyst Notes + +* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability` +to Build Settings. +* FirebaseFirestore requires signing the +[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +iOS SDK. + +## License + +The contents of this repository is licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). + +[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions +[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg +[gh-datatransport-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/datatransport/badge.svg +[gh-dynamiclinks-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/dynamiclinks/badge.svg +[gh-storage-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/storage/badge.svg +[gh-zip-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/zip/badge.svg diff --git a/Example/Pods/FirebaseAnalytics/Frameworks/FIRAnalyticsConnector.framework/FIRAnalyticsConnector b/Example/Pods/FirebaseAnalytics/Frameworks/FIRAnalyticsConnector.framework/FIRAnalyticsConnector index 1d76f36..1a7eaec 100755 Binary files a/Example/Pods/FirebaseAnalytics/Frameworks/FIRAnalyticsConnector.framework/FIRAnalyticsConnector and b/Example/Pods/FirebaseAnalytics/Frameworks/FIRAnalyticsConnector.framework/FIRAnalyticsConnector differ diff --git a/Example/Pods/FirebaseAnalytics/Frameworks/FIRAnalyticsConnector.framework/Modules/module.modulemap b/Example/Pods/FirebaseAnalytics/Frameworks/FIRAnalyticsConnector.framework/Modules/module.modulemap index 270ad21..99a4b1d 100755 --- a/Example/Pods/FirebaseAnalytics/Frameworks/FIRAnalyticsConnector.framework/Modules/module.modulemap +++ b/Example/Pods/FirebaseAnalytics/Frameworks/FIRAnalyticsConnector.framework/Modules/module.modulemap @@ -3,6 +3,7 @@ framework module FIRAnalyticsConnector { module * { export * } link "sqlite3" link "z" + link framework "CoreData" link framework "Security" link framework "StoreKit" link framework "SystemConfiguration" diff --git a/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/FirebaseAnalytics b/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/FirebaseAnalytics index 635a347..fa7ceb9 100755 Binary files a/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/FirebaseAnalytics and b/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/FirebaseAnalytics differ diff --git a/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics.h b/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics.h index afb9f82..be0b1fa 100755 --- a/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics.h +++ b/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRAnalytics.h @@ -9,6 +9,10 @@ NS_ASSUME_NONNULL_BEGIN /// The top level Firebase Analytics singleton that provides methods for logging events and setting /// user properties. See the developer guides for general /// information on using Firebase Analytics in your apps. +/// +/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling +/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in +/// unexpected crashes at runtime. NS_SWIFT_NAME(Analytics) @interface FIRAnalytics : NSObject diff --git a/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h b/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h index f50707f..132aef7 100755 --- a/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h +++ b/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h @@ -15,3 +15,15 @@ /// The method used to sign in. For example, "google", "facebook" or "twitter". static NSString *const kFIRUserPropertySignUpMethod NS_SWIFT_NAME(AnalyticsUserPropertySignUpMethod) = @"sign_up_method"; + +/// Indicates whether events logged by Google Analytics can be used to personalize ads for the user. +/// Set to "YES" to enable, or "NO" to disable. Default is enabled. See the +/// documentation for +/// more details and information about related settings. +/// +///
+///     [FIRAnalytics setUserPropertyString:@"NO"
+///                                 forName:kFIRUserPropertyAllowAdPersonalizationSignals];
+/// 
+static NSString *const kFIRUserPropertyAllowAdPersonalizationSignals + NS_SWIFT_NAME(AnalyticsUserPropertyAllowAdPersonalizationSignals) = @"allow_personalized_ads"; diff --git a/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Modules/module.modulemap b/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Modules/module.modulemap index 6118e37..d7c5905 100755 --- a/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Modules/module.modulemap +++ b/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Modules/module.modulemap @@ -4,6 +4,7 @@ framework module FirebaseAnalytics { module * { export * } link "sqlite3" link "z" + link framework "CoreData" link framework "Security" link framework "StoreKit" link framework "SystemConfiguration" diff --git a/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseCoreDiagnostics.framework/FirebaseCoreDiagnostics b/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseCoreDiagnostics.framework/FirebaseCoreDiagnostics deleted file mode 100755 index 4d6ec2c..0000000 Binary files a/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseCoreDiagnostics.framework/FirebaseCoreDiagnostics and /dev/null differ diff --git a/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseCoreDiagnostics.framework/Modules/module.modulemap b/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseCoreDiagnostics.framework/Modules/module.modulemap deleted file mode 100755 index ce076e0..0000000 --- a/Example/Pods/FirebaseAnalytics/Frameworks/FirebaseCoreDiagnostics.framework/Modules/module.modulemap +++ /dev/null @@ -1,7 +0,0 @@ -framework module FirebaseCoreDiagnostics { - export * - module * { export * } - link "z" - link framework "Security" - link framework "SystemConfiguration" -} diff --git a/Example/Pods/FirebaseCore/Firebase/Core/FIRComponentContainer.m b/Example/Pods/FirebaseCore/Firebase/Core/FIRComponentContainer.m deleted file mode 100644 index 1977d0e..0000000 --- a/Example/Pods/FirebaseCore/Firebase/Core/FIRComponentContainer.m +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#import "Private/FIRComponentContainer.h" - -#import "Private/FIRAppInternal.h" -#import "Private/FIRComponent.h" -#import "Private/FIRLibrary.h" -#import "Private/FIRLogger.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface FIRComponentContainer () - -/// The dictionary of components that are registered for a particular app. The key is an NSString -/// of the protocol. -@property(nonatomic, strong) NSMutableDictionary *components; - -/// Cached instances of components that requested to be cached. -@property(nonatomic, strong) NSMutableDictionary *cachedInstances; - -@end - -@implementation FIRComponentContainer - -// Collection of all classes that register to provide components. -static NSMutableSet *sFIRComponentRegistrants; - -#pragma mark - Public Registration - -+ (void)registerAsComponentRegistrant:(Class)klass { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - sFIRComponentRegistrants = [[NSMutableSet alloc] init]; - }); - - [self registerAsComponentRegistrant:klass inSet:sFIRComponentRegistrants]; -} - -+ (void)registerAsComponentRegistrant:(Class)klass - inSet:(NSMutableSet *)allRegistrants { - [allRegistrants addObject:klass]; -} - -#pragma mark - Internal Initialization - -- (instancetype)initWithApp:(FIRApp *)app { - return [self initWithApp:app registrants:sFIRComponentRegistrants]; -} - -- (instancetype)initWithApp:(FIRApp *)app registrants:(NSMutableSet *)allRegistrants { - self = [super init]; - if (self) { - _app = app; - _cachedInstances = [NSMutableDictionary dictionary]; - _components = [NSMutableDictionary dictionary]; - - [self populateComponentsFromRegisteredClasses:allRegistrants forApp:app]; - } - return self; -} - -- (void)populateComponentsFromRegisteredClasses:(NSSet *)classes forApp:(FIRApp *)app { - // Loop through the verified component registrants and populate the components array. - for (Class klass in classes) { - // Loop through all the components being registered and store them as appropriate. - // Classes which do not provide functionality should use a dummy FIRComponentRegistrant - // protocol. - for (FIRComponent *component in [klass componentsToRegister]) { - // Check if the component has been registered before, and error out if so. - NSString *protocolName = NSStringFromProtocol(component.protocol); - if (self.components[protocolName]) { - FIRLogError(kFIRLoggerCore, @"I-COR000029", - @"Attempted to register protocol %@, but it already has an implementation.", - protocolName); - continue; - } - - // Store the creation block for later usage. - self.components[protocolName] = component.creationBlock; - - // Instantiate the - BOOL shouldInstantiateEager = - (component.instantiationTiming == FIRInstantiationTimingAlwaysEager); - BOOL shouldInstantiateDefaultEager = - (component.instantiationTiming == FIRInstantiationTimingEagerInDefaultApp && - [app isDefaultApp]); - if (shouldInstantiateEager || shouldInstantiateDefaultEager) { - [self instantiateInstanceForProtocol:component.protocol withBlock:component.creationBlock]; - } - } - } -} - -#pragma mark - Instance Creation - -/// Instantiate an instance of a class that conforms to the specified protocol. -/// This will: -/// - Call the block to create an instance if possible, -/// - Validate that the instance returned conforms to the protocol it claims to, -/// - Cache the instance if the block requests it -- (nullable id)instantiateInstanceForProtocol:(Protocol *)protocol - withBlock:(FIRComponentCreationBlock)creationBlock { - if (!creationBlock) { - return nil; - } - - // Create an instance using the creation block. - BOOL shouldCache = NO; - id instance = creationBlock(self, &shouldCache); - if (!instance) { - return nil; - } - - // An instance was created, validate that it conforms to the protocol it claims to. - NSString *protocolName = NSStringFromProtocol(protocol); - if (![instance conformsToProtocol:protocol]) { - FIRLogError(kFIRLoggerCore, @"I-COR000030", - @"An instance conforming to %@ was requested, but the instance provided does not " - @"conform to the protocol", - protocolName); - } - - // The instance is ready to be returned, but check if it should be cached first before returning. - if (shouldCache) { - self.cachedInstances[protocolName] = instance; - } - - return instance; -} - -#pragma mark - Internal Retrieval - -- (nullable id)instanceForProtocol:(Protocol *)protocol { - // Check if there is a cached instance, and return it if so. - NSString *protocolName = NSStringFromProtocol(protocol); - id cachedInstance = self.cachedInstances[protocolName]; - if (cachedInstance) { - return cachedInstance; - } - - // Use the creation block to instantiate an instance and return it. - FIRComponentCreationBlock creationBlock = self.components[protocolName]; - return [self instantiateInstanceForProtocol:protocol withBlock:creationBlock]; -} - -#pragma mark - Lifecycle - -- (void)removeAllCachedInstances { - // Loop through the cache and notify each instance that is a maintainer to clean up after itself. - for (id instance in self.cachedInstances.allValues) { - if ([instance conformsToProtocol:@protocol(FIRComponentLifecycleMaintainer)] && - [instance respondsToSelector:@selector(appWillBeDeleted:)]) { - [instance appWillBeDeleted:self.app]; - } - } - - [self.cachedInstances removeAllObjects]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseCore/Firebase/Core/FIRErrors.m b/Example/Pods/FirebaseCore/Firebase/Core/FIRErrors.m deleted file mode 100644 index 6d6d52d..0000000 --- a/Example/Pods/FirebaseCore/Firebase/Core/FIRErrors.m +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2017 Google -// -// 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. - -#import "Private/FIRErrors.h" - -NSString *const kFirebaseErrorDomain = @"com.firebase"; -NSString *const kFirebaseAdMobErrorDomain = @"com.firebase.admob"; -NSString *const kFirebaseAppInviteErrorDomain = @"com.firebase.appinvite"; -NSString *const kFirebaseAuthErrorDomain = @"com.firebase.auth"; -NSString *const kFirebaseCloudMessagingErrorDomain = @"com.firebase.cloudmessaging"; -NSString *const kFirebaseConfigErrorDomain = @"com.firebase.config"; -NSString *const kFirebaseCoreErrorDomain = @"com.firebase.core"; -NSString *const kFirebaseCrashReportingErrorDomain = @"com.firebase.crashreporting"; -NSString *const kFirebaseDatabaseErrorDomain = @"com.firebase.database"; -NSString *const kFirebaseDurableDeepLinkErrorDomain = @"com.firebase.durabledeeplink"; -NSString *const kFirebaseInstanceIDErrorDomain = @"com.firebase.instanceid"; -NSString *const kFirebasePerfErrorDomain = @"com.firebase.perf"; -NSString *const kFirebaseStorageErrorDomain = @"com.firebase.storage"; diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRAnalyticsConfiguration+Internal.h b/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRAnalyticsConfiguration+Internal.h deleted file mode 100644 index be624b4..0000000 --- a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRAnalyticsConfiguration+Internal.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "FIRAnalyticsConfiguration.h" - -/// Values stored in analyticsEnabledState. Never alter these constants since they must match with -/// values persisted to disk. -typedef NS_ENUM(int64_t, FIRAnalyticsEnabledState) { - // 0 is the default value for keys not found stored in persisted config, so it cannot represent - // kFIRAnalyticsEnabledStateSetNo. It must represent kFIRAnalyticsEnabledStateNotSet. - kFIRAnalyticsEnabledStateNotSet = 0, - kFIRAnalyticsEnabledStateSetYes = 1, - kFIRAnalyticsEnabledStateSetNo = 2, -}; - -/// The user defaults key for the persisted measurementEnabledState value. FIRAPersistedConfig reads -/// measurementEnabledState using this same key. -static NSString *const kFIRAPersistedConfigMeasurementEnabledStateKey = - @"/google/measurement/measurement_enabled_state"; - -static NSString *const kFIRAnalyticsConfigurationSetEnabledNotification = - @"FIRAnalyticsConfigurationSetEnabledNotification"; -static NSString *const kFIRAnalyticsConfigurationSetMinimumSessionIntervalNotification = - @"FIRAnalyticsConfigurationSetMinimumSessionIntervalNotification"; -static NSString *const kFIRAnalyticsConfigurationSetSessionTimeoutIntervalNotification = - @"FIRAnalyticsConfigurationSetSessionTimeoutIntervalNotification"; - -@interface FIRAnalyticsConfiguration (Internal) - -/// Sets whether analytics collection is enabled for this app on this device, and a flag to persist -/// the value or not. The setting should not be persisted if being set by the global data collection -/// flag. -- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled - persistSetting:(BOOL)shouldPersist; - -@end diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRErrorCode.h b/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRErrorCode.h deleted file mode 100644 index 01d3c56..0000000 --- a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRErrorCode.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -/** Error codes in Firebase error domain. */ -typedef NS_ENUM(NSInteger, FIRErrorCode) { - /** - * Unknown error. - */ - FIRErrorCodeUnknown = 0, - /** - * Loading data from the GoogleService-Info.plist file failed. This is a fatal error and should - * not be ignored. Further calls to the API will fail and/or possibly cause crashes. - */ - FIRErrorCodeInvalidPlistFile = -100, - - /** - * Validating the Google App ID format failed. - */ - FIRErrorCodeInvalidAppID = -101, - - /** - * Error code for failing to configure a specific service. - */ - FIRErrorCodeAdMobFailed = -110, - FIRErrorCodeAppInviteFailed = -112, - FIRErrorCodeCloudMessagingFailed = -113, - FIRErrorCodeConfigFailed = -114, - FIRErrorCodeDatabaseFailed = -115, - FIRErrorCodeCrashReportingFailed = -118, - FIRErrorCodeDurableDeepLinkFailed = -119, - FIRErrorCodeAuthFailed = -120, - FIRErrorCodeInstanceIDFailed = -121, - FIRErrorCodeStorageFailed = -123, - - /** - * Error codes returned by Dynamic Links - */ - FIRErrorCodeDynamicLinksStrongMatchNotAvailable = -124, - FIRErrorCodeDynamicLinksManualRetrievalNotEnabled = -125, - FIRErrorCodeDynamicLinksPendingLinkOnlyAvailableAtFirstLaunch = -126, - FIRErrorCodeDynamicLinksPendingLinkRetrievalAlreadyRunning = -127, -}; diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRErrors.h b/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRErrors.h deleted file mode 100644 index cf69252..0000000 --- a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRErrors.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include "FIRErrorCode.h" - -extern NSString *const kFirebaseErrorDomain; -extern NSString *const kFirebaseAdMobErrorDomain; -extern NSString *const kFirebaseAppInviteErrorDomain; -extern NSString *const kFirebaseAuthErrorDomain; -extern NSString *const kFirebaseCloudMessagingErrorDomain; -extern NSString *const kFirebaseConfigErrorDomain; -extern NSString *const kFirebaseCoreErrorDomain; -extern NSString *const kFirebaseCrashReportingErrorDomain; -extern NSString *const kFirebaseDatabaseErrorDomain; -extern NSString *const kFirebaseDurableDeepLinkErrorDomain; -extern NSString *const kFirebaseInstanceIDErrorDomain; -extern NSString *const kFirebasePerfErrorDomain; -extern NSString *const kFirebaseStorageErrorDomain; diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Public/FIRAnalyticsConfiguration.h b/Example/Pods/FirebaseCore/Firebase/Core/Public/FIRAnalyticsConfiguration.h deleted file mode 100644 index add4a38..0000000 --- a/Example/Pods/FirebaseCore/Firebase/Core/Public/FIRAnalyticsConfiguration.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -NS_ASSUME_NONNULL_BEGIN - -/** - * This class provides configuration fields for Firebase Analytics. - */ -NS_SWIFT_NAME(AnalyticsConfiguration) -DEPRECATED_MSG_ATTRIBUTE("Use these methods directly on the `Analytics` class.") -@interface FIRAnalyticsConfiguration : NSObject - -/** - * Returns the shared instance of FIRAnalyticsConfiguration. - */ -+ (FIRAnalyticsConfiguration *)sharedInstance NS_SWIFT_NAME(shared()); - -/** - * Deprecated. - * Sets the minimum engagement time in seconds required to start a new session. The default value - * is 10 seconds. - */ -- (void)setMinimumSessionInterval:(NSTimeInterval)minimumSessionInterval - DEPRECATED_MSG_ATTRIBUTE( - "Sessions are started immediately. More information at https://bit.ly/2FU46av"); - -/** - * Sets the interval of inactivity in seconds that terminates the current session. The default - * value is 1800 seconds (30 minutes). - */ -- (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; - -/** - * Sets whether analytics collection is enabled for this app on this device. This setting is - * persisted across app sessions. By default it is enabled. - */ -- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseCore/Firebase/Core/FIRAnalyticsConfiguration.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m similarity index 80% rename from Example/Pods/FirebaseCore/Firebase/Core/FIRAnalyticsConfiguration.m rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m index e584839..3a7d6de 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/FIRAnalyticsConfiguration.m +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import "FIRAnalyticsConfiguration.h" +#import -#import "Private/FIRAnalyticsConfiguration+Internal.h" +#import "FirebaseCore/Sources/Private/FIRAnalyticsConfiguration.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-implementations" @@ -39,16 +39,6 @@ - (void)postNotificationName:(NSString *)name value:(id)value { userInfo:@{name : value}]; } -- (void)setMinimumSessionInterval:(NSTimeInterval)minimumSessionInterval { - [self postNotificationName:kFIRAnalyticsConfigurationSetMinimumSessionIntervalNotification - value:@(minimumSessionInterval)]; -} - -- (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval { - [self postNotificationName:kFIRAnalyticsConfigurationSetSessionTimeoutIntervalNotification - value:@(sessionTimeoutInterval)]; -} - - (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled { [self setAnalyticsCollectionEnabled:analyticsCollectionEnabled persistSetting:YES]; } diff --git a/Example/Pods/FirebaseCore/Firebase/Core/FIRApp.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m similarity index 79% rename from Example/Pods/FirebaseCore/Firebase/Core/FIRApp.m rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m index a38e8f3..02f3ac3 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/FIRApp.m +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m @@ -14,33 +14,50 @@ #include -#import "FIRApp.h" -#import "FIRConfiguration.h" -#import "Private/FIRAnalyticsConfiguration+Internal.h" -#import "Private/FIRAppInternal.h" -#import "Private/FIRBundleUtil.h" -#import "Private/FIRComponentContainerInternal.h" -#import "Private/FIRLibrary.h" -#import "Private/FIRLogger.h" -#import "Private/FIROptionsInternal.h" - -NSString *const kFIRServiceAdMob = @"AdMob"; -NSString *const kFIRServiceAuth = @"Auth"; -NSString *const kFIRServiceAuthUI = @"AuthUI"; -NSString *const kFIRServiceCrash = @"Crash"; -NSString *const kFIRServiceDatabase = @"Database"; -NSString *const kFIRServiceDynamicLinks = @"DynamicLinks"; -NSString *const kFIRServiceFirestore = @"Firestore"; -NSString *const kFIRServiceFunctions = @"Functions"; -NSString *const kFIRServiceInstanceID = @"InstanceID"; -NSString *const kFIRServiceInvites = @"Invites"; -NSString *const kFIRServiceMessaging = @"Messaging"; -NSString *const kFIRServiceMeasurement = @"Measurement"; -NSString *const kFIRServicePerformance = @"Performance"; -NSString *const kFIRServiceRemoteConfig = @"RemoteConfig"; -NSString *const kFIRServiceStorage = @"Storage"; -NSString *const kGGLServiceAnalytics = @"Analytics"; -NSString *const kGGLServiceSignIn = @"SignIn"; +#if __has_include() +#import +#endif + +#if __has_include() +#import +#endif + +#import + +#import "FirebaseCore/Sources/FIRBundleUtil.h" +#import "FirebaseCore/Sources/FIRVersion.h" +#import "FirebaseCore/Sources/Private/FIRAnalyticsConfiguration.h" +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" +#import "FirebaseCore/Sources/Private/FIRComponentContainerInternal.h" +#import "FirebaseCore/Sources/Private/FIRConfigurationInternal.h" +#import "FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h" +#import "FirebaseCore/Sources/Private/FIRLibrary.h" +#import "FirebaseCore/Sources/Private/FIRLogger.h" +#import "FirebaseCore/Sources/Private/FIROptionsInternal.h" + +#import + +#import + +// The kFIRService strings are only here while transitioning CoreDiagnostics from the Analytics +// pod to a Core dependency. These symbols are not used and should be deleted after the transition. +NSString *const kFIRServiceAdMob; +NSString *const kFIRServiceAuth; +NSString *const kFIRServiceAuthUI; +NSString *const kFIRServiceCrash; +NSString *const kFIRServiceDatabase; +NSString *const kFIRServiceDynamicLinks; +NSString *const kFIRServiceFirestore; +NSString *const kFIRServiceFunctions; +NSString *const kFIRServiceInstanceID; +NSString *const kFIRServiceInvites; +NSString *const kFIRServiceMessaging; +NSString *const kFIRServiceMeasurement; +NSString *const kFIRServicePerformance; +NSString *const kFIRServiceRemoteConfig; +NSString *const kFIRServiceStorage; +NSString *const kGGLServiceAnalytics; +NSString *const kGGLServiceSignIn; NSString *const kFIRDefaultAppName = @"__FIRAPP_DEFAULT"; NSString *const kFIRAppReadyToConfigureSDKNotification = @"FIRAppReadyToConfigureSDKNotification"; @@ -99,23 +116,11 @@ @implementation FIRApp static NSMutableDictionary *sAllApps; static FIRApp *sDefaultApp; static NSMutableDictionary *sLibraryVersions; +static dispatch_once_t sFirebaseUserAgentOnceToken; + (void)configure { FIROptions *options = [FIROptions defaultOptions]; if (!options) { - // Read the Info.plist to see if the flag is set. At this point we can't check any user defaults - // since the app isn't configured at all, so only rely on the Info.plist value. - NSNumber *collectionEnabledPlistValue = [[self class] readDataCollectionSwitchFromPlist]; - if (collectionEnabledPlistValue == nil || [collectionEnabledPlistValue boolValue]) { - [[NSNotificationCenter defaultCenter] - postNotificationName:kFIRAppDiagnosticsNotification - object:nil - userInfo:@{ - kFIRAppDiagnosticsConfigurationTypeKey : @(FIRConfigTypeCore), - kFIRAppDiagnosticsErrorKey : [FIRApp errorForMissingOptions] - }]; - } - [NSException raise:kFirebaseCoreErrorDomain format:@"`[FIRApp configure];` (`FirebaseApp.configure()` in Swift) could not find " @"a valid GoogleService-Info.plist in your project. Please download one " @@ -139,6 +144,17 @@ + (void)configureWithOptions:(FIROptions *)options { [FIRApp configureWithName:kFIRDefaultAppName options:options]; } ++ (NSCharacterSet *)applicationNameAllowedCharacters { + static NSCharacterSet *applicationNameAllowedCharacters; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSMutableCharacterSet *allowedNameCharacters = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedNameCharacters addCharactersInString:@"-_"]; + applicationNameAllowedCharacters = [allowedNameCharacters copy]; + }); + return applicationNameAllowedCharacters; +} + + (void)configureWithName:(NSString *)name options:(FIROptions *)options { if (!name || !options) { [NSException raise:kFirebaseCoreErrorDomain format:@"Neither name nor options can be nil."]; @@ -149,27 +165,27 @@ + (void)configureWithName:(NSString *)name options:(FIROptions *)options { if ([name isEqualToString:kFIRDefaultAppName]) { if (sDefaultApp) { - [NSException raise:kFirebaseCoreErrorDomain - format:@"Default app has already been configured."]; + // The default app already exixts. Handle duplicate `configure` calls and return. + [self appWasConfiguredTwice:sDefaultApp usingOptions:options]; + return; } FIRLogDebug(kFIRLoggerCore, @"I-COR000001", @"Configuring the default app."); } else { // Validate the app name and ensure it hasn't been configured already. - for (NSUInteger charIndex = 0; charIndex < name.length; charIndex++) { - char character = [name characterAtIndex:charIndex]; - if (!((character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z') || - (character >= '0' && character <= '9') || character == '_' || character == '-')) { - [NSException raise:kFirebaseCoreErrorDomain - format:@"App name can only contain alphanumeric (A-Z,a-z,0-9), " - @"hyphen (-), and underscore (_) characters"]; - } + NSCharacterSet *nameCharacters = [NSCharacterSet characterSetWithCharactersInString:name]; + + if (![[self applicationNameAllowedCharacters] isSupersetOfSet:nameCharacters]) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App name can only contain alphanumeric, " + @"hyphen (-), and underscore (_) characters"]; } @synchronized(self) { if (sAllApps && sAllApps[name]) { - [NSException raise:kFirebaseCoreErrorDomain - format:@"App named %@ has already been configured.", name]; + // The app already exists. Handle a duplicate `configure` call and return. + [self appWasConfiguredTwice:sAllApps[name] usingOptions:options]; + return; } } @@ -183,10 +199,44 @@ + (void)configureWithName:(NSString *)name options:(FIROptions *)options { } [FIRApp addAppToAppDictionary:app]; + + // The FIRApp instance is ready to go, `sDefaultApp` is assigned, other SDKs are now ready to be + // instantiated. + [app.container instantiateEagerComponents]; [FIRApp sendNotificationsToSDKs:app]; } } +/// Called when `configure` has been called multiple times for the same app. This can either throw +/// an exception (most cases) or ignore the duplicate configuration in situations where it's allowed +/// like an extension. ++ (void)appWasConfiguredTwice:(FIRApp *)app usingOptions:(FIROptions *)options { + // Only extensions should potentially be able to call `configure` more than once. + if (![GULAppEnvironmentUtil isAppExtension]) { + // Throw an exception since this is now an invalid state. + if (app.isDefaultApp) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"Default app has already been configured."]; + } else { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App named %@ has already been configured.", app.name]; + } + } + + // In an extension, the entry point could be called multiple times. As long as the options are + // identical we should allow multiple `configure` calls. + if ([options isEqual:app.options]) { + // Everything is identical but the extension's lifecycle triggered `configure` twice. + // Ignore duplicate calls and return since everything should still be in a valid state. + FIRLogDebug(kFIRLoggerCore, @"I-COR000035", + @"Ignoring second `configure` call in an extension."); + return; + } else { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App named %@ has already been configured.", app.name]; + } +} + + (FIRApp *)defaultApp { if (sDefaultApp) { return sDefaultApp; @@ -228,6 +278,7 @@ + (void)resetApps { sAllApps = nil; [sLibraryVersions removeAllObjects]; sLibraryVersions = nil; + sFirebaseUserAgentOnceToken = 0; } } @@ -281,41 +332,24 @@ - (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)opti return self; } +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + - (BOOL)configureCore { [self checkExpectedBundleID]; if (![self isAppIDValid]) { - if (_options.usingOptionsFromDefaultPlist && [self isDataCollectionDefaultEnabled]) { - [[NSNotificationCenter defaultCenter] - postNotificationName:kFIRAppDiagnosticsNotification - object:nil - userInfo:@{ - kFIRAppDiagnosticsConfigurationTypeKey : @(FIRConfigTypeCore), - kFIRAppDiagnosticsErrorKey : [FIRApp errorForInvalidAppID], - }]; - } return NO; } - if ([self isDataCollectionDefaultEnabled]) { - [[NSNotificationCenter defaultCenter] - postNotificationName:kFIRAppDiagnosticsNotification - object:nil - userInfo:@{ - kFIRAppDiagnosticsConfigurationTypeKey : @(FIRConfigTypeCore), - kFIRAppDiagnosticsFIRAppKey : self - }]; - } + [self logCoreTelemetryIfEnabled]; #if TARGET_OS_IOS // Initialize the Analytics once there is a valid options under default app. Analytics should // always initialize first by itself before the other SDKs. if ([self.name isEqualToString:kFIRDefaultAppName]) { Class firAnalyticsClass = NSClassFromString(@"FIRAnalytics"); - if (!firAnalyticsClass) { - FIRLogWarning(kFIRLoggerCore, @"I-COR000022", - @"Firebase Analytics is not available. To add it, include Firebase/Core in the " - @"Podfile or add FirebaseAnalytics.framework to the Link Build Phase"); - } else { + if (firAnalyticsClass) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" SEL startWithConfigurationSelector = @selector(startWithConfiguration:options:); @@ -333,6 +367,8 @@ - (BOOL)configureCore { } #endif + [self subscribeForAppDidBecomeActiveNotifications]; + return YES; } @@ -359,7 +395,7 @@ - (void)setDataCollectionDefaultEnabled:(BOOL)dataCollectionDefaultEnabled { } // Check if the Analytics flag is explicitly set. If so, no further actions are necessary. - if ([self.options isAnalyticsCollectionExpicitlySet]) { + if ([self.options isAnalyticsCollectionExplicitlySet]) { return; } @@ -524,6 +560,25 @@ + (void)registerInternalLibrary:(nonnull Class)library + (NSString *)firebaseUserAgent { @synchronized(self) { + dispatch_once(&sFirebaseUserAgentOnceToken, ^{ + // Report FirebaseCore version for useragent string + [FIRApp registerLibrary:@"fire-ios" + withVersion:[NSString stringWithUTF8String:FIRCoreVersionString]]; + + NSDictionary *info = [[NSBundle mainBundle] infoDictionary]; + NSString *xcodeVersion = info[@"DTXcodeBuild"]; + NSString *sdkVersion = info[@"DTSDKBuild"]; + if (xcodeVersion) { + [FIRApp registerLibrary:@"xcode" withVersion:xcodeVersion]; + } + if (sdkVersion) { + [FIRApp registerLibrary:@"apple-sdk" withVersion:sdkVersion]; + } + + NSString *swiftFlagValue = [self hasSwiftRuntime] ? @"true" : @"false"; + [FIRApp registerLibrary:@"swift" withVersion:swiftFlagValue]; + }); + NSMutableArray *libraries = [[NSMutableArray alloc] initWithCapacity:sLibraryVersions.count]; for (NSString *libraryName in sLibraryVersions) { @@ -535,6 +590,20 @@ + (NSString *)firebaseUserAgent { } } ++ (BOOL)hasSwiftRuntime { + // The class + // [Swift._SwiftObject](https://github.com/apple/swift/blob/5eac3e2818eb340b11232aff83edfbd1c307fa03/stdlib/public/runtime/SwiftObject.h#L35) + // is a part of Swift runtime, so it should be present if Swift runtime is available. + + BOOL hasSwiftRuntime = + objc_lookUpClass("Swift._SwiftObject") != nil || + // Swift object class name before + // https://github.com/apple/swift/commit/9637b4a6e11ddca72f5f6dbe528efc7c92f14d01 + objc_getClass("_TtCs12_SwiftObject") != nil; + + return hasSwiftRuntime; +} + - (void)checkExpectedBundleID { NSArray *bundles = [FIRBundleUtil relevantBundles]; NSString *expectedBundleID = [self expectedBundleID]; @@ -804,26 +873,40 @@ + (nullable NSNumber *)readDataCollectionSwitchFromPlist { #pragma mark - Sending Logs +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" - (void)sendLogsWithServiceName:(NSString *)serviceName version:(NSString *)version error:(NSError *)error { - // If the user has manually turned off data collection, return and don't send logs. - if (![self isDataCollectionDefaultEnabled]) { - return; - } + // Do nothing. Please remove calls to this method. +} +#pragma clang diagnostic pop - NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithDictionary:@{ - kFIRAppDiagnosticsConfigurationTypeKey : @(FIRConfigTypeSDK), - kFIRAppDiagnosticsSDKNameKey : serviceName, - kFIRAppDiagnosticsSDKVersionKey : version, - kFIRAppDiagnosticsFIRAppKey : self - }]; - if (error) { - userInfo[kFIRAppDiagnosticsErrorKey] = error; +#pragma mark - App Life Cycle + +- (void)subscribeForAppDidBecomeActiveNotifications { +#if TARGET_OS_IOS || TARGET_OS_TV + NSNotificationName notificationName = UIApplicationDidBecomeActiveNotification; +#elif TARGET_OS_OSX + NSNotificationName notificationName = NSApplicationDidBecomeActiveNotification; +#endif + +#if !TARGET_OS_WATCH + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appDidBecomeActive:) + name:notificationName + object:nil]; +#endif +} + +- (void)appDidBecomeActive:(NSNotification *)notification { + [self logCoreTelemetryIfEnabled]; +} + +- (void)logCoreTelemetryIfEnabled { + if ([self isDataCollectionDefaultEnabled]) { + [FIRCoreDiagnosticsConnector logCoreTelemetryWithOptions:_options]; } - [[NSNotificationCenter defaultCenter] postNotificationName:kFIRAppDiagnosticsNotification - object:nil - userInfo:userInfo]; } @end diff --git a/Example/Pods/FirebaseCore/Firebase/Core/FIRAppAssociationRegistration.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRAppAssociationRegistration.m similarity index 96% rename from Example/Pods/FirebaseCore/Firebase/Core/FIRAppAssociationRegistration.m rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRAppAssociationRegistration.m index 2aecdab..e4125cd 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/FIRAppAssociationRegistration.m +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRAppAssociationRegistration.m @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import "Private/FIRAppAssociationRegistration.h" +#import "FirebaseCore/Sources/Private/FIRAppAssociationRegistration.h" #import diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRBundleUtil.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h similarity index 100% rename from Example/Pods/FirebaseCore/Firebase/Core/Private/FIRBundleUtil.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h diff --git a/Example/Pods/FirebaseCore/Firebase/Core/FIRBundleUtil.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m similarity index 93% rename from Example/Pods/FirebaseCore/Firebase/Core/FIRBundleUtil.m rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m index 841833a..b858f14 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/FIRBundleUtil.m +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import "Private/FIRBundleUtil.h" +#import "FirebaseCore/Sources/FIRBundleUtil.h" #import @@ -52,10 +52,10 @@ + (BOOL)hasBundleIdentifierPrefix:(NSString *)bundleIdentifier inBundles:(NSArra // This allows app extensions that have the app's bundle as their prefix to pass this test. NSString *applicationBundleIdentifier = [GULAppEnvironmentUtil isAppExtension] - ? [self bundleIdentifierByRemovingLastPartFrom:bundleIdentifier] - : bundleIdentifier; + ? [self bundleIdentifierByRemovingLastPartFrom:bundle.bundleIdentifier] + : bundle.bundleIdentifier; - if ([applicationBundleIdentifier isEqualToString:bundle.bundleIdentifier]) { + if ([applicationBundleIdentifier isEqualToString:bundleIdentifier]) { return YES; } } diff --git a/Example/Pods/FirebaseCore/Firebase/Core/FIRComponent.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m similarity index 93% rename from Example/Pods/FirebaseCore/Firebase/Core/FIRComponent.m rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m index 2474d1a..9c1fbed 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/FIRComponent.m +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m @@ -14,10 +14,10 @@ * limitations under the License. */ -#import "Private/FIRComponent.h" +#import "FirebaseCore/Sources/Private/FIRComponent.h" -#import "Private/FIRComponentContainer.h" -#import "Private/FIRDependency.h" +#import "FirebaseCore/Sources/Private/FIRComponentContainer.h" +#import "FirebaseCore/Sources/Private/FIRDependency.h" @interface FIRComponent () diff --git a/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m new file mode 100644 index 0000000..9f91786 --- /dev/null +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m @@ -0,0 +1,208 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#import "FirebaseCore/Sources/Private/FIRComponentContainer.h" + +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" +#import "FirebaseCore/Sources/Private/FIRComponent.h" +#import "FirebaseCore/Sources/Private/FIRLibrary.h" +#import "FirebaseCore/Sources/Private/FIRLogger.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRComponentContainer () + +/// The dictionary of components that are registered for a particular app. The key is an `NSString` +/// of the protocol. +@property(nonatomic, strong) NSMutableDictionary *components; + +/// Cached instances of components that requested to be cached. +@property(nonatomic, strong) NSMutableDictionary *cachedInstances; + +/// Protocols of components that have requested to be eagerly instantiated. +@property(nonatomic, strong, nullable) NSMutableArray *eagerProtocolsToInstantiate; + +@end + +@implementation FIRComponentContainer + +// Collection of all classes that register to provide components. +static NSMutableSet *sFIRComponentRegistrants; + +#pragma mark - Public Registration + ++ (void)registerAsComponentRegistrant:(Class)klass { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sFIRComponentRegistrants = [[NSMutableSet alloc] init]; + }); + + [self registerAsComponentRegistrant:klass inSet:sFIRComponentRegistrants]; +} + ++ (void)registerAsComponentRegistrant:(Class)klass + inSet:(NSMutableSet *)allRegistrants { + [allRegistrants addObject:klass]; +} + +#pragma mark - Internal Initialization + +- (instancetype)initWithApp:(FIRApp *)app { + return [self initWithApp:app registrants:sFIRComponentRegistrants]; +} + +- (instancetype)initWithApp:(FIRApp *)app registrants:(NSMutableSet *)allRegistrants { + self = [super init]; + if (self) { + _app = app; + _cachedInstances = [NSMutableDictionary dictionary]; + _components = [NSMutableDictionary dictionary]; + + [self populateComponentsFromRegisteredClasses:allRegistrants forApp:app]; + } + return self; +} + +- (void)populateComponentsFromRegisteredClasses:(NSSet *)classes forApp:(FIRApp *)app { + // Keep track of any components that need to eagerly instantiate after all components are added. + self.eagerProtocolsToInstantiate = [[NSMutableArray alloc] init]; + + // Loop through the verified component registrants and populate the components array. + for (Class klass in classes) { + // Loop through all the components being registered and store them as appropriate. + // Classes which do not provide functionality should use a dummy FIRComponentRegistrant + // protocol. + for (FIRComponent *component in [klass componentsToRegister]) { + // Check if the component has been registered before, and error out if so. + NSString *protocolName = NSStringFromProtocol(component.protocol); + if (self.components[protocolName]) { + FIRLogError(kFIRLoggerCore, @"I-COR000029", + @"Attempted to register protocol %@, but it already has an implementation.", + protocolName); + continue; + } + + // Store the creation block for later usage. + self.components[protocolName] = component.creationBlock; + + // Queue any protocols that should be eagerly instantiated. Don't instantiate them yet + // because they could depend on other components that haven't been added to the components + // array yet. + BOOL shouldInstantiateEager = + (component.instantiationTiming == FIRInstantiationTimingAlwaysEager); + BOOL shouldInstantiateDefaultEager = + (component.instantiationTiming == FIRInstantiationTimingEagerInDefaultApp && + [app isDefaultApp]); + if (shouldInstantiateEager || shouldInstantiateDefaultEager) { + [self.eagerProtocolsToInstantiate addObject:component.protocol]; + } + } + } +} + +#pragma mark - Instance Creation + +- (void)instantiateEagerComponents { + // After all components are registered, instantiate the ones that are requesting eager + // instantiation. + @synchronized(self) { + for (Protocol *protocol in self.eagerProtocolsToInstantiate) { + // Get an instance for the protocol, which will instantiate it since it couldn't have been + // cached yet. Ignore the instance coming back since we don't need it. + __unused id unusedInstance = [self instanceForProtocol:protocol]; + } + + // All eager instantiation is complete, clear the stored property now. + self.eagerProtocolsToInstantiate = nil; + } +} + +/// Instantiate an instance of a class that conforms to the specified protocol. +/// This will: +/// - Call the block to create an instance if possible, +/// - Validate that the instance returned conforms to the protocol it claims to, +/// - Cache the instance if the block requests it +/// +/// Note that this method assumes the caller already has @sychronized on self. +- (nullable id)instantiateInstanceForProtocol:(Protocol *)protocol + withBlock:(FIRComponentCreationBlock)creationBlock { + if (!creationBlock) { + return nil; + } + + // Create an instance using the creation block. + BOOL shouldCache = NO; + id instance = creationBlock(self, &shouldCache); + if (!instance) { + return nil; + } + + // An instance was created, validate that it conforms to the protocol it claims to. + NSString *protocolName = NSStringFromProtocol(protocol); + if (![instance conformsToProtocol:protocol]) { + FIRLogError(kFIRLoggerCore, @"I-COR000030", + @"An instance conforming to %@ was requested, but the instance provided does not " + @"conform to the protocol", + protocolName); + } + + // The instance is ready to be returned, but check if it should be cached first before returning. + if (shouldCache) { + self.cachedInstances[protocolName] = instance; + } + + return instance; +} + +#pragma mark - Internal Retrieval + +- (nullable id)instanceForProtocol:(Protocol *)protocol { + // Check if there is a cached instance, and return it if so. + NSString *protocolName = NSStringFromProtocol(protocol); + + id cachedInstance; + @synchronized(self) { + cachedInstance = self.cachedInstances[protocolName]; + if (!cachedInstance) { + // Use the creation block to instantiate an instance and return it. + FIRComponentCreationBlock creationBlock = self.components[protocolName]; + cachedInstance = [self instantiateInstanceForProtocol:protocol withBlock:creationBlock]; + } + } + return cachedInstance; +} + +#pragma mark - Lifecycle + +- (void)removeAllCachedInstances { + @synchronized(self) { + // Loop through the cache and notify each instance that is a maintainer to clean up after + // itself. + for (id instance in self.cachedInstances.allValues) { + if ([instance conformsToProtocol:@protocol(FIRComponentLifecycleMaintainer)] && + [instance respondsToSelector:@selector(appWillBeDeleted:)]) { + [instance appWillBeDeleted:self.app]; + } + } + + // Empty the cache. + [self.cachedInstances removeAllObjects]; + } +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseCore/Firebase/Core/FIRComponentType.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m similarity index 86% rename from Example/Pods/FirebaseCore/Firebase/Core/FIRComponentType.m rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m index bdc004f..6410f2e 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/FIRComponentType.m +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m @@ -14,9 +14,9 @@ * limitations under the License. */ -#import "Private/FIRComponentType.h" +#import "FirebaseCore/Sources/Private/FIRComponentType.h" -#import "Private/FIRComponentContainerInternal.h" +#import "FirebaseCore/Sources/Private/FIRComponentContainerInternal.h" @implementation FIRComponentType diff --git a/Example/Pods/FirebaseCore/Firebase/Core/FIRConfiguration.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m similarity index 89% rename from Example/Pods/FirebaseCore/Firebase/Core/FIRConfiguration.m rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m index f8378d7..a1c9f4a 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/FIRConfiguration.m +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m @@ -12,7 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import "FIRConfiguration.h" +#import "FirebaseCore/Sources/Private/FIRConfigurationInternal.h" + +#import "FirebaseCore/Sources/Private/FIRAnalyticsConfiguration.h" extern void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); @@ -30,10 +32,7 @@ + (instancetype)sharedInstance { - (instancetype)init { self = [super init]; if (self) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" _analyticsConfiguration = [FIRAnalyticsConfiguration sharedInstance]; -#pragma clang diagnostic pop } return self; } diff --git a/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRCoreDiagnosticsConnector.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRCoreDiagnosticsConnector.m new file mode 100644 index 0000000..4981ca1 --- /dev/null +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRCoreDiagnosticsConnector.m @@ -0,0 +1,61 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import "FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h" + +#import + +#import + +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" +#import "FirebaseCore/Sources/Private/FIRDiagnosticsData.h" +#import "FirebaseCore/Sources/Private/FIROptionsInternal.h" + +// Define the interop class symbol declared as an extern in FIRCoreDiagnosticsInterop. +Class FIRCoreDiagnosticsImplementation; + +@implementation FIRCoreDiagnosticsConnector + ++ (void)initialize { + if (!FIRCoreDiagnosticsImplementation) { + FIRCoreDiagnosticsImplementation = NSClassFromString(@"FIRCoreDiagnostics"); + if (FIRCoreDiagnosticsImplementation) { + NSAssert([FIRCoreDiagnosticsImplementation + conformsToProtocol:@protocol(FIRCoreDiagnosticsInterop)], + @"If FIRCoreDiagnostics is implemented, it must conform to the interop protocol."); + NSAssert( + [FIRCoreDiagnosticsImplementation respondsToSelector:@selector(sendDiagnosticsData:)], + @"If FIRCoreDiagnostics is implemented, it must implement +sendDiagnosticsData."); + } + } +} + ++ (void)logCoreTelemetryWithOptions:(FIROptions *)options { + if (FIRCoreDiagnosticsImplementation) { + FIRDiagnosticsData *diagnosticsData = [[FIRDiagnosticsData alloc] init]; + [diagnosticsData insertValue:@(YES) forKey:kFIRCDIsDataCollectionDefaultEnabledKey]; + [diagnosticsData insertValue:[FIRApp firebaseUserAgent] forKey:kFIRCDFirebaseUserAgentKey]; + [diagnosticsData insertValue:@(FIRConfigTypeCore) forKey:kFIRCDConfigurationTypeKey]; + [diagnosticsData insertValue:options.googleAppID forKey:kFIRCDGoogleAppIDKey]; + [diagnosticsData insertValue:options.bundleID forKey:kFIRCDBundleIDKey]; + [diagnosticsData insertValue:@(options.usingOptionsFromDefaultPlist) + forKey:kFIRCDUsingOptionsFromDefaultPlistKey]; + [diagnosticsData insertValue:options.libraryVersionID forKey:kFIRCDLibraryVersionIDKey]; + [FIRCoreDiagnosticsImplementation sendDiagnosticsData:diagnosticsData]; + } +} + +@end diff --git a/Example/Pods/FirebaseCore/Firebase/Core/FIRDependency.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRDependency.m similarity index 95% rename from Example/Pods/FirebaseCore/Firebase/Core/FIRDependency.m rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRDependency.m index f979984..e1e2578 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/FIRDependency.m +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRDependency.m @@ -14,7 +14,7 @@ * limitations under the License. */ -#import "Private/FIRDependency.h" +#import "FirebaseCore/Sources/Private/FIRDependency.h" @interface FIRDependency () diff --git a/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRDiagnosticsData.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRDiagnosticsData.m new file mode 100644 index 0000000..bbe0561 --- /dev/null +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRDiagnosticsData.m @@ -0,0 +1,66 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import "FirebaseCore/Sources/Private/FIRDiagnosticsData.h" + +#import + +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" +#import "FirebaseCore/Sources/Private/FIROptionsInternal.h" + +@implementation FIRDiagnosticsData { + /** Backing ivar for the diagnosticObjects property. */ + NSMutableDictionary *_diagnosticObjects; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _diagnosticObjects = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)insertValue:(nullable id)value forKey:(NSString *)key { + if (key) { + _diagnosticObjects[key] = value; + } +} + +#pragma mark - FIRCoreDiagnosticsData + +- (NSDictionary *)diagnosticObjects { + if (!_diagnosticObjects[kFIRCDllAppsCountKey]) { + _diagnosticObjects[kFIRCDllAppsCountKey] = @([FIRApp allApps].count); + } + if (!_diagnosticObjects[kFIRCDIsDataCollectionDefaultEnabledKey]) { + _diagnosticObjects[kFIRCDIsDataCollectionDefaultEnabledKey] = + @([[FIRApp defaultApp] isDataCollectionDefaultEnabled]); + } + if (!_diagnosticObjects[kFIRCDFirebaseUserAgentKey]) { + _diagnosticObjects[kFIRCDFirebaseUserAgentKey] = [FIRApp firebaseUserAgent]; + } + return _diagnosticObjects; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +- (void)setDiagnosticObjects:(NSDictionary *)diagnosticObjects { + NSAssert(NO, @"Please use -insertValue:forKey:"); +} +#pragma clang diagnostic pop + +@end diff --git a/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRErrors.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRErrors.m new file mode 100644 index 0000000..104eeb8 --- /dev/null +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRErrors.m @@ -0,0 +1,21 @@ +// Copyright 2017 Google +// +// 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. + +#import "FirebaseCore/Sources/Private/FIRErrors.h" + +NSString *const kFirebaseErrorDomain = @"com.firebase"; +NSString *const kFirebaseConfigErrorDomain = @"com.firebase.config"; +NSString *const kFirebaseCoreErrorDomain = @"com.firebase.core"; +NSString *const kFirebasePerfErrorDomain = @"com.firebase.perf"; +NSString *const kFirebaseStorageErrorDomain = @"com.firebase.storage"; diff --git a/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatInfo.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatInfo.m new file mode 100644 index 0000000..277b0f7 --- /dev/null +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatInfo.m @@ -0,0 +1,61 @@ +// Copyright 2019 Google +// +// 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. + +#import "FirebaseCore/Sources/Private/FIRHeartbeatInfo.h" +#import +#import + +const static long secondsInDay = 86400; +@implementation FIRHeartbeatInfo : NSObject + +/** Updates the storage with the heartbeat information corresponding to this tag. + * @param heartbeatTag Tag which could either be sdk specific tag or the global tag. + * @return Boolean representing whether the heartbeat needs to be sent for this tag or not. + */ ++ (BOOL)updateIfNeededHeartbeatDateForTag:(NSString *)heartbeatTag { + @synchronized(self) { + NSString *const kHeartbeatStorageFile = @"HEARTBEAT_INFO_STORAGE"; + GULHeartbeatDateStorage *dataStorage = + [[GULHeartbeatDateStorage alloc] initWithFileName:kHeartbeatStorageFile]; + NSDate *heartbeatTime = [dataStorage heartbeatDateForTag:heartbeatTag]; + NSDate *currentDate = [NSDate date]; + if (heartbeatTime != nil) { + NSTimeInterval secondsBetween = [currentDate timeIntervalSinceDate:heartbeatTime]; + if (secondsBetween < secondsInDay) { + return false; + } + } + return [dataStorage setHearbeatDate:currentDate forTag:heartbeatTag]; + } +} + ++ (FIRHeartbeatInfoCode)heartbeatCodeForTag:(NSString *)heartbeatTag { + NSString *globalTag = @"GLOBAL"; + BOOL isSdkHeartbeatNeeded = [FIRHeartbeatInfo updateIfNeededHeartbeatDateForTag:heartbeatTag]; + BOOL isGlobalHeartbeatNeeded = [FIRHeartbeatInfo updateIfNeededHeartbeatDateForTag:globalTag]; + if (!isSdkHeartbeatNeeded && !isGlobalHeartbeatNeeded) { + // Both sdk and global heartbeat not needed. + return FIRHeartbeatInfoCodeNone; + } else if (isSdkHeartbeatNeeded && !isGlobalHeartbeatNeeded) { + // Only SDK heartbeat needed. + return FIRHeartbeatInfoCodeSDK; + } else if (!isSdkHeartbeatNeeded && isGlobalHeartbeatNeeded) { + // Only global heartbeat needed. + return FIRHeartbeatInfoCodeGlobal; + } else { + // Both sdk and global heartbeat are needed. + return FIRHeartbeatInfoCodeCombined; + } +} +@end diff --git a/Example/Pods/FirebaseCore/Firebase/Core/FIRLogger.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m similarity index 92% rename from Example/Pods/FirebaseCore/Firebase/Core/FIRLogger.m rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m index d1e3b37..ba2ee1f 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/FIRLogger.m +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m @@ -12,31 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import "Private/FIRLogger.h" +#import "FirebaseCore/Sources/Private/FIRLogger.h" #import #import #import -#import "Private/FIRVersion.h" +#import "FirebaseCore/Sources/FIRVersion.h" +FIRLoggerService kFIRLoggerCore = @"[Firebase/Core]"; + +// All the FIRLoggerService definitions should be migrated to clients. Do not add new ones! FIRLoggerService kFIRLoggerABTesting = @"[Firebase/ABTesting]"; FIRLoggerService kFIRLoggerAdMob = @"[Firebase/AdMob]"; FIRLoggerService kFIRLoggerAnalytics = @"[Firebase/Analytics]"; FIRLoggerService kFIRLoggerAuth = @"[Firebase/Auth]"; -FIRLoggerService kFIRLoggerCore = @"[Firebase/Core]"; FIRLoggerService kFIRLoggerCrash = @"[Firebase/Crash]"; -FIRLoggerService kFIRLoggerDatabase = @"[Firebase/Database]"; -FIRLoggerService kFIRLoggerDynamicLinks = @"[Firebase/DynamicLinks]"; -FIRLoggerService kFIRLoggerFirestore = @"[Firebase/Firestore]"; -FIRLoggerService kFIRLoggerInstanceID = @"[Firebase/InstanceID]"; -FIRLoggerService kFIRLoggerInvites = @"[Firebase/Invites]"; FIRLoggerService kFIRLoggerMLKit = @"[Firebase/MLKit]"; -FIRLoggerService kFIRLoggerMessaging = @"[Firebase/Messaging]"; FIRLoggerService kFIRLoggerPerf = @"[Firebase/Performance]"; FIRLoggerService kFIRLoggerRemoteConfig = @"[Firebase/RemoteConfig]"; -FIRLoggerService kFIRLoggerStorage = @"[Firebase/Storage]"; -FIRLoggerService kFIRLoggerSwizzler = @"[FirebaseSwizzlingUtilities]"; /// Arguments passed on launch. NSString *const kFIRDisableDebugModeApplicationArgument = @"-FIRDebugDisabled"; diff --git a/Example/Pods/FirebaseCore/Firebase/Core/FIROptions.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m similarity index 80% rename from Example/Pods/FirebaseCore/Firebase/Core/FIROptions.m rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m index 72901f5..d185330 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/FIROptions.m +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m @@ -12,11 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import "Private/FIRAppInternal.h" -#import "Private/FIRBundleUtil.h" -#import "Private/FIRErrors.h" -#import "Private/FIRLogger.h" -#import "Private/FIROptionsInternal.h" +#import "FirebaseCore/Sources/FIRBundleUtil.h" +#import "FirebaseCore/Sources/FIRVersion.h" +#import "FirebaseCore/Sources/Private/FIRAppInternal.h" +#import "FirebaseCore/Sources/Private/FIRLogger.h" +#import "FirebaseCore/Sources/Private/FIROptionsInternal.h" // Keys for the strings in the plist file. NSString *const kFIRAPIKey = @"API_KEY"; @@ -39,11 +39,13 @@ NSString *const kFIRIsAnalyticsEnabled = @"IS_ANALYTICS_ENABLED"; NSString *const kFIRIsSignInEnabled = @"IS_SIGNIN_ENABLED"; -// Library version ID. -NSString *const kFIRLibraryVersionID = @"5" // Major version (one or more digits) - @"04" // Minor version (exactly 2 digits) - @"01" // Build number (exactly 2 digits) - @"000"; // Fixed "000" +// Library version ID formatted like: +// @"5" // Major version (one or more digits) +// @"04" // Minor version (exactly 2 digits) +// @"01" // Build number (exactly 2 digits) +// @"000"; // Fixed "000" +NSString *kFIRLibraryVersionID; + // Plist file name. NSString *const kServiceInfoFileName = @"GoogleService-Info"; // Plist file type. @@ -107,30 +109,6 @@ + (FIROptions *)defaultOptions { #pragma mark - Private class methods -+ (void)initialize { - // Report FirebaseCore version for useragent string - NSRange major = NSMakeRange(0, 1); - NSRange minor = NSMakeRange(1, 2); - NSRange patch = NSMakeRange(3, 2); - [FIRApp - registerLibrary:@"fire-ios" - withVersion:[NSString stringWithFormat:@"%@.%d.%d", - [kFIRLibraryVersionID substringWithRange:major], - [[kFIRLibraryVersionID substringWithRange:minor] - intValue], - [[kFIRLibraryVersionID substringWithRange:patch] - intValue]]]; - NSDictionary *info = [[NSBundle mainBundle] infoDictionary]; - NSString *xcodeVersion = info[@"DTXcodeBuild"]; - NSString *sdkVersion = info[@"DTSDKBuild"]; - if (xcodeVersion) { - [FIRApp registerLibrary:@"xcode" withVersion:xcodeVersion]; - } - if (sdkVersion) { - [FIRApp registerLibrary:@"apple-sdk" withVersion:sdkVersion]; - } -} - + (NSDictionary *)defaultOptionsDictionary { if (sDefaultOptionsDictionary != nil) { return sDefaultOptionsDictionary; @@ -184,6 +162,7 @@ - (id)copyWithZone:(NSZone *)zone { if (newOptions) { newOptions.optionsDictionary = self.optionsDictionary; newOptions.deepLinkURLScheme = self.deepLinkURLScheme; + newOptions.appGroupID = self.appGroupID; newOptions.editingLocked = self.isEditingLocked; newOptions.usingOptionsFromDefaultPlist = self.usingOptionsFromDefaultPlist; } @@ -295,6 +274,16 @@ - (void)setGoogleAppID:(NSString *)googleAppID { } - (NSString *)libraryVersionID { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // The unit tests are set up to catch anything that does not properly convert. + NSString *version = [NSString stringWithUTF8String:FIRCoreVersionString]; + NSArray *components = [version componentsSeparatedByString:@"."]; + NSString *major = [components objectAtIndex:0]; + NSString *minor = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:1] intValue]]; + NSString *patch = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:2] intValue]]; + kFIRLibraryVersionID = [NSString stringWithFormat:@"%@%@%@000", major, minor, patch]; + }); return kFIRLibraryVersionID; } @@ -335,6 +324,64 @@ - (void)setBundleID:(NSString *)bundleID { _optionsDictionary[kFIRBundleID] = [bundleID copy]; } +- (void)setAppGroupID:(NSString *)appGroupID { + [self checkEditingLocked]; + _appGroupID = [appGroupID copy]; +} + +#pragma mark - Equality + +- (BOOL)isEqual:(id)object { + if (!object || ![object isKindOfClass:[FIROptions class]]) { + return NO; + } + + return [self isEqualToOptions:(FIROptions *)object]; +} + +- (BOOL)isEqualToOptions:(FIROptions *)options { + // Skip any non-FIROptions classes. + if (![options isKindOfClass:[FIROptions class]]) { + return NO; + } + + // Check the internal dictionary and custom properties for differences. + if (![options.optionsDictionary isEqualToDictionary:self.optionsDictionary]) { + return NO; + } + + // Validate extra properties not contained in the dictionary. Only validate it if one of the + // objects has the property set. + if ((options.deepLinkURLScheme != nil || self.deepLinkURLScheme != nil) && + ![options.deepLinkURLScheme isEqualToString:self.deepLinkURLScheme]) { + return NO; + } + + if ((options.appGroupID != nil || self.appGroupID != nil) && + ![options.appGroupID isEqualToString:self.appGroupID]) { + return NO; + } + + // Validate the Analytics options haven't changed with the Info.plist. + if (![options.analyticsOptionsDictionary isEqualToDictionary:self.analyticsOptionsDictionary]) { + return NO; + } + + // We don't care about the `editingLocked` or `usingOptionsFromDefaultPlist` properties since + // those relate to lifecycle and construction, we only care if the contents of the options + // themselves are equal. + return YES; +} + +- (NSUInteger)hash { + // This is strongly recommended for any object that implements a custom `isEqual:` method to + // ensure that dictionary and set behavior matches other `isEqual:` checks. + // Note: `self.analyticsOptionsDictionary` was left out here since it solely relies on the + // contents of the main bundle's `Info.plist`. We should avoid reading that file and the contents + // should be identical. + return self.optionsDictionary.hash ^ self.deepLinkURLScheme.hash ^ self.appGroupID.hash; +} + #pragma mark - Internal instance methods - (NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:(NSDictionary *)infoDictionary { @@ -388,7 +435,7 @@ - (BOOL)isMeasurementEnabled { return [value boolValue]; } -- (BOOL)isAnalyticsCollectionExpicitlySet { +- (BOOL)isAnalyticsCollectionExplicitlySet { // If it's de-activated, it classifies as explicity set. If not, it's not a good enough indication // that the developer wants FirebaseAnalytics enabled so continue checking. if (self.isAnalyticsCollectionDeactivated) { diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRVersion.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.h similarity index 100% rename from Example/Pods/FirebaseCore/Firebase/Core/Private/FIRVersion.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.h diff --git a/Example/Pods/FirebaseCore/Firebase/Core/FIRVersion.m b/Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m similarity index 100% rename from Example/Pods/FirebaseCore/Firebase/Core/FIRVersion.m rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m diff --git a/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRAnalyticsConfiguration.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRAnalyticsConfiguration.h new file mode 100644 index 0000000..6429ac7 --- /dev/null +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRAnalyticsConfiguration.h @@ -0,0 +1,56 @@ +/* + * Copyright 2017 Google + * + * 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. + */ + +#import + +/// Values stored in analyticsEnabledState. Never alter these constants since they must match with +/// values persisted to disk. +typedef NS_ENUM(int64_t, FIRAnalyticsEnabledState) { + // 0 is the default value for keys not found stored in persisted config, so it cannot represent + // kFIRAnalyticsEnabledStateSetNo. It must represent kFIRAnalyticsEnabledStateNotSet. + kFIRAnalyticsEnabledStateNotSet = 0, + kFIRAnalyticsEnabledStateSetYes = 1, + kFIRAnalyticsEnabledStateSetNo = 2, +}; + +/// The user defaults key for the persisted measurementEnabledState value. FIRAPersistedConfig reads +/// measurementEnabledState using this same key. +static NSString *const kFIRAPersistedConfigMeasurementEnabledStateKey = + @"/google/measurement/measurement_enabled_state"; + +static NSString *const kFIRAnalyticsConfigurationSetEnabledNotification = + @"FIRAnalyticsConfigurationSetEnabledNotification"; +static NSString *const kFIRAnalyticsConfigurationSetMinimumSessionIntervalNotification = + @"FIRAnalyticsConfigurationSetMinimumSessionIntervalNotification"; +static NSString *const kFIRAnalyticsConfigurationSetSessionTimeoutIntervalNotification = + @"FIRAnalyticsConfigurationSetSessionTimeoutIntervalNotification"; + +@interface FIRAnalyticsConfiguration : NSObject + +/// Returns the shared instance of FIRAnalyticsConfiguration. ++ (FIRAnalyticsConfiguration *)sharedInstance; + +// Sets whether analytics collection is enabled for this app on this device. This setting is +// persisted across app sessions. By default it is enabled. +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets whether analytics collection is enabled for this app on this device, and a flag to persist +/// the value or not. The setting should not be persisted if being set by the global data collection +/// flag. +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled + persistSetting:(BOOL)shouldPersist; + +@end diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRAppAssociationRegistration.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRAppAssociationRegistration.h similarity index 100% rename from Example/Pods/FirebaseCore/Firebase/Core/Private/FIRAppAssociationRegistration.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRAppAssociationRegistration.h diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRAppInternal.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRAppInternal.h similarity index 87% rename from Example/Pods/FirebaseCore/Firebase/Core/Private/FIRAppInternal.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRAppInternal.h index d663d3e..ad1a186 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRAppInternal.h +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRAppInternal.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#import "FIRApp.h" -#import "FIRErrors.h" +#import +#import @class FIRComponentContainer; @protocol FIRLibrary; @@ -34,28 +34,6 @@ typedef NS_ENUM(NSInteger, FIRConfigType) { FIRConfigTypeSDK = 2, }; -/** - * Names of services provided by Firebase. - */ -extern NSString *const kFIRServiceAdMob; -extern NSString *const kFIRServiceAuth; -extern NSString *const kFIRServiceAuthUI; -extern NSString *const kFIRServiceCrash; -extern NSString *const kFIRServiceDatabase; -extern NSString *const kFIRServiceDynamicLinks; -extern NSString *const kFIRServiceInstanceID; -extern NSString *const kFIRServiceInvites; -extern NSString *const kFIRServiceMessaging; -extern NSString *const kFIRServiceMeasurement; -extern NSString *const kFIRServiceRemoteConfig; -extern NSString *const kFIRServiceStorage; - -/** - * Names of services provided by the Google pod, but logged by the Firebase pod. - */ -extern NSString *const kGGLServiceAnalytics; -extern NSString *const kGGLServiceSignIn; - extern NSString *const kFIRDefaultAppName; extern NSString *const kFIRAppReadyToConfigureSDKNotification; extern NSString *const kFIRAppDeleteNotification; @@ -162,6 +140,8 @@ extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; /** * Used by each SDK to send logs about SDK configuration status to Clearcut. + * + * @note This API is a no-op, please remove calls to it. */ - (void)sendLogsWithServiceName:(NSString *)serviceName version:(NSString *)version diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRComponent.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponent.h similarity index 100% rename from Example/Pods/FirebaseCore/Firebase/Core/Private/FIRComponent.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponent.h diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRComponentContainer.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentContainer.h similarity index 95% rename from Example/Pods/FirebaseCore/Firebase/Core/Private/FIRComponentContainer.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentContainer.h index f3dc356..8dfab9c 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRComponentContainer.h +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentContainer.h @@ -15,8 +15,8 @@ */ #import -#import "FIRComponentType.h" -#import "FIRLibrary.h" +#import +#import NS_ASSUME_NONNULL_BEGIN diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRComponentContainerInternal.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentContainerInternal.h similarity index 76% rename from Example/Pods/FirebaseCore/Firebase/Core/Private/FIRComponentContainerInternal.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentContainerInternal.h index e8552fa..2b77981 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRComponentContainerInternal.h +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentContainerInternal.h @@ -15,8 +15,8 @@ */ #import -#import "FIRComponent.h" -#import "FIRComponentContainer.h" +#import +#import @class FIRApp; @@ -24,13 +24,16 @@ NS_ASSUME_NONNULL_BEGIN @interface FIRComponentContainer (Private) -/// Initializes a contain for a given app. This should only be called by the app itself. +/// Initializes a container for a given app. This should only be called by the app itself. - (instancetype)initWithApp:(FIRApp *)app; /// Retrieves an instance that conforms to the specified protocol. This will return `nil` if the -/// protocol wasn't registered, or if the instance couldn't instantiate for the provided app. +/// protocol wasn't registered, or if the instance couldn't be instantiated for the provided app. - (nullable id)instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); +/// Instantiates all the components that have registered as "eager" after initialization. +- (void)instantiateEagerComponents; + /// Remove all of the cached instances stored and allow them to clean up after themselves. - (void)removeAllCachedInstances; diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRComponentType.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentType.h similarity index 100% rename from Example/Pods/FirebaseCore/Firebase/Core/Private/FIRComponentType.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRComponentType.h diff --git a/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRConfigurationInternal.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRConfigurationInternal.h new file mode 100644 index 0000000..0d1a36f --- /dev/null +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRConfigurationInternal.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import + +@class FIRAnalyticsConfiguration; + +@interface FIRConfiguration () + +/** + * The configuration class for Firebase Analytics. This should be removed once the logic for + * enabling and disabling Analytics is moved to Analytics. + */ +@property(nonatomic, readwrite) FIRAnalyticsConfiguration *analyticsConfiguration; + +@end diff --git a/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h new file mode 100644 index 0000000..76c0c05 --- /dev/null +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRCoreDiagnosticsConnector.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import + +@class FIRDiagnosticsData; +@class FIROptions; + +NS_ASSUME_NONNULL_BEGIN + +/** Connects FIRCore with the CoreDiagnostics library. */ +@interface FIRCoreDiagnosticsConnector : NSObject + +/** Logs FirebaseCore related data. + * + * @param options The options object containing data to log. + */ ++ (void)logCoreTelemetryWithOptions:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRDependency.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRDependency.h similarity index 100% rename from Example/Pods/FirebaseCore/Firebase/Core/Private/FIRDependency.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRDependency.h diff --git a/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRDiagnosticsData.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRDiagnosticsData.h new file mode 100644 index 0000000..ac5ef2c --- /dev/null +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRDiagnosticsData.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** Implements the FIRCoreDiagnosticsData protocol to log diagnostics data. */ +@interface FIRDiagnosticsData : NSObject + +/** Inserts values into the diagnosticObjects dictionary if the value isn't nil. + * + * @param value The value to insert if it's not nil. + * @param key The key to associate it with. + */ +- (void)insertValue:(nullable id)value forKey:(NSString *)key; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRErrorCode.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRErrorCode.h new file mode 100644 index 0000000..f77b3d0 --- /dev/null +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRErrorCode.h @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Google + * + * 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. + */ + +/** Error codes in Firebase error domain. */ +typedef NS_ENUM(NSInteger, FIRErrorCode) { + /** + * Unknown error. + */ + FIRErrorCodeUnknown = 0, + /** + * Loading data from the GoogleService-Info.plist file failed. This is a fatal error and should + * not be ignored. Further calls to the API will fail and/or possibly cause crashes. + */ + FIRErrorCodeInvalidPlistFile = -100, + + /** + * Validating the Google App ID format failed. + */ + FIRErrorCodeInvalidAppID = -101, + + /** + * Error code for failing to configure a specific service. + */ + FIRErrorCodeConfigFailed = -114, +}; diff --git a/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRErrors.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRErrors.h new file mode 100644 index 0000000..19e4732 --- /dev/null +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRErrors.h @@ -0,0 +1,24 @@ +/* + * Copyright 2017 Google + * + * 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. + */ + +#import + +#include "FIRErrorCode.h" + +extern NSString *const kFirebaseErrorDomain; +extern NSString *const kFirebaseConfigErrorDomain; +extern NSString *const kFirebaseCoreErrorDomain; +extern NSString *const kFirebasePerfErrorDomain; diff --git a/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h new file mode 100644 index 0000000..bfff73e --- /dev/null +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRHeartbeatInfo.h @@ -0,0 +1,39 @@ +// Copyright 2019 Google +// +// 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. + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRHeartbeatInfo : NSObject + +// Enum representing the different heartbeat codes. +typedef NS_ENUM(NSInteger, FIRHeartbeatInfoCode) { + FIRHeartbeatInfoCodeNone = 0, + FIRHeartbeatInfoCodeSDK = 1, + FIRHeartbeatInfoCodeGlobal = 2, + FIRHeartbeatInfoCodeCombined = 3, +}; + +/** + * Get heartbeat code requred for the sdk. + * @param heartbeatTag String representing the sdk heartbeat tag. + * @return Heartbeat code indicating whether or not an sdk/global heartbeat + * needs to be sent + */ ++ (FIRHeartbeatInfoCode)heartbeatCodeForTag:(NSString *)heartbeatTag; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRLibrary.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRLibrary.h similarity index 97% rename from Example/Pods/FirebaseCore/Firebase/Core/Private/FIRLibrary.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRLibrary.h index 728c062..af9d968 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRLibrary.h +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRLibrary.h @@ -18,7 +18,8 @@ #define FIRLibrary_h #import -#import "FIRComponent.h" + +#import @class FIRApp; diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRLogger.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRLogger.h similarity index 93% rename from Example/Pods/FirebaseCore/Firebase/Core/Private/FIRLogger.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRLogger.h index a538199..548e389 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIRLogger.h +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIRLogger.h @@ -16,7 +16,7 @@ #import -#import "FIRLoggerLevel.h" +#import NS_ASSUME_NONNULL_BEGIN @@ -29,19 +29,11 @@ extern FIRLoggerService kFIRLoggerABTesting; extern FIRLoggerService kFIRLoggerAdMob; extern FIRLoggerService kFIRLoggerAnalytics; extern FIRLoggerService kFIRLoggerAuth; -extern FIRLoggerService kFIRLoggerCore; extern FIRLoggerService kFIRLoggerCrash; -extern FIRLoggerService kFIRLoggerDatabase; -extern FIRLoggerService kFIRLoggerDynamicLinks; -extern FIRLoggerService kFIRLoggerFirestore; -extern FIRLoggerService kFIRLoggerInstanceID; -extern FIRLoggerService kFIRLoggerInvites; +extern FIRLoggerService kFIRLoggerCore; extern FIRLoggerService kFIRLoggerMLKit; -extern FIRLoggerService kFIRLoggerMessaging; extern FIRLoggerService kFIRLoggerPerf; extern FIRLoggerService kFIRLoggerRemoteConfig; -extern FIRLoggerService kFIRLoggerStorage; -extern FIRLoggerService kFIRLoggerSwizzler; /** * The key used to store the logger's error count. diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIROptionsInternal.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIROptionsInternal.h similarity index 96% rename from Example/Pods/FirebaseCore/Firebase/Core/Private/FIROptionsInternal.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIROptionsInternal.h index 7bb40fc..0660a3c 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/Private/FIROptionsInternal.h +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Private/FIROptionsInternal.h @@ -14,7 +14,7 @@ * limitations under the License. */ -#import "FIROptions.h" +#import /** * Keys for the strings in the plist file. @@ -65,7 +65,7 @@ extern NSString *const kServiceInfoFileType; * Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at * runtime. */ -@property(nonatomic, readonly) BOOL isAnalyticsCollectionExpicitlySet; +@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet; /** * Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Public/FIRApp.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Public/FIRApp.h similarity index 100% rename from Example/Pods/FirebaseCore/Firebase/Core/Public/FIRApp.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Public/FIRApp.h diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Public/FIRConfiguration.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Public/FIRConfiguration.h similarity index 79% rename from Example/Pods/FirebaseCore/Firebase/Core/Public/FIRConfiguration.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Public/FIRConfiguration.h index b88fcaf..8de3b07 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/Public/FIRConfiguration.h +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Public/FIRConfiguration.h @@ -16,14 +16,12 @@ #import -#import "FIRAnalyticsConfiguration.h" -#import "FIRLoggerLevel.h" +#import NS_ASSUME_NONNULL_BEGIN /** - * This interface provides global level properties that the developer can tweak, and the singleton - * of the Firebase Analytics configuration class. + * This interface provides global level properties that the developer can tweak. */ NS_SWIFT_NAME(FirebaseConfiguration) @interface FIRConfiguration : NSObject @@ -31,11 +29,6 @@ NS_SWIFT_NAME(FirebaseConfiguration) /** Returns the shared configuration object. */ @property(class, nonatomic, readonly) FIRConfiguration *sharedInstance NS_SWIFT_NAME(shared); -/** The configuration class for Firebase Analytics. */ -@property(nonatomic, readwrite) - FIRAnalyticsConfiguration *analyticsConfiguration DEPRECATED_MSG_ATTRIBUTE( - "Use the methods available here directly on the `Analytics` class."); - /** * Sets the logging level for internal Firebase logging. Firebase will only log messages * that are logged at or below loggerLevel. The messages are logged both to the Xcode diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Public/FIRLoggerLevel.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Public/FIRLoggerLevel.h similarity index 100% rename from Example/Pods/FirebaseCore/Firebase/Core/Public/FIRLoggerLevel.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Public/FIRLoggerLevel.h diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Public/FIROptions.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Public/FIROptions.h similarity index 93% rename from Example/Pods/FirebaseCore/Firebase/Core/Public/FIROptions.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Public/FIROptions.h index 87a01dd..67fbe5b 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/Public/FIROptions.h +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Public/FIROptions.h @@ -90,6 +90,13 @@ NS_SWIFT_NAME(FirebaseOptions) */ @property(nonatomic, copy, nullable) NSString *storageBucket; +/** + * The App Group identifier to share data between the application and the application extensions. + * The App Group must be configured in the application and on the Apple Developer Portal. Default + * value `nil`. + */ +@property(nonatomic, copy, nullable) NSString *appGroupID; + /** * Initializes a customized instance of FIROptions from the file at the given plist file path. This * will read the file synchronously from disk. diff --git a/Example/Pods/FirebaseCore/Firebase/Core/Public/FirebaseCore.h b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore.h similarity index 94% rename from Example/Pods/FirebaseCore/Firebase/Core/Public/FirebaseCore.h rename to Example/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore.h index fa26f69..95119ae 100644 --- a/Example/Pods/FirebaseCore/Firebase/Core/Public/FirebaseCore.h +++ b/Example/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore.h @@ -14,7 +14,6 @@ * limitations under the License. */ -#import "FIRAnalyticsConfiguration.h" #import "FIRApp.h" #import "FIRConfiguration.h" #import "FIRLoggerLevel.h" diff --git a/Example/Pods/FirebaseCore/README.md b/Example/Pods/FirebaseCore/README.md index ad8de0f..8c6e952 100644 --- a/Example/Pods/FirebaseCore/README.md +++ b/Example/Pods/FirebaseCore/README.md @@ -1,9 +1,16 @@ -# Firebase iOS Open Source Development [![Build Status](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk) +# Firebase iOS Open Source Development + [![Actions Status][gh-core-badge]][gh-actions] + [![Actions Status][gh-dynamiclinks-badge]][gh-actions] + [![Actions Status][gh-datatransport-badge]][gh-actions] + [![Actions Status][gh-storage-badge]][gh-actions] + [![Actions Status][gh-zip-badge]][gh-actions] + [![Travis](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk) This repository contains a subset of the Firebase iOS SDK source. It currently -includes FirebaseCore, FirebaseAuth, FirebaseDatabase, FirebaseFirestore, -FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging, -FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage. +includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase, +FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging, +FirebaseInAppMessagingDisplay, FirebaseMessaging, FirebaseRemoteConfig, and +FirebaseStorage. The repository also includes GoogleUtilities source. The [GoogleUtilities](GoogleUtilities/README.md) pod is @@ -70,19 +77,39 @@ Instructions for installing binary frameworks via ## Development -Follow the subsequent instructions to develop, debug, unit test, run integration -tests, and try out reference samples: +To develop Firebase software in this repository, ensure that you have at least +the following software: -``` -$ git clone git@github.com:firebase/firebase-ios-sdk.git -$ cd firebase-ios-sdk/Example -$ pod update -$ open Firebase.xcworkspace -``` + * Xcode 10.1 (or later) + * CocoaPods 1.7.2 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self contained Xcode project. See +[Firestore/README.md](Firestore/README.md). + +### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test -Firestore and Functions have self contained Xcode projects. See -[Firestore/README.md](Firestore/README.md) and -[Functions/README.md](Functions/README.md). +### Adding a New Firebase Pod + +See [AddNewPod.md](AddNewPod.md). ### Code Formatting @@ -92,9 +119,19 @@ before creating a PR. Travis will verify that any code changes are done in a style compliant way. Install `clang-format` and `swiftformat`. -This command will get the right `clang-format` version: +These commands will get the right versions: + +``` +brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/e3496d9/Formula/clang-format.rb +brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/7963c3d/Formula/swiftformat.rb +``` -`brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/773cb75d360b58f32048f5964038d09825a507c8/Formula/clang-format.rb` +Note: if you already have a newer version of these installed you may need to +`brew switch` to this version. + +To update this section, find the versions of clang-format and swiftformat.rb to +match the versions in the CI failure logs +[here](https://github.com/Homebrew/homebrew-core/tree/master/Formula). ### Running Unit Tests @@ -168,32 +205,42 @@ We've seen an amazing amount of interest and contributions to improve the Fireba very grateful! We'd like to empower as many developers as we can to be able to use Firebase and participate in the Firebase community. -### macOS and tvOS -Thanks to contributions from the community, FirebaseAuth, FirebaseCore, FirebaseDatabase, -FirebaseFunctions and FirebaseStorage now compile, run unit tests, and work on macOS and tvOS. -FirebaseFirestore is availiable for macOS and FirebaseMessaging for tvOS. +### tvOS, macOS, and Catalyst +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and work on +tvOS, macOS, and Catalyst. For tvOS, checkout the [Sample](Example/tvOSSample). -Keep in mind that macOS and tvOS are not officially supported by Firebase, and this repository is -actively developed primarily for iOS. While we can catch basic unit test issues with Travis, there -may be some changes where the SDK no longer works as expected on macOS or tvOS. If you encounter -this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues). +Keep in mind that macOS, Catalyst and tvOS are not officially supported by Firebase, and this +repository is actively developed primarily for iOS. While we can catch basic unit test issues with +Travis, there may be some changes where the SDK no longer works as expected on macOS or tvOS. If you +encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues). -Note that the Firebase pod is not available for macOS and tvOS. +During app setup in the console, you may get to a step that mentions something like "Checking if the app +has communicated with our servers". This relies on Analytics and will not work on macOS/tvOS/Catalyst. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. To install, add a subset of the following to the Podfile: ``` -pod 'FirebaseAuth' -pod 'FirebaseCore' -pod 'FirebaseDatabase' -pod 'FirebaseFirestore' # Only iOS and macOS -pod 'FirebaseFunctions' -pod 'FirebaseMessaging' # Only iOS and tvOS -pod 'FirebaseStorage' +pod 'Firebase/ABTesting' +pod 'Firebase/Auth' +pod 'Firebase/Crashlytics' +pod 'Firebase/Database' +pod 'Firebase/Firestore' +pod 'Firebase/Functions' +pod 'Firebase/Messaging' +pod 'Firebase/RemoteConfig' +pod 'Firebase/Storage' ``` +#### Additional Catalyst Notes + +* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability` +to Build Settings. +* FirebaseFirestore requires signing the +[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681). + ## Roadmap See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source @@ -211,3 +258,10 @@ The contents of this repository is licensed under the Your use of Firebase is governed by the [Terms of Service for Firebase Services](https://firebase.google.com/terms/). + +[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions +[gh-core-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/core/badge.svg +[gh-datatransport-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/datatransport/badge.svg +[gh-dynamiclinks-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/dynamiclinks/badge.svg +[gh-storage-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/storage/badge.svg +[gh-zip-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/zip/badge.svg diff --git a/Example/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnostics.m b/Example/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnostics.m new file mode 100644 index 0000000..bb0326b --- /dev/null +++ b/Example/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnostics.m @@ -0,0 +1,641 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import +#include + +#import +#import +#import +#import + +#import +#import +#import + +#import +#import + +#import +#import +#import + +#import "FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h" + +/** The logger service string to use when printing to the console. */ +static GULLoggerService kFIRCoreDiagnostics = @"[FirebaseCoreDiagnostics/FIRCoreDiagnostics]"; + +#ifdef FIREBASE_BUILD_ZIP_FILE +static BOOL kUsingZipFile = YES; +#else // FIREBASE_BUILD_ZIP_FILE +static BOOL kUsingZipFile = NO; +#endif // FIREBASE_BUILD_ZIP_FILE + +#ifdef FIREBASE_BUILD_CARTHAGE +#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_CARTHAGE +#elif FIREBASE_BUILD_ZIP_FILE +#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ZIP_FILE +#else +#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_COCOAPODS +#endif + +static NSString *const kFIRServiceMLVisionOnDeviceAutoML = @"MLVisionOnDeviceAutoML"; +static NSString *const kFIRServiceMLVisionOnDeviceFace = @"MLVisionOnDeviceFace"; +static NSString *const kFIRServiceMLVisionOnDeviceBarcode = @"MLVisionOnDeviceBarcode"; +static NSString *const kFIRServiceMLVisionOnDeviceText = @"MLVisionOnDeviceText"; +static NSString *const kFIRServiceMLVisionOnDeviceLabel = @"MLVisionOnDeviceLabel"; +static NSString *const kFIRServiceMLVisionOnDeviceObjectDetection = + @"MLVisionOnDeviceObjectDetection"; +static NSString *const kFIRServiceMLModelInterpreter = @"MLModelInterpreter"; + +static NSString *const kFIRServiceAdMob = @"AdMob"; +static NSString *const kFIRServiceAuth = @"Auth"; +static NSString *const kFIRServiceAuthUI = @"AuthUI"; +static NSString *const kFIRServiceCrash = @"Crash"; +static NSString *const kFIRServiceDatabase = @"Database"; +static NSString *const kFIRServiceDynamicLinks = @"DynamicLinks"; +static NSString *const kFIRServiceFirestore = @"Firestore"; +static NSString *const kFIRServiceFunctions = @"Functions"; +static NSString *const kFIRServiceIAM = @"InAppMessaging"; +static NSString *const kFIRServiceInstanceID = @"InstanceID"; +static NSString *const kFIRServiceInvites = @"Invites"; +static NSString *const kFIRServiceMessaging = @"Messaging"; +static NSString *const kFIRServiceMeasurement = @"Measurement"; +static NSString *const kFIRServicePerformance = @"Performance"; +static NSString *const kFIRServiceRemoteConfig = @"RemoteConfig"; +static NSString *const kFIRServiceStorage = @"Storage"; +static NSString *const kGGLServiceAnalytics = @"Analytics"; +static NSString *const kGGLServiceSignIn = @"SignIn"; +static NSString *const kFIRAppDiagnosticsConfigurationTypeKey = + @"FIRAppDiagnosticsConfigurationTypeKey"; +static NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRAppDiagnosticsFIRAppKey"; +static NSString *const kFIRAppDiagnosticsSDKNameKey = @"FIRAppDiagnosticsSDKNameKey"; +static NSString *const kFIRAppDiagnosticsSDKVersionKey = @"FIRAppDiagnosticsSDKVersionKey"; +static NSString *const kFIRCoreDiagnosticsHeartbeatTag = @"FIRCoreDiagnostics"; + +/** + * The file name to the recent heartbeat date. + */ +NSString *const kFIRCoreDiagnosticsHeartbeatDateFileName = @"FIREBASE_DIAGNOSTICS_HEARTBEAT_DATE"; + +/** + * @note This should implement the GDTCOREventDataObject protocol, but can't because of + * weak-linking. + */ +@interface FIRCoreDiagnosticsLog : NSObject + +/** The config that will be converted to proto bytes. */ +@property(nonatomic) logs_proto_mobilesdk_ios_ICoreConfiguration config; + +@end + +@implementation FIRCoreDiagnosticsLog + +- (instancetype)initWithConfig:(logs_proto_mobilesdk_ios_ICoreConfiguration)config { + self = [super init]; + if (self) { + _config = config; + } + return self; +} + +// Provided and required by the GDTCOREventDataObject protocol. +- (NSData *)transportBytes { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + + // Encode 1 time to determine the size. + if (!pb_encode(&sizestream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) { + GDTCORLogError(GDTCORMCETransportBytesError, @"Error in nanopb encoding for size: %s", + PB_GET_ERROR(&sizestream)); + } + + // Encode a 2nd time to actually get the bytes from it. + size_t bufferSize = sizestream.bytes_written; + CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize); + pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize); + if (!pb_encode(&ostream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) { + GDTCORLogError(GDTCORMCETransportBytesError, @"Error in nanopb encoding for bytes: %s", + PB_GET_ERROR(&ostream)); + } + CFDataSetLength(dataRef, ostream.bytes_written); + + return CFBridgingRelease(dataRef); +} + +- (void)dealloc { + pb_release(logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config); +} + +@end + +NS_ASSUME_NONNULL_BEGIN + +/** This class produces a protobuf containing diagnostics and usage data to be logged. */ +@interface FIRCoreDiagnostics : NSObject + +/** The queue on which all diagnostics collection will occur. */ +@property(nonatomic, readonly) dispatch_queue_t diagnosticsQueue; + +/** The transport object used to send data. */ +@property(nonatomic, readonly) GDTCORTransport *transport; + +/** The storage to store the date of the last sent heartbeat. */ +@property(nonatomic, readonly) GULHeartbeatDateStorage *heartbeatDateStorage; + +@end + +NS_ASSUME_NONNULL_END + +@implementation FIRCoreDiagnostics + ++ (instancetype)sharedInstance { + static FIRCoreDiagnostics *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[FIRCoreDiagnostics alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + GDTCORTransport *transport = [[GDTCORTransport alloc] initWithMappingID:@"137" + transformers:nil + target:kGDTCORTargetFLL]; + + GULHeartbeatDateStorage *dateStorage = + [[GULHeartbeatDateStorage alloc] initWithFileName:kFIRCoreDiagnosticsHeartbeatDateFileName]; + + return [self initWithTransport:transport heartbeatDateStorage:dateStorage]; +} + +/** Initializer for unit tests. + * + * @param transport A `GDTCORTransport` instance which that be used to send event. + * @param heartbeatDateStorage An instanse of date storage to track heartbeat sending. + * @return Returns the initialized `FIRCoreDiagnostics` instance. + */ +- (instancetype)initWithTransport:(GDTCORTransport *)transport + heartbeatDateStorage:(GULHeartbeatDateStorage *)heartbeatDateStorage { + self = [super init]; + if (self) { + _diagnosticsQueue = + dispatch_queue_create("com.google.FIRCoreDiagnostics", DISPATCH_QUEUE_SERIAL); + _transport = transport; + _heartbeatDateStorage = heartbeatDateStorage; + } + return self; +} + +#pragma mark - Metadata helpers + +/** Returns the model of iOS device. Sample platform strings are @"iPhone7,1" for iPhone 6 Plus, + * @"iPhone7,2" for iPhone 6, etc. Refer to the Hardware strings at + * https://en.wikipedia.org/wiki/List_of_iOS_devices + * + * @return The device model as an NSString. + */ ++ (NSString *)deviceModel { + static NSString *deviceModel = nil; + if (deviceModel == nil) { + struct utsname systemInfo; + uname(&systemInfo); + deviceModel = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; + } + return deviceModel; +} + +#pragma mark - nanopb helper functions + +/** Mallocs a pb_bytes_array and copies the given NSString's bytes into the bytes array. + * + * @note Memory needs to be free manually, through pb_free or pb_release. + * @param string The string to encode as pb_bytes. + */ +pb_bytes_array_t *FIREncodeString(NSString *string) { + NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding]; + return FIREncodeData(stringBytes); +} + +/** Mallocs a pb_bytes_array and copies the given NSData bytes into the bytes array. + * + * @note Memory needs to be free manually, through pb_free or pb_release. + * @param data The data to copy into the new bytes array. + */ +pb_bytes_array_t *FIREncodeData(NSData *data) { + pb_bytes_array_t *pbBytes = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); + memcpy(pbBytes->bytes, [data bytes], data.length); + pbBytes->size = (pb_size_t)data.length; + return pbBytes; +} + +/** Maps a service string to the representative nanopb enum. + * + * @param serviceString The SDK service string to convert. + * @return The representative nanopb enum. + */ +logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType FIRMapFromServiceStringToTypeEnum( + NSString *serviceString) { + static NSDictionary *serviceStringToTypeEnum; + if (serviceStringToTypeEnum == nil) { + serviceStringToTypeEnum = @{ + kFIRServiceAdMob : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ADMOB), + kFIRServiceMessaging : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MESSAGING), + kFIRServiceMeasurement : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MEASUREMENT), + kFIRServiceRemoteConfig : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_REMOTE_CONFIG), + kFIRServiceDatabase : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DATABASE), + kFIRServiceDynamicLinks : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DYNAMIC_LINKS), + kFIRServiceAuth : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH), + kFIRServiceAuthUI : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH_UI), + kFIRServiceFirestore : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FIRESTORE), + kFIRServiceFunctions : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FUNCTIONS), + kFIRServicePerformance : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_PERFORMANCE), + kFIRServiceStorage : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_STORAGE), + kFIRServiceMLVisionOnDeviceAutoML : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_AUTOML), + kFIRServiceMLVisionOnDeviceFace : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_FACE), + kFIRServiceMLVisionOnDeviceBarcode : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_BARCODE), + kFIRServiceMLVisionOnDeviceText : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_TEXT), + kFIRServiceMLVisionOnDeviceLabel : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_LABEL), + kFIRServiceMLVisionOnDeviceObjectDetection : @( + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION), + kFIRServiceMLModelInterpreter : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_MODEL_INTERPRETER), + kGGLServiceAnalytics : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ANALYTICS), + kGGLServiceSignIn : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_SIGN_IN), + kFIRServiceIAM : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_IN_APP_MESSAGING), + }; + } + if (serviceStringToTypeEnum[serviceString] != nil) { + return (int32_t)serviceStringToTypeEnum[serviceString].longLongValue; + } + return logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_UNKNOWN_SDK_SERVICE; +} + +#pragma mark - Proto population functions + +/** Populates the given proto with data related to an SDK logDiagnostics call from the + * diagnosticObjects dictionary. + * + * @param config The proto to populate + * @param diagnosticObjects The dictionary of diagnostics objects. + */ +void FIRPopulateProtoWithInfoFromUserInfoParams(logs_proto_mobilesdk_ios_ICoreConfiguration *config, + NSDictionary *diagnosticObjects) { + NSNumber *configurationType = diagnosticObjects[kFIRCDConfigurationTypeKey]; + if (configurationType != nil) { + switch (configurationType.integerValue) { + case logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE: + config->configuration_type = + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE; + config->has_configuration_type = 1; + break; + case logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK: + config->configuration_type = + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK; + config->has_configuration_type = 1; + break; + default: + break; + } + } + + NSString *sdkName = diagnosticObjects[kFIRCDSdkNameKey]; + if (sdkName) { + config->sdk_name = FIRMapFromServiceStringToTypeEnum(sdkName); + config->has_sdk_name = 1; + } + + NSString *version = diagnosticObjects[kFIRCDSdkVersionKey]; + if (version) { + config->sdk_version = FIREncodeString(version); + } +} + +/** Populates the given proto with data from the calling FIRApp using the given + * diagnosticObjects dictionary. + * + * @param config The proto to populate + * @param diagnosticObjects The dictionary of diagnostics objects. + */ +void FIRPopulateProtoWithCommonInfoFromApp(logs_proto_mobilesdk_ios_ICoreConfiguration *config, + NSDictionary *diagnosticObjects) { + config->pod_name = logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE; + config->has_pod_name = 1; + + if (!diagnosticObjects[kFIRCDllAppsCountKey]) { + GDTCORLogError(GDTCORMCEGeneralError, @"%@", + @"App count is a required value in the data dict."); + } + config->app_count = (int32_t)[diagnosticObjects[kFIRCDllAppsCountKey] integerValue]; + config->has_app_count = 1; + + NSString *googleAppID = diagnosticObjects[kFIRCDGoogleAppIDKey]; + if (googleAppID.length) { + config->app_id = FIREncodeString(googleAppID); + } + + NSString *bundleID = diagnosticObjects[kFIRCDBundleIDKey]; + if (bundleID.length) { + config->bundle_id = FIREncodeString(bundleID); + } + + NSString *firebaseUserAgent = diagnosticObjects[kFIRCDFirebaseUserAgentKey]; + if (firebaseUserAgent.length) { + config->platform_info = FIREncodeString(firebaseUserAgent); + } + + NSNumber *usingOptionsFromDefaultPlist = diagnosticObjects[kFIRCDUsingOptionsFromDefaultPlistKey]; + if (usingOptionsFromDefaultPlist != nil) { + config->use_default_app = [usingOptionsFromDefaultPlist boolValue]; + config->has_use_default_app = 1; + } + + NSString *libraryVersionID = diagnosticObjects[kFIRCDLibraryVersionIDKey]; + if (libraryVersionID) { + config->icore_version = FIREncodeString(libraryVersionID); + } + + NSString *deviceModel = [FIRCoreDiagnostics deviceModel]; + if (deviceModel.length) { + config->device_model = FIREncodeString(deviceModel); + } + + NSString *osVersion = [GULAppEnvironmentUtil systemVersion]; + if (osVersion.length) { + config->os_version = FIREncodeString(osVersion); + } + + config->using_zip_file = kUsingZipFile; + config->has_using_zip_file = 1; + config->deployment_type = kDeploymentType; + config->has_deployment_type = 1; + config->deployed_in_app_store = [GULAppEnvironmentUtil isFromAppStore]; + config->has_deployed_in_app_store = 1; +} + +/** Populates the given proto with installed services data. + * + * @param config The proto to populate + */ +void FIRPopulateProtoWithInstalledServices(logs_proto_mobilesdk_ios_ICoreConfiguration *config) { + NSMutableArray *sdkServiceInstalledArray = [NSMutableArray array]; + + // AdMob + if (NSClassFromString(@"GADBannerView") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAdMob))]; + } + // CloudMessaging + if (NSClassFromString(@"FIRMessaging") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMessaging))]; + } + // RemoteConfig + if (NSClassFromString(@"FIRRemoteConfig") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceRemoteConfig))]; + } + // Measurement/Analtyics + if (NSClassFromString(@"FIRAnalytics") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMeasurement))]; + } + // ML Vision On Device AutoML. + if (NSClassFromString(@"FIRVisionOnDeviceAutoMLImageLabelerOptions") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceAutoML))]; + } + // ML Vision On Device Face. + if (NSClassFromString(@"FIRVisionFaceDetector") != nil && + NSClassFromString(@"GMVFaceDetector") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceFace))]; + } + // ML Vision On Device Barcode. + if (NSClassFromString(@"FIRVisionBarcodeDetector") != nil && + NSClassFromString(@"GMVBarcodeDetector") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceBarcode))]; + } + // ML Vision On Device Text. + if (NSClassFromString(@"FIRVisionTextDetector") != nil && + NSClassFromString(@"GMVTextDetector") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceText))]; + } + // ML Vision On Device Image Label. + if (NSClassFromString(@"FIRVisionLabelDetector") != nil && + NSClassFromString(@"GMVLabelDetector") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceLabel))]; + } + // ML Vision On Device Object. + if (NSClassFromString(@"FIRVisionObjectDetector") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceObjectDetection))]; + } + // ML Model Interpreter + if (NSClassFromString(@"FIRCustomModelInterpreter") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLModelInterpreter))]; + } + // Database + if (NSClassFromString(@"FIRDatabase") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceDatabase))]; + } + // DynamicDeepLink + if (NSClassFromString(@"FIRDynamicLinks") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceDynamicLinks))]; + } + // Auth + if (NSClassFromString(@"FIRAuth") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAuth))]; + } + // AuthUI + if (NSClassFromString(@"FUIAuth") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAuthUI))]; + } + // Firestore + if (NSClassFromString(@"FIRFirestore") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceFirestore))]; + } + // Functions + if (NSClassFromString(@"FIRFunctions") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceFunctions))]; + } + // Performance + if (NSClassFromString(@"FIRPerformance") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServicePerformance))]; + } + // Storage + if (NSClassFromString(@"FIRStorage") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceStorage))]; + } + // SignIn via Google pod + if (NSClassFromString(@"GIDSignIn") != nil && NSClassFromString(@"GGLContext") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kGGLServiceSignIn))]; + } + // Analytics via Google pod + if (NSClassFromString(@"GAI") != nil && NSClassFromString(@"GGLContext") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kGGLServiceAnalytics))]; + } + + // In-App Messaging + if (NSClassFromString(@"FIRInAppMessaging") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceIAM))]; + } + + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *servicesInstalled = + malloc(sizeof(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType) * + sdkServiceInstalledArray.count); + for (NSUInteger i = 0; i < sdkServiceInstalledArray.count; i++) { + NSNumber *typeEnum = sdkServiceInstalledArray[i]; + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType serviceType = + (int32_t)typeEnum.integerValue; + servicesInstalled[i] = serviceType; + } + + config->sdk_service_installed = servicesInstalled; + config->sdk_service_installed_count = (int32_t)sdkServiceInstalledArray.count; +} + +/** Populates the proto with the number of linked frameworks. + * + * @param config The proto to populate. + */ +void FIRPopulateProtoWithNumberOfLinkedFrameworks( + logs_proto_mobilesdk_ios_ICoreConfiguration *config) { + int numFrameworks = -1; // Subtract the app binary itself. + unsigned int numImages; + const char **imageNames = objc_copyImageNames(&numImages); + for (unsigned int i = 0; i < numImages; i++) { + NSString *imageName = [NSString stringWithUTF8String:imageNames[i]]; + if ([imageName rangeOfString:@"System/Library"].length != 0 // Apple .frameworks + || [imageName rangeOfString:@"Developer/Library"].length != 0 // Xcode debug .frameworks + || [imageName rangeOfString:@"usr/lib"].length != 0) { // Public .dylibs + continue; + } + numFrameworks++; + } + free(imageNames); + config->dynamic_framework_count = numFrameworks; + config->has_dynamic_framework_count = 1; +} + +/** Populates the proto with Info.plist values. + * + * @param config The proto to populate. + */ +void FIRPopulateProtoWithInfoPlistValues(logs_proto_mobilesdk_ios_ICoreConfiguration *config) { + NSDictionary *info = [[NSBundle mainBundle] infoDictionary]; + + NSString *xcodeVersion = info[@"DTXcodeBuild"] ?: @""; + NSString *sdkVersion = info[@"DTSDKBuild"] ?: @""; + NSString *combinedVersions = [NSString stringWithFormat:@"%@-%@", xcodeVersion, sdkVersion]; + config->apple_framework_version = FIREncodeString(combinedVersions); + + NSString *minVersion = info[@"MinimumOSVersion"]; + if (minVersion) { + config->min_supported_ios_version = FIREncodeString(minVersion); + } + + // Apps can turn off swizzling in the Info.plist, check if they've explicitly set the value and + // report it. It's enabled by default. + NSNumber *appDelegateSwizzledNum = info[@"FirebaseAppDelegateProxyEnabled"]; + BOOL appDelegateSwizzled = YES; + if ([appDelegateSwizzledNum isKindOfClass:[NSNumber class]]) { + appDelegateSwizzled = [appDelegateSwizzledNum boolValue]; + } + config->swizzling_enabled = appDelegateSwizzled; + config->has_swizzling_enabled = 1; +} + +#pragma mark - FIRCoreDiagnosticsInterop + ++ (void)sendDiagnosticsData:(nonnull id)diagnosticsData { + FIRCoreDiagnostics *diagnostics = [FIRCoreDiagnostics sharedInstance]; + [diagnostics sendDiagnosticsData:diagnosticsData]; +} + +- (void)sendDiagnosticsData:(nonnull id)diagnosticsData { + dispatch_async(self.diagnosticsQueue, ^{ + NSDictionary *diagnosticObjects = diagnosticsData.diagnosticObjects; + NSNumber *isDataCollectionDefaultEnabled = + diagnosticObjects[kFIRCDIsDataCollectionDefaultEnabledKey]; + if (isDataCollectionDefaultEnabled && ![isDataCollectionDefaultEnabled boolValue]) { + return; + } + + // Create the proto. + logs_proto_mobilesdk_ios_ICoreConfiguration icore_config = + logs_proto_mobilesdk_ios_ICoreConfiguration_init_default; + + icore_config.using_gdt = 1; + icore_config.has_using_gdt = 1; + + // Populate the proto with information. + FIRPopulateProtoWithInfoFromUserInfoParams(&icore_config, diagnosticObjects); + FIRPopulateProtoWithCommonInfoFromApp(&icore_config, diagnosticObjects); + FIRPopulateProtoWithInstalledServices(&icore_config); + FIRPopulateProtoWithNumberOfLinkedFrameworks(&icore_config); + FIRPopulateProtoWithInfoPlistValues(&icore_config); + [self setHeartbeatFlagIfNeededToConfig:&icore_config]; + + // This log object is capable of converting the proto to bytes. + FIRCoreDiagnosticsLog *log = [[FIRCoreDiagnosticsLog alloc] initWithConfig:icore_config]; + + // Send the log as a telemetry event. + GDTCOREvent *event = [self.transport eventForTransport]; + event.dataObject = (id)log; + [self.transport sendTelemetryEvent:event]; + }); +} + +#pragma mark - Heartbeat + +- (void)setHeartbeatFlagIfNeededToConfig:(logs_proto_mobilesdk_ios_ICoreConfiguration *)config { + // Check if need to send a heartbeat. + NSDate *currentDate = [NSDate date]; + NSDate *lastCheckin = + [self.heartbeatDateStorage heartbeatDateForTag:kFIRCoreDiagnosticsHeartbeatTag]; + if (lastCheckin) { + // Ensure the previous checkin was on a different date in the past. + if ([self isDate:currentDate inSameDayOrBeforeThan:lastCheckin]) { + return; + } + } + + // Update heartbeat sent date. + [self.heartbeatDateStorage setHearbeatDate:currentDate forTag:kFIRCoreDiagnosticsHeartbeatTag]; + // Set the flag. + config->sdk_name = logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ICORE; + config->has_sdk_name = 1; +} + +- (BOOL)isDate:(NSDate *)date1 inSameDayOrBeforeThan:(NSDate *)date2 { + return [[NSCalendar currentCalendar] isDate:date1 inSameDayAsDate:date2] || + [date1 compare:date2] == NSOrderedAscending; +} + +@end diff --git a/Example/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.c b/Example/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.c new file mode 100644 index 0000000..4b2ac2f --- /dev/null +++ b/Example/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.c @@ -0,0 +1,60 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.3 */ + +#include "firebasecore.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t logs_proto_mobilesdk_ios_ICoreConfiguration_fields[22] = { + PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, logs_proto_mobilesdk_ios_ICoreConfiguration, configuration_type, configuration_type, 0), + PB_FIELD( 7, UENUM , REPEATED, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_service_installed, configuration_type, 0), + PB_FIELD( 9, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, device_model, sdk_service_installed, 0), + PB_FIELD( 10, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, app_id, device_model, 0), + PB_FIELD( 12, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, bundle_id, app_id, 0), + PB_FIELD( 16, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, pod_name, bundle_id, 0), + PB_FIELD( 18, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, icore_version, pod_name, 0), + PB_FIELD( 19, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_version, icore_version, 0), + PB_FIELD( 20, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_name, sdk_version, 0), + PB_FIELD( 21, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, app_count, sdk_name, 0), + PB_FIELD( 22, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, os_version, app_count, 0), + PB_FIELD( 24, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, min_supported_ios_version, os_version, 0), + PB_FIELD( 25, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, use_default_app, min_supported_ios_version, 0), + PB_FIELD( 26, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, deployed_in_app_store, use_default_app, 0), + PB_FIELD( 27, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, dynamic_framework_count, deployed_in_app_store, 0), + PB_FIELD( 28, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, apple_framework_version, dynamic_framework_count, 0), + PB_FIELD( 29, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, using_zip_file, apple_framework_version, 0), + PB_FIELD( 30, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, deployment_type, using_zip_file, 0), + PB_FIELD( 31, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, platform_info, deployment_type, 0), + PB_FIELD( 33, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, swizzling_enabled, platform_info, 0), + PB_FIELD( 36, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, using_gdt, swizzling_enabled, 0), + PB_LAST_FIELD +}; + + + + + + + +/* @@protoc_insertion_point(eof) */ diff --git a/Example/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h b/Example/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h new file mode 100644 index 0000000..3e4c195 --- /dev/null +++ b/Example/Pods/FirebaseCoreDiagnostics/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h @@ -0,0 +1,193 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.3 */ + +#ifndef PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED +#define PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED +#include + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType { + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_UNKNOWN_CONFIGURATION_TYPE = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK = 2 +} logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_UNKNOWN_CONFIGURATION_TYPE +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType)(logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK+1)) + +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType { + logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_UNKNOWN_BUILD_TYPE = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_INTERNAL = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_EAP = 2, + logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_PROD = 3 +} logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_UNKNOWN_BUILD_TYPE +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_PROD +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType)(logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_PROD+1)) + +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType { + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_UNKNOWN_SDK_SERVICE = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ICORE = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ADMOB = 2, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_APP_INVITE = 3, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_SIGN_IN = 5, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_GCM = 6, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MAPS = 7, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_SCION = 8, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ANALYTICS = 9, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_APP_INDEXING = 10, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_CONFIG = 11, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DURABLE_DEEP_LINKS = 12, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_CRASH = 13, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH = 14, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DATABASE = 15, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_STORAGE = 16, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MESSAGING = 17, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MEASUREMENT = 18, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_REMOTE_CONFIG = 19, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DYNAMIC_LINKS = 20, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_INVITES = 21, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH_UI = 22, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FIRESTORE = 23, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_PERFORMANCE = 24, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_FACE = 26, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_BARCODE = 27, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_TEXT = 28, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_LABEL = 29, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_MODEL_INTERPRETER = 30, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_IN_APP_MESSAGING = 31, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FUNCTIONS = 32, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_NATURAL_LANGUAGE = 33, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_AUTOML = 34, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION = 35 +} logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_UNKNOWN_SDK_SERVICE +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType)(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION+1)) + +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName { + logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_UNKNOWN_POD_NAME = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_GOOGLE = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE = 2 +} logs_proto_mobilesdk_ios_ICoreConfiguration_PodName; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_UNKNOWN_POD_NAME +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_PodName)(logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE+1)) + +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType { + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_UNKNOWN = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_COCOAPODS = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ZIP_FILE = 2, + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_CARTHAGE = 3, + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM = 4 +} logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_UNKNOWN +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType)(logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM+1)) + +/* Struct definitions */ +typedef struct _logs_proto_mobilesdk_ios_ICoreConfiguration { + bool has_configuration_type; + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType configuration_type; + pb_size_t sdk_service_installed_count; + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *sdk_service_installed; + pb_bytes_array_t *device_model; + pb_bytes_array_t *app_id; + pb_bytes_array_t *bundle_id; + bool has_pod_name; + logs_proto_mobilesdk_ios_ICoreConfiguration_PodName pod_name; + pb_bytes_array_t *icore_version; + pb_bytes_array_t *sdk_version; + bool has_sdk_name; + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType sdk_name; + bool has_app_count; + int32_t app_count; + pb_bytes_array_t *os_version; + pb_bytes_array_t *min_supported_ios_version; + bool has_use_default_app; + bool use_default_app; + bool has_deployed_in_app_store; + bool deployed_in_app_store; + bool has_dynamic_framework_count; + int32_t dynamic_framework_count; + pb_bytes_array_t *apple_framework_version; + bool has_using_zip_file; + bool using_zip_file; + bool has_deployment_type; + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType deployment_type; + pb_bytes_array_t *platform_info; + bool has_swizzling_enabled; + bool swizzling_enabled; + bool has_using_gdt; + bool using_gdt; +/* @@protoc_insertion_point(struct:logs_proto_mobilesdk_ios_ICoreConfiguration) */ +} logs_proto_mobilesdk_ios_ICoreConfiguration; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define logs_proto_mobilesdk_ios_ICoreConfiguration_init_default {false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN, 0, NULL, NULL, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN, false, 0, NULL, NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN, NULL, false, 0, false, 0} +#define logs_proto_mobilesdk_ios_ICoreConfiguration_init_zero {false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN, 0, NULL, NULL, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN, false, 0, NULL, NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN, NULL, false, 0, false, 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define logs_proto_mobilesdk_ios_ICoreConfiguration_pod_name_tag 16 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_configuration_type_tag 1 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_icore_version_tag 18 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_version_tag 19 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_service_installed_tag 7 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_name_tag 20 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_device_model_tag 9 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_os_version_tag 22 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_id_tag 10 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_bundle_id_tag 12 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_min_supported_ios_version_tag 24 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_use_default_app_tag 25 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_count_tag 21 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_deployed_in_app_store_tag 26 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_dynamic_framework_count_tag 27 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_apple_framework_version_tag 28 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_using_zip_file_tag 29 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_deployment_type_tag 30 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_platform_info_tag 31 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_swizzling_enabled_tag 33 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_using_gdt_tag 36 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t logs_proto_mobilesdk_ios_ICoreConfiguration_fields[22]; + +/* Maximum encoded size of messages (where known) */ +/* logs_proto_mobilesdk_ios_ICoreConfiguration_size depends on runtime parameters */ + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define FIREBASECORE_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/Example/Pods/FirebaseCoreDiagnostics/LICENSE b/Example/Pods/FirebaseCoreDiagnostics/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Example/Pods/FirebaseCoreDiagnostics/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 [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Example/Pods/FirebaseCoreDiagnostics/README.md b/Example/Pods/FirebaseCoreDiagnostics/README.md new file mode 100644 index 0000000..3ddc8fb --- /dev/null +++ b/Example/Pods/FirebaseCoreDiagnostics/README.md @@ -0,0 +1,251 @@ +# Firebase iOS Open Source Development [![Build Status](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk) + +This repository contains a subset of the Firebase iOS SDK source. It currently +includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase, +FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging, +FirebaseInAppMessagingDisplay, FirebaseMessaging, FirebaseRemoteConfig, and +FirebaseStorage. + +The repository also includes GoogleUtilities source. The +[GoogleUtilities](GoogleUtilities/README.md) pod is +a set of utilities used by Firebase and other Google products. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found at +[https://firebase.google.com](https://firebase.google.com). + +## Installation + +See the three subsections for details about three different installation methods. +1. [Standard pod install](README.md#standard-pod-install) +1. [Installing from the GitHub repo](README.md#installing-from-github) +1. [Experimental Carthage](README.md#carthage-ios-only) + +### Standard pod install + +Go to +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Installing from GitHub + +For releases starting with 5.0.0, the source for each release is also deployed +to CocoaPods master and available via standard +[CocoaPods Podfile syntax](https://guides.cocoapods.org/syntax/podfile.html#pod). + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See +[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All of the official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +``` +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +``` + +To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do: + +``` +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution are at +[Carthage](Carthage.md). + +### Rome + +Instructions for installing binary frameworks via +[Rome](https://github.com/CocoaPods/Rome) are at [Rome](Rome.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + + * Xcode 10.1 (or later) + * CocoaPods 1.7.2 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self contained Xcode project. See +[Firestore/README.md](Firestore/README.md). + +### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +### Adding a New Firebase Pod + +See [AddNewPod.md](AddNewPod.md). + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/style.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/style.sh) +before creating a PR. + +Travis will verify that any code changes are done in a style compliant way. Install +`clang-format` and `swiftformat`. +These commands will get the right versions: + +``` +brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/e3496d9/Formula/clang-format.rb +brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/7963c3d/Formula/swiftformat.rb +``` + +Note: if you already have a newer version of these installed you may need to +`brew switch` to this version. + +To update this section, find the versions of clang-format and swiftformat.rb to +match the versions in the CI failure logs +[here](https://github.com/Homebrew/homebrew-core/tree/master/Formula). + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +#### Viewing Code Coverage + +First, make sure that [xcov](https://github.com/nakiostudio/xcov) is installed with `gem install xcov`. + +After running the `AllUnitTests_iOS` scheme in Xcode, execute +`xcov --workspace Firebase.xcworkspace --scheme AllUnitTests_iOS --output_directory xcov_output` +at Example/ in the terminal. This will aggregate the coverage, and you can run `open xcov_output/index.html` to see the results. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need valid +`GoogleService-Info.plist` files for those samples. The Firebase Xcode project contains dummy plist +files without real values, but can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g. `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and replace the appropriate dummy plist file +(e.g. in [Example/Database/App/](Example/Database/App/)); + +Some sample apps like Firebase Messaging ([Example/Messaging/App](Example/Messaging/App)) require +special Apple capabilities, and you will have to change the sample app to use a unique bundle +identifier that you can control in your own Apple Developer account. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +If you're doing specific Firebase Auth development, see +[the Auth Sample README](Example/Auth/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +To run the Database Integration tests, make your database authentication rules +[public](https://firebase.google.com/docs/database/security/quickstart). + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[FIRStorageIntegrationTests.m](Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to actually test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account, and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications, and will not receive push notifications. +In order to receive push notifications, you'll have to follow the steps above and run the app on a +physical device. + +## Community Supported Efforts + +We've seen an amazing amount of interest and contributions to improve the Firebase SDKs, and we are +very grateful! We'd like to empower as many developers as we can to be able to use Firebase and +participate in the Firebase community. + +### tvOS, macOS, and Catalyst +Thanks to contributions from the community, FirebaseABTesting, FirebaseAuth, FirebaseCore, +FirebaseDatabase, FirebaseMessaging, FirebaseFirestore, +FirebaseFunctions, FirebaseRemoteConfig, and FirebaseStorage now compile, run unit tests, and work on +tvOS, macOS, and Catalyst. + +For tvOS, checkout the [Sample](Example/tvOSSample). + +Keep in mind that macOS, Catalyst and tvOS are not officially supported by Firebase, and this +repository is actively developed primarily for iOS. While we can catch basic unit test issues with +Travis, there may be some changes where the SDK no longer works as expected on macOS or tvOS. If you +encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +To install, add a subset of the following to the Podfile: + +``` +pod 'Firebase/ABTesting' +pod 'Firebase/Auth' +pod 'Firebase/Database' +pod 'Firebase/Firestore' +pod 'Firebase/Functions' +pod 'Firebase/Messaging' +pod 'Firebase/RemoteConfig' +pod 'Firebase/Storage' +``` + +#### Additional Catalyst Notes + +* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability` +to Build Settings. +* FirebaseFirestore requires signing the +[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +iOS SDK. + +## License + +The contents of this repository is licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Example/Pods/FirebaseCoreDiagnosticsInterop/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h b/Example/Pods/FirebaseCoreDiagnosticsInterop/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h new file mode 100644 index 0000000..69c4072 --- /dev/null +++ b/Example/Pods/FirebaseCoreDiagnosticsInterop/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h @@ -0,0 +1,61 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** If present, is a BOOL wrapped in an NSNumber. */ +#define kFIRCDIsDataCollectionDefaultEnabledKey @"FIRCDIsDataCollectionDefaultEnabledKey" + +/** If present, is an int32_t wrapped in an NSNumber. */ +#define kFIRCDConfigurationTypeKey @"FIRCDConfigurationTypeKey" + +/** If present, is an NSString. */ +#define kFIRCDSdkNameKey @"FIRCDSdkNameKey" + +/** If present, is an NSString. */ +#define kFIRCDSdkVersionKey @"FIRCDSdkVersionKey" + +/** If present, is an int32_t wrapped in an NSNumber. */ +#define kFIRCDllAppsCountKey @"FIRCDllAppsCountKey" + +/** If present, is an NSString. */ +#define kFIRCDGoogleAppIDKey @"FIRCDGoogleAppIDKey" + +/** If present, is an NSString. */ +#define kFIRCDBundleIDKey @"FIRCDBundleID" + +/** If present, is a BOOL wrapped in an NSNumber. */ +#define kFIRCDUsingOptionsFromDefaultPlistKey @"FIRCDUsingOptionsFromDefaultPlistKey" + +/** If present, is an NSString. */ +#define kFIRCDLibraryVersionIDKey @"FIRCDLibraryVersionIDKey" + +/** If present, is an NSString. */ +#define kFIRCDFirebaseUserAgentKey @"FIRCDFirebaseUserAgentKey" + +/** Defines the interface of a data object needed to log diagnostics data. */ +@protocol FIRCoreDiagnosticsData + +@required + +/** A dictionary containing data (non-exhaustive) to be logged in diagnostics. */ +@property(nonatomic) NSDictionary *diagnosticObjects; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseCoreDiagnosticsInterop/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h b/Example/Pods/FirebaseCoreDiagnosticsInterop/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h new file mode 100644 index 0000000..2b0eb71 --- /dev/null +++ b/Example/Pods/FirebaseCoreDiagnosticsInterop/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h @@ -0,0 +1,34 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import + +#import "FIRCoreDiagnosticsData.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Allows the interoperation of FirebaseCore and FirebaseCoreDiagnostics. */ +@protocol FIRCoreDiagnosticsInterop + +/** Sends the given diagnostics data. + * + * @param diagnosticsData The diagnostics data object to send. + */ ++ (void)sendDiagnosticsData:(id)diagnosticsData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseCoreDiagnosticsInterop/LICENSE b/Example/Pods/FirebaseCoreDiagnosticsInterop/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Example/Pods/FirebaseCoreDiagnosticsInterop/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 [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Example/Pods/FirebaseCoreDiagnosticsInterop/README.md b/Example/Pods/FirebaseCoreDiagnosticsInterop/README.md new file mode 100644 index 0000000..3ddc8fb --- /dev/null +++ b/Example/Pods/FirebaseCoreDiagnosticsInterop/README.md @@ -0,0 +1,251 @@ +# Firebase iOS Open Source Development [![Build Status](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk) + +This repository contains a subset of the Firebase iOS SDK source. It currently +includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase, +FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging, +FirebaseInAppMessagingDisplay, FirebaseMessaging, FirebaseRemoteConfig, and +FirebaseStorage. + +The repository also includes GoogleUtilities source. The +[GoogleUtilities](GoogleUtilities/README.md) pod is +a set of utilities used by Firebase and other Google products. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found at +[https://firebase.google.com](https://firebase.google.com). + +## Installation + +See the three subsections for details about three different installation methods. +1. [Standard pod install](README.md#standard-pod-install) +1. [Installing from the GitHub repo](README.md#installing-from-github) +1. [Experimental Carthage](README.md#carthage-ios-only) + +### Standard pod install + +Go to +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Installing from GitHub + +For releases starting with 5.0.0, the source for each release is also deployed +to CocoaPods master and available via standard +[CocoaPods Podfile syntax](https://guides.cocoapods.org/syntax/podfile.html#pod). + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See +[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All of the official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +``` +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +``` + +To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do: + +``` +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution are at +[Carthage](Carthage.md). + +### Rome + +Instructions for installing binary frameworks via +[Rome](https://github.com/CocoaPods/Rome) are at [Rome](Rome.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + + * Xcode 10.1 (or later) + * CocoaPods 1.7.2 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self contained Xcode project. See +[Firestore/README.md](Firestore/README.md). + +### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +### Adding a New Firebase Pod + +See [AddNewPod.md](AddNewPod.md). + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/style.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/style.sh) +before creating a PR. + +Travis will verify that any code changes are done in a style compliant way. Install +`clang-format` and `swiftformat`. +These commands will get the right versions: + +``` +brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/e3496d9/Formula/clang-format.rb +brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/7963c3d/Formula/swiftformat.rb +``` + +Note: if you already have a newer version of these installed you may need to +`brew switch` to this version. + +To update this section, find the versions of clang-format and swiftformat.rb to +match the versions in the CI failure logs +[here](https://github.com/Homebrew/homebrew-core/tree/master/Formula). + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +#### Viewing Code Coverage + +First, make sure that [xcov](https://github.com/nakiostudio/xcov) is installed with `gem install xcov`. + +After running the `AllUnitTests_iOS` scheme in Xcode, execute +`xcov --workspace Firebase.xcworkspace --scheme AllUnitTests_iOS --output_directory xcov_output` +at Example/ in the terminal. This will aggregate the coverage, and you can run `open xcov_output/index.html` to see the results. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need valid +`GoogleService-Info.plist` files for those samples. The Firebase Xcode project contains dummy plist +files without real values, but can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g. `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and replace the appropriate dummy plist file +(e.g. in [Example/Database/App/](Example/Database/App/)); + +Some sample apps like Firebase Messaging ([Example/Messaging/App](Example/Messaging/App)) require +special Apple capabilities, and you will have to change the sample app to use a unique bundle +identifier that you can control in your own Apple Developer account. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +If you're doing specific Firebase Auth development, see +[the Auth Sample README](Example/Auth/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +To run the Database Integration tests, make your database authentication rules +[public](https://firebase.google.com/docs/database/security/quickstart). + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[FIRStorageIntegrationTests.m](Example/Storage/Tests/Integration/FIRStorageIntegrationTests.m). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to actually test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account, and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications, and will not receive push notifications. +In order to receive push notifications, you'll have to follow the steps above and run the app on a +physical device. + +## Community Supported Efforts + +We've seen an amazing amount of interest and contributions to improve the Firebase SDKs, and we are +very grateful! We'd like to empower as many developers as we can to be able to use Firebase and +participate in the Firebase community. + +### tvOS, macOS, and Catalyst +Thanks to contributions from the community, FirebaseABTesting, FirebaseAuth, FirebaseCore, +FirebaseDatabase, FirebaseMessaging, FirebaseFirestore, +FirebaseFunctions, FirebaseRemoteConfig, and FirebaseStorage now compile, run unit tests, and work on +tvOS, macOS, and Catalyst. + +For tvOS, checkout the [Sample](Example/tvOSSample). + +Keep in mind that macOS, Catalyst and tvOS are not officially supported by Firebase, and this +repository is actively developed primarily for iOS. While we can catch basic unit test issues with +Travis, there may be some changes where the SDK no longer works as expected on macOS or tvOS. If you +encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +To install, add a subset of the following to the Podfile: + +``` +pod 'Firebase/ABTesting' +pod 'Firebase/Auth' +pod 'Firebase/Database' +pod 'Firebase/Firestore' +pod 'Firebase/Functions' +pod 'Firebase/Messaging' +pod 'Firebase/RemoteConfig' +pod 'Firebase/Storage' +``` + +#### Additional Catalyst Notes + +* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability` +to Build Settings. +* FirebaseFirestore requires signing the +[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase iOS SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +iOS SDK. + +## License + +The contents of this repository is licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDataSnapshot.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDataSnapshot.m index b774493..c1d48ec 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDataSnapshot.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDataSnapshot.m @@ -15,20 +15,19 @@ */ #import "FIRDataSnapshot.h" -#import "FIRDataSnapshot_Private.h" #import "FChildrenNode.h" -#import "FValidation.h" -#import "FTransformedEnumerator.h" +#import "FIRDataSnapshot_Private.h" #import "FIRDatabaseReference.h" +#import "FTransformedEnumerator.h" +#import "FValidation.h" @interface FIRDataSnapshot () -@property (nonatomic, strong) FIRDatabaseReference *ref; +@property(nonatomic, strong) FIRDatabaseReference *ref; @end @implementation FIRDataSnapshot -- (id)initWithRef:(FIRDatabaseReference *)ref indexedNode:(FIndexedNode *)node -{ +- (id)initWithRef:(FIRDatabaseReference *)ref indexedNode:(FIndexedNode *)node { self = [super init]; if (self != nil) { self->_ref = ref; @@ -37,65 +36,70 @@ - (id)initWithRef:(FIRDatabaseReference *)ref indexedNode:(FIndexedNode *)node return self; } -- (id) value { +- (id)value { return [self.node.node val]; } -- (id) valueInExportFormat { +- (id)valueInExportFormat { return [self.node.node valForExport:YES]; } - (FIRDataSnapshot *)childSnapshotForPath:(NSString *)childPathString { [FValidation validateFrom:@"child:" validPathString:childPathString]; - FPath* childPath = [[FPath alloc] initWith:childPathString]; - FIRDatabaseReference * childRef = [self.ref child:childPathString]; + FPath *childPath = [[FPath alloc] initWith:childPathString]; + FIRDatabaseReference *childRef = [self.ref child:childPathString]; id childNode = [self.node.node getChild:childPath]; - return [[FIRDataSnapshot alloc] initWithRef:childRef indexedNode:[FIndexedNode indexedNodeWithNode:childNode]]; + return [[FIRDataSnapshot alloc] + initWithRef:childRef + indexedNode:[FIndexedNode indexedNodeWithNode:childNode]]; } -- (BOOL) hasChild:(NSString *)childPathString { +- (BOOL)hasChild:(NSString *)childPathString { [FValidation validateFrom:@"hasChild:" validPathString:childPathString]; - FPath* childPath = [[FPath alloc] initWith:childPathString]; - return ! [[self.node.node getChild:childPath] isEmpty]; + FPath *childPath = [[FPath alloc] initWith:childPathString]; + return ![[self.node.node getChild:childPath] isEmpty]; } -- (id) priority { +- (id)priority { id priority = [self.node.node getPriority]; return priority.val; } - -- (BOOL) hasChildren { - if([self.node.node isLeafNode]) { +- (BOOL)hasChildren { + if ([self.node.node isLeafNode]) { return false; - } - else { + } else { return ![self.node.node isEmpty]; } } -- (BOOL) exists { +- (BOOL)exists { return ![self.node.node isEmpty]; } -- (NSString *) key { +- (NSString *)key { return [self.ref key]; } -- (NSUInteger) childrenCount { +- (NSUInteger)childrenCount { return [self.node.node numChildren]; } -- (NSEnumerator *) children { - return [[FTransformedEnumerator alloc] initWithEnumerator:self.node.childEnumerator andTransform:^id(FNamedNode *node) { - FIRDatabaseReference *childRef = [self.ref child:node.name]; - return [[FIRDataSnapshot alloc] initWithRef:childRef indexedNode:[FIndexedNode indexedNodeWithNode:node.node]]; - }]; +- (NSEnumerator *)children { + return [[FTransformedEnumerator alloc] + initWithEnumerator:self.node.childEnumerator + andTransform:^id(FNamedNode *node) { + FIRDatabaseReference *childRef = [self.ref child:node.name]; + return [[FIRDataSnapshot alloc] + initWithRef:childRef + indexedNode:[FIndexedNode indexedNodeWithNode:node.node]]; + }]; } -- (NSString *) description { - return [NSString stringWithFormat:@"Snap (%@) %@", self.key, self.node.node]; +- (NSString *)description { + return + [NSString stringWithFormat:@"Snap (%@) %@", self.key, self.node.node]; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabase.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabase.m index 1a2ba88..8957336 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabase.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabase.m @@ -35,8 +35,9 @@ @implementation FIRDatabase -// The STR and STR_EXPAND macro allow a numeric version passed to he compiler driver -// with a -D to be treated as a string instead of an invalid floating point value. +// The STR and STR_EXPAND macro allow a numeric version passed to he compiler +// driver with a -D to be treated as a string instead of an invalid floating +// point value. #define STR(x) STR_EXPAND(x) #define STR_EXPAND(x) #x static const char *FIREBASE_SEMVER = (const char *)STR(FIRDatabase_VERSION); @@ -44,8 +45,10 @@ @implementation FIRDatabase + (FIRDatabase *)database { if (![FIRApp isDefaultAppConfigured]) { [NSException raise:@"FIRAppNotConfigured" - format:@"Failed to get default Firebase Database instance. Must call `[FIRApp " - @"configure]` (`FirebaseApp.configure()` in Swift) before using " + format:@"Failed to get default Firebase Database instance. " + @"Must call `[FIRApp " + @"configure]` (`FirebaseApp.configure()` in Swift) " + @"before using " @"Firebase Database."]; } return [FIRDatabase databaseForApp:[FIRApp defaultApp]]; @@ -54,57 +57,66 @@ + (FIRDatabase *)database { + (FIRDatabase *)databaseWithURL:(NSString *)url { FIRApp *app = [FIRApp defaultApp]; if (app == nil) { - [NSException raise:@"FIRAppNotConfigured" - format:@"Failed to get default Firebase Database instance. " - @"Must call `[FIRApp configure]` (`FirebaseApp.configure()` in " - @"Swift) before using Firebase Database."]; + [NSException + raise:@"FIRAppNotConfigured" + format: + @"Failed to get default Firebase Database instance. " + @"Must call `[FIRApp configure]` (`FirebaseApp.configure()` in " + @"Swift) before using Firebase Database."]; } return [FIRDatabase databaseForApp:app URL:url]; } + (FIRDatabase *)databaseForApp:(FIRApp *)app { if (app == nil) { - [NSException raise:@"InvalidFIRApp" format:@"nil FIRApp instance passed to databaseForApp."]; + [NSException raise:@"InvalidFIRApp" + format:@"nil FIRApp instance passed to databaseForApp."]; } return [FIRDatabase databaseForApp:app URL:app.options.databaseURL]; } + (FIRDatabase *)databaseForApp:(FIRApp *)app URL:(NSString *)url { - if (app == nil) { - [NSException raise:@"InvalidFIRApp" - format:@"nil FIRApp instance passed to databaseForApp."]; - } - if (url == nil) { - [NSException raise:@"MissingDatabaseURL" - format:@"Failed to get FirebaseDatabase instance: " - @"Specify DatabaseURL within FIRApp or from your databaseForApp:URL: call."]; - } - id provider = FIR_COMPONENT(FIRDatabaseProvider, app.container); - return [provider databaseForApp:app URL:url]; -} - -+ (NSString *) buildVersion { + if (app == nil) { + [NSException raise:@"InvalidFIRApp" + format:@"nil FIRApp instance passed to databaseForApp."]; + } + if (url == nil) { + [NSException raise:@"MissingDatabaseURL" + format:@"Failed to get FirebaseDatabase instance: " + @"Specify DatabaseURL within FIRApp or from your " + @"databaseForApp:URL: call."]; + } + id provider = + FIR_COMPONENT(FIRDatabaseProvider, app.container); + return [provider databaseForApp:app URL:url]; +} + ++ (NSString *)buildVersion { // TODO: Restore git hash when build moves back to git return [NSString stringWithFormat:@"%s_%s", FIREBASE_SEMVER, __DATE__]; } -+ (FIRDatabase *)createDatabaseForTests:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config { - FIRDatabase *db = [[FIRDatabase alloc] initWithApp:nil repoInfo:repoInfo config:config]; ++ (FIRDatabase *)createDatabaseForTests:(FRepoInfo *)repoInfo + config:(FIRDatabaseConfig *)config { + FIRDatabase *db = [[FIRDatabase alloc] initWithApp:nil + repoInfo:repoInfo + config:config]; [db ensureRepo]; return db; } -+ (NSString *) sdkVersion { ++ (NSString *)sdkVersion { return [NSString stringWithUTF8String:FIREBASE_SEMVER]; } -+ (void) setLoggingEnabled:(BOOL)enabled { ++ (void)setLoggingEnabled:(BOOL)enabled { [FUtilities setLoggingEnabled:enabled]; FFLog(@"I-RDB024001", @"BUILD Version: %@", [FIRDatabase buildVersion]); } - -- (id)initWithApp:(FIRApp *)app repoInfo:(FRepoInfo *)info config:(FIRDatabaseConfig *)config { +- (id)initWithApp:(FIRApp *)app + repoInfo:(FRepoInfo *)info + config:(FIRDatabaseConfig *)config { self = [super init]; if (self != nil) { self->_repoInfo = info; @@ -117,7 +129,8 @@ - (id)initWithApp:(FIRApp *)app repoInfo:(FRepoInfo *)info config:(FIRDatabaseCo - (FIRDatabaseReference *)reference { [self ensureRepo]; - return [[FIRDatabaseReference alloc] initWithRepo:self.repo path:[FPath empty]]; + return [[FIRDatabaseReference alloc] initWithRepo:self.repo + path:[FPath empty]]; } - (FIRDatabaseReference *)referenceWithPath:(NSString *)path { @@ -132,23 +145,28 @@ - (FIRDatabaseReference *)referenceFromURL:(NSString *)databaseUrl { [self ensureRepo]; if (databaseUrl == nil) { - [NSException raise:@"InvalidDatabaseURL" format:@"Invalid nil url passed to referenceFromURL:"]; + [NSException raise:@"InvalidDatabaseURL" + format:@"Invalid nil url passed to referenceFromURL:"]; } FParsedUrl *parsedUrl = [FUtilities parseUrl:databaseUrl]; [FValidation validateFrom:@"referenceFromURL:" validURL:parsedUrl]; if (![parsedUrl.repoInfo.host isEqualToString:_repoInfo.host]) { - [NSException raise:@"InvalidDatabaseURL" format:@"Invalid URL (%@) passed to getReference(). URL was expected " - "to match configured Database URL: %@", databaseUrl, [self reference].URL]; + [NSException + raise:@"InvalidDatabaseURL" + format: + @"Invalid URL (%@) passed to getReference(). URL was expected " + "to match configured Database URL: %@", + databaseUrl, [self reference].URL]; } - return [[FIRDatabaseReference alloc] initWithRepo:self.repo path:parsedUrl.path]; + return [[FIRDatabaseReference alloc] initWithRepo:self.repo + path:parsedUrl.path]; } - - (void)purgeOutstandingWrites { [self ensureRepo]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo purgeOutstandingWrites]; + [self.repo purgeOutstandingWrites]; }); } @@ -156,7 +174,7 @@ - (void)goOnline { [self ensureRepo]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo resume]; + [self.repo resume]; }); } @@ -164,7 +182,7 @@ - (void)goOffline { [self ensureRepo]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo interrupt]; + [self.repo interrupt]; }); } @@ -195,16 +213,21 @@ - (dispatch_queue_t)callbackQueue { return self->_config.callbackQueue; } -- (void) assertUnfrozen:(NSString*)methodName { +- (void)assertUnfrozen:(NSString *)methodName { if (self.repo != nil) { - [NSException raise:@"FIRDatabaseAlreadyInUse" format:@"Calls to %@ must be made before any other usage of " - "FIRDatabase instance.", methodName]; + [NSException + raise:@"FIRDatabaseAlreadyInUse" + format:@"Calls to %@ must be made before any other usage of " + "FIRDatabase instance.", + methodName]; } } -- (void) ensureRepo { +- (void)ensureRepo { if (self.repo == nil) { - self.repo = [FRepoManager createRepo:self.repoInfo config:self.config database:self]; + self.repo = [FRepoManager createRepo:self.repoInfo + config:self.config + database:self]; } } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseComponent.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseComponent.h index 37840a1..9d8bdb2 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseComponent.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseComponent.h @@ -21,16 +21,18 @@ NS_ASSUME_NONNULL_BEGIN -/// This protocol is used in the interop registration process to register an instance provider for -/// individual FIRApps. +/// This protocol is used in the interop registration process to register an +/// instance provider for individual FIRApps. @protocol FIRDatabaseProvider -/// Gets a FirebaseDatabase instance for the specified URL, using the specified FirebaseApp. +/// Gets a FirebaseDatabase instance for the specified URL, using the specified +/// FirebaseApp. - (FIRDatabase *)databaseForApp:(FIRApp *)app URL:(NSString *)url; @end -/// A concrete implementation for FIRDatabaseProvider to create Database instances. +/// A concrete implementation for FIRDatabaseProvider to create Database +/// instances. @interface FIRDatabaseComponent : NSObject /// The FIRApp that instances will be set up with. diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseComponent.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseComponent.m index 5662f28..8e44778 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseComponent.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseComponent.m @@ -16,8 +16,8 @@ #import "FIRDatabaseComponent.h" -#import "FIRDatabase_Private.h" #import "FIRDatabaseConfig_Private.h" +#import "FIRDatabase_Private.h" #import "FRepoManager.h" #import @@ -30,11 +30,12 @@ NS_ASSUME_NONNULL_BEGIN -/** A NSMutableDictionary of FirebaseApp name and FRepoInfo to FirebaseDatabase instance. */ +/** A NSMutableDictionary of FirebaseApp name and FRepoInfo to FirebaseDatabase + * instance. */ typedef NSMutableDictionary FIRDatabaseDictionary; @interface FIRDatabaseComponent () -@property (nonatomic) FIRDatabaseDictionary *instances; +@property(nonatomic) FIRDatabaseDictionary *instances; /// Internal intializer. - (instancetype)initWithApp:(FIRApp *)app; @end @@ -44,113 +45,127 @@ @implementation FIRDatabaseComponent #pragma mark - Initialization - (instancetype)initWithApp:(FIRApp *)app { - self = [super init]; - if (self) { - _app = app; - _instances = [NSMutableDictionary dictionary]; - } - return self; + self = [super init]; + if (self) { + _app = app; + _instances = [NSMutableDictionary dictionary]; + } + return self; } #pragma mark - Lifecycle + (void)load { - [FIRApp registerInternalLibrary:(Class)self - withName:@"fire-db" - withVersion:[FIRDatabase sdkVersion]]; + [FIRApp registerInternalLibrary:(Class)self + withName:@"fire-db" + withVersion:[FIRDatabase sdkVersion]]; } #pragma mark - FIRComponentRegistrant + (NSArray *)componentsToRegister { - FIRDependency *authDep = - [FIRDependency dependencyWithProtocol:@protocol(FIRAuthInterop) isRequired:NO]; - FIRComponentCreationBlock creationBlock = - ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { + FIRDependency *authDep = + [FIRDependency dependencyWithProtocol:@protocol(FIRAuthInterop) + isRequired:NO]; + FIRComponentCreationBlock creationBlock = + ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { *isCacheable = YES; return [[FIRDatabaseComponent alloc] initWithApp:container.app]; - }; - FIRComponent *databaseProvider = - [FIRComponent componentWithProtocol:@protocol(FIRDatabaseProvider) - instantiationTiming:FIRInstantiationTimingLazy - dependencies:@[ authDep ] - creationBlock:creationBlock]; - return @[ databaseProvider ]; + }; + FIRComponent *databaseProvider = + [FIRComponent componentWithProtocol:@protocol(FIRDatabaseProvider) + instantiationTiming:FIRInstantiationTimingLazy + dependencies:@[ authDep ] + creationBlock:creationBlock]; + return @[ databaseProvider ]; } #pragma mark - Instance management. - (void)appWillBeDeleted:(FIRApp *)app { - NSString *appName = app.name; - if (appName == nil) { - return; - } - FIRDatabaseDictionary* instances = [self instances]; - @synchronized (instances) { - // Clean up the deleted instance in an effort to remove any resources still in use. - // Note: Any leftover instances of this exact database will be invalid. - for (FIRDatabase * database in [instances allValues]) { - [FRepoManager disposeRepos:database.config]; + NSString *appName = app.name; + if (appName == nil) { + return; + } + FIRDatabaseDictionary *instances = [self instances]; + @synchronized(instances) { + // Clean up the deleted instance in an effort to remove any resources + // still in use. Note: Any leftover instances of this exact database + // will be invalid. + for (FIRDatabase *database in [instances allValues]) { + [FRepoManager disposeRepos:database.config]; + } + [instances removeAllObjects]; } - [instances removeAllObjects]; - } } #pragma mark - FIRDatabaseProvider Conformance - - (FIRDatabase *)databaseForApp:(FIRApp *)app URL:(NSString *)url { - if (app == nil) { - [NSException raise:@"InvalidFIRApp" - format:@"nil FIRApp instance passed to databaseForApp."]; - } - - if (url == nil) { - [NSException raise:@"MissingDatabaseURL" - format:@"Failed to get FirebaseDatabase instance: " - "Specify DatabaseURL within FIRApp or from your databaseForApp:URL: call."]; - } - - NSURL *databaseUrl = [NSURL URLWithString:url]; - - if (databaseUrl == nil) { - [NSException raise:@"InvalidDatabaseURL" format:@"The Database URL '%@' cannot be parsed. " - "Specify a valid DatabaseURL within FIRApp or from your databaseForApp:URL: call.", databaseUrl]; - } else if (![databaseUrl.path isEqualToString:@""] && ![databaseUrl.path isEqualToString:@"/"]) { - [NSException raise:@"InvalidDatabaseURL" format:@"Configured Database URL '%@' is invalid. It should point " - "to the root of a Firebase Database but it includes a path: %@",databaseUrl, databaseUrl.path]; - } - - FIRDatabaseDictionary *instances = [self instances]; - @synchronized (instances) { - FParsedUrl *parsedUrl = [FUtilities parseUrl:databaseUrl.absoluteString]; - NSString *urlIndex = - [NSString stringWithFormat:@"%@:%@", parsedUrl.repoInfo.host, [parsedUrl.path toString]]; - FIRDatabase *database = instances[urlIndex]; - if (!database) { - id authTokenProvider = - [FAuthTokenProvider authTokenProviderWithAuth: - FIR_COMPONENT(FIRAuthInterop, app.container)]; - - // If this is the default app, don't set the session persistence key so that we use our - // default ("default") instead of the FIRApp default ("[DEFAULT]") so that we - // preserve the default location used by the legacy Firebase SDK. - NSString *sessionIdentifier = @"default"; - if (![FIRApp isDefaultAppConfigured] || app != [FIRApp defaultApp]) { - sessionIdentifier = app.name; - } - - FIRDatabaseConfig *config = - [[FIRDatabaseConfig alloc] initWithSessionIdentifier:sessionIdentifier - authTokenProvider:authTokenProvider]; - database = [[FIRDatabase alloc] initWithApp:app - repoInfo:parsedUrl.repoInfo - config:config]; - instances[urlIndex] = database; + if (app == nil) { + [NSException raise:@"InvalidFIRApp" + format:@"nil FIRApp instance passed to databaseForApp."]; } - return database; - } + if (url == nil) { + [NSException raise:@"MissingDatabaseURL" + format:@"Failed to get FirebaseDatabase instance: " + "Specify DatabaseURL within FIRApp or from your " + "databaseForApp:URL: call."]; + } + + NSURL *databaseUrl = [NSURL URLWithString:url]; + + if (databaseUrl == nil) { + [NSException raise:@"InvalidDatabaseURL" + format:@"The Database URL '%@' cannot be parsed. " + "Specify a valid DatabaseURL within FIRApp or from " + "your databaseForApp:URL: call.", + databaseUrl]; + } else if (![databaseUrl.path isEqualToString:@""] && + ![databaseUrl.path isEqualToString:@"/"]) { + [NSException + raise:@"InvalidDatabaseURL" + format:@"Configured Database URL '%@' is invalid. It should point " + "to the root of a Firebase Database but it includes a " + "path: %@", + databaseUrl, databaseUrl.path]; + } + + FIRDatabaseDictionary *instances = [self instances]; + @synchronized(instances) { + FParsedUrl *parsedUrl = + [FUtilities parseUrl:databaseUrl.absoluteString]; + NSString *urlIndex = + [NSString stringWithFormat:@"%@:%@", parsedUrl.repoInfo.host, + [parsedUrl.path toString]]; + FIRDatabase *database = instances[urlIndex]; + if (!database) { + id authTokenProvider = [FAuthTokenProvider + authTokenProviderWithAuth:FIR_COMPONENT(FIRAuthInterop, + app.container)]; + + // If this is the default app, don't set the session persistence key + // so that we use our default ("default") instead of the FIRApp + // default ("[DEFAULT]") so that we preserve the default location + // used by the legacy Firebase SDK. + NSString *sessionIdentifier = @"default"; + if (![FIRApp isDefaultAppConfigured] || + app != [FIRApp defaultApp]) { + sessionIdentifier = app.name; + } + + FIRDatabaseConfig *config = [[FIRDatabaseConfig alloc] + initWithSessionIdentifier:sessionIdentifier + authTokenProvider:authTokenProvider]; + database = [[FIRDatabase alloc] initWithApp:app + repoInfo:parsedUrl.repoInfo + config:config]; + instances[urlIndex] = database; + } + + return database; + } } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseConfig.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseConfig.h index d41f3a8..85399f9 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseConfig.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseConfig.h @@ -25,38 +25,45 @@ NS_ASSUME_NONNULL_BEGIN */ @interface FIRDatabaseConfig : NSObject -- (id)initWithSessionIdentifier:(NSString *)identifier authTokenProvider:(id)authTokenProvider; +- (id)initWithSessionIdentifier:(NSString *)identifier + authTokenProvider:(id)authTokenProvider; /** - * By default the Firebase Database client will keep data in memory while your application is running, but not - * when it is restarted. By setting this value to YES, the data will be persisted to on-device (disk) - * storage and will thus be available again when the app is restarted (even when there is no network - * connectivity at that time). Note that this property must be set before creating your first FIRDatabaseReference - * and only needs to be called once per application. + * By default the Firebase Database client will keep data in memory while your + * application is running, but not when it is restarted. By setting this value + * to YES, the data will be persisted to on-device (disk) storage and will thus + * be available again when the app is restarted (even when there is no network + * connectivity at that time). Note that this property must be set before + * creating your first FIRDatabaseReference and only needs to be called once per + * application. * - * If your app uses Firebase Authentication, the client will automatically persist the user's authentication - * token across restarts, even without persistence enabled. But if the auth token expired while offline and - * you've enabled persistence, the client will pause write operations until you successfully re-authenticate - * (or explicitly unauthenticate) to prevent your writes from being sent unauthenticated and failing due to - * security rules. + * If your app uses Firebase Authentication, the client will automatically + * persist the user's authentication token across restarts, even without + * persistence enabled. But if the auth token expired while offline and you've + * enabled persistence, the client will pause write operations until you + * successfully re-authenticate (or explicitly unauthenticate) to prevent your + * writes from being sent unauthenticated and failing due to security rules. */ -@property (nonatomic) BOOL persistenceEnabled; +@property(nonatomic) BOOL persistenceEnabled; /** - * By default the Firebase Database client will use up to 10MB of disk space to cache data. If the cache grows beyond this size, - * the client will start removing data that hasn't been recently used. If you find that your application caches too - * little or too much data, call this method to change the cache size. This property must be set before creating - * your first FIRDatabaseReference and only needs to be called once per application. + * By default the Firebase Database client will use up to 10MB of disk space to + * cache data. If the cache grows beyond this size, the client will start + * removing data that hasn't been recently used. If you find that your + * application caches too little or too much data, call this method to change + * the cache size. This property must be set before creating your first + * FIRDatabaseReference and only needs to be called once per application. * - * Note that the specified cache size is only an approximation and the size on disk may temporarily exceed it - * at times. + * Note that the specified cache size is only an approximation and the size on + * disk may temporarily exceed it at times. */ -@property (nonatomic) NSUInteger persistenceCacheSizeBytes; +@property(nonatomic) NSUInteger persistenceCacheSizeBytes; /** - * Sets the dispatch queue on which all events are raised. The default queue is the main queue. + * Sets the dispatch queue on which all events are raised. The default queue is + * the main queue. */ -@property (nonatomic, strong) dispatch_queue_t callbackQueue; +@property(nonatomic, strong) dispatch_queue_t callbackQueue; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseConfig.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseConfig.m index a49d4a0..9e9f8b5 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseConfig.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseConfig.m @@ -22,23 +22,26 @@ @interface FIRDatabaseConfig (Private) -@property (nonatomic, strong, readwrite) NSString *sessionIdentifier; +@property(nonatomic, strong, readwrite) NSString *sessionIdentifier; @end @implementation FIRDatabaseConfig - (id)init { - [NSException raise:NSInvalidArgumentException format:@"Can't create config objects!"]; + [NSException raise:NSInvalidArgumentException + format:@"Can't create config objects!"]; return nil; } -- (id)initWithSessionIdentifier:(NSString *)identifier authTokenProvider:(id)authTokenProvider { +- (id)initWithSessionIdentifier:(NSString *)identifier + authTokenProvider:(id)authTokenProvider { self = [super init]; if (self != nil) { self->_sessionIdentifier = identifier; self->_callbackQueue = dispatch_get_main_queue(); - self->_persistenceCacheSizeBytes = 10*1024*1024; // Default cache size is 10MB + self->_persistenceCacheSizeBytes = + 10 * 1024 * 1024; // Default cache size is 10MB self->_authTokenProvider = authTokenProvider; } return self; @@ -46,7 +49,9 @@ - (id)initWithSessionIdentifier:(NSString *)identifier authTokenProvider:(id 100*1024*1024) { - [NSException raise:NSInvalidArgumentException format:@"Firebase Database currently doesn't support a cache size larger than 100MB"]; + if (persistenceCacheSizeBytes > 100 * 1024 * 1024) { + [NSException raise:NSInvalidArgumentException + format:@"Firebase Database currently doesn't support a " + @"cache size larger than 100MB"]; } self->_persistenceCacheSizeBytes = persistenceCacheSizeBytes; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseQuery.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseQuery.m index de18a7c..cd62979 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseQuery.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRDatabaseQuery.m @@ -15,20 +15,20 @@ */ #import "FIRDatabaseQuery.h" -#import "FIRDatabaseQuery_Private.h" -#import "FValidation.h" -#import "FQueryParams.h" -#import "FQuerySpec.h" -#import "FValueEventRegistration.h" #import "FChildEventRegistration.h" -#import "FPath.h" +#import "FConstants.h" +#import "FIRDatabaseQuery_Private.h" #import "FKeyIndex.h" +#import "FLeafNode.h" +#import "FPath.h" #import "FPathIndex.h" #import "FPriorityIndex.h" -#import "FValueIndex.h" -#import "FLeafNode.h" +#import "FQueryParams.h" +#import "FQuerySpec.h" #import "FSnapshotUtilities.h" -#import "FConstants.h" +#import "FValidation.h" +#import "FValueEventRegistration.h" +#import "FValueIndex.h" @implementation FIRDatabaseQuery @@ -38,29 +38,32 @@ @implementation FIRDatabaseQuery #define INVALID_QUERY_PARAM_ERROR @"InvalidQueryParameter" - -+ (dispatch_queue_t)sharedQueue -{ - // We use this shared queue across all of the FQueries so things happen FIFO (as opposed to dispatch_get_global_queue(0, 0) which is concurrent) ++ (dispatch_queue_t)sharedQueue { + // We use this shared queue across all of the FQueries so things happen FIFO + // (as opposed to dispatch_get_global_queue(0, 0) which is concurrent) static dispatch_once_t pred; static dispatch_queue_t sharedDispatchQueue; dispatch_once(&pred, ^{ - sharedDispatchQueue = dispatch_queue_create("FirebaseWorker", NULL); + sharedDispatchQueue = dispatch_queue_create("FirebaseWorker", NULL); }); return sharedDispatchQueue; } -- (id) initWithRepo:(FRepo *)theRepo path:(FPath *)thePath { - return [self initWithRepo:theRepo path:thePath params:nil orderByCalled:NO priorityMethodCalled:NO]; +- (id)initWithRepo:(FRepo *)theRepo path:(FPath *)thePath { + return [self initWithRepo:theRepo + path:thePath + params:nil + orderByCalled:NO + priorityMethodCalled:NO]; } -- (id) initWithRepo:(FRepo *)theRepo - path:(FPath *)thePath - params:(FQueryParams *)theParams - orderByCalled:(BOOL)orderByCalled -priorityMethodCalled:(BOOL)priorityMethodCalled { +- (id)initWithRepo:(FRepo *)theRepo + path:(FPath *)thePath + params:(FQueryParams *)theParams + orderByCalled:(BOOL)orderByCalled + priorityMethodCalled:(BOOL)priorityMethodCalled { self = [super init]; if (self) { self.repo = theRepo; @@ -69,7 +72,10 @@ - (id) initWithRepo:(FRepo *)theRepo theParams = [FQueryParams defaultInstance]; } if (![theParams isValid]) { - @throw [[NSException alloc] initWithName:@"InvalidArgumentError" reason:@"Queries are limited to two constraints" userInfo:nil]; + @throw [[NSException alloc] + initWithName:@"InvalidArgumentError" + reason:@"Queries are limited to two constraints" + userInfo:nil]; } self.queryParams = theParams; self.orderByCalled = orderByCalled; @@ -86,61 +92,96 @@ - (void)validateQueryEndpointsForParams:(FQueryParams *)params { if ([params.index isEqual:[FKeyIndex keyIndex]]) { if ([params hasStart]) { if (params.indexStartKey != [FUtilities minName]) { - [NSException raise:INVALID_QUERY_PARAM_ERROR format:@"Can't use queryStartingAtValue:childKey: or queryEqualTo:andChildKey: in combination with queryOrderedByKey"]; + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't use queryStartingAtValue:childKey: " + @"or queryEqualTo:andChildKey: in " + @"combination with queryOrderedByKey"]; } if (![params.indexStartValue.val isKindOfClass:[NSString class]]) { - [NSException raise:INVALID_QUERY_PARAM_ERROR format:@"Can't use queryStartingAtValue: with other types than string in combination with queryOrderedByKey"]; + [NSException + raise:INVALID_QUERY_PARAM_ERROR + format: + @"Can't use queryStartingAtValue: with other types " + @"than string in combination with queryOrderedByKey"]; } } if ([params hasEnd]) { if (params.indexEndKey != [FUtilities maxName]) { - [NSException raise:INVALID_QUERY_PARAM_ERROR format:@"Can't use queryEndingAtValue:childKey: or queryEqualToValue:childKey: in combination with queryOrderedByKey"]; + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't use queryEndingAtValue:childKey: or " + @"queryEqualToValue:childKey: in " + @"combination with queryOrderedByKey"]; } if (![params.indexEndValue.val isKindOfClass:[NSString class]]) { - [NSException raise:INVALID_QUERY_PARAM_ERROR format:@"Can't use queryEndingAtValue: with other types than string in combination with queryOrderedByKey"]; + [NSException + raise:INVALID_QUERY_PARAM_ERROR + format: + @"Can't use queryEndingAtValue: with other types than " + @"string in combination with queryOrderedByKey"]; } } } else if ([params.index isEqual:[FPriorityIndex priorityIndex]]) { - if (([params hasStart] && ![FValidation validatePriorityValue:params.indexStartValue.val]) || - ([params hasEnd] && ![FValidation validatePriorityValue:params.indexEndValue.val])) { - [NSException raise:INVALID_QUERY_PARAM_ERROR format:@"When using queryOrderedByPriority, values provided to queryStartingAtValue:, queryEndingAtValue:, or queryEqualToValue: must be valid priorities."]; + if (([params hasStart] && + ![FValidation validatePriorityValue:params.indexStartValue.val]) || + ([params hasEnd] && + ![FValidation validatePriorityValue:params.indexEndValue.val])) { + [NSException + raise:INVALID_QUERY_PARAM_ERROR + format:@"When using queryOrderedByPriority, values provided to " + @"queryStartingAtValue:, queryEndingAtValue:, or " + @"queryEqualToValue: must be valid priorities."]; } } } - (void)validateEqualToCall { if ([self.queryParams hasStart]) { - [NSException raise:INVALID_QUERY_PARAM_ERROR format:@"Cannot combine queryEqualToValue: and queryStartingAtValue:"]; + [NSException + raise:INVALID_QUERY_PARAM_ERROR + format: + @"Cannot combine queryEqualToValue: and queryStartingAtValue:"]; } if ([self.queryParams hasEnd]) { - [NSException raise:INVALID_QUERY_PARAM_ERROR format:@"Cannot combine queryEqualToValue: and queryEndingAtValue:"]; + [NSException + raise:INVALID_QUERY_PARAM_ERROR + format: + @"Cannot combine queryEqualToValue: and queryEndingAtValue:"]; } } - (void)validateNoPreviousOrderByCalled { if (self.orderByCalled) { - [NSException raise:INVALID_QUERY_PARAM_ERROR format:@"Cannot use multiple queryOrderedBy calls!"]; + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Cannot use multiple queryOrderedBy calls!"]; } } - (void)validateIndexValueType:(id)type fromMethod:(NSString *)method { - if (type != nil && - ![type isKindOfClass:[NSNumber class]] && + if (type != nil && ![type isKindOfClass:[NSNumber class]] && ![type isKindOfClass:[NSString class]] && ![type isKindOfClass:[NSNull class]]) { - [NSException raise:INVALID_QUERY_PARAM_ERROR format:@"You can only pass nil, NSString or NSNumber to %@", method]; + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"You can only pass nil, NSString or NSNumber to %@", + method]; } } - (FIRDatabaseQuery *)queryStartingAtValue:(id)startValue { - return [self queryStartingAtInternal:startValue childKey:nil from:@"queryStartingAtValue:" priorityMethod:NO]; + return [self queryStartingAtInternal:startValue + childKey:nil + from:@"queryStartingAtValue:" + priorityMethod:NO]; } -- (FIRDatabaseQuery *)queryStartingAtValue:(id)startValue childKey:(NSString *)childKey { +- (FIRDatabaseQuery *)queryStartingAtValue:(id)startValue + childKey:(NSString *)childKey { if ([self.queryParams.index isEqual:[FKeyIndex keyIndex]]) { - @throw [[NSException alloc] initWithName:INVALID_QUERY_PARAM_ERROR - reason:@"You must use queryStartingAtValue: instead of queryStartingAtValue:childKey: when using queryOrderedByKey:" - userInfo:nil]; + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:@"You must use queryStartingAtValue: instead of " + @"queryStartingAtValue:childKey: when using " + @"queryOrderedByKey:" + userInfo:nil]; } return [self queryStartingAtInternal:startValue childKey:childKey @@ -154,20 +195,24 @@ - (FIRDatabaseQuery *)queryStartingAtInternal:(id)startValue priorityMethod:(BOOL)priorityMethod { [self validateIndexValueType:startValue fromMethod:methodName]; if (childKey != nil) { - [FValidation validateFrom:methodName validKey:childKey]; + [FValidation validateFrom:methodName validKey:childKey]; } if ([self.queryParams hasStart]) { [NSException raise:INVALID_QUERY_PARAM_ERROR - format:@"Can't call %@ after queryStartingAtValue or queryEqualToValue was previously called", methodName]; + format:@"Can't call %@ after queryStartingAtValue or " + @"queryEqualToValue was previously called", + methodName]; } id startNode = [FSnapshotUtilities nodeFrom:startValue]; - FQueryParams* params = [self.queryParams startAt:startNode childKey:childKey]; + FQueryParams *params = [self.queryParams startAt:startNode + childKey:childKey]; [self validateQueryEndpointsForParams:params]; - return [[FIRDatabaseQuery alloc] initWithRepo:self.repo - path:self.path - params:params - orderByCalled:self.orderByCalled - priorityMethodCalled:priorityMethod || self.priorityMethodCalled]; + return [[FIRDatabaseQuery alloc] + initWithRepo:self.repo + path:self.path + params:params + orderByCalled:self.orderByCalled + priorityMethodCalled:priorityMethod || self.priorityMethodCalled]; } - (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue { @@ -177,15 +222,19 @@ - (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue { priorityMethod:NO]; } -- (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue childKey:(NSString *)childKey { +- (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue + childKey:(NSString *)childKey { if ([self.queryParams.index isEqual:[FKeyIndex keyIndex]]) { - @throw [[NSException alloc] initWithName:INVALID_QUERY_PARAM_ERROR - reason:@"You must use queryEndingAtValue: instead of queryEndingAtValue:childKey: when using queryOrderedByKey:" - userInfo:nil]; + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:@"You must use queryEndingAtValue: instead of " + @"queryEndingAtValue:childKey: when using " + @"queryOrderedByKey:" + userInfo:nil]; } return [self queryEndingAtInternal:endValue - childKey:childKey + childKey:childKey from:@"queryEndingAtValue:childKey:" priorityMethod:NO]; } @@ -200,29 +249,41 @@ - (FIRDatabaseQuery *)queryEndingAtInternal:(id)endValue } if ([self.queryParams hasEnd]) { [NSException raise:INVALID_QUERY_PARAM_ERROR - format:@"Can't call %@ after queryEndingAtValue or queryEqualToValue was previously called", methodName]; + format:@"Can't call %@ after queryEndingAtValue or " + @"queryEqualToValue was previously called", + methodName]; } id endNode = [FSnapshotUtilities nodeFrom:endValue]; - FQueryParams* params = [self.queryParams endAt:endNode childKey:childKey]; + FQueryParams *params = [self.queryParams endAt:endNode childKey:childKey]; [self validateQueryEndpointsForParams:params]; - return [[FIRDatabaseQuery alloc] initWithRepo:self.repo - path:self.path - params:params - orderByCalled:self.orderByCalled - priorityMethodCalled:priorityMethod || self.priorityMethodCalled]; + return [[FIRDatabaseQuery alloc] + initWithRepo:self.repo + path:self.path + params:params + orderByCalled:self.orderByCalled + priorityMethodCalled:priorityMethod || self.priorityMethodCalled]; } - (FIRDatabaseQuery *)queryEqualToValue:(id)value { - return [self queryEqualToInternal:value childKey:nil from:@"queryEqualToValue:" priorityMethod:NO]; + return [self queryEqualToInternal:value + childKey:nil + from:@"queryEqualToValue:" + priorityMethod:NO]; } -- (FIRDatabaseQuery *)queryEqualToValue:(id)value childKey:(NSString *)childKey { +- (FIRDatabaseQuery *)queryEqualToValue:(id)value + childKey:(NSString *)childKey { if ([self.queryParams.index isEqual:[FKeyIndex keyIndex]]) { - @throw [[NSException alloc] initWithName:INVALID_QUERY_PARAM_ERROR - reason:@"You must use queryEqualToValue: instead of queryEqualTo:childKey: when using queryOrderedByKey:" - userInfo:nil]; + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:@"You must use queryEqualToValue: instead of " + @"queryEqualTo:childKey: when using queryOrderedByKey:" + userInfo:nil]; } - return [self queryEqualToInternal:value childKey:childKey from:@"queryEqualToValue:childKey:" priorityMethod:NO]; + return [self queryEqualToInternal:value + childKey:childKey + from:@"queryEqualToValue:childKey:" + priorityMethod:NO]; } - (FIRDatabaseQuery *)queryEqualToInternal:(id)value @@ -234,36 +295,46 @@ - (FIRDatabaseQuery *)queryEqualToInternal:(id)value [FValidation validateFrom:methodName validKey:childKey]; } if ([self.queryParams hasEnd] || [self.queryParams hasStart]) { - [NSException raise:INVALID_QUERY_PARAM_ERROR - format:@"Can't call %@ after queryStartingAtValue, queryEndingAtValue or queryEqualToValue was previously called", methodName]; + [NSException + raise:INVALID_QUERY_PARAM_ERROR + format: + @"Can't call %@ after queryStartingAtValue, queryEndingAtValue " + @"or queryEqualToValue was previously called", + methodName]; } id node = [FSnapshotUtilities nodeFrom:value]; - FQueryParams* params = [[self.queryParams startAt:node childKey:childKey] endAt:node childKey:childKey]; + FQueryParams *params = [[self.queryParams startAt:node + childKey:childKey] endAt:node + childKey:childKey]; [self validateQueryEndpointsForParams:params]; - return [[FIRDatabaseQuery alloc] initWithRepo:self.repo - path:self.path - params:params - orderByCalled:self.orderByCalled - priorityMethodCalled:priorityMethod || self.priorityMethodCalled]; + return [[FIRDatabaseQuery alloc] + initWithRepo:self.repo + path:self.path + params:params + orderByCalled:self.orderByCalled + priorityMethodCalled:priorityMethod || self.priorityMethodCalled]; } -- (void)validateLimitRange:(NSUInteger)limit -{ +- (void)validateLimitRange:(NSUInteger)limit { // No need to check for negative ranges, since limit is unsigned if (limit == 0) { - [NSException raise:INVALID_QUERY_PARAM_ERROR format:@"Limit can't be zero"]; + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Limit can't be zero"]; } - if (limit >= 1ul<<31) { - [NSException raise:INVALID_QUERY_PARAM_ERROR format:@"Limit must be less than 2,147,483,648"]; + if (limit >= 1ul << 31) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Limit must be less than 2,147,483,648"]; } } - (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit { if (self.queryParams.limitSet) { - [NSException raise:INVALID_QUERY_PARAM_ERROR format:@"Can't call queryLimitedToFirst: if a limit was previously set"]; + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't call queryLimitedToFirst: if a limit was " + @"previously set"]; } [self validateLimitRange:limit]; - FQueryParams* params = [self.queryParams limitToFirst:limit]; + FQueryParams *params = [self.queryParams limitToFirst:limit]; return [[FIRDatabaseQuery alloc] initWithRepo:self.repo path:self.path params:params @@ -273,10 +344,12 @@ - (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit { - (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit { if (self.queryParams.limitSet) { - [NSException raise:INVALID_QUERY_PARAM_ERROR format:@"Can't call queryLimitedToLast: if a limit was previously set"]; + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't call queryLimitedToLast: if a limit was " + @"previously set"]; } [self validateLimitRange:limit]; - FQueryParams* params = [self.queryParams limitToLast:limit]; + FQueryParams *params = [self.queryParams limitToLast:limit]; return [[FIRDatabaseQuery alloc] initWithRepo:self.repo path:self.path params:params @@ -285,27 +358,47 @@ - (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit { } - (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)indexPathString { - if ([indexPathString isEqualToString:@"$key"] || [indexPathString isEqualToString:@".key"]) { - @throw [[NSException alloc] initWithName:INVALID_QUERY_PARAM_ERROR - reason:[NSString stringWithFormat:@"(queryOrderedByChild:) %@ is invalid. Use queryOrderedByKey: instead.", indexPathString] - userInfo:nil]; - } else if ([indexPathString isEqualToString:@"$priority"] || [indexPathString isEqualToString:@".priority"]) { - @throw [[NSException alloc] initWithName:INVALID_QUERY_PARAM_ERROR - reason:[NSString stringWithFormat:@"(queryOrderedByChild:) %@ is invalid. Use queryOrderedByPriority: instead.", indexPathString] - userInfo:nil]; - } else if ([indexPathString isEqualToString:@"$value"] || [indexPathString isEqualToString:@".value"]) { - @throw [[NSException alloc] initWithName:INVALID_QUERY_PARAM_ERROR - reason:[NSString stringWithFormat:@"(queryOrderedByChild:) %@ is invalid. Use queryOrderedByValue: instead.", indexPathString] - userInfo:nil]; + if ([indexPathString isEqualToString:@"$key"] || + [indexPathString isEqualToString:@".key"]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:[NSString stringWithFormat: + @"(queryOrderedByChild:) %@ is invalid. " + @" Use queryOrderedByKey: instead.", + indexPathString] + userInfo:nil]; + } else if ([indexPathString isEqualToString:@"$priority"] || + [indexPathString isEqualToString:@".priority"]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:[NSString stringWithFormat: + @"(queryOrderedByChild:) %@ is invalid. " + @" Use queryOrderedByPriority: instead.", + indexPathString] + userInfo:nil]; + } else if ([indexPathString isEqualToString:@"$value"] || + [indexPathString isEqualToString:@".value"]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:[NSString stringWithFormat: + @"(queryOrderedByChild:) %@ is invalid. " + @" Use queryOrderedByValue: instead.", + indexPathString] + userInfo:nil]; } [self validateNoPreviousOrderByCalled]; - [FValidation validateFrom:@"queryOrderedByChild:" validPathString:indexPathString]; + [FValidation validateFrom:@"queryOrderedByChild:" + validPathString:indexPathString]; FPath *indexPath = [FPath pathWithString:indexPathString]; if (indexPath.isEmpty) { - @throw [[NSException alloc] initWithName:INVALID_QUERY_PARAM_ERROR - reason:[NSString stringWithFormat:@"(queryOrderedByChild:) with an empty path is invalid. Use queryOrderedByValue: instead."] - userInfo:nil]; + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:[NSString + stringWithFormat:@"(queryOrderedByChild:) with an " + @"empty path is invalid. Use " + @"queryOrderedByValue: instead."] + userInfo:nil]; } id index = [[FPathIndex alloc] initWithPath:indexPath]; @@ -318,7 +411,7 @@ - (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)indexPathString { priorityMethodCalled:self.priorityMethodCalled]; } -- (FIRDatabaseQuery *) queryOrderedByKey { +- (FIRDatabaseQuery *)queryOrderedByKey { [self validateNoPreviousOrderByCalled]; FQueryParams *params = [self.queryParams orderBy:[FKeyIndex keyIndex]]; [self validateQueryEndpointsForParams:params]; @@ -329,7 +422,7 @@ - (FIRDatabaseQuery *) queryOrderedByKey { priorityMethodCalled:self.priorityMethodCalled]; } -- (FIRDatabaseQuery *) queryOrderedByValue { +- (FIRDatabaseQuery *)queryOrderedByValue { [self validateNoPreviousOrderByCalled]; FQueryParams *params = [self.queryParams orderBy:[FValueIndex valueIndex]]; return [[FIRDatabaseQuery alloc] initWithRepo:self.repo @@ -339,9 +432,10 @@ - (FIRDatabaseQuery *) queryOrderedByValue { priorityMethodCalled:self.priorityMethodCalled]; } -- (FIRDatabaseQuery *) queryOrderedByPriority { +- (FIRDatabaseQuery *)queryOrderedByPriority { [self validateNoPreviousOrderByCalled]; - FQueryParams *params = [self.queryParams orderBy:[FPriorityIndex priorityIndex]]; + FQueryParams *params = + [self.queryParams orderBy:[FPriorityIndex priorityIndex]]; return [[FIRDatabaseQuery alloc] initWithRepo:self.repo path:self.path params:params @@ -349,176 +443,234 @@ - (FIRDatabaseQuery *) queryOrderedByPriority { priorityMethodCalled:self.priorityMethodCalled]; } -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *))block { - [FValidation validateFrom:@"observeEventType:withBlock:" knownEventType:eventType]; - return [self observeEventType:eventType withBlock:block withCancelBlock:nil]; +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *))block { + [FValidation validateFrom:@"observeEventType:withBlock:" + knownEventType:eventType]; + return [self observeEventType:eventType + withBlock:block + withCancelBlock:nil]; } - -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { - [FValidation validateFrom:@"observeEventType:andPreviousSiblingKeyWithBlock:" knownEventType:eventType]; - return [self observeEventType:eventType andPreviousSiblingKeyWithBlock:block withCancelBlock:nil]; +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { + [FValidation + validateFrom:@"observeEventType:andPreviousSiblingKeyWithBlock:" + knownEventType:eventType]; + return [self observeEventType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:nil]; } - -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(fbt_void_datasnapshot)block withCancelBlock:(fbt_void_nserror)cancelBlock { - [FValidation validateFrom:@"observeEventType:withBlock:withCancelBlock:" knownEventType:eventType]; +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + [FValidation validateFrom:@"observeEventType:withBlock:withCancelBlock:" + knownEventType:eventType]; if (eventType == FIRDataEventTypeValue) { - // Handle FIRDataEventTypeValue specially because they shouldn't have prevName callbacks + // Handle FIRDataEventTypeValue specially because they shouldn't have + // prevName callbacks NSUInteger handle = [[FUtilities LUIDGenerator] integerValue]; - [self observeValueEventWithHandle:handle withBlock:block cancelCallback:cancelBlock]; + [self observeValueEventWithHandle:handle + withBlock:block + cancelCallback:cancelBlock]; return handle; } else { - // Wrap up the userCallback so we can treat everything as a callback that has a prevName + // Wrap up the userCallback so we can treat everything as a callback + // that has a prevName fbt_void_datasnapshot userCallback = [block copy]; - return [self observeEventType:eventType andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *prevName) { - if (userCallback != nil) { - userCallback(snapshot); + return [self observeEventType:eventType + andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, + NSString *prevName) { + if (userCallback != nil) { + userCallback(snapshot); + } } - } withCancelBlock:cancelBlock]; + withCancelBlock:cancelBlock]; } } -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block withCancelBlock:(fbt_void_nserror)cancelBlock { - [FValidation validateFrom:@"observeEventType:andPreviousSiblingKeyWithBlock:withCancelBlock:" knownEventType:eventType]; - +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + [FValidation validateFrom:@"observeEventType:" + @"andPreviousSiblingKeyWithBlock:withCancelBlock:" + knownEventType:eventType]; if (eventType == FIRDataEventTypeValue) { // TODO: This gets hit by observeSingleEventOfType. Need to fix. /* @throw [[NSException alloc] initWithName:@"InvalidEventTypeForObserver" - reason:@"(observeEventType:andPreviousSiblingKeyWithBlock:withCancelBlock:) Cannot use observeEventType:andPreviousSiblingKeyWithBlock:withCancelBlock: with FIRDataEventTypeValue. Use observeEventType:withBlock:withCancelBlock: instead." - userInfo:nil]; + reason:@"(observeEventType:andPreviousSiblingKeyWithBlock:withCancelBlock:) + Cannot use + observeEventType:andPreviousSiblingKeyWithBlock:withCancelBlock: with + FIRDataEventTypeValue. Use observeEventType:withBlock:withCancelBlock: + instead." userInfo:nil]; */ } NSUInteger handle = [[FUtilities LUIDGenerator] integerValue]; - NSDictionary *callbacks = @{[NSNumber numberWithInteger:eventType]: [block copy]}; - [self observeChildEventWithHandle:handle withCallbacks:callbacks cancelCallback:cancelBlock]; + NSDictionary *callbacks = + @{[NSNumber numberWithInteger:eventType] : [block copy]}; + [self observeChildEventWithHandle:handle + withCallbacks:callbacks + cancelCallback:cancelBlock]; return handle; } -// If we want to distinguish between value event listeners and child event listeners, like in the Java client, we can -// consider exporting this. If we do, add argument validation. Otherwise, arguments are validated in the public-facing -// portions of the API. Also, move the FIRDatabaseHandle logic. -- (void)observeValueEventWithHandle:(FIRDatabaseHandle)handle withBlock:(fbt_void_datasnapshot)block cancelCallback:(fbt_void_nserror)cancelBlock { - // Note that we don't need to copy the callbacks here, FEventRegistration callback properties set to copy - FValueEventRegistration *registration = [[FValueEventRegistration alloc] initWithRepo:self.repo - handle:handle - callback:block - cancelCallback:cancelBlock]; +// If we want to distinguish between value event listeners and child event +// listeners, like in the Java client, we can consider exporting this. If we do, +// add argument validation. Otherwise, arguments are validated in the +// public-facing portions of the API. Also, move the FIRDatabaseHandle logic. +- (void)observeValueEventWithHandle:(FIRDatabaseHandle)handle + withBlock:(fbt_void_datasnapshot)block + cancelCallback:(fbt_void_nserror)cancelBlock { + // Note that we don't need to copy the callbacks here, FEventRegistration + // callback properties set to copy + FValueEventRegistration *registration = + [[FValueEventRegistration alloc] initWithRepo:self.repo + handle:handle + callback:block + cancelCallback:cancelBlock]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo addEventRegistration:registration forQuery:self.querySpec]; + [self.repo addEventRegistration:registration forQuery:self.querySpec]; }); } // Note: as with the above method, we may wish to expose this at some point. -- (void)observeChildEventWithHandle:(FIRDatabaseHandle)handle withCallbacks:(NSDictionary *)callbacks cancelCallback:(fbt_void_nserror)cancelBlock { - // Note that we don't need to copy the callbacks here, FEventRegistration callback properties set to copy - FChildEventRegistration *registration = [[FChildEventRegistration alloc] initWithRepo:self.repo - handle:handle - callbacks:callbacks - cancelCallback:cancelBlock]; +- (void)observeChildEventWithHandle:(FIRDatabaseHandle)handle + withCallbacks:(NSDictionary *)callbacks + cancelCallback:(fbt_void_nserror)cancelBlock { + // Note that we don't need to copy the callbacks here, FEventRegistration + // callback properties set to copy + FChildEventRegistration *registration = + [[FChildEventRegistration alloc] initWithRepo:self.repo + handle:handle + callbacks:callbacks + cancelCallback:cancelBlock]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo addEventRegistration:registration forQuery:self.querySpec]; + [self.repo addEventRegistration:registration forQuery:self.querySpec]; }); } - -- (void) removeObserverWithHandle:(FIRDatabaseHandle)handle { - FValueEventRegistration *event = [[FValueEventRegistration alloc] initWithRepo:self.repo - handle:handle - callback:nil - cancelCallback:nil]; +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle { + FValueEventRegistration *event = + [[FValueEventRegistration alloc] initWithRepo:self.repo + handle:handle + callback:nil + cancelCallback:nil]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo removeEventRegistration:event forQuery:self.querySpec]; + [self.repo removeEventRegistration:event forQuery:self.querySpec]; }); } - -- (void) removeAllObservers { +- (void)removeAllObservers { [self removeObserverWithHandle:NSNotFound]; } - (void)keepSynced:(BOOL)keepSynced { if ([self.path.getFront isEqualToString:kDotInfoPrefix]) { - [NSException raise:NSInvalidArgumentException format:@"Can't keep query on .info tree synced (this already is the case)."]; + [NSException raise:NSInvalidArgumentException + format:@"Can't keep query on .info tree synced (this " + @"already is the case)."]; } dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo keepQuery:self.querySpec synced:keepSynced]; + [self.repo keepQuery:self.querySpec synced:keepSynced]; }); } -- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(fbt_void_datasnapshot)block { +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block { - [self observeSingleEventOfType:eventType withBlock:block withCancelBlock:nil]; + [self observeSingleEventOfType:eventType + withBlock:block + withCancelBlock:nil]; } +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { -- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { - - [self observeSingleEventOfType:eventType andPreviousSiblingKeyWithBlock:block withCancelBlock:nil]; + [self observeSingleEventOfType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:nil]; } - -- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(fbt_void_datasnapshot)block withCancelBlock:(fbt_void_nserror)cancelBlock { +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block + withCancelBlock:(fbt_void_nserror)cancelBlock { // XXX: user reported memory leak in method - // "When you copy a block, any references to other blocks from within that block are copied if necessary—an entire tree may be copied (from the top). If you have block variables and you reference a block from within the block, that block will be copied." + // "When you copy a block, any references to other blocks from within that + // block are copied if necessary—an entire tree may be copied (from the + // top). If you have block variables and you reference a block from within + // the block, that block will be copied." // http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW1 - // So... we don't need to do this since inside the on: we copy this block off the stack to the heap. + // So... we don't need to do this since inside the on: we copy this block + // off the stack to the heap. // __block fbt_void_datasnapshot userCallback = [callback copy]; - [self observeSingleEventOfType:eventType andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *prevName) { - if (block != nil) { - block(snapshot); + [self observeSingleEventOfType:eventType + andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, + NSString *prevName) { + if (block != nil) { + block(snapshot); + } } - } withCancelBlock:cancelBlock]; + withCancelBlock:cancelBlock]; } /** -* Attaches a listener, waits for the first event, and then removes the listener -*/ -- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block withCancelBlock:(fbt_void_nserror)cancelBlock { + * Attaches a listener, waits for the first event, and then removes the listener + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block + withCancelBlock:(fbt_void_nserror)cancelBlock { // XXX: user reported memory leak in method - // "When you copy a block, any references to other blocks from within that block are copied if necessary—an entire tree may be copied (from the top). If you have block variables and you reference a block from within the block, that block will be copied." + // "When you copy a block, any references to other blocks from within that + // block are copied if necessary—an entire tree may be copied (from the + // top). If you have block variables and you reference a block from within + // the block, that block will be copied." // http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW1 - // So... we don't need to do this since inside the on: we copy this block off the stack to the heap. + // So... we don't need to do this since inside the on: we copy this block + // off the stack to the heap. // __block fbt_void_datasnapshot userCallback = [callback copy]; __block FIRDatabaseHandle handle; __block BOOL firstCall = YES; fbt_void_datasnapshot_nsstring callback = [block copy]; - fbt_void_datasnapshot_nsstring wrappedCallback = ^(FIRDataSnapshot *snap, NSString* prevName) { - if (firstCall) { - firstCall = NO; - [self removeObserverWithHandle:handle]; - callback(snap, prevName); - } - }; + fbt_void_datasnapshot_nsstring wrappedCallback = + ^(FIRDataSnapshot *snap, NSString *prevName) { + if (firstCall) { + firstCall = NO; + [self removeObserverWithHandle:handle]; + callback(snap, prevName); + } + }; fbt_void_nserror cancelCallback = [cancelBlock copy]; - handle = [self observeEventType:eventType andPreviousSiblingKeyWithBlock:wrappedCallback withCancelBlock:^(NSError* error){ - - [self removeObserverWithHandle:handle]; + handle = [self observeEventType:eventType + andPreviousSiblingKeyWithBlock:wrappedCallback + withCancelBlock:^(NSError *error) { + [self removeObserverWithHandle:handle]; - if (cancelCallback) { - cancelCallback(error); - } - }]; + if (cancelCallback) { + cancelCallback(error); + } + }]; } -- (NSString *) description { - return [NSString stringWithFormat:@"(%@ %@)", self.path, self.queryParams.description]; +- (NSString *)description { + return [NSString + stringWithFormat:@"(%@ %@)", self.path, self.queryParams.description]; } -- (FIRDatabaseReference *) ref { +- (FIRDatabaseReference *)ref { return [[FIRDatabaseReference alloc] initWithRepo:self.repo path:self.path]; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRMutableData.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRMutableData.m index 77a022a..5da7fae 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRMutableData.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRMutableData.m @@ -15,20 +15,21 @@ */ #import "FIRMutableData.h" +#import "FChildrenNode.h" #import "FIRMutableData_Private.h" +#import "FIndexedNode.h" +#import "FNamedNode.h" #import "FSnapshotHolder.h" #import "FSnapshotUtilities.h" -#import "FChildrenNode.h" #import "FTransformedEnumerator.h" -#import "FNamedNode.h" -#import "FIndexedNode.h" @interface FIRMutableData () -- (id) initWithPrefixPath:(FPath *)path andSnapshotHolder:(FSnapshotHolder *)snapshotHolder; +- (id)initWithPrefixPath:(FPath *)path + andSnapshotHolder:(FSnapshotHolder *)snapshotHolder; -@property (strong, nonatomic) FSnapshotHolder* data; -@property (strong, nonatomic) FPath* prefixPath; +@property(strong, nonatomic) FSnapshotHolder *data; +@property(strong, nonatomic) FPath *prefixPath; @end @@ -37,14 +38,15 @@ @implementation FIRMutableData @synthesize data; @synthesize prefixPath; -- (id) initWithNode:(id)node { - FSnapshotHolder* holder = [[FSnapshotHolder alloc] init]; - FPath* path = [FPath empty]; +- (id)initWithNode:(id)node { + FSnapshotHolder *holder = [[FSnapshotHolder alloc] init]; + FPath *path = [FPath empty]; [holder updateSnapshot:path withNewSnapshot:node]; return [self initWithPrefixPath:path andSnapshotHolder:holder]; } -- (id) initWithPrefixPath:(FPath *)path andSnapshotHolder:(FSnapshotHolder *)snapshotHolder { +- (id)initWithPrefixPath:(FPath *)path + andSnapshotHolder:(FSnapshotHolder *)snapshotHolder { self = [super init]; if (self) { self.prefixPath = path; @@ -54,80 +56,93 @@ - (id) initWithPrefixPath:(FPath *)path andSnapshotHolder:(FSnapshotHolder *)sna } - (FIRMutableData *)childDataByAppendingPath:(NSString *)path { - FPath* wholePath = [self.prefixPath childFromString:path]; - return [[FIRMutableData alloc] initWithPrefixPath:wholePath andSnapshotHolder:self.data]; + FPath *wholePath = [self.prefixPath childFromString:path]; + return [[FIRMutableData alloc] initWithPrefixPath:wholePath + andSnapshotHolder:self.data]; } -- (FIRMutableData *) parent { +- (FIRMutableData *)parent { if ([self.prefixPath isEmpty]) { return nil; } else { - FPath* path = [self.prefixPath parent]; - return [[FIRMutableData alloc] initWithPrefixPath:path andSnapshotHolder:self.data]; + FPath *path = [self.prefixPath parent]; + return [[FIRMutableData alloc] initWithPrefixPath:path + andSnapshotHolder:self.data]; } } -- (void) setValue:(id)aValue { - id node = [FSnapshotUtilities nodeFrom:aValue withValidationFrom:@"setValue:"]; +- (void)setValue:(id)aValue { + id node = [FSnapshotUtilities nodeFrom:aValue + withValidationFrom:@"setValue:"]; [self.data updateSnapshot:self.prefixPath withNewSnapshot:node]; } -- (void) setPriority:(id)aPriority { +- (void)setPriority:(id)aPriority { id node = [self.data getNode:self.prefixPath]; id pri = [FSnapshotUtilities nodeFrom:aPriority]; node = [node updatePriority:pri]; [self.data updateSnapshot:self.prefixPath withNewSnapshot:node]; } -- (id) value { +- (id)value { return [[self.data getNode:self.prefixPath] val]; } -- (id) priority { +- (id)priority { return [[[self.data getNode:self.prefixPath] getPriority] val]; } -- (BOOL) hasChildren { +- (BOOL)hasChildren { id node = [self.data getNode:self.prefixPath]; - return ![node isLeafNode] && ![(FChildrenNode*)node isEmpty]; + return ![node isLeafNode] && ![(FChildrenNode *)node isEmpty]; } -- (BOOL) hasChildAtPath:(NSString *)path { +- (BOOL)hasChildAtPath:(NSString *)path { id node = [self.data getNode:self.prefixPath]; - FPath* childPath = [[FPath alloc] initWith:path]; + FPath *childPath = [[FPath alloc] initWith:path]; return ![[node getChild:childPath] isEmpty]; } -- (NSUInteger) childrenCount { +- (NSUInteger)childrenCount { return [[self.data getNode:self.prefixPath] numChildren]; } -- (NSString *) key { +- (NSString *)key { return [self.prefixPath getBack]; } -- (id) nodeValue { +- (id)nodeValue { return [self.data getNode:self.prefixPath]; } -- (NSEnumerator *) children { - FIndexedNode *indexedNode = [FIndexedNode indexedNodeWithNode:self.nodeValue]; - return [[FTransformedEnumerator alloc] initWithEnumerator:[indexedNode childEnumerator] andTransform:^id(FNamedNode *node) { - FPath* childPath = [self.prefixPath childFromString:node.name]; - FIRMutableData * childData = [[FIRMutableData alloc] initWithPrefixPath:childPath andSnapshotHolder:self.data]; - return childData; - }]; +- (NSEnumerator *)children { + FIndexedNode *indexedNode = + [FIndexedNode indexedNodeWithNode:self.nodeValue]; + return [[FTransformedEnumerator alloc] + initWithEnumerator:[indexedNode childEnumerator] + andTransform:^id(FNamedNode *node) { + FPath *childPath = [self.prefixPath childFromString:node.name]; + FIRMutableData *childData = + [[FIRMutableData alloc] initWithPrefixPath:childPath + andSnapshotHolder:self.data]; + return childData; + }]; } -- (BOOL) isEqualToData:(FIRMutableData *)other { - return self.data == other.data && [[self.prefixPath description] isEqualToString:[other.prefixPath description]]; +- (BOOL)isEqualToData:(FIRMutableData *)other { + return self.data == other.data && + [[self.prefixPath description] + isEqualToString:[other.prefixPath description]]; } -- (NSString *) description { +- (NSString *)description { if (self.key == nil) { - return [NSString stringWithFormat:@"FIRMutableData (top-most transaction) %@ %@", self.key, self.value]; + return [NSString + stringWithFormat:@"FIRMutableData (top-most transaction) %@ %@", + self.key, self.value]; } else { - return [NSString stringWithFormat:@"FIRMutableData (%@) %@", self.key, self.value]; + return [NSString + stringWithFormat:@"FIRMutableData (%@) %@", self.key, self.value]; } } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRServerValue.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRServerValue.m index 14bb745..e5be5c5 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRServerValue.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRServerValue.m @@ -14,15 +14,15 @@ * limitations under the License. */ -#import "FIRDatabaseReference.h" #import "FIRServerValue.h" +#import "FIRDatabaseReference.h" @implementation FIRServerValue -+ (NSDictionary *) timestamp { ++ (NSDictionary *)timestamp { static NSDictionary *timestamp = nil; if (timestamp == nil) { - timestamp = @{ @".sv": @"timestamp" }; + timestamp = @{@".sv" : @"timestamp"}; } return timestamp; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRTransactionResult.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRTransactionResult.m index 8afc5b7..9fec862 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRTransactionResult.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/FIRTransactionResult.m @@ -23,14 +23,14 @@ @implementation FIRTransactionResult @synthesize isSuccess; + (FIRTransactionResult *)successWithValue:(FIRMutableData *)value { - FIRTransactionResult * result = [[FIRTransactionResult alloc] init]; + FIRTransactionResult *result = [[FIRTransactionResult alloc] init]; result.isSuccess = YES; result.update = value; return result; } -+ (FIRTransactionResult *) abort { - FIRTransactionResult * result = [[FIRTransactionResult alloc] init]; ++ (FIRTransactionResult *)abort { + FIRTransactionResult *result = [[FIRTransactionResult alloc] init]; result.isSuccess = NO; result.update = nil; return result; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDataSnapshot_Private.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDataSnapshot_Private.h index c2d3871..ac23045 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDataSnapshot_Private.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDataSnapshot_Private.h @@ -21,7 +21,7 @@ @interface FIRDataSnapshot () // in _Private for testing purposes -@property (nonatomic, strong) FIndexedNode *node; +@property(nonatomic, strong) FIndexedNode *node; - (id)initWithRef:(FIRDatabaseReference *)ref indexedNode:(FIndexedNode *)node; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDatabaseQuery_Private.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDatabaseQuery_Private.h index 3a10fe3..30f19f0 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDatabaseQuery_Private.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDatabaseQuery_Private.h @@ -14,29 +14,29 @@ * limitations under the License. */ -#import "FRepo.h" +#import "FIRDatabaseQuery.h" #import "FPath.h" +#import "FQueryParams.h" +#import "FRepo.h" #import "FRepoManager.h" #import "FTypedefs_Private.h" -#import "FQueryParams.h" -#import "FIRDatabaseQuery.h" @interface FIRDatabaseQuery () + (dispatch_queue_t)sharedQueue; -- (id) initWithRepo:(FRepo *)repo path:(FPath *)path; -- (id) initWithRepo:(FRepo *)repo - path:(FPath *)path - params:(FQueryParams *)params - orderByCalled:(BOOL)orderByCalled -priorityMethodCalled:(BOOL)priorityMethodCalled; +- (id)initWithRepo:(FRepo *)repo path:(FPath *)path; +- (id)initWithRepo:(FRepo *)repo + path:(FPath *)path + params:(FQueryParams *)params + orderByCalled:(BOOL)orderByCalled + priorityMethodCalled:(BOOL)priorityMethodCalled; -@property (nonatomic, strong) FRepo* repo; -@property (nonatomic, strong) FPath* path; -@property (nonatomic, strong) FQueryParams *queryParams; -@property (nonatomic) BOOL orderByCalled; -@property (nonatomic) BOOL priorityMethodCalled; +@property(nonatomic, strong) FRepo *repo; +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) FQueryParams *queryParams; +@property(nonatomic) BOOL orderByCalled; +@property(nonatomic) BOOL priorityMethodCalled; - (FQuerySpec *)querySpec; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDatabaseReference_Private.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDatabaseReference_Private.h index 6063cb8..1d7e37c 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDatabaseReference_Private.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDatabaseReference_Private.h @@ -14,10 +14,10 @@ * limitations under the License. */ -#import "FIRDatabaseReference.h" -#import "FTypedefs_Private.h" #import "FIRDatabaseConfig.h" +#import "FIRDatabaseReference.h" #import "FRepo.h" +#import "FTypedefs_Private.h" @interface FIRDatabaseReference () diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDatabase_Private.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDatabase_Private.h index 5e29451..0ff3e70 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDatabase_Private.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRDatabase_Private.h @@ -22,13 +22,16 @@ @interface FIRDatabase () -@property (nonatomic, strong) FRepoInfo *repoInfo; -@property (nonatomic, strong) FIRDatabaseConfig *config; -@property (nonatomic, strong) FRepo *repo; +@property(nonatomic, strong) FRepoInfo *repoInfo; +@property(nonatomic, strong) FIRDatabaseConfig *config; +@property(nonatomic, strong) FRepo *repo; -- (id)initWithApp:(FIRApp *)app repoInfo:(FRepoInfo *)info config:(FIRDatabaseConfig *)config; +- (id)initWithApp:(FIRApp *)app + repoInfo:(FRepoInfo *)info + config:(FIRDatabaseConfig *)config; -+ (NSString *) buildVersion; -+ (FIRDatabase *) createDatabaseForTests:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config; ++ (NSString *)buildVersion; ++ (FIRDatabase *)createDatabaseForTests:(FRepoInfo *)repoInfo + config:(FIRDatabaseConfig *)config; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRMutableData_Private.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRMutableData_Private.h index ee3aa96..fded102 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRMutableData_Private.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRMutableData_Private.h @@ -19,8 +19,8 @@ @interface FIRMutableData () -- (id) initWithNode:(id)node; -- (id) nodeValue; -- (BOOL) isEqualToData:(FIRMutableData *)other; +- (id)initWithNode:(id)node; +- (id)nodeValue; +- (BOOL)isEqualToData:(FIRMutableData *)other; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRTransactionResult_Private.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRTransactionResult_Private.h index 82290f2..bdf250a 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRTransactionResult_Private.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FIRTransactionResult_Private.h @@ -14,12 +14,12 @@ * limitations under the License. */ -#import "FIRTransactionResult.h" #import "FIRMutableData.h" +#import "FIRTransactionResult.h" @interface FIRTransactionResult () -@property (nonatomic) BOOL isSuccess; -@property (nonatomic, strong) FIRMutableData * update; +@property(nonatomic) BOOL isSuccess; +@property(nonatomic, strong) FIRMutableData *update; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FTypedefs_Private.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FTypedefs_Private.h index 73f4c9a..dac55bc 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FTypedefs_Private.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Api/Private/FTypedefs_Private.h @@ -20,12 +20,12 @@ #import typedef NS_ENUM(NSInteger, FTransactionStatus) { - FTransactionInitializing, // 0 - FTransactionRun, // 1 - FTransactionSent, // 2 - FTransactionCompleted, // 3 - FTransactionSentNeedsAbort, // 4 - FTransactionNeedsAbort // 5 + FTransactionInitializing, // 0 + FTransactionRun, // 1 + FTransactionSent, // 2 + FTransactionCompleted, // 3 + FTransactionSentNeedsAbort, // 4 + FTransactionNeedsAbort // 5 }; @protocol FNode; @@ -35,22 +35,26 @@ typedef NS_ENUM(NSInteger, FTransactionStatus) { @class FIRDataSnapshot; @class FCompoundHash; -typedef void (^fbt_void_nserror_bool_datasnapshot) (NSError* error, BOOL committed, FIRDataSnapshot * snapshot); -typedef FIRTransactionResult * (^fbt_transactionresult_mutabledata) (FIRMutableData * currentData); -typedef void (^fbt_void_path_node) (FPath*, id); -typedef void (^fbt_void_nsstring) (NSString *); -typedef BOOL (^fbt_bool_nsstring_node) (NSString *, id); -typedef void (^fbt_void_path_node_marray) (FPath *, id, NSMutableArray *); -typedef BOOL (^fbt_bool_void) (void); -typedef void (^fbt_void_nsstring_nsstring)(NSString *str1, NSString* str2); -typedef void (^fbt_void_nsstring_nserror)(NSString *str, NSError* error); +typedef void (^fbt_void_nserror_bool_datasnapshot)(NSError *error, + BOOL committed, + FIRDataSnapshot *snapshot); +typedef FIRTransactionResult * (^fbt_transactionresult_mutabledata)( + FIRMutableData *currentData); +typedef void (^fbt_void_path_node)(FPath *, id); +typedef void (^fbt_void_nsstring)(NSString *); +typedef BOOL (^fbt_bool_nsstring_node)(NSString *, id); +typedef void (^fbt_void_path_node_marray)(FPath *, id, NSMutableArray *); +typedef BOOL (^fbt_bool_void)(void); +typedef void (^fbt_void_nsstring_nsstring)(NSString *str1, NSString *str2); +typedef void (^fbt_void_nsstring_nserror)(NSString *str, NSError *error); typedef BOOL (^fbt_bool_path)(FPath *str); typedef void (^fbt_void_id)(id data); -typedef NSString* (^fbt_nsstring_void) (void); -typedef FCompoundHash* (^fbt_compoundhash_void) (void); -typedef NSArray* (^fbt_nsarray_nsstring_id)(NSString *status, id Data); -typedef NSArray* (^fbt_nsarray_nsstring)(NSString *status); +typedef NSString * (^fbt_nsstring_void)(void); +typedef FCompoundHash * (^fbt_compoundhash_void)(void); +typedef NSArray * (^fbt_nsarray_nsstring_id)(NSString *status, id Data); +typedef NSArray * (^fbt_nsarray_nsstring)(NSString *status); -// WWDC 2012 session 712 starting in page 83 for saving blocks in properties (use @property (strong) type name). +// WWDC 2012 session 712 starting in page 83 for saving blocks in properties +// (use @property (strong) type name). #endif diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Constants/FConstants.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Constants/FConstants.h index e97a8a1..4327a0d 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Constants/FConstants.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Constants/FConstants.h @@ -44,7 +44,9 @@ FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataRangeMerge; FOUNDATION_EXPORT NSString *const kFWPAsyncServerAuthRevoked; FOUNDATION_EXPORT NSString *const kFWPASyncServerListenCancelled; FOUNDATION_EXPORT NSString *const kFWPAsyncServerSecurityDebug; -FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdateBodyPath; // {“a”: “d”, “b”: {“p”: “/”, “d”: “”}} +FOUNDATION_EXPORT NSString + *const kFWPAsyncServerDataUpdateBodyPath; // {“a”: “d”, “b”: {“p”: “/”, “d”: + // “”}} FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdateBodyData; FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdateStartPath; FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdateEndPath; @@ -75,7 +77,9 @@ FOUNDATION_EXPORT NSString *const kFWPRequestActionPut; FOUNDATION_EXPORT NSString *const kFWPRequestActionMerge; FOUNDATION_EXPORT NSString *const kFWPRequestActionTaggedListen; FOUNDATION_EXPORT NSString *const kFWPRequestActionTaggedUnlisten; -FOUNDATION_EXPORT NSString *const kFWPRequestActionListen; // {"t": "d", "d": {"r": 1, "a": "l", "b": { "p": "/" } } } +FOUNDATION_EXPORT NSString + *const kFWPRequestActionListen; // {"t": "d", "d": {"r": 1, "a": "l", "b": { + // "p": "/" } } } FOUNDATION_EXPORT NSString *const kFWPRequestActionUnlisten; FOUNDATION_EXPORT NSString *const kFWPRequestActionStats; FOUNDATION_EXPORT NSString *const kFWPRequestActionDisconnectPut; @@ -108,7 +112,8 @@ FOUNDATION_EXPORT NSUInteger const kWebsocketConnectTimeout; FOUNDATION_EXPORT float const kPersistentConnReconnectMinDelay; FOUNDATION_EXPORT float const kPersistentConnReconnectMaxDelay; FOUNDATION_EXPORT float const kPersistentConnReconnectMultiplier; -FOUNDATION_EXPORT float const kPersistentConnSuccessfulConnectionEstablishedDelay; +FOUNDATION_EXPORT float const + kPersistentConnSuccessfulConnectionEstablishedDelay; #pragma mark - #pragma mark Query / QueryParams constants @@ -148,7 +153,7 @@ FOUNDATION_EXPORT NSString *const kServerValueSubKey; FOUNDATION_EXPORT NSString *const kServerValuePriority; #pragma mark - -#pragma mark .info/ constants +#pragma mark.info/ constants FOUNDATION_EXPORT NSString *const kDotInfoPrefix; FOUNDATION_EXPORT NSString *const kDotInfoConnected; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Constants/FConstants.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Constants/FConstants.m index e492ba1..1cf50ad 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Constants/FConstants.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Constants/FConstants.m @@ -22,7 +22,7 @@ NSString *const kFWPRequestType = @"t"; NSString *const kFWPRequestTypeData = @"d"; NSString *const kFWPRequestDataPayload = @"d"; -NSString *const kFWPRequestNumber = @"r"; +NSString *const kFWPRequestNumber = @"r"; NSString *const kFWPRequestPayloadBody = @"b"; NSString *const kFWPRequestError = @"error"; NSString *const kFWPRequestAction = @"a"; @@ -40,7 +40,8 @@ NSString *const kFWPAsyncServerAuthRevoked = @"ac"; NSString *const kFWPASyncServerListenCancelled = @"c"; NSString *const kFWPAsyncServerSecurityDebug = @"sd"; -NSString *const kFWPAsyncServerDataUpdateBodyPath = @"p"; // {“a”: “d”, “b”: {“p”: “/”, “d”: “”}} +NSString *const kFWPAsyncServerDataUpdateBodyPath = + @"p"; // {“a”: “d”, “b”: {“p”: “/”, “d”: “”}} NSString *const kFWPAsyncServerDataUpdateBodyData = @"d"; NSString *const kFWPAsyncServerDataUpdateStartPath = @"s"; NSString *const kFWPAsyncServerDataUpdateEndPath = @"e"; @@ -69,7 +70,8 @@ NSString *const kFWPRequestActionPut = @"p"; NSString *const kFWPRequestActionMerge = @"m"; -NSString *const kFWPRequestActionListen = @"l"; // {"t": "d", "d": {"r": 1, "a": "l", "b": { "p": "/" } } } +NSString *const kFWPRequestActionListen = + @"l"; // {"t": "d", "d": {"r": 1, "a": "l", "b": { "p": "/" } } } NSString *const kFWPRequestActionUnlisten = @"u"; NSString *const kFWPRequestActionStats = @"s"; NSString *const kFWPRequestActionTaggedListen = @"q"; @@ -143,7 +145,7 @@ NSString *const kServerValuePriority = @"timestamp"; #pragma mark - -#pragma mark .info/ constants +#pragma mark.info/ constants NSString *const kDotInfoPrefix = @".info"; NSString *const kDotInfoConnected = @"connected"; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FCompoundHash.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FCompoundHash.h index cd5240e..2453a81 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FCompoundHash.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FCompoundHash.h @@ -18,23 +18,21 @@ #import "FNode.h" - @interface FCompoundHashBuilder : NSObject - (FPath *)currentPath; @end - -typedef BOOL (^FCompoundHashSplitStrategy) (FCompoundHashBuilder *builder); - +typedef BOOL (^FCompoundHashSplitStrategy)(FCompoundHashBuilder *builder); @interface FCompoundHash : NSObject -@property (nonatomic, strong, readonly) NSArray *posts; -@property (nonatomic, strong, readonly) NSArray *hashes; +@property(nonatomic, strong, readonly) NSArray *posts; +@property(nonatomic, strong, readonly) NSArray *hashes; + (FCompoundHash *)fromNode:(id)node; -+ (FCompoundHash *)fromNode:(id)node splitStrategy:(FCompoundHashSplitStrategy)strategy; ++ (FCompoundHash *)fromNode:(id)node + splitStrategy:(FCompoundHashSplitStrategy)strategy; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FCompoundHash.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FCompoundHash.m index b4f72cd..ced79cd 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FCompoundHash.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FCompoundHash.m @@ -15,29 +15,32 @@ */ #import "FCompoundHash.h" +#import "FChildrenNode.h" #import "FLeafNode.h" -#import "FStringUtilities.h" #import "FSnapshotUtilities.h" -#import "FChildrenNode.h" +#import "FStringUtilities.h" @interface FCompoundHashBuilder () -@property (nonatomic, strong) FCompoundHashSplitStrategy splitStrategy; +@property(nonatomic, strong) FCompoundHashSplitStrategy splitStrategy; -@property (nonatomic, strong) NSMutableArray *currentPaths; -@property (nonatomic, strong) NSMutableArray *currentHashes; +@property(nonatomic, strong) NSMutableArray *currentPaths; +@property(nonatomic, strong) NSMutableArray *currentHashes; @end @implementation FCompoundHashBuilder { - // NOTE: We use the existence of this to know if we've started building a range (i.e. encountered a leaf node). + // NOTE: We use the existence of this to know if we've started building a + // range (i.e. encountered a leaf node). NSMutableString *optHashValueBuilder; - // The current path as a stack. This is used in combination with currentPathDepth to simultaneously store the - // last leaf node path. The depth is changed when descending and ascending, at the same time the current key - // is set for the current depth. Because the keys are left unchanged for ascending the path will also contain - // the path of the last visited leaf node (using lastLeafDepth elements) + // The current path as a stack. This is used in combination with + // currentPathDepth to simultaneously store the last leaf node path. The + // depth is changed when descending and ascending, at the same time the + // current key is set for the current depth. Because the keys are left + // unchanged for ascending the path will also contain the path of the last + // visited leaf node (using lastLeafDepth elements) NSMutableArray *currentPath; NSInteger lastLeafDepth; NSInteger currentPathDepth; @@ -73,28 +76,34 @@ - (FPath *)currentPath { } - (FPath *)currentPathWithDepth:(NSInteger)depth { - NSArray *pieces = [self->currentPath subarrayWithRange:NSMakeRange(0, depth)]; + NSArray *pieces = + [self->currentPath subarrayWithRange:NSMakeRange(0, depth)]; return [[FPath alloc] initWithPieces:pieces andPieceNum:0]; } -- (void)enumerateCurrentPathToDepth:(NSInteger)depth withBlock:(void (^) (NSString *key))block { +- (void)enumerateCurrentPathToDepth:(NSInteger)depth + withBlock:(void (^)(NSString *key))block { for (NSInteger i = 0; i < depth; i++) { block(self->currentPath[i]); } } - (void)appendKey:(NSString *)key toString:(NSMutableString *)string { - [FSnapshotUtilities appendHashV2RepresentationForString:key toString:string]; + [FSnapshotUtilities appendHashV2RepresentationForString:key + toString:string]; } - (void)ensureRange { if (![self isBuildingRange]) { optHashValueBuilder = [NSMutableString string]; [optHashValueBuilder appendString:@"("]; - [self enumerateCurrentPathToDepth:self->currentPathDepth withBlock:^(NSString *key) { - [self appendKey:key toString:self->optHashValueBuilder]; - [self->optHashValueBuilder appendString:@":("]; - }]; + [self + enumerateCurrentPathToDepth:self->currentPathDepth + withBlock:^(NSString *key) { + [self appendKey:key + toString:self->optHashValueBuilder]; + [self->optHashValueBuilder appendString:@":("]; + }]; self->needsComma = NO; } } @@ -103,9 +112,10 @@ - (void)processLeaf:(FLeafNode *)leafNode { [self ensureRange]; self->lastLeafDepth = self->currentPathDepth; - [FSnapshotUtilities appendHashRepresentationForLeafNode:leafNode - toString:self->optHashValueBuilder - hashVersion:FDataHashVersionV2]; + [FSnapshotUtilities + appendHashRepresentationForLeafNode:leafNode + toString:self->optHashValueBuilder + hashVersion:FDataHashVersionV2]; self->needsComma = YES; if (self.splitStrategy(self)) { [self endRange]; @@ -138,17 +148,20 @@ - (void)endChild { } - (void)finishHashing { - NSAssert(self->currentPathDepth == 0, @"Can't finish hashing in the middle of processing a child"); - if ([self isBuildingRange] ) { + NSAssert(self->currentPathDepth == 0, + @"Can't finish hashing in the middle of processing a child"); + if ([self isBuildingRange]) { [self endRange]; } - // Always close with the empty hash for the remaining range to allow simple appending + // Always close with the empty hash for the remaining range to allow simple + // appending [self.currentHashes addObject:@""]; } - (void)endRange { - NSAssert([self isBuildingRange], @"Can't end range without starting a range!"); + NSAssert([self isBuildingRange], + @"Can't end range without starting a range!"); // Add closing parenthesis for current depth for (NSUInteger i = 0; i < currentPathDepth; i++) { [self->optHashValueBuilder appendString:@")"]; @@ -156,7 +169,8 @@ - (void)endRange { [self->optHashValueBuilder appendString:@")"]; FPath *lastLeafPath = [self currentPathWithDepth:self->lastLeafDepth]; - NSString *hash = [FStringUtilities base64EncodedSha1:self->optHashValueBuilder]; + NSString *hash = + [FStringUtilities base64EncodedSha1:self->optHashValueBuilder]; [self.currentHashes addObject:hash]; [self.currentPaths addObject:lastLeafPath]; @@ -165,11 +179,10 @@ - (void)endRange { @end - @interface FCompoundHash () -@property (nonatomic, strong, readwrite) NSArray *posts; -@property (nonatomic, strong, readwrite) NSArray *hashes; +@property(nonatomic, strong, readwrite) NSArray *posts; +@property(nonatomic, strong, readwrite) NSArray *hashes; @end @@ -179,7 +192,9 @@ - (id)initWithPosts:(NSArray *)posts hashes:(NSArray *)hashes { self = [super init]; if (self != nil) { if (posts.count != hashes.count - 1) { - [NSException raise:NSInvalidArgumentException format:@"Number of posts need to be n-1 for n hashes in FCompoundHash"]; + [NSException raise:NSInvalidArgumentException + format:@"Number of posts need to be n-1 for n hashes " + @"in FCompoundHash"]; } self.posts = posts; self.hashes = hashes; @@ -188,7 +203,8 @@ - (id)initWithPosts:(NSArray *)posts hashes:(NSArray *)hashes { } + (FCompoundHashSplitStrategy)simpleSizeSplitStrategyForNode:(id)node { - NSUInteger estimatedSize = [FSnapshotUtilities estimateSerializedNodeSize:node]; + NSUInteger estimatedSize = + [FSnapshotUtilities estimateSerializedNodeSize:node]; // Splits for // 1k -> 512 (2 parts) @@ -199,23 +215,29 @@ + (FCompoundHashSplitStrategy)simpleSizeSplitStrategyForNode:(id)node { NSUInteger splitThreshold = MAX(512, (NSUInteger)sqrt(estimatedSize * 100)); return ^BOOL(FCompoundHashBuilder *builder) { - // Never split on priorities - return [builder currentHashLength] > splitThreshold && ![[[builder currentPath] getBack] isEqualToString:@".priority"]; + // Never split on priorities + return [builder currentHashLength] > splitThreshold && + ![[[builder currentPath] getBack] isEqualToString:@".priority"]; }; } + (FCompoundHash *)fromNode:(id)node { - return [FCompoundHash fromNode:node splitStrategy:[FCompoundHash simpleSizeSplitStrategyForNode:node]]; + return [FCompoundHash + fromNode:node + splitStrategy:[FCompoundHash simpleSizeSplitStrategyForNode:node]]; } -+ (FCompoundHash *)fromNode:(id)node splitStrategy:(FCompoundHashSplitStrategy)strategy { ++ (FCompoundHash *)fromNode:(id)node + splitStrategy:(FCompoundHashSplitStrategy)strategy { if ([node isEmpty]) { - return [[FCompoundHash alloc] initWithPosts:@[] hashes:@[@""]]; + return [[FCompoundHash alloc] initWithPosts:@[] hashes:@[ @"" ]]; } else { - FCompoundHashBuilder *builder = [[FCompoundHashBuilder alloc] initWithSplitStrategy:strategy]; + FCompoundHashBuilder *builder = + [[FCompoundHashBuilder alloc] initWithSplitStrategy:strategy]; [FCompoundHash processNode:node builder:builder]; [builder finishHashing]; - return [[FCompoundHash alloc] initWithPosts:builder.currentPaths hashes:builder.currentHashes]; + return [[FCompoundHash alloc] initWithPosts:builder.currentPaths + hashes:builder.currentHashes]; } } @@ -225,10 +247,11 @@ + (void)processNode:(id)node builder:(FCompoundHashBuilder *)builder { } else { NSAssert(![node isEmpty], @"Can't calculate hash on empty node!"); FChildrenNode *childrenNode = (FChildrenNode *)node; - [childrenNode enumerateChildrenAndPriorityUsingBlock:^(NSString *key, id node, BOOL *stop) { - [builder startChild:key]; - [self processNode:node builder:builder]; - [builder endChild]; + [childrenNode enumerateChildrenAndPriorityUsingBlock:^( + NSString *key, id node, BOOL *stop) { + [builder startChild:key]; + [self processNode:node builder:builder]; + [builder endChild]; }]; } } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FListenProvider.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FListenProvider.h index 7a41754..8efd803 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FListenProvider.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FListenProvider.h @@ -19,15 +19,14 @@ @class FQuerySpec; @protocol FSyncTreeHash; -typedef NSArray* (^fbt_startListeningBlock)(FQuerySpec *query, - NSNumber *tagId, - id hash, - fbt_nsarray_nsstring onComplete); +typedef NSArray * (^fbt_startListeningBlock)(FQuerySpec *query, NSNumber *tagId, + id hash, + fbt_nsarray_nsstring onComplete); typedef void (^fbt_stopListeningBlock)(FQuerySpec *query, NSNumber *tagId); @interface FListenProvider : NSObject -@property (nonatomic, copy) fbt_startListeningBlock startListening; -@property (nonatomic, copy) fbt_stopListeningBlock stopListening; +@property(nonatomic, copy) fbt_startListeningBlock startListening; +@property(nonatomic, copy) fbt_stopListeningBlock stopListening; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FListenProvider.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FListenProvider.m index 7a49609..27da015 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FListenProvider.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FListenProvider.m @@ -17,7 +17,6 @@ #import "FListenProvider.h" #import "FIRDatabaseQuery.h" - @implementation FListenProvider @synthesize startListening; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FPersistentConnection.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FPersistentConnection.h index 412c874..81836fd 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FPersistentConnection.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FPersistentConnection.h @@ -14,11 +14,11 @@ * limitations under the License. */ -#import #import "FConnection.h" #import "FRepoInfo.h" #import "FTypedefs.h" #import "FTypedefs_Private.h" +#import @protocol FPersistentConnectionDelegate; @protocol FSyncTreeHash; @@ -27,8 +27,8 @@ @interface FPersistentConnection : NSObject -@property (nonatomic, weak) id delegate; -@property (nonatomic) BOOL pauseWrites; +@property(nonatomic, weak) id delegate; +@property(nonatomic) BOOL pauseWrites; - (id)initWithRepoInfo:(FRepoInfo *)repoInfo dispatchQueue:(dispatch_queue_t)queue @@ -36,43 +36,64 @@ - (void)open; -- (void) putData:(id)data forPath:(NSString *)pathString withHash:(NSString *)hash withCallback:(fbt_void_nsstring_nsstring)onComplete; -- (void) mergeData:(id)data forPath:(NSString *)pathString withCallback:(fbt_void_nsstring_nsstring)onComplete; - -- (void) listen:(FQuerySpec *)query - tagId:(NSNumber *)tagId - hash:(id)hash - onComplete:(fbt_void_nsstring)onComplete; - -- (void) unlisten:(FQuerySpec *)query tagId:(NSNumber *)tagId; -- (void) refreshAuthToken:(NSString *)token; -- (void) onDisconnectPutData:(id)data forPath:(FPath *)path withCallback:(fbt_void_nsstring_nsstring)callback; -- (void) onDisconnectMergeData:(id)data forPath:(FPath *)path withCallback:(fbt_void_nsstring_nsstring)callback; -- (void) onDisconnectCancelPath:(FPath *)path withCallback:(fbt_void_nsstring_nsstring)callback; -- (void) ackPuts; -- (void) purgeOutstandingWrites; - -- (void) interruptForReason:(NSString *)reason; -- (void) resumeForReason:(NSString *)reason; -- (BOOL) isInterruptedForReason:(NSString *)reason; +- (void)putData:(id)data + forPath:(NSString *)pathString + withHash:(NSString *)hash + withCallback:(fbt_void_nsstring_nsstring)onComplete; +- (void)mergeData:(id)data + forPath:(NSString *)pathString + withCallback:(fbt_void_nsstring_nsstring)onComplete; + +- (void)listen:(FQuerySpec *)query + tagId:(NSNumber *)tagId + hash:(id)hash + onComplete:(fbt_void_nsstring)onComplete; + +- (void)unlisten:(FQuerySpec *)query tagId:(NSNumber *)tagId; +- (void)refreshAuthToken:(NSString *)token; +- (void)onDisconnectPutData:(id)data + forPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback; +- (void)onDisconnectMergeData:(id)data + forPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback; +- (void)onDisconnectCancelPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback; +- (void)ackPuts; +- (void)purgeOutstandingWrites; + +- (void)interruptForReason:(NSString *)reason; +- (void)resumeForReason:(NSString *)reason; +- (BOOL)isInterruptedForReason:(NSString *)reason; // FConnection delegate methods -- (void)onReady:(FConnection *)fconnection atTime:(NSNumber *)timestamp sessionID:(NSString *)sessionID; -- (void)onDataMessage:(FConnection *)fconnection withMessage:(NSDictionary *)message; -- (void)onDisconnect:(FConnection *)fconnection withReason:(FDisconnectReason)reason; +- (void)onReady:(FConnection *)fconnection + atTime:(NSNumber *)timestamp + sessionID:(NSString *)sessionID; +- (void)onDataMessage:(FConnection *)fconnection + withMessage:(NSDictionary *)message; +- (void)onDisconnect:(FConnection *)fconnection + withReason:(FDisconnectReason)reason; - (void)onKill:(FConnection *)fconnection withReason:(NSString *)reason; // Testing methods -- (NSDictionary *) dumpListens; +- (NSDictionary *)dumpListens; @end @protocol FPersistentConnectionDelegate -- (void)onDataUpdate:(FPersistentConnection *)fpconnection forPath:(NSString *)pathString message:(id)message isMerge:(BOOL)isMerge tagId:(NSNumber *)tagId; -- (void)onRangeMerge:(NSArray *)ranges forPath:(NSString *)path tagId:(NSNumber *)tag; +- (void)onDataUpdate:(FPersistentConnection *)fpconnection + forPath:(NSString *)pathString + message:(id)message + isMerge:(BOOL)isMerge + tagId:(NSNumber *)tagId; +- (void)onRangeMerge:(NSArray *)ranges + forPath:(NSString *)path + tagId:(NSNumber *)tag; - (void)onConnect:(FPersistentConnection *)fpconnection; - (void)onDisconnect:(FPersistentConnection *)fpconnection; -- (void)onServerInfoUpdate:(FPersistentConnection *)fpconnection updates:(NSDictionary *)updates; +- (void)onServerInfoUpdate:(FPersistentConnection *)fpconnection + updates:(NSDictionary *)updates; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FPersistentConnection.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FPersistentConnection.m index f341bb1..69f52c1 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FPersistentConnection.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FPersistentConnection.m @@ -15,35 +15,35 @@ */ #import -#import -#import -#import -#import +#import "FAtomicNumber.h" +#import "FAuthTokenProvider.h" +#import "FCompoundHash.h" +#import "FConstants.h" +#import "FIRDatabaseConfig.h" +#import "FIRDatabaseConfig_Private.h" #import "FIRDatabaseReference.h" +#import "FIRRetryHelper.h" +#import "FIndex.h" #import "FPersistentConnection.h" -#import "FConstants.h" -#import "FAtomicNumber.h" #import "FQueryParams.h" -#import "FTupleOnDisconnect.h" -#import "FTupleCallbackStatus.h" #import "FQuerySpec.h" -#import "FIndex.h" -#import "FIRDatabaseConfig.h" -#import "FIRDatabaseConfig_Private.h" -#import "FSnapshotUtilities.h" #import "FRangeMerge.h" -#import "FCompoundHash.h" +#import "FSnapshotUtilities.h" #import "FSyncTree.h" -#import "FIRRetryHelper.h" -#import "FAuthTokenProvider.h" +#import "FTupleCallbackStatus.h" +#import "FTupleOnDisconnect.h" #import "FUtilities.h" +#import +#import +#import +#import @interface FOutstandingQuery : NSObject -@property (nonatomic, strong) FQuerySpec* query; -@property (nonatomic, strong) NSNumber *tagId; -@property (nonatomic, strong) id syncTreeHash; -@property (nonatomic, copy) fbt_void_nsstring onComplete; +@property(nonatomic, strong) FQuerySpec *query; +@property(nonatomic, strong) NSNumber *tagId; +@property(nonatomic, strong) id syncTreeHash; +@property(nonatomic, copy) fbt_void_nsstring onComplete; @end @@ -51,13 +51,12 @@ @implementation FOutstandingQuery @end - @interface FOutstandingPut : NSObject -@property (nonatomic, strong) NSString *action; -@property (nonatomic, strong) NSDictionary *request; -@property (nonatomic, copy) fbt_void_nsstring_nsstring onCompleteBlock; -@property (nonatomic) BOOL sent; +@property(nonatomic, strong) NSString *action; +@property(nonatomic, strong) NSDictionary *request; +@property(nonatomic, copy) fbt_void_nsstring_nsstring onCompleteBlock; +@property(nonatomic) BOOL sent; @end @@ -65,7 +64,6 @@ @implementation FOutstandingPut @end - typedef enum { ConnectionStateDisconnected, ConnectionStateGettingToken, @@ -83,44 +81,49 @@ @interface FPersistentConnection () { SCNetworkReachabilityRef reachability; } -- (int) getNextRequestNumber; -- (void) onDataPushWithAction:(NSString *)action andBody:(NSDictionary *)body; -- (void) handleTimestamp:(NSNumber *)timestamp; -- (void) sendOnDisconnectAction:(NSString *)action forPath:(NSString *)pathString withData:(id)data andCallback:(fbt_void_nsstring_nsstring)callback; - -@property (nonatomic, strong) FConnection* realtime; -@property (nonatomic, strong) NSMutableDictionary* listens; -@property (nonatomic, strong) NSMutableDictionary* outstandingPuts; -@property (nonatomic, strong) NSMutableArray* onDisconnectQueue; -@property (nonatomic, strong) FRepoInfo* repoInfo; -@property (nonatomic, strong) FAtomicNumber* putCounter; -@property (nonatomic, strong) FAtomicNumber* requestNumber; -@property (nonatomic, strong) NSMutableDictionary* requestCBHash; -@property (nonatomic, strong) FIRDatabaseConfig *config; -@property (nonatomic) NSUInteger unackedListensCount; -@property (nonatomic, strong) NSMutableArray *putsToAck; -@property (nonatomic, strong) dispatch_queue_t dispatchQueue; -@property (nonatomic, strong) NSString* lastSessionID; -@property (nonatomic, strong) NSMutableSet *interruptReasons; -@property (nonatomic, strong) FIRRetryHelper *retryHelper; -@property (nonatomic, strong) id authTokenProvider; -@property (nonatomic, strong) NSString *authToken; -@property (nonatomic) BOOL forceAuthTokenRefresh; -@property (nonatomic) NSUInteger currentFetchTokenAttempt; +- (int)getNextRequestNumber; +- (void)onDataPushWithAction:(NSString *)action andBody:(NSDictionary *)body; +- (void)handleTimestamp:(NSNumber *)timestamp; +- (void)sendOnDisconnectAction:(NSString *)action + forPath:(NSString *)pathString + withData:(id)data + andCallback:(fbt_void_nsstring_nsstring)callback; + +@property(nonatomic, strong) FConnection *realtime; +@property(nonatomic, strong) NSMutableDictionary *listens; +@property(nonatomic, strong) NSMutableDictionary *outstandingPuts; +@property(nonatomic, strong) NSMutableArray *onDisconnectQueue; +@property(nonatomic, strong) FRepoInfo *repoInfo; +@property(nonatomic, strong) FAtomicNumber *putCounter; +@property(nonatomic, strong) FAtomicNumber *requestNumber; +@property(nonatomic, strong) NSMutableDictionary *requestCBHash; +@property(nonatomic, strong) FIRDatabaseConfig *config; +@property(nonatomic) NSUInteger unackedListensCount; +@property(nonatomic, strong) NSMutableArray *putsToAck; +@property(nonatomic, strong) dispatch_queue_t dispatchQueue; +@property(nonatomic, strong) NSString *lastSessionID; +@property(nonatomic, strong) NSMutableSet *interruptReasons; +@property(nonatomic, strong) FIRRetryHelper *retryHelper; +@property(nonatomic, strong) id authTokenProvider; +@property(nonatomic, strong) NSString *authToken; +@property(nonatomic) BOOL forceAuthTokenRefresh; +@property(nonatomic) NSUInteger currentFetchTokenAttempt; @end - @implementation FPersistentConnection -- (id)initWithRepoInfo:(FRepoInfo *)repoInfo dispatchQueue:(dispatch_queue_t)dispatchQueue config:(FIRDatabaseConfig *)config { +- (id)initWithRepoInfo:(FRepoInfo *)repoInfo + dispatchQueue:(dispatch_queue_t)dispatchQueue + config:(FIRDatabaseConfig *)config { self = [super init]; if (self) { self->_config = config; self->_repoInfo = repoInfo; self->_dispatchQueue = dispatchQueue; self->_authTokenProvider = config.authTokenProvider; - NSAssert(self->_authTokenProvider != nil, @"Expected auth token provider"); + NSAssert(self->_authTokenProvider != nil, + @"Expected auth token provider"); self.interruptReasons = [NSMutableSet set]; self.listens = [[NSMutableDictionary alloc] init]; @@ -135,24 +138,26 @@ - (id)initWithRepoInfo:(FRepoInfo *)repoInfo dispatchQueue:(dispatch_queue_t)dis firstConnection = YES; reconnectDelay = kPersistentConnReconnectMinDelay; - self->_retryHelper = [[FIRRetryHelper alloc] initWithDispatchQueue:dispatchQueue - minRetryDelayAfterFailure:kPersistentConnReconnectMinDelay - maxRetryDelay:kPersistentConnReconnectMaxDelay - retryExponent:kPersistentConnReconnectMultiplier - jitterFactor:0.7]; + self->_retryHelper = [[FIRRetryHelper alloc] + initWithDispatchQueue:dispatchQueue + minRetryDelayAfterFailure:kPersistentConnReconnectMinDelay + maxRetryDelay:kPersistentConnReconnectMaxDelay + retryExponent:kPersistentConnReconnectMultiplier + jitterFactor:0.7]; [self setupNotifications]; // Make sure we don't actually connect until open is called [self interruptForReason:kFInterruptReasonWaitingForOpen]; } - // nb: The reason establishConnection isn't called here like the JS version is because - // callers need to set the delegate first. The ctor can be modified to accept the delegate - // but that deviates from normal ios conventions. After the delegate has been set, the caller - // is responsible for calling establishConnection: + // nb: The reason establishConnection isn't called here like the JS version + // is because callers need to set the delegate first. The ctor can be + // modified to accept the delegate but that deviates from normal ios + // conventions. After the delegate has been set, the caller is responsible + // for calling establishConnection: return self; } -- (void) dealloc { +- (void)dealloc { if (reachability) { // Unschedule the notifications SCNetworkReachabilitySetDispatchQueue(reachability, NULL); @@ -163,26 +168,30 @@ - (void) dealloc { #pragma mark - #pragma mark Public methods -- (void) open { +- (void)open { [self resumeForReason:kFInterruptReasonWaitingForOpen]; } /** -* Note that the listens dictionary has a type of Map[String (pathString), Map[FQueryParams, FOutstandingQuery]] -* -* This means, for each path we care about, there are sets of queryParams that correspond to an FOutstandingQuery object. -* There can be multiple sets at a path since we overlap listens for a short time while adding or removing a query from a -* location in the tree. -*/ -- (void) listen:(FQuerySpec *)query - tagId:(NSNumber *)tagId - hash:(id)hash - onComplete:(fbt_void_nsstring)onComplete { + * Note that the listens dictionary has a type of Map[String (pathString), + * Map[FQueryParams, FOutstandingQuery]] + * + * This means, for each path we care about, there are sets of queryParams that + * correspond to an FOutstandingQuery object. There can be multiple sets at a + * path since we overlap listens for a short time while adding or removing a + * query from a location in the tree. + */ +- (void)listen:(FQuerySpec *)query + tagId:(NSNumber *)tagId + hash:(id)hash + onComplete:(fbt_void_nsstring)onComplete { FFLog(@"I-RDB034001", @"Listen called for %@", query); - NSAssert(self.listens[query] == nil, @"listen() called twice for the same query"); - NSAssert(query.isDefault || !query.loadsAllData, @"listen called for non-default but complete query"); - FOutstandingQuery* outstanding = [[FOutstandingQuery alloc] init]; + NSAssert(self.listens[query] == nil, + @"listen() called twice for the same query"); + NSAssert(query.isDefault || !query.loadsAllData, + @"listen called for non-default but complete query"); + FOutstandingQuery *outstanding = [[FOutstandingQuery alloc] init]; outstanding.query = query; outstanding.tagId = tagId; outstanding.syncTreeHash = hash; @@ -193,19 +202,37 @@ - (void) listen:(FQuerySpec *)query } } -- (void) putData:(id)data forPath:(NSString *)pathString withHash:(NSString *)hash withCallback:(fbt_void_nsstring_nsstring)onComplete { - [self putInternal:data forAction:kFWPRequestActionPut forPath:pathString withHash:hash withCallback:onComplete]; +- (void)putData:(id)data + forPath:(NSString *)pathString + withHash:(NSString *)hash + withCallback:(fbt_void_nsstring_nsstring)onComplete { + [self putInternal:data + forAction:kFWPRequestActionPut + forPath:pathString + withHash:hash + withCallback:onComplete]; } -- (void) mergeData:(id)data forPath:(NSString *)pathString withCallback:(fbt_void_nsstring_nsstring)onComplete { - [self putInternal:data forAction:kFWPRequestActionMerge forPath:pathString withHash:nil withCallback:onComplete]; +- (void)mergeData:(id)data + forPath:(NSString *)pathString + withCallback:(fbt_void_nsstring_nsstring)onComplete { + [self putInternal:data + forAction:kFWPRequestActionMerge + forPath:pathString + withHash:nil + withCallback:onComplete]; } -- (void) onDisconnectPutData:(id)data forPath:(FPath *)path withCallback:(fbt_void_nsstring_nsstring)callback { +- (void)onDisconnectPutData:(id)data + forPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback { if ([self canSendWrites]) { - [self sendOnDisconnectAction:kFWPRequestActionDisconnectPut forPath:[path description] withData:data andCallback:callback]; + [self sendOnDisconnectAction:kFWPRequestActionDisconnectPut + forPath:[path description] + withData:data + andCallback:callback]; } else { - FTupleOnDisconnect* tuple = [[FTupleOnDisconnect alloc] init]; + FTupleOnDisconnect *tuple = [[FTupleOnDisconnect alloc] init]; tuple.pathString = [path description]; tuple.action = kFWPRequestActionDisconnectPut; tuple.data = data; @@ -214,11 +241,16 @@ - (void) onDisconnectPutData:(id)data forPath:(FPath *)path withCallback:(fbt_vo } } -- (void) onDisconnectMergeData:(id)data forPath:(FPath *)path withCallback:(fbt_void_nsstring_nsstring)callback { +- (void)onDisconnectMergeData:(id)data + forPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback { if ([self canSendWrites]) { - [self sendOnDisconnectAction:kFWPRequestActionDisconnectMerge forPath:[path description] withData:data andCallback:callback]; + [self sendOnDisconnectAction:kFWPRequestActionDisconnectMerge + forPath:[path description] + withData:data + andCallback:callback]; } else { - FTupleOnDisconnect* tuple = [[FTupleOnDisconnect alloc] init]; + FTupleOnDisconnect *tuple = [[FTupleOnDisconnect alloc] init]; tuple.pathString = [path description]; tuple.action = kFWPRequestActionDisconnectMerge; tuple.data = data; @@ -227,11 +259,15 @@ - (void) onDisconnectMergeData:(id)data forPath:(FPath *)path withCallback:(fbt_ } } -- (void) onDisconnectCancelPath:(FPath *)path withCallback:(fbt_void_nsstring_nsstring)callback { +- (void)onDisconnectCancelPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback { if ([self canSendWrites]) { - [self sendOnDisconnectAction:kFWPRequestActionDisconnectCancel forPath:[path description] withData:[NSNull null] andCallback:callback]; + [self sendOnDisconnectAction:kFWPRequestActionDisconnectCancel + forPath:[path description] + withData:[NSNull null] + andCallback:callback]; } else { - FTupleOnDisconnect* tuple = [[FTupleOnDisconnect alloc] init]; + FTupleOnDisconnect *tuple = [[FTupleOnDisconnect alloc] init]; tuple.pathString = [path description]; tuple.action = kFWPRequestActionDisconnectCancel; tuple.data = [NSNull null]; @@ -240,7 +276,7 @@ - (void) onDisconnectCancelPath:(FPath *)path withCallback:(fbt_void_nsstring_ns } } -- (void) unlisten:(FQuerySpec *)query tagId:(NSNumber *)tagId { +- (void)unlisten:(FQuerySpec *)query tagId:(NSNumber *)tagId { FPath *path = query.path; FFLog(@"I-RDB034002", @"Unlistening for %@", query); @@ -250,7 +286,7 @@ - (void) unlisten:(FQuerySpec *)query tagId:(NSNumber *)tagId { } } -- (void) refreshAuthToken:(NSString *)token { +- (void)refreshAuthToken:(NSString *)token { self.authToken = token; if ([self connected]) { if (token != nil) { @@ -265,7 +301,8 @@ - (void) refreshAuthToken:(NSString *)token { #pragma mark Connection status - (BOOL)connected { - return self->connectionState == ConnectionStateAuthenticating || self->connectionState == ConnectionStateConnected; + return self->connectionState == ConnectionStateAuthenticating || + self->connectionState == ConnectionStateConnected; } - (BOOL)canSendWrites { @@ -275,7 +312,9 @@ - (BOOL)canSendWrites { #pragma mark - #pragma mark FConnection delegate methods -- (void)onReady:(FConnection *)fconnection atTime:(NSNumber *)timestamp sessionID:(NSString *)sessionID { +- (void)onReady:(FConnection *)fconnection + atTime:(NSNumber *)timestamp + sessionID:(NSString *)sessionID { FFLog(@"I-RDB034003", @"On ready"); lastConnectionEstablishedTime = [[NSDate date] timeIntervalSince1970]; [self handleTimestamp:timestamp]; @@ -288,37 +327,45 @@ - (void)onReady:(FConnection *)fconnection atTime:(NSNumber *)timestamp sessionI firstConnection = NO; self.lastSessionID = sessionID; dispatch_async(self.dispatchQueue, ^{ - [self.delegate onConnect:self]; + [self.delegate onConnect:self]; }); } -- (void)onDataMessage:(FConnection *)fconnection withMessage:(NSDictionary *)message { +- (void)onDataMessage:(FConnection *)fconnection + withMessage:(NSDictionary *)message { if (message[kFWPRequestNumber] != nil) { // this is a response to a request we sent - NSNumber* rn = [NSNumber numberWithInt:[[message objectForKey:kFWPRequestNumber] intValue]]; + NSNumber *rn = [NSNumber + numberWithInt:[[message objectForKey:kFWPRequestNumber] intValue]]; if ([self.requestCBHash objectForKey:rn]) { - void (^callback)(NSDictionary*) = [self.requestCBHash objectForKey:rn]; + void (^callback)(NSDictionary *) = + [self.requestCBHash objectForKey:rn]; [self.requestCBHash removeObjectForKey:rn]; if (callback) { - //dispatch_async(self.dispatchQueue, ^{ - callback([message objectForKey:kFWPResponseForRNData]); + // dispatch_async(self.dispatchQueue, ^{ + callback([message objectForKey:kFWPResponseForRNData]); //}); } } } else if (message[kFWPRequestError] != nil) { - NSString* error = [message objectForKey:kFWPRequestError]; - @throw [[NSException alloc] initWithName:@"FirebaseDatabaseServerError" reason:error userInfo:nil]; + NSString *error = [message objectForKey:kFWPRequestError]; + @throw [[NSException alloc] initWithName:@"FirebaseDatabaseServerError" + reason:error + userInfo:nil]; } else if (message[kFWPAsyncServerAction] != nil) { // this is a server push of some sort - NSString* action = [message objectForKey:kFWPAsyncServerAction]; - NSDictionary* body = [message objectForKey:kFWPAsyncServerPayloadBody]; + NSString *action = [message objectForKey:kFWPAsyncServerAction]; + NSDictionary *body = [message objectForKey:kFWPAsyncServerPayloadBody]; [self onDataPushWithAction:action andBody:body]; } } -- (void)onDisconnect:(FConnection *)fconnection withReason:(FDisconnectReason)reason { - FFLog(@"I-RDB034004", @"Got on disconnect due to %s", (reason == DISCONNECT_REASON_SERVER_RESET) ? "server_reset" : "other"); +- (void)onDisconnect:(FConnection *)fconnection + withReason:(FDisconnectReason)reason { + FFLog(@"I-RDB034004", @"Got on disconnect due to %s", + (reason == DISCONNECT_REASON_SERVER_RESET) ? "server_reset" + : "other"); connectionState = ConnectionStateDisconnected; // Drop the realtime connection self.realtime = nil; @@ -326,15 +373,20 @@ - (void)onDisconnect:(FConnection *)fconnection withReason:(FDisconnectReason)re [self.requestCBHash removeAllObjects]; self.unackedListensCount = 0; if ([self shouldReconnect]) { - NSTimeInterval timeSinceLastConnectSucceeded = [[NSDate date] timeIntervalSince1970] - lastConnectionEstablishedTime; + NSTimeInterval timeSinceLastConnectSucceeded = + [[NSDate date] timeIntervalSince1970] - + lastConnectionEstablishedTime; BOOL lastConnectionWasSuccessful; if (lastConnectionEstablishedTime > 0) { - lastConnectionWasSuccessful = timeSinceLastConnectSucceeded > kPersistentConnSuccessfulConnectionEstablishedDelay; + lastConnectionWasSuccessful = + timeSinceLastConnectSucceeded > + kPersistentConnSuccessfulConnectionEstablishedDelay; } else { lastConnectionWasSuccessful = NO; } - if (reason == DISCONNECT_REASON_SERVER_RESET || lastConnectionWasSuccessful) { + if (reason == DISCONNECT_REASON_SERVER_RESET || + lastConnectionWasSuccessful) { [self.retryHelper signalSuccess]; } [self tryScheduleReconnect]; @@ -344,14 +396,17 @@ - (void)onDisconnect:(FConnection *)fconnection withReason:(FDisconnectReason)re } - (void)onKill:(FConnection *)fconnection withReason:(NSString *)reason { - FFWarn(@"I-RDB034005", @"Firebase Database connection was forcefully killed by the server. Will not attempt reconnect. Reason: %@", reason); + FFWarn(@"I-RDB034005", + @"Firebase Database connection was forcefully killed by the server. " + @" Will not attempt reconnect. Reason: %@", + reason); [self interruptForReason:kFInterruptReasonServerKill]; } #pragma mark - #pragma mark Connection handling methods -- (void) interruptForReason:(NSString *)reason { +- (void)interruptForReason:(NSString *)reason { FFLog(@"I-RDB034006", @"Connection interrupted for: %@", reason); [self.interruptReasons addObject:reason]; @@ -367,27 +422,28 @@ - (void) interruptForReason:(NSString *)reason { [self.retryHelper signalSuccess]; } -- (void) resumeForReason:(NSString *)reason { +- (void)resumeForReason:(NSString *)reason { FFLog(@"I-RDB034007", @"Connection no longer interrupted for: %@", reason); [self.interruptReasons removeObject:reason]; - if ([self shouldReconnect] && connectionState == ConnectionStateDisconnected) { + if ([self shouldReconnect] && + connectionState == ConnectionStateDisconnected) { [self tryScheduleReconnect]; } } -- (BOOL) shouldReconnect { +- (BOOL)shouldReconnect { return self.interruptReasons.count == 0; } -- (BOOL) isInterruptedForReason:(NSString *)reason { +- (BOOL)isInterruptedForReason:(NSString *)reason { return [self.interruptReasons containsObject:reason]; } #pragma mark - #pragma mark Private methods -- (void) tryScheduleReconnect { +- (void)tryScheduleReconnect { if ([self shouldReconnect]) { NSAssert(self->connectionState == ConnectionStateDisconnected, @"Not in disconnected state: %d", self->connectionState); @@ -395,42 +451,62 @@ - (void) tryScheduleReconnect { self.forceAuthTokenRefresh = NO; FFLog(@"I-RDB034008", @"Scheduling connection attempt"); [self.retryHelper retry:^{ - FFLog(@"I-RDB034009", @"Trying to fetch auth token"); - NSAssert(self->connectionState == ConnectionStateDisconnected, - @"Not in disconnected state: %d", self->connectionState); - self->connectionState = ConnectionStateGettingToken; - self.currentFetchTokenAttempt++; - NSUInteger thisFetchTokenAttempt = self.currentFetchTokenAttempt; - [self.authTokenProvider fetchTokenForcingRefresh:forceRefresh withCallback:^(NSString *token, NSError *error) { - if (thisFetchTokenAttempt == self.currentFetchTokenAttempt) { - if (error != nil) { - self->connectionState = ConnectionStateDisconnected; - FFLog(@"I-RDB034010", @"Error fetching token: %@", error); - [self tryScheduleReconnect]; - } else { - // Someone could have interrupted us while fetching the token, - // marking the connection as Disconnected - if (self->connectionState == ConnectionStateGettingToken) { - FFLog(@"I-RDB034011", @"Successfully fetched token, opening connection"); - [self openNetworkConnectionWithToken:token]; - } else { - NSAssert(self->connectionState == ConnectionStateDisconnected, - @"Expected connection state disconnected, but got %d", self->connectionState); - FFLog(@"I-RDB034012", @"Not opening connection after token refresh, because connection was set to disconnected."); - } - } - } else { - FFLog(@"I-RDB034013", @"Ignoring fetch token result, because this was not the latest attempt."); - } - }]; + FFLog(@"I-RDB034009", @"Trying to fetch auth token"); + NSAssert(self->connectionState == ConnectionStateDisconnected, + @"Not in disconnected state: %d", self->connectionState); + self->connectionState = ConnectionStateGettingToken; + self.currentFetchTokenAttempt++; + NSUInteger thisFetchTokenAttempt = self.currentFetchTokenAttempt; + [self.authTokenProvider + fetchTokenForcingRefresh:forceRefresh + withCallback:^(NSString *token, NSError *error) { + if (thisFetchTokenAttempt == + self.currentFetchTokenAttempt) { + if (error != nil) { + self->connectionState = + ConnectionStateDisconnected; + FFLog(@"I-RDB034010", + @"Error fetching token: %@", error); + [self tryScheduleReconnect]; + } else { + // Someone could have interrupted us while + // fetching the token, marking the + // connection as Disconnected + if (self->connectionState == + ConnectionStateGettingToken) { + FFLog(@"I-RDB034011", + @"Successfully fetched token, " + @"opening connection"); + [self openNetworkConnectionWithToken: + token]; + } else { + NSAssert( + self->connectionState == + ConnectionStateDisconnected, + @"Expected connection state " + @"disconnected, but got %d", + self->connectionState); + FFLog(@"I-RDB034012", + @"Not opening connection after " + @"token refresh, because " + @"connection was set to " + @"disconnected."); + } + } + } else { + FFLog(@"I-RDB034013", + @"Ignoring fetch token result, because " + @"this was not the latest attempt."); + } + }]; }]; - } } -- (void) openNetworkConnectionWithToken:(NSString *)token { +- (void)openNetworkConnectionWithToken:(NSString *)token { NSAssert(self->connectionState == ConnectionStateGettingToken, - @"Trying to open network connection while in wrong state: %d", self->connectionState); + @"Trying to open network connection while in wrong state: %d", + self->connectionState); self.authToken = token; self->connectionState = ConnectionStateConnecting; self.realtime = [[FConnection alloc] initWith:self.repoInfo @@ -440,10 +516,12 @@ - (void) openNetworkConnectionWithToken:(NSString *)token { [self.realtime open]; } -static void reachabilityCallback(SCNetworkReachabilityRef ref, SCNetworkReachabilityFlags flags, void* info) { +static void reachabilityCallback(SCNetworkReachabilityRef ref, + SCNetworkReachabilityFlags flags, void *info) { if (flags & kSCNetworkReachabilityFlagsReachable) { - FFLog(@"I-RDB034014", @"Network became reachable. Trigger a connection attempt"); - FPersistentConnection* self = (__bridge FPersistentConnection *)info; + FFLog(@"I-RDB034014", + @"Network became reachable. Trigger a connection attempt"); + FPersistentConnection *self = (__bridge FPersistentConnection *)info; // Reset reconnect delay [self.retryHelper signalSuccess]; if (self->connectionState == ConnectionStateDisconnected) { @@ -454,79 +532,98 @@ static void reachabilityCallback(SCNetworkReachabilityRef ref, SCNetworkReachabi } } -- (void) enteringForeground { +- (void)enteringForeground { dispatch_async(self.dispatchQueue, ^{ - // Reset reconnect delay - [self.retryHelper signalSuccess]; - if (self->connectionState == ConnectionStateDisconnected) { - [self tryScheduleReconnect]; - } + // Reset reconnect delay + [self.retryHelper signalSuccess]; + if (self->connectionState == ConnectionStateDisconnected) { + [self tryScheduleReconnect]; + } }); } -- (void) setupNotifications { +- (void)setupNotifications { - NSString * const* foregroundConstant = (NSString * const *) dlsym(RTLD_DEFAULT, "UIApplicationWillEnterForegroundNotification"); + NSString *const *foregroundConstant = (NSString *const *)dlsym( + RTLD_DEFAULT, "UIApplicationWillEnterForegroundNotification"); if (foregroundConstant) { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(enteringForeground) - name:*foregroundConstant - object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(enteringForeground) + name:*foregroundConstant + object:nil]; } // An empty address is interpreted a generic internet access struct sockaddr_in zeroAddress; bzero(&zeroAddress, sizeof(zeroAddress)); zeroAddress.sin_len = sizeof(zeroAddress); zeroAddress.sin_family = AF_INET; - reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)&zeroAddress); - SCNetworkReachabilityContext ctx = {0, (__bridge void *)(self), NULL, NULL, NULL}; - if (SCNetworkReachabilitySetCallback(reachability, reachabilityCallback, &ctx)) { + reachability = SCNetworkReachabilityCreateWithAddress( + kCFAllocatorDefault, (const struct sockaddr *)&zeroAddress); + SCNetworkReachabilityContext ctx = {0, (__bridge void *)(self), NULL, NULL, + NULL}; + if (SCNetworkReachabilitySetCallback(reachability, reachabilityCallback, + &ctx)) { SCNetworkReachabilitySetDispatchQueue(reachability, self.dispatchQueue); } else { - FFLog(@"I-RDB034016", @"Failed to set up network reachability monitoring"); + FFLog(@"I-RDB034016", + @"Failed to set up network reachability monitoring"); CFRelease(reachability); reachability = NULL; } } -- (void) sendAuthAndRestoreStateAfterComplete:(BOOL)restoreStateAfterComplete { +- (void)sendAuthAndRestoreStateAfterComplete:(BOOL)restoreStateAfterComplete { NSAssert([self connected], @"Must be connected to send auth"); - NSAssert(self.authToken != nil, @"Can't send auth if there is no credential"); + NSAssert(self.authToken != nil, + @"Can't send auth if there is no credential"); - NSDictionary* requestData = @{kFWPRequestCredential: self.authToken}; - [self sendAction:kFWPRequestActionAuth body:requestData sensitive:YES callback:^(NSDictionary *data) { - self->connectionState = ConnectionStateConnected; - NSString* status = [data objectForKey:kFWPResponseForActionStatus]; - id responseData = [data objectForKey:kFWPResponseForActionData]; - if (responseData == nil) { - responseData = @"error"; - } - - BOOL statusOk = [status isEqualToString:kFWPResponseForActionStatusOk]; - if (statusOk) { - if (restoreStateAfterComplete) { - [self restoreState]; - } - } else { - self.authToken = nil; - self.forceAuthTokenRefresh = YES; - if ([status isEqualToString:@"expired_token"]) { - FFLog(@"I-RDB034017", @"Authentication failed: %@ (%@)", status, responseData); - } else { - FFWarn(@"I-RDB034018", @"Authentication failed: %@ (%@)", status, responseData); - } - [self.realtime close]; - } - }]; + NSDictionary *requestData = @{kFWPRequestCredential : self.authToken}; + [self sendAction:kFWPRequestActionAuth + body:requestData + sensitive:YES + callback:^(NSDictionary *data) { + self->connectionState = ConnectionStateConnected; + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + id responseData = [data objectForKey:kFWPResponseForActionData]; + if (responseData == nil) { + responseData = @"error"; + } + + BOOL statusOk = + [status isEqualToString:kFWPResponseForActionStatusOk]; + if (statusOk) { + if (restoreStateAfterComplete) { + [self restoreState]; + } + } else { + self.authToken = nil; + self.forceAuthTokenRefresh = YES; + if ([status isEqualToString:@"expired_token"]) { + FFLog(@"I-RDB034017", @"Authentication failed: %@ (%@)", + status, responseData); + } else { + FFWarn(@"I-RDB034018", @"Authentication failed: %@ (%@)", + status, responseData); + } + [self.realtime close]; + } + }]; } -- (void) sendUnauth { - [self sendAction:kFWPRequestActionUnauth body:@{} sensitive:NO callback:nil]; +- (void)sendUnauth { + [self sendAction:kFWPRequestActionUnauth + body:@{} + sensitive:NO + callback:nil]; } -- (void) onAuthRevokedWithStatus:(NSString *)status andReason:(NSString *)reason { - // This might be for an earlier token than we just recently sent. But since we need to close the connection anyways, - // we can set it to null here and we will refresh the token later on reconnect +- (void)onAuthRevokedWithStatus:(NSString *)status + andReason:(NSString *)reason { + // This might be for an earlier token than we just recently sent. But since + // we need to close the connection anyways, we can set it to null here and + // we will refresh the token later on reconnect if ([status isEqualToString:@"expired_token"]) { FFLog(@"I-RDB034019", @"Auth token revoked: %@ (%@)", status, reason); } else { @@ -538,70 +635,87 @@ - (void) onAuthRevokedWithStatus:(NSString *)status andReason:(NSString *)reason [self.realtime close]; } -- (void) onListenRevoked:(FPath *)path { +- (void)onListenRevoked:(FPath *)path { NSArray *queries = [self removeAllListensAtPath:path]; - for (FOutstandingQuery* query in queries) { + for (FOutstandingQuery *query in queries) { query.onComplete(@"permission_denied"); } } -- (void) sendOnDisconnectAction:(NSString *)action forPath:(NSString *)pathString withData:(id)data andCallback:(fbt_void_nsstring_nsstring)callback { +- (void)sendOnDisconnectAction:(NSString *)action + forPath:(NSString *)pathString + withData:(id)data + andCallback:(fbt_void_nsstring_nsstring)callback { - NSDictionary* request = @{kFWPRequestPath: pathString, kFWPRequestData: data}; + NSDictionary *request = + @{kFWPRequestPath : pathString, kFWPRequestData : data}; FFLog(@"I-RDB034021", @"onDisconnect %@: %@", action, request); [self sendAction:action body:request sensitive:NO callback:^(NSDictionary *data) { - NSString* status = [data objectForKey:kFWPResponseForActionStatus]; - NSString* errorReason = [data objectForKey:kFWPResponseForActionData]; - callback(status, errorReason); - }]; + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + NSString *errorReason = + [data objectForKey:kFWPResponseForActionData]; + callback(status, errorReason); + }]; } -- (void) sendPut:(NSNumber *) index { - NSAssert([self canSendWrites], @"sendPut called when not able to send writes"); - FOutstandingPut* put = self.outstandingPuts[index]; +- (void)sendPut:(NSNumber *)index { + NSAssert([self canSendWrites], + @"sendPut called when not able to send writes"); + FOutstandingPut *put = self.outstandingPuts[index]; assert(put != nil); fbt_void_nsstring_nsstring onComplete = put.onCompleteBlock; - // Do not async this block; copying the block insinde sendAction: doesn't happen in time (or something) so coredumps + // Do not async this block; copying the block insinde sendAction: doesn't + // happen in time (or something) so coredumps put.sent = YES; [self sendAction:put.action body:put.request sensitive:NO - callback:^(NSDictionary* data) { - - FOutstandingPut *currentPut = self.outstandingPuts[index]; - if (currentPut == put) { - [self.outstandingPuts removeObjectForKey:index]; - - if (onComplete != nil) { - NSString *status = [data objectForKey:kFWPResponseForActionStatus]; - NSString *errorReason = [data objectForKey:kFWPResponseForActionData]; - if (self.unackedListensCount == 0) { - onComplete(status, errorReason); - } else { - FTupleCallbackStatus *putToAck = [[FTupleCallbackStatus alloc] init]; - putToAck.block = onComplete; - putToAck.status = status; - putToAck.errorReason = errorReason; - [self.putsToAck addObject:putToAck]; - } - } - } else { - FFLog(@"I-RDB034022", @"Ignoring on complete for put %@ because it was already removed", index); - } - }]; + callback:^(NSDictionary *data) { + FOutstandingPut *currentPut = self.outstandingPuts[index]; + if (currentPut == put) { + [self.outstandingPuts removeObjectForKey:index]; + + if (onComplete != nil) { + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + NSString *errorReason = + [data objectForKey:kFWPResponseForActionData]; + if (self.unackedListensCount == 0) { + onComplete(status, errorReason); + } else { + FTupleCallbackStatus *putToAck = + [[FTupleCallbackStatus alloc] init]; + putToAck.block = onComplete; + putToAck.status = status; + putToAck.errorReason = errorReason; + [self.putsToAck addObject:putToAck]; + } + } + } else { + FFLog(@"I-RDB034022", + @"Ignoring on complete for put %@ because it was " + @"already removed", + index); + } + }]; } -- (void) sendUnlisten:(FPath *)path queryParams:(FQueryParams *)queryParams tagId:(NSNumber *)tagId { +- (void)sendUnlisten:(FPath *)path + queryParams:(FQueryParams *)queryParams + tagId:(NSNumber *)tagId { FFLog(@"I-RDB034023", @"Unlisten on %@ for %@", path, queryParams); - NSMutableDictionary* request = [NSMutableDictionary dictionaryWithObjectsAndKeys:[path toString], kFWPRequestPath, nil]; + NSMutableDictionary *request = [NSMutableDictionary + dictionaryWithObjectsAndKeys:[path toString], kFWPRequestPath, nil]; if (tagId != nil) { - [request setObject:queryParams.wireProtocolParams forKey:kFWPRequestQueries]; + [request setObject:queryParams.wireProtocolParams + forKey:kFWPRequestQueries]; [request setObject:tagId forKey:kFWPRequestTag]; } @@ -611,12 +725,16 @@ - (void) sendUnlisten:(FPath *)path queryParams:(FQueryParams *)queryParams tagI callback:nil]; } -- (void) putInternal:(id)data forAction:(NSString *)action forPath:(NSString *)pathString withHash:(NSString *)hash withCallback:(fbt_void_nsstring_nsstring)onComplete { +- (void)putInternal:(id)data + forAction:(NSString *)action + forPath:(NSString *)pathString + withHash:(NSString *)hash + withCallback:(fbt_void_nsstring_nsstring)onComplete { - NSMutableDictionary *request = [NSMutableDictionary dictionaryWithObjectsAndKeys: - pathString, kFWPRequestPath, - data, kFWPRequestData, nil]; - if(hash) { + NSMutableDictionary *request = [NSMutableDictionary + dictionaryWithObjectsAndKeys:pathString, kFWPRequestPath, data, + kFWPRequestData, nil]; + if (hash) { [request setObject:hash forKey:kFWPRequestHash]; } @@ -626,64 +744,75 @@ - (void) putInternal:(id)data forAction:(NSString *)action forPath:(NSString *)p put.onCompleteBlock = onComplete; put.sent = NO; - NSNumber* index = [self.putCounter getAndIncrement]; + NSNumber *index = [self.putCounter getAndIncrement]; self.outstandingPuts[index] = put; if ([self canSendWrites]) { FFLog(@"I-RDB034024", @"Was connected, and added as index: %@", index); [self sendPut:index]; - } - else { - FFLog(@"I-RDB034025", @"Wasn't connected or writes paused, so added to outstanding puts only. Path: %@", pathString); + } else { + FFLog(@"I-RDB034025", + @"Wasn't connected or writes paused, so added to outstanding " + @"puts only. Path: %@", + pathString); } } -- (void) sendListen:(FOutstandingQuery *)listenSpec { +- (void)sendListen:(FOutstandingQuery *)listenSpec { FQuerySpec *query = listenSpec.query; FFLog(@"I-RDB034026", @"Listen for %@", query); - NSMutableDictionary *request = [NSMutableDictionary dictionaryWithObject:[query.path toString] forKey:kFWPRequestPath]; + NSMutableDictionary *request = + [NSMutableDictionary dictionaryWithObject:[query.path toString] + forKey:kFWPRequestPath]; // Only bother to send query if it's non-default if (listenSpec.tagId != nil) { - [request setObject:[query.params wireProtocolParams] forKey:kFWPRequestQueries]; + [request setObject:[query.params wireProtocolParams] + forKey:kFWPRequestQueries]; [request setObject:listenSpec.tagId forKey:kFWPRequestTag]; } - [request setObject:[listenSpec.syncTreeHash simpleHash] forKey:kFWPRequestHash]; + [request setObject:[listenSpec.syncTreeHash simpleHash] + forKey:kFWPRequestHash]; if ([listenSpec.syncTreeHash includeCompoundHash]) { FCompoundHash *compoundHash = [listenSpec.syncTreeHash compoundHash]; NSMutableArray *posts = [NSMutableArray array]; for (FPath *path in compoundHash.posts) { [posts addObject:path.wireFormat]; } - request[kFWPRequestCompoundHash] = @{ kFWPRequestCompoundHashHashes: compoundHash.hashes, - kFWPRequestCompoundHashPaths: posts }; + request[kFWPRequestCompoundHash] = @{ + kFWPRequestCompoundHashHashes : compoundHash.hashes, + kFWPRequestCompoundHashPaths : posts + }; } fbt_void_nsdictionary onResponse = ^(NSDictionary *response) { - FFLog(@"I-RDB034027", @"Listen response %@", response); - // warn in any case, even if the listener was removed - [self warnOnListenWarningsForQuery:query payload:response[kFWPResponseForActionData]]; - - FOutstandingQuery *currentListenSpec = self.listens[query]; - - // only trigger actions if the listen hasn't been removed (and maybe readded) - if (currentListenSpec == listenSpec) { - NSString *status = [response objectForKey:kFWPRequestStatus]; - if (![status isEqualToString:@"ok"]) { - [self removeListen:query]; - } - - if (listenSpec.onComplete) { - listenSpec.onComplete(status); - } - } - - self.unackedListensCount--; - NSAssert(self.unackedListensCount >= 0, @"unackedListensCount decremented to be negative."); - if (self.unackedListensCount == 0) { - [self ackPuts]; - } + FFLog(@"I-RDB034027", @"Listen response %@", response); + // warn in any case, even if the listener was removed + [self warnOnListenWarningsForQuery:query + payload:response[kFWPResponseForActionData]]; + + FOutstandingQuery *currentListenSpec = self.listens[query]; + + // only trigger actions if the listen hasn't been removed (and maybe + // readded) + if (currentListenSpec == listenSpec) { + NSString *status = [response objectForKey:kFWPRequestStatus]; + if (![status isEqualToString:@"ok"]) { + [self removeListen:query]; + } + + if (listenSpec.onComplete) { + listenSpec.onComplete(status); + } + } + + self.unackedListensCount--; + NSAssert(self.unackedListensCount >= 0, + @"unackedListensCount decremented to be negative."); + if (self.unackedListensCount == 0) { + [self ackPuts]; + } }; [self sendAction:kFWPRequestActionTaggedListen @@ -694,82 +823,107 @@ - (void) sendListen:(FOutstandingQuery *)listenSpec { self.unackedListensCount++; } -- (void) warnOnListenWarningsForQuery:(FQuerySpec *)query payload:(id)payload { +- (void)warnOnListenWarningsForQuery:(FQuerySpec *)query payload:(id)payload { if (payload != nil && [payload isKindOfClass:[NSDictionary class]]) { NSDictionary *payloadDict = payload; id warnings = payloadDict[kFWPResponseDataWarnings]; if (warnings != nil && [warnings isKindOfClass:[NSArray class]]) { NSArray *warningsArr = warnings; if ([warningsArr containsObject:@"no_index"]) { - NSString *indexSpec = [NSString stringWithFormat:@"\".indexOn\": \"%@\"", [query.params.index queryDefinition]]; + NSString *indexSpec = [NSString + stringWithFormat:@"\".indexOn\": \"%@\"", + [query.params.index queryDefinition]]; NSString *indexPath = [query.path description]; - FFWarn(@"I-RDB034028", @"Using an unspecified index. Your data will be downloaded and filtered on the client. " - "Consider adding %@ at %@ to your security rules for better performance", indexSpec, indexPath); + FFWarn(@"I-RDB034028", + @"Using an unspecified index. Your data will be " + @"downloaded and filtered on the client. " + "Consider adding %@ at %@ to your security rules for " + "better performance", + indexSpec, indexPath); } } } } -- (int) getNextRequestNumber { +- (int)getNextRequestNumber { return [[self.requestNumber getAndIncrement] intValue]; } - (void)sendAction:(NSString *)action body:(NSDictionary *)message sensitive:(BOOL)sensitive - callback:(void (^)(NSDictionary* data))onMessage { + callback:(void (^)(NSDictionary *data))onMessage { // Hold onto the onMessage callback for this request before firing it off - NSNumber* rn = [NSNumber numberWithInt:[self getNextRequestNumber]]; - NSDictionary* msg = [NSDictionary dictionaryWithObjectsAndKeys: - rn, kFWPRequestNumber, - action, kFWPRequestAction, - message, kFWPRequestPayloadBody, - nil]; + NSNumber *rn = [NSNumber numberWithInt:[self getNextRequestNumber]]; + NSDictionary *msg = [NSDictionary + dictionaryWithObjectsAndKeys:rn, kFWPRequestNumber, action, + kFWPRequestAction, message, + kFWPRequestPayloadBody, nil]; [self.realtime sendRequest:msg sensitive:sensitive]; if (onMessage) { - // Debug message without a callback; bump the rn, but don't hold onto the cb + // Debug message without a callback; bump the rn, but don't hold onto + // the cb [self.requestCBHash setObject:[onMessage copy] forKey:rn]; } } -- (void) cancelSentTransactions { - NSMutableDictionary* cancelledOutstandingPuts = [[NSMutableDictionary alloc] init]; +- (void)cancelSentTransactions { + NSMutableDictionary + *cancelledOutstandingPuts = [[NSMutableDictionary alloc] init]; - for (NSNumber* index in self.outstandingPuts) { - FOutstandingPut* put = self.outstandingPuts[index]; + for (NSNumber *index in self.outstandingPuts) { + FOutstandingPut *put = self.outstandingPuts[index]; if (put.request[kFWPRequestHash] && put.sent) { // This is a sent transaction put. cancelledOutstandingPuts[index] = put; } } - [cancelledOutstandingPuts enumerateKeysAndObjectsUsingBlock:^(NSNumber *index, FOutstandingPut *outstandingPut, BOOL *stop) { - // `onCompleteBlock:` may invoke `rerunTransactionsForPath:` and enqueue new writes. We defer calling - // it until we have finished enumerating all existing writes. - outstandingPut.onCompleteBlock(kFTransactionDisconnect, @"Client was disconnected while running a transaction"); - [self.outstandingPuts removeObjectForKey:index]; - }]; + [cancelledOutstandingPuts + enumerateKeysAndObjectsUsingBlock:^( + NSNumber *index, FOutstandingPut *outstandingPut, BOOL *stop) { + // `onCompleteBlock:` may invoke `rerunTransactionsForPath:` and + // enqueue new writes. We defer calling it until we have finished + // enumerating all existing writes. + outstandingPut.onCompleteBlock( + kFTransactionDisconnect, + @"Client was disconnected while running a transaction"); + [self.outstandingPuts removeObjectForKey:index]; + }]; } -- (void) onDataPushWithAction:(NSString *)action andBody:(NSDictionary *)body { +- (void)onDataPushWithAction:(NSString *)action andBody:(NSDictionary *)body { FFLog(@"I-RDB034029", @"handleServerMessage: %@, %@", action, body); id delegate = self.delegate; - if ([action isEqualToString:kFWPAsyncServerDataUpdate] || [action isEqualToString:kFWPAsyncServerDataMerge]) { + if ([action isEqualToString:kFWPAsyncServerDataUpdate] || + [action isEqualToString:kFWPAsyncServerDataMerge]) { BOOL isMerge = [action isEqualToString:kFWPAsyncServerDataMerge]; - if ([body objectForKey:kFWPAsyncServerDataUpdateBodyPath] && [body objectForKey:kFWPAsyncServerDataUpdateBodyData]) { - NSString* path = [body objectForKey:kFWPAsyncServerDataUpdateBodyPath]; - id payloadData = [body objectForKey:kFWPAsyncServerDataUpdateBodyData]; - if (isMerge && [payloadData isKindOfClass:[NSDictionary class]] && [payloadData count] == 0) { + if ([body objectForKey:kFWPAsyncServerDataUpdateBodyPath] && + [body objectForKey:kFWPAsyncServerDataUpdateBodyData]) { + NSString *path = + [body objectForKey:kFWPAsyncServerDataUpdateBodyPath]; + id payloadData = + [body objectForKey:kFWPAsyncServerDataUpdateBodyData]; + if (isMerge && [payloadData isKindOfClass:[NSDictionary class]] && + [payloadData count] == 0) { // ignore empty merge } else { - [delegate onDataUpdate:self forPath:path message:payloadData isMerge:isMerge tagId:[body objectForKey:kFWPAsyncServerDataUpdateBodyTag]]; + [delegate + onDataUpdate:self + forPath:path + message:payloadData + isMerge:isMerge + tagId:[body objectForKey: + kFWPAsyncServerDataUpdateBodyTag]]; } - } - else { - FFLog(@"I-RDB034030", @"Malformed data response from server missing path or data: %@", body); + } else { + FFLog( + @"I-RDB034030", + @"Malformed data response from server missing path or data: %@", + body); } } else if ([action isEqualToString:kFWPAsyncServerDataRangeMerge]) { NSString *path = body[kFWPAsyncServerDataUpdateBodyPath]; @@ -781,24 +935,30 @@ - (void) onDataPushWithAction:(NSString *)action andBody:(NSDictionary *)body { NSString *endString = range[kFWPAsyncServerDataUpdateEndPath]; id updateData = range[kFWPAsyncServerDataUpdateRangeMerge]; id updates = [FSnapshotUtilities nodeFrom:updateData]; - FPath *start = (startString != nil) ? [[FPath alloc] initWith:startString] : nil; - FPath *end = (endString != nil) ? [[FPath alloc] initWith:endString] : nil; - FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:start end:end updates:updates]; + FPath *start = (startString != nil) + ? [[FPath alloc] initWith:startString] + : nil; + FPath *end = + (endString != nil) ? [[FPath alloc] initWith:endString] : nil; + FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:start + end:end + updates:updates]; [rangeMerges addObject:merge]; } [delegate onRangeMerge:rangeMerges forPath:path tagId:tag]; } else if ([action isEqualToString:kFWPAsyncServerAuthRevoked]) { - NSString* status = [body objectForKey:kFWPResponseForActionStatus]; - NSString* reason = [body objectForKey:kFWPResponseForActionData]; + NSString *status = [body objectForKey:kFWPResponseForActionStatus]; + NSString *reason = [body objectForKey:kFWPResponseForActionData]; [self onAuthRevokedWithStatus:status andReason:reason]; } else if ([action isEqualToString:kFWPASyncServerListenCancelled]) { - NSString* pathString = [body objectForKey:kFWPAsyncServerDataUpdateBodyPath]; + NSString *pathString = + [body objectForKey:kFWPAsyncServerDataUpdateBodyPath]; [self onListenRevoked:[[FPath alloc] initWith:pathString]]; } else if ([action isEqualToString:kFWPAsyncServerSecurityDebug]) { - NSString* msg = [body objectForKey:@"msg"]; + NSString *msg = [body objectForKey:@"msg"]; if (msg != nil) { NSArray *msgs = [msg componentsSeparatedByString:@"\n"]; - for (NSString* m in msgs) { + for (NSString *m in msgs) { FFWarn(@"I-RDB034031", @"%@", m); } } @@ -808,11 +968,12 @@ - (void) onDataPushWithAction:(NSString *)action andBody:(NSDictionary *)body { } } -- (void) restoreAuth { +- (void)restoreAuth { FFLog(@"I-RDB034033", @"Calling restore state"); NSAssert(self->connectionState == ConnectionStateConnecting, - @"Wanted to restore auth, but was in wrong state: %d", self->connectionState); + @"Wanted to restore auth, but was in wrong state: %d", + self->connectionState); if (self.authToken == nil) { FFLog(@"I-RDB034034", @"Not restoring auth because token is nil"); self->connectionState = ConnectionStateConnected; @@ -824,64 +985,77 @@ - (void) restoreAuth { } } -- (void) restoreState { +- (void)restoreState { NSAssert(self->connectionState == ConnectionStateConnected, - @"Should be connected if we're restoring state, but we are: %d", self->connectionState); - - [self.listens enumerateKeysAndObjectsUsingBlock:^(FQuerySpec *query, FOutstandingQuery *outstandingListen, BOOL *stop) { - FFLog(@"I-RDB034036", @"Restoring listen for %@", query); - [self sendListen:outstandingListen]; + @"Should be connected if we're restoring state, but we are: %d", + self->connectionState); + + [self.listens enumerateKeysAndObjectsUsingBlock:^( + FQuerySpec *query, FOutstandingQuery *outstandingListen, + BOOL *stop) { + FFLog(@"I-RDB034036", @"Restoring listen for %@", query); + [self sendListen:outstandingListen]; }]; - NSArray* keys = [[self.outstandingPuts allKeys] sortedArrayUsingSelector:@selector(compare:)]; - for(int i = 0; i < [keys count]; i++) { - if([self.outstandingPuts objectForKey:[keys objectAtIndex:i]] != nil) { + NSArray *keys = [[self.outstandingPuts allKeys] + sortedArrayUsingSelector:@selector(compare:)]; + for (int i = 0; i < [keys count]; i++) { + if ([self.outstandingPuts objectForKey:[keys objectAtIndex:i]] != nil) { FFLog(@"I-RDB034037", @"Restoring put: %d", i); [self sendPut:[keys objectAtIndex:i]]; - } - else { + } else { FFLog(@"I-RDB034038", @"Restoring put: skipped nil: %d", i); } } - for (FTupleOnDisconnect* tuple in self.onDisconnectQueue) { - [self sendOnDisconnectAction:tuple.action forPath:tuple.pathString withData:tuple.data andCallback:tuple.onComplete]; + for (FTupleOnDisconnect *tuple in self.onDisconnectQueue) { + [self sendOnDisconnectAction:tuple.action + forPath:tuple.pathString + withData:tuple.data + andCallback:tuple.onComplete]; } [self.onDisconnectQueue removeAllObjects]; } -- (NSArray *) removeListen:(FQuerySpec *)query { - NSAssert(query.isDefault || !query.loadsAllData, @"removeListen called for non-default but complete query"); +- (NSArray *)removeListen:(FQuerySpec *)query { + NSAssert(query.isDefault || !query.loadsAllData, + @"removeListen called for non-default but complete query"); - FOutstandingQuery* outstanding = self.listens[query]; + FOutstandingQuery *outstanding = self.listens[query]; if (!outstanding) { - FFLog(@"I-RDB034039", @"Trying to remove listener for query %@ but no listener exists", query); + FFLog(@"I-RDB034039", + @"Trying to remove listener for query %@ but no listener exists", + query); return @[]; } else { [self.listens removeObjectForKey:query]; - return @[outstanding]; + return @[ outstanding ]; } } -- (NSArray *) removeAllListensAtPath:(FPath *)path { +- (NSArray *)removeAllListensAtPath:(FPath *)path { FFLog(@"I-RDB034040", @"Removing all listens at path %@", path); NSMutableArray *removed = [NSMutableArray array]; NSMutableArray *toRemove = [NSMutableArray array]; - [self.listens enumerateKeysAndObjectsUsingBlock:^(FQuerySpec *spec, FOutstandingQuery *outstanding, BOOL *stop) { - if ([spec.path isEqual:path]) { - [removed addObject:outstanding]; - [toRemove addObject:spec]; - } - }]; + [self.listens + enumerateKeysAndObjectsUsingBlock:^( + FQuerySpec *spec, FOutstandingQuery *outstanding, BOOL *stop) { + if ([spec.path isEqual:path]) { + [removed addObject:outstanding]; + [toRemove addObject:spec]; + } + }]; [self.listens removeObjectsForKeys:toRemove]; return removed; } -- (void) purgeOutstandingWrites { - // We might have unacked puts in our queue that we need to ack now before we send out any cancels... +- (void)purgeOutstandingWrites { + // We might have unacked puts in our queue that we need to ack now before we + // send out any cancels... [self ackPuts]; // Cancel in order - NSArray* keys = [[self.outstandingPuts allKeys] sortedArrayUsingSelector:@selector(compare:)]; + NSArray *keys = [[self.outstandingPuts allKeys] + sortedArrayUsingSelector:@selector(compare:)]; for (NSNumber *key in keys) { FOutstandingPut *put = self.outstandingPuts[key]; if (put.onCompleteBlock != nil) { @@ -897,55 +1071,70 @@ - (void) purgeOutstandingWrites { [self.onDisconnectQueue removeAllObjects]; } -- (void) ackPuts { +- (void)ackPuts { for (FTupleCallbackStatus *put in self.putsToAck) { put.block(put.status, put.errorReason); } [self.putsToAck removeAllObjects]; } -- (void) handleTimestamp:(NSNumber *)timestamp { +- (void)handleTimestamp:(NSNumber *)timestamp { FFLog(@"I-RDB034041", @"Handling timestamp: %@", timestamp); - double timestampDeltaMs = [timestamp doubleValue] - ([[NSDate date] timeIntervalSince1970] * 1000); - [self.delegate onServerInfoUpdate:self updates:@{kDotInfoServerTimeOffset: [NSNumber numberWithDouble:timestampDeltaMs]}]; + double timestampDeltaMs = [timestamp doubleValue] - + ([[NSDate date] timeIntervalSince1970] * 1000); + [self.delegate onServerInfoUpdate:self + updates:@{ + kDotInfoServerTimeOffset : [NSNumber + numberWithDouble:timestampDeltaMs] + }]; } -- (void) sendStats:(NSDictionary *)stats { +- (void)sendStats:(NSDictionary *)stats { if ([stats count] > 0) { - NSDictionary *request = @{ kFWPRequestCounters: stats }; - [self sendAction:kFWPRequestActionStats body:request sensitive:NO callback:^(NSDictionary *data) { - NSString* status = [data objectForKey:kFWPResponseForActionStatus]; - NSString* errorReason = [data objectForKey:kFWPResponseForActionData]; - BOOL statusOk = [status isEqualToString:kFWPResponseForActionStatusOk]; - if (!statusOk) { - FFLog(@"I-RDB034042", @"Failed to send stats: %@", errorReason); - } - }]; + NSDictionary *request = @{kFWPRequestCounters : stats}; + [self sendAction:kFWPRequestActionStats + body:request + sensitive:NO + callback:^(NSDictionary *data) { + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + NSString *errorReason = + [data objectForKey:kFWPResponseForActionData]; + BOOL statusOk = + [status isEqualToString:kFWPResponseForActionStatusOk]; + if (!statusOk) { + FFLog(@"I-RDB034042", @"Failed to send stats: %@", + errorReason); + } + }]; } else { FFLog(@"I-RDB034043", @"Not sending stats because stats are empty"); } } -- (void) sendConnectStats { +- (void)sendConnectStats { NSMutableDictionary *stats = [NSMutableDictionary dictionary]; - #if TARGET_OS_IOS || TARGET_OS_TV +#if TARGET_OS_IOS || TARGET_OS_TV if (self.config.persistenceEnabled) { stats[@"persistence.ios.enabled"] = @1; } - #elif TARGET_OS_OSX +#elif TARGET_OS_OSX if (self.config.persistenceEnabled) { stats[@"persistence.osx.enabled"] = @1; } - #endif - NSString *sdkVersion = [[FIRDatabase sdkVersion] stringByReplacingOccurrencesOfString:@"." withString:@"-"]; - NSString *sdkStatName = [NSString stringWithFormat:@"sdk.objc.%@", sdkVersion]; +#endif + NSString *sdkVersion = + [[FIRDatabase sdkVersion] stringByReplacingOccurrencesOfString:@"." + withString:@"-"]; + NSString *sdkStatName = + [NSString stringWithFormat:@"sdk.objc.%@", sdkVersion]; stats[sdkStatName] = @1; FFLog(@"I-RDB034044", @"Sending first connection stats"); [self sendStats:stats]; } -- (NSDictionary *) dumpListens { +- (NSDictionary *)dumpListens { return self.listens; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQueryParams.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQueryParams.h index e9728e7..5d957c5 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQueryParams.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQueryParams.h @@ -16,44 +16,45 @@ #import -@protocol FIndex, FNodeFilter, FNode; +@protocol FIndex +, FNodeFilter, FNode; @interface FQueryParams : NSObject -@property (nonatomic, readonly) BOOL limitSet; -@property (nonatomic, readonly) NSInteger limit; +@property(nonatomic, readonly) BOOL limitSet; +@property(nonatomic, readonly) NSInteger limit; -@property (nonatomic, strong, readonly) NSString *viewFrom; -@property (nonatomic, strong, readonly) id indexStartValue; -@property (nonatomic, strong, readonly) NSString *indexStartKey; -@property (nonatomic, strong, readonly) id indexEndValue; -@property (nonatomic, strong, readonly) NSString *indexEndKey; +@property(nonatomic, strong, readonly) NSString *viewFrom; +@property(nonatomic, strong, readonly) id indexStartValue; +@property(nonatomic, strong, readonly) NSString *indexStartKey; +@property(nonatomic, strong, readonly) id indexEndValue; +@property(nonatomic, strong, readonly) NSString *indexEndKey; -@property (nonatomic, strong, readonly) id index; +@property(nonatomic, strong, readonly) id index; - (BOOL)loadsAllData; - (BOOL)isDefault; - (BOOL)isValid; - (BOOL)hasAnchoredLimit; -- (FQueryParams *) limitTo:(NSInteger) limit; -- (FQueryParams *) limitToFirst:(NSInteger) newLimit; -- (FQueryParams *) limitToLast:(NSInteger) newLimit; +- (FQueryParams *)limitTo:(NSInteger)limit; +- (FQueryParams *)limitToFirst:(NSInteger)newLimit; +- (FQueryParams *)limitToLast:(NSInteger)newLimit; -- (FQueryParams *) startAt:(id)indexValue childKey:(NSString *)key; -- (FQueryParams *) startAt:(id)indexValue; -- (FQueryParams *) endAt:(id)indexValue childKey:(NSString *)key; -- (FQueryParams *) endAt:(id)indexValue; +- (FQueryParams *)startAt:(id)indexValue childKey:(NSString *)key; +- (FQueryParams *)startAt:(id)indexValue; +- (FQueryParams *)endAt:(id)indexValue childKey:(NSString *)key; +- (FQueryParams *)endAt:(id)indexValue; -- (FQueryParams *) orderBy:(id) index; +- (FQueryParams *)orderBy:(id)index; -+ (FQueryParams *) defaultInstance; -+ (FQueryParams *) fromQueryObject:(NSDictionary *)dict; ++ (FQueryParams *)defaultInstance; ++ (FQueryParams *)fromQueryObject:(NSDictionary *)dict; - (BOOL)hasStart; - (BOOL)hasEnd; -- (NSDictionary *) wireProtocolParams; -- (BOOL) isViewFromLeft; -- (id) nodeFilter; +- (NSDictionary *)wireProtocolParams; +- (BOOL)isViewFromLeft; +- (id)nodeFilter; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQueryParams.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQueryParams.m index 7920358..c19cfba 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQueryParams.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQueryParams.m @@ -15,51 +15,50 @@ */ #import "FQueryParams.h" -#import "FValidation.h" #import "FConstants.h" #import "FIndex.h" -#import "FPriorityIndex.h" -#import "FUtilities.h" -#import "FNodeFilter.h" #import "FIndexedFilter.h" #import "FLimitedFilter.h" -#import "FRangedFilter.h" #import "FNode.h" +#import "FNodeFilter.h" +#import "FPriorityIndex.h" +#import "FRangedFilter.h" #import "FSnapshotUtilities.h" +#import "FUtilities.h" +#import "FValidation.h" @interface FQueryParams () -@property (nonatomic, readwrite) BOOL limitSet; -@property (nonatomic, readwrite) NSInteger limit; +@property(nonatomic, readwrite) BOOL limitSet; +@property(nonatomic, readwrite) NSInteger limit; -@property (nonatomic, strong, readwrite) NSString *viewFrom; +@property(nonatomic, strong, readwrite) NSString *viewFrom; /** -* indexStartValue is anything you can store as a priority / value. -*/ -@property (nonatomic, strong, readwrite) id indexStartValue; -@property (nonatomic, strong, readwrite) NSString *indexStartKey; + * indexStartValue is anything you can store as a priority / value. + */ +@property(nonatomic, strong, readwrite) id indexStartValue; +@property(nonatomic, strong, readwrite) NSString *indexStartKey; /** -* indexStartValue is anything you can store as a priority / value. -*/ -@property (nonatomic, strong, readwrite) id indexEndValue; -@property (nonatomic, strong, readwrite) NSString *indexEndKey; + * indexStartValue is anything you can store as a priority / value. + */ +@property(nonatomic, strong, readwrite) id indexEndValue; +@property(nonatomic, strong, readwrite) NSString *indexEndKey; -@property (nonatomic, strong, readwrite) id index; +@property(nonatomic, strong, readwrite) id index; @end @implementation FQueryParams -+ (FQueryParams *) defaultInstance { ++ (FQueryParams *)defaultInstance { static FQueryParams *defaultParams = nil; static dispatch_once_t defaultParamsToken; dispatch_once(&defaultParamsToken, ^{ - defaultParams = [[FQueryParams alloc] init]; + defaultParams = [[FQueryParams alloc] init]; }); return defaultParams; } - - (id)init { self = [super init]; if (self) { @@ -78,18 +77,18 @@ - (id)init { } /** -* Only valid if hasStart is true -*/ -- (id) indexStartValue { + * Only valid if hasStart is true + */ +- (id)indexStartValue { NSAssert([self hasStart], @"Only valid if start has been set"); return _indexStartValue; } /** -* Only valid if hasStart is true. -* @return The starting key name for the range defined by these query parameters -*/ -- (NSString *) indexStartKey { + * Only valid if hasStart is true. + * @return The starting key name for the range defined by these query parameters + */ +- (NSString *)indexStartKey { NSAssert([self hasStart], @"Only valid if start has been set"); if (_indexStartKey == nil) { return [FUtilities minName]; @@ -99,18 +98,18 @@ - (NSString *) indexStartKey { } /** -* Only valid if hasEnd is true. -*/ -- (id) indexEndValue { + * Only valid if hasEnd is true. + */ +- (id)indexEndValue { NSAssert([self hasEnd], @"Only valid if end has been set"); return _indexEndValue; } /** -* Only valid if hasEnd is true. -* @return The end key name for the range defined by these query parameters -*/ -- (NSString *) indexEndKey { + * Only valid if hasEnd is true. + * @return The end key name for the range defined by these query parameters + */ +- (NSString *)indexEndKey { NSAssert([self hasEnd], @"Only valid if end has been set"); if (_indexEndKey == nil) { return [FUtilities maxName]; @@ -120,16 +119,16 @@ - (NSString *) indexEndKey { } /** -* @return true if a limit has been set and has been explicitly anchored -*/ -- (BOOL) hasAnchoredLimit { + * @return true if a limit has been set and has been explicitly anchored + */ +- (BOOL)hasAnchoredLimit { return self.limitSet && self.viewFrom != nil; } /** -* Only valid to call if limitSet returns true -*/ -- (NSInteger) limit { + * Only valid to call if limitSet returns true + */ +- (NSInteger)limit { NSAssert(self.limitSet, @"Only valid if limit has been set"); return _limit; } @@ -142,13 +141,13 @@ - (BOOL)hasEnd { return self->_indexEndValue != nil; } -- (id) copyWithZone:(NSZone *)zone { +- (id)copyWithZone:(NSZone *)zone { // Immutable return self; } -- (id) mutableCopy { - FQueryParams* other = [[[self class] alloc] init]; +- (id)mutableCopy { + FQueryParams *other = [[[self class] alloc] init]; // Maybe need to do extra copying here other->_limitSet = _limitSet; other->_limit = _limit; @@ -161,7 +160,7 @@ - (id) mutableCopy { return other; } -- (FQueryParams *) limitTo:(NSInteger)newLimit { +- (FQueryParams *)limitTo:(NSInteger)newLimit { FQueryParams *newParams = [self mutableCopy]; newParams->_limitSet = YES; newParams->_limit = newLimit; @@ -169,7 +168,7 @@ - (FQueryParams *) limitTo:(NSInteger)newLimit { return newParams; } -- (FQueryParams *) limitToFirst:(NSInteger)newLimit { +- (FQueryParams *)limitToFirst:(NSInteger)newLimit { FQueryParams *newParams = [self mutableCopy]; newParams->_limitSet = YES; newParams->_limit = newLimit; @@ -177,7 +176,7 @@ - (FQueryParams *) limitToFirst:(NSInteger)newLimit { return newParams; } -- (FQueryParams *) limitToLast:(NSInteger)newLimit { +- (FQueryParams *)limitToLast:(NSInteger)newLimit { FQueryParams *newParams = [self mutableCopy]; newParams->_limitSet = YES; newParams->_limit = newLimit; @@ -185,7 +184,7 @@ - (FQueryParams *) limitToLast:(NSInteger)newLimit { return newParams; } -- (FQueryParams *) startAt:(id)indexValue childKey:(NSString *)key { +- (FQueryParams *)startAt:(id)indexValue childKey:(NSString *)key { NSAssert([indexValue isLeafNode] || [indexValue isEmpty], nil); FQueryParams *newParams = [self mutableCopy]; newParams->_indexStartValue = indexValue; @@ -193,11 +192,11 @@ - (FQueryParams *) startAt:(id)indexValue childKey:(NSString *)key { return newParams; } -- (FQueryParams *) startAt:(id)indexValue { +- (FQueryParams *)startAt:(id)indexValue { return [self startAt:indexValue childKey:nil]; } -- (FQueryParams *) endAt:(id)indexValue childKey:(NSString *)key { +- (FQueryParams *)endAt:(id)indexValue childKey:(NSString *)key { NSAssert([indexValue isLeafNode] || [indexValue isEmpty], nil); FQueryParams *newParams = [self mutableCopy]; newParams->_indexEndValue = indexValue; @@ -205,20 +204,21 @@ - (FQueryParams *) endAt:(id)indexValue childKey:(NSString *)key { return newParams; } -- (FQueryParams *) endAt:(id)indexValue { +- (FQueryParams *)endAt:(id)indexValue { return [self endAt:indexValue childKey:nil]; } -- (FQueryParams *) orderBy:(id)newIndex { +- (FQueryParams *)orderBy:(id)newIndex { FQueryParams *newParams = [self mutableCopy]; newParams->_index = newIndex; return newParams; } -- (NSDictionary *) wireProtocolParams { - NSMutableDictionary* dict = [[NSMutableDictionary alloc] init]; +- (NSDictionary *)wireProtocolParams { + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; if ([self hasStart]) { - [dict setObject:[self.indexStartValue valForExport:YES] forKey:kFQPIndexStartValue]; + [dict setObject:[self.indexStartValue valForExport:YES] + forKey:kFQPIndexStartValue]; // Don't use property as it will be [MIN-NAME] if (self->_indexStartKey != nil) { @@ -227,7 +227,8 @@ - (NSDictionary *) wireProtocolParams { } if ([self hasEnd]) { - [dict setObject:[self.indexEndValue valForExport:YES] forKey:kFQPIndexEndValue]; + [dict setObject:[self.indexEndValue valForExport:YES] + forKey:kFQPIndexEndValue]; // Don't use property as it will be [MAX-NAME] if (self->_indexEndKey != nil) { @@ -236,13 +237,14 @@ - (NSDictionary *) wireProtocolParams { } if (self.limitSet) { - [dict setObject:[NSNumber numberWithInteger:self.limit] forKey:kFQPLimit]; + [dict setObject:[NSNumber numberWithInteger:self.limit] + forKey:kFQPLimit]; NSString *vf = self.viewFrom; if (vf == nil) { // limit() rather than limitToFirst or limitToLast was called. // This means that only one of startSet or endSet is true. Use them - // to calculate which side of the view to anchor to. If neither is set, - // Anchor to end + // to calculate which side of the view to anchor to. If neither is + // set, Anchor to end if ([self hasStart]) { vf = kFQPViewFromLeft; } else { @@ -252,7 +254,8 @@ - (NSDictionary *) wireProtocolParams { [dict setObject:vf forKey:kFQPViewFrom]; } - // For now, priority index is the default, so we only specify if it's some other index. + // For now, priority index is the default, so we only specify if it's some + // other index. if (![self.index isEqual:[FPriorityIndex priorityIndex]]) { [dict setObject:[self.index queryDefinition] forKey:kFQPIndex]; } @@ -272,14 +275,16 @@ + (FQueryParams *)fromQueryObject:(NSDictionary *)dict { } if (dict[kFQPIndexStartValue] != nil) { - params->_indexStartValue = [FSnapshotUtilities nodeFrom:dict[kFQPIndexStartValue]]; + params->_indexStartValue = + [FSnapshotUtilities nodeFrom:dict[kFQPIndexStartValue]]; if (dict[kFQPIndexStartName] != nil) { params->_indexStartKey = dict[kFQPIndexStartName]; } } if (dict[kFQPIndexEndValue] != nil) { - params->_indexEndValue = [FSnapshotUtilities nodeFrom:dict[kFQPIndexEndValue]]; + params->_indexEndValue = + [FSnapshotUtilities nodeFrom:dict[kFQPIndexEndValue]]; if (dict[kFQPIndexEndName] != nil) { params->_indexEndKey = dict[kFQPIndexEndName]; } @@ -287,8 +292,10 @@ + (FQueryParams *)fromQueryObject:(NSDictionary *)dict { if (dict[kFQPViewFrom] != nil) { NSString *viewFrom = dict[kFQPViewFrom]; - if (![viewFrom isEqualToString:kFQPViewFromLeft] && ![viewFrom isEqualToString:kFQPViewFromRight]) { - [NSException raise:NSInvalidArgumentException format:@"Unknown view from paramter: %@", viewFrom]; + if (![viewFrom isEqualToString:kFQPViewFromLeft] && + ![viewFrom isEqualToString:kFQPViewFromRight]) { + [NSException raise:NSInvalidArgumentException + format:@"Unknown view from paramter: %@", viewFrom]; } params->_viewFrom = viewFrom; } @@ -301,7 +308,7 @@ + (FQueryParams *)fromQueryObject:(NSDictionary *)dict { return params; } -- (BOOL) isViewFromLeft { +- (BOOL)isViewFromLeft { if (self.viewFrom != nil) { // Not null, we can just check return [self.viewFrom isEqualToString:kFQPViewFromLeft]; @@ -311,7 +318,7 @@ - (BOOL) isViewFromLeft { } } -- (id) nodeFilter { +- (id)nodeFilter { if (self.loadsAllData) { return [[FIndexedFilter alloc] initWithIndex:self.index]; } else if (self.limitSet) { @@ -321,24 +328,25 @@ - (BOOL) isViewFromLeft { } } - -- (BOOL) isValid { - return !(self.hasStart && self.hasEnd && self.limitSet && !self.hasAnchoredLimit); +- (BOOL)isValid { + return !(self.hasStart && self.hasEnd && self.limitSet && + !self.hasAnchoredLimit); } -- (BOOL) loadsAllData { +- (BOOL)loadsAllData { return !(self.hasStart || self.hasEnd || self.limitSet); } -- (BOOL) isDefault { - return [self loadsAllData] && [self.index isEqual:[FPriorityIndex priorityIndex]]; +- (BOOL)isDefault { + return [self loadsAllData] && + [self.index isEqual:[FPriorityIndex priorityIndex]]; } -- (NSString *) description { +- (NSString *)description { return [[self wireProtocolParams] description]; } -- (BOOL) isEqual:(id)obj { +- (BOOL)isEqual:(id)obj { if (self == obj) { return YES; } @@ -346,19 +354,32 @@ - (BOOL) isEqual:(id)obj { return NO; } FQueryParams *other = (FQueryParams *)obj; - if (self->_limitSet != other->_limitSet) return NO; - if (self->_limit != other->_limit) return NO; - if ((self->_index != other->_index) && ![self->_index isEqual:other->_index]) return NO; - if ((self->_indexStartKey != other->_indexStartKey) && ![self->_indexStartKey isEqualToString:other->_indexStartKey]) return NO; - if ((self->_indexStartValue != other->_indexStartValue) && ![self->_indexStartValue isEqual:other->_indexStartValue]) return NO; - if ((self->_indexEndKey != other->_indexEndKey) && ![self->_indexEndKey isEqualToString:other->_indexEndKey]) return NO; - if ((self->_indexEndValue != other->_indexEndValue) && ![self->_indexEndValue isEqual:other->_indexEndValue]) return NO; - if ([self isViewFromLeft] != [other isViewFromLeft]) return NO; + if (self->_limitSet != other->_limitSet) + return NO; + if (self->_limit != other->_limit) + return NO; + if ((self->_index != other->_index) && ! + [self->_index isEqual:other->_index]) + return NO; + if ((self->_indexStartKey != other->_indexStartKey) && + ![self->_indexStartKey isEqualToString:other->_indexStartKey]) + return NO; + if ((self->_indexStartValue != other->_indexStartValue) && + ![self->_indexStartValue isEqual:other->_indexStartValue]) + return NO; + if ((self->_indexEndKey != other->_indexEndKey) && + ![self->_indexEndKey isEqualToString:other->_indexEndKey]) + return NO; + if ((self->_indexEndValue != other->_indexEndValue) && + ![self->_indexEndValue isEqual:other->_indexEndValue]) + return NO; + if ([self isViewFromLeft] != [other isViewFromLeft]) + return NO; return YES; } -- (NSUInteger) hash { +- (NSUInteger)hash { NSUInteger result = _limitSet ? _limit : 0; result = 31 * result + ([self isViewFromLeft] ? 1231 : 1237); result = 31 * result + [_indexStartKey hash]; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQuerySpec.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQuerySpec.h index 49ed536..2eece87 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQuerySpec.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQuerySpec.h @@ -16,14 +16,14 @@ #import -#import "FQueryParams.h" -#import "FPath.h" #import "FIndex.h" +#import "FPath.h" +#import "FQueryParams.h" -@interface FQuerySpec : NSObject +@interface FQuerySpec : NSObject -@property (nonatomic, strong, readonly) FPath* path; -@property (nonatomic, strong, readonly) FQueryParams *params; +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) FQueryParams *params; - (id)initWithPath:(FPath *)path params:(FQueryParams *)params; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQuerySpec.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQuerySpec.m index 24be433..c408bf8 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQuerySpec.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FQuerySpec.m @@ -18,9 +18,8 @@ @interface FQuerySpec () -@property (nonatomic, strong, readwrite) FPath* path; -@property (nonatomic, strong, readwrite) FQueryParams *params; - +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, strong, readwrite) FQueryParams *params; @end @@ -36,7 +35,8 @@ - (id)initWithPath:(FPath *)path params:(FQueryParams *)params { } + (FQuerySpec *)defaultQueryAtPath:(FPath *)path { - return [[FQuerySpec alloc] initWithPath:path params:[FQueryParams defaultInstance]]; + return [[FQuerySpec alloc] initWithPath:path + params:[FQueryParams defaultInstance]]; } - (id)copyWithZone:(NSZone *)zone { @@ -79,7 +79,8 @@ - (NSUInteger)hash { } - (NSString *)description { - return [NSString stringWithFormat:@"FQuerySpec (path: %@, params: %@)", self.path, self.params]; + return [NSString stringWithFormat:@"FQuerySpec (path: %@, params: %@)", + self.path, self.params]; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRangeMerge.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRangeMerge.h index 8825e0e..5f7938a 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRangeMerge.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRangeMerge.h @@ -20,15 +20,19 @@ /** * Applies a merge of a snap for a given interval of paths. - * Each leaf in the current node which the relative path lies *after* (the optional) start and lies *before or at* - * (the optional) end will be deleted. Each leaf in snap that lies in the interval will be added to the resulting node. - * Nodes outside of the range are ignored. nil for start and end are sentinel values that represent -infinity and - * +infinity respectively (aka includes any path). - * Priorities of children nodes are treated as leaf children of that node. + * Each leaf in the current node which the relative path lies *after* (the + * optional) start and lies *before or at* (the optional) end will be deleted. + * Each leaf in snap that lies in the interval will be added to the resulting + * node. Nodes outside of the range are ignored. nil for start and end are + * sentinel values that represent -infinity and +infinity respectively (aka + * includes any path). Priorities of children nodes are treated as leaf children + * of that node. */ @interface FRangeMerge : NSObject -- (instancetype)initWithStart:(FPath *)start end:(FPath *)end updates:(id)updates; +- (instancetype)initWithStart:(FPath *)start + end:(FPath *)end + updates:(id)updates; - (id)applyToNode:(id)node; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRangeMerge.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRangeMerge.m index 8bc67bf..3dc1576 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRangeMerge.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRangeMerge.m @@ -20,15 +20,17 @@ @interface FRangeMerge () -@property (nonatomic, strong) FPath *optExclusiveStart; -@property (nonatomic, strong) FPath *optInclusiveEnd; -@property (nonatomic, strong) id updates; +@property(nonatomic, strong) FPath *optExclusiveStart; +@property(nonatomic, strong) FPath *optInclusiveEnd; +@property(nonatomic, strong) id updates; @end @implementation FRangeMerge -- (instancetype)initWithStart:(FPath *)start end:(FPath *)end updates:(id)updates { +- (instancetype)initWithStart:(FPath *)start + end:(FPath *)end + updates:(id)updates { self = [super init]; if (self != nil) { self->_optExclusiveStart = start; @@ -39,22 +41,38 @@ - (instancetype)initWithStart:(FPath *)start end:(FPath *)end updates:(id } - (id)applyToNode:(id)node { - return [self updateRangeInNode:[FPath empty] node:node updates:self.updates]; + return [self updateRangeInNode:[FPath empty] + node:node + updates:self.updates]; } -- (id)updateRangeInNode:(FPath *)currentPath node:(id)node updates:(id)updates { - NSComparisonResult startComparison = (self.optExclusiveStart == nil) ? NSOrderedDescending : [currentPath compare:self.optExclusiveStart]; - NSComparisonResult endComparison = (self.optInclusiveEnd == nil) ? NSOrderedAscending : [currentPath compare:self.optInclusiveEnd]; - BOOL startInNode = self.optExclusiveStart != nil && [currentPath contains:self.optExclusiveStart]; - BOOL endInNode = self.optInclusiveEnd != nil && [currentPath contains:self.optInclusiveEnd]; - if (startComparison == NSOrderedDescending && endComparison == NSOrderedAscending && !endInNode) { +- (id)updateRangeInNode:(FPath *)currentPath + node:(id)node + updates:(id)updates { + NSComparisonResult startComparison = + (self.optExclusiveStart == nil) + ? NSOrderedDescending + : [currentPath compare:self.optExclusiveStart]; + NSComparisonResult endComparison = + (self.optInclusiveEnd == nil) + ? NSOrderedAscending + : [currentPath compare:self.optInclusiveEnd]; + BOOL startInNode = self.optExclusiveStart != nil && + [currentPath contains:self.optExclusiveStart]; + BOOL endInNode = self.optInclusiveEnd != nil && + [currentPath contains:self.optInclusiveEnd]; + if (startComparison == NSOrderedDescending && + endComparison == NSOrderedAscending && !endInNode) { // child is completly contained return updates; - } else if (startComparison == NSOrderedDescending && endInNode && [updates isLeafNode]) { + } else if (startComparison == NSOrderedDescending && endInNode && + [updates isLeafNode]) { return updates; - } else if (startComparison == NSOrderedDescending && endComparison == NSOrderedSame) { + } else if (startComparison == NSOrderedDescending && + endComparison == NSOrderedSame) { NSAssert(endInNode, @"End not in node"); - NSAssert(![updates isLeafNode], @"Found leaf node update, this case should have been handled above."); + NSAssert(![updates isLeafNode], @"Found leaf node update, this case " + @"should have been handled above."); if ([node isLeafNode]) { // Update node was not a leaf node, so we can delete it return [FEmptyNode emptyNode]; @@ -63,25 +81,30 @@ - (instancetype)initWithStart:(FPath *)start end:(FPath *)end updates:(id return node; } } else if (startInNode || endInNode) { - // There is a partial update we need to do, so collect all relevant children + // There is a partial update we need to do, so collect all relevant + // children NSMutableSet *allChildren = [NSMutableSet set]; - [node enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - [allChildren addObject:key]; + [node enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + [allChildren addObject:key]; }]; - [updates enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - [allChildren addObject:key]; + [updates enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + [allChildren addObject:key]; }]; __block id newNode = node; void (^action)(id, BOOL *) = ^void(NSString *key, BOOL *stop) { - id currentChild = [node getImmediateChild:key]; - id updatedChild = [self updateRangeInNode:[currentPath childFromString:key] - node:currentChild - updates:[updates getImmediateChild:key]]; - // Only need to update if the node changed - if (updatedChild != currentChild) { - newNode = [newNode updateImmediateChild:key withNewChild:updatedChild]; - } + id currentChild = [node getImmediateChild:key]; + id updatedChild = + [self updateRangeInNode:[currentPath childFromString:key] + node:currentChild + updates:[updates getImmediateChild:key]]; + // Only need to update if the node changed + if (updatedChild != currentChild) { + newNode = [newNode updateImmediateChild:key + withNewChild:updatedChild]; + } }; [allChildren enumerateObjectsUsingBlock:action]; @@ -94,14 +117,18 @@ - (instancetype)initWithStart:(FPath *)start end:(FPath *)end updates:(id return newNode; } else { // Unaffected by this range - NSAssert(endComparison == NSOrderedDescending || startComparison <= NSOrderedSame, @"Invalid range for update"); + NSAssert(endComparison == NSOrderedDescending || + startComparison <= NSOrderedSame, + @"Invalid range for update"); return node; } } - (NSString *)description { - return [NSString stringWithFormat:@"RangeMerge (optExclusiveStart = %@, optExclusiveEng = %@, updates = %@)", - self.optExclusiveStart, self.optInclusiveEnd, self.updates]; + return [NSString stringWithFormat:@"RangeMerge (optExclusiveStart = %@, " + @"optExclusiveEng = %@, updates = %@)", + self.optExclusiveStart, + self.optInclusiveEnd, self.updates]; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepo.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepo.h index ab0b074..4e3899a 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepo.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepo.h @@ -14,11 +14,11 @@ * limitations under the License. */ -#import -#import "FRepoInfo.h" -#import "FPersistentConnection.h" #import "FIRDataEventType.h" +#import "FPersistentConnection.h" +#import "FRepoInfo.h" #import "FTupleUserCallback.h" +#import @class FQuerySpec; @class FPersistence; @@ -31,46 +31,63 @@ @interface FRepo : NSObject -@property (nonatomic, strong) FIRDatabaseConfig *config; +@property(nonatomic, strong) FIRDatabaseConfig *config; -- (id)initWithRepoInfo:(FRepoInfo *)info config:(FIRDatabaseConfig *)config database:(FIRDatabase *)database; +- (id)initWithRepoInfo:(FRepoInfo *)info + config:(FIRDatabaseConfig *)config + database:(FIRDatabase *)database; -- (void) set:(FPath *)path withNode:(id)node withCallback:(fbt_void_nserror_ref)onComplete; -- (void) update:(FPath *)path withNodes:(FCompoundWrite *)compoundWrite withCallback:(fbt_void_nserror_ref)callback; -- (void) purgeOutstandingWrites; +- (void)set:(FPath *)path + withNode:(id)node + withCallback:(fbt_void_nserror_ref)onComplete; +- (void)update:(FPath *)path + withNodes:(FCompoundWrite *)compoundWrite + withCallback:(fbt_void_nserror_ref)callback; +- (void)purgeOutstandingWrites; -- (void) addEventRegistration:(id)eventRegistration forQuery:(FQuerySpec *)query; -- (void) removeEventRegistration:(id)eventRegistration forQuery:(FQuerySpec *)query; -- (void) keepQuery:(FQuerySpec *)query synced:(BOOL)synced; +- (void)addEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query; +- (void)removeEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query; +- (void)keepQuery:(FQuerySpec *)query synced:(BOOL)synced; -- (NSString*)name; +- (NSString *)name; - (NSTimeInterval)serverTime; -- (void) onDataUpdate:(FPersistentConnection *)fpconnection forPath:(NSString *)pathString message:(id)message isMerge:(BOOL)isMerge tagId:(NSNumber *)tagId; -- (void) onConnect:(FPersistentConnection *)fpconnection; -- (void) onDisconnect:(FPersistentConnection *)fpconnection; +- (void)onDataUpdate:(FPersistentConnection *)fpconnection + forPath:(NSString *)pathString + message:(id)message + isMerge:(BOOL)isMerge + tagId:(NSNumber *)tagId; +- (void)onConnect:(FPersistentConnection *)fpconnection; +- (void)onDisconnect:(FPersistentConnection *)fpconnection; // Disconnect methods -- (void) onDisconnectCancel:(FPath *)path withCallback:(fbt_void_nserror_ref)callback; -- (void) onDisconnectSet:(FPath *)path withNode:(id)node withCallback:(fbt_void_nserror_ref)callback; -- (void) onDisconnectUpdate:(FPath *)path withNodes:(FCompoundWrite *)compoundWrite withCallback:(fbt_void_nserror_ref)callback; +- (void)onDisconnectCancel:(FPath *)path + withCallback:(fbt_void_nserror_ref)callback; +- (void)onDisconnectSet:(FPath *)path + withNode:(id)node + withCallback:(fbt_void_nserror_ref)callback; +- (void)onDisconnectUpdate:(FPath *)path + withNodes:(FCompoundWrite *)compoundWrite + withCallback:(fbt_void_nserror_ref)callback; // Connection Management. -- (void) interrupt; -- (void) resume; +- (void)interrupt; +- (void)resume; // Transactions -- (void) startTransactionOnPath:(FPath *)path - update:(fbt_transactionresult_mutabledata)update - onComplete:(fbt_void_nserror_bool_datasnapshot)onComplete - withLocalEvents:(BOOL)applyLocally; +- (void)startTransactionOnPath:(FPath *)path + update:(fbt_transactionresult_mutabledata)update + onComplete:(fbt_void_nserror_bool_datasnapshot)onComplete + withLocalEvents:(BOOL)applyLocally; // Testing methods -- (NSDictionary *) dumpListens; -- (void) dispose; -- (void) setHijackHash:(BOOL)hijack; +- (NSDictionary *)dumpListens; +- (void)dispose; +- (void)setHijackHash:(BOOL)hijack; -@property (nonatomic, strong, readonly) FAuthenticationManager *auth; -@property (nonatomic, strong, readonly) FIRDatabase *database; +@property(nonatomic, strong, readonly) FAuthenticationManager *auth; +@property(nonatomic, strong, readonly) FIRDatabase *database; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepo.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepo.m index ae1d8e8..5d894bf 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepo.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepo.m @@ -16,85 +16,92 @@ #import -#import -#import -#import "FRepo.h" -#import "FSnapshotUtilities.h" +#import "FAtomicNumber.h" +#import "FCachePolicy.h" +#import "FClock.h" #import "FConstants.h" +#import "FEmptyNode.h" +#import "FEventRaiser.h" +#import "FEventRegistration.h" +#import "FIRDataSnapshot.h" +#import "FIRDataSnapshot_Private.h" +#import "FIRDatabaseConfig_Private.h" #import "FIRDatabaseQuery_Private.h" +#import "FIRDatabase_Private.h" +#import "FIRMutableData.h" +#import "FIRMutableData_Private.h" +#import "FIRTransactionResult.h" +#import "FIRTransactionResult_Private.h" +#import "FLevelDBStorageEngine.h" +#import "FListenProvider.h" +#import "FPersistenceManager.h" #import "FQuerySpec.h" -#import "FTupleNodePath.h" -#import "FRepo_Private.h" +#import "FRepo.h" #import "FRepoManager.h" +#import "FRepo_Private.h" #import "FServerValues.h" -#import "FTupleSetIdPath.h" -#import "FSyncTree.h" -#import "FEventRegistration.h" -#import "FAtomicNumber.h" -#import "FSyncTree.h" -#import "FListenProvider.h" -#import "FEventRaiser.h" #import "FSnapshotHolder.h" -#import "FIRDatabaseConfig_Private.h" -#import "FLevelDBStorageEngine.h" -#import "FPersistenceManager.h" -#import "FWriteRecord.h" -#import "FCachePolicy.h" -#import "FClock.h" -#import "FIRDatabase_Private.h" +#import "FSnapshotUtilities.h" +#import "FSyncTree.h" #import "FTree.h" +#import "FTupleNodePath.h" +#import "FTupleSetIdPath.h" #import "FTupleTransaction.h" -#import "FIRTransactionResult.h" -#import "FIRTransactionResult_Private.h" -#import "FIRMutableData.h" -#import "FIRMutableData_Private.h" -#import "FIRDataSnapshot.h" -#import "FIRDataSnapshot_Private.h" #import "FValueEventRegistration.h" -#import "FEmptyNode.h" +#import "FWriteRecord.h" +#import +#import #if TARGET_OS_IOS || TARGET_OS_TV #import #endif -@interface FRepo() +@interface FRepo () -@property (nonatomic, strong) FOffsetClock *serverClock; -@property (nonatomic, strong) FPersistenceManager* persistenceManager; -@property (nonatomic, strong) FIRDatabase *database; -@property (nonatomic, strong, readwrite) FAuthenticationManager *auth; -@property (nonatomic, strong) FSyncTree *infoSyncTree; -@property (nonatomic) NSInteger writeIdCounter; -@property (nonatomic) BOOL hijackHash; -@property (nonatomic, strong) FTree *transactionQueueTree; -@property (nonatomic) BOOL loggedTransactionPersistenceWarning; +@property(nonatomic, strong) FOffsetClock *serverClock; +@property(nonatomic, strong) FPersistenceManager *persistenceManager; +@property(nonatomic, strong) FIRDatabase *database; +@property(nonatomic, strong, readwrite) FAuthenticationManager *auth; +@property(nonatomic, strong) FSyncTree *infoSyncTree; +@property(nonatomic) NSInteger writeIdCounter; +@property(nonatomic) BOOL hijackHash; +@property(nonatomic, strong) FTree *transactionQueueTree; +@property(nonatomic) BOOL loggedTransactionPersistenceWarning; /** -* Test only. For load testing the server. -*/ -@property (nonatomic, strong) id (^interceptServerDataCallback)(NSString *pathString, id data); + * Test only. For load testing the server. + */ +@property(nonatomic, strong) id (^interceptServerDataCallback) + (NSString *pathString, id data); @end - @implementation FRepo -- (id)initWithRepoInfo:(FRepoInfo*)info config:(FIRDatabaseConfig *)config database:(FIRDatabase *)database { +- (id)initWithRepoInfo:(FRepoInfo *)info + config:(FIRDatabaseConfig *)config + database:(FIRDatabase *)database { self = [super init]; if (self) { self.repoInfo = info; self.config = config; self.database = database; - // Access can occur outside of shared queue, so the clock needs to be initialized here - self.serverClock = [[FOffsetClock alloc] initWithClock:[FSystemClock clock] offset:0]; + // Access can occur outside of shared queue, so the clock needs to be + // initialized here + self.serverClock = + [[FOffsetClock alloc] initWithClock:[FSystemClock clock] offset:0]; - self.connection = [[FPersistentConnection alloc] initWithRepoInfo:self.repoInfo dispatchQueue:[FIRDatabaseQuery sharedQueue] config:self.config]; + self.connection = [[FPersistentConnection alloc] + initWithRepoInfo:self.repoInfo + dispatchQueue:[FIRDatabaseQuery sharedQueue] + config:self.config]; // Needs to be called before authentication manager is instantiated - self.eventRaiser = [[FEventRaiser alloc] initWithQueue:self.config.callbackQueue]; + self.eventRaiser = + [[FEventRaiser alloc] initWithQueue:self.config.callbackQueue]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self deferredInit]; + [self deferredInit]; }); } return self; @@ -104,11 +111,12 @@ - (void)deferredInit { // TODO: cleanup on dealloc __weak FRepo *weakSelf = self; [self.config.authTokenProvider listenForTokenChanges:^(NSString *token) { - [weakSelf.connection refreshAuthToken:token]; + [weakSelf.connection refreshAuthToken:token]; }]; - // Open connection now so that by the time we are connected the deferred init has run - // This relies on the fact that all callbacks run on repos queue + // Open connection now so that by the time we are connected the deferred + // init has run This relies on the fact that all callbacks run on repos + // queue self.connection.delegate = self; [self.connection open]; @@ -117,23 +125,33 @@ - (void)deferredInit { self.interceptServerDataCallback = nil; if (self.config.persistenceEnabled) { - NSString* repoHashString = [NSString stringWithFormat:@"%@_%@", self.repoInfo.host, self.repoInfo.namespace]; - NSString* persistencePrefix = [NSString stringWithFormat:@"%@/%@", self.config.sessionIdentifier, repoHashString]; + NSString *repoHashString = + [NSString stringWithFormat:@"%@_%@", self.repoInfo.host, + self.repoInfo.namespace]; + NSString *persistencePrefix = + [NSString stringWithFormat:@"%@/%@", self.config.sessionIdentifier, + repoHashString]; - id cachePolicy = [[FLRUCachePolicy alloc] initWithMaxSize:self.config.persistenceCacheSizeBytes]; + id cachePolicy = [[FLRUCachePolicy alloc] + initWithMaxSize:self.config.persistenceCacheSizeBytes]; id engine; if (self.config.forceStorageEngine != nil) { engine = self.config.forceStorageEngine; } else { - FLevelDBStorageEngine *levelDBEngine = [[FLevelDBStorageEngine alloc] initWithPath:persistencePrefix]; - // We need the repo info to run the legacy migration. Future migrations will be managed by the database itself - // Remove this once we are confident that no-one is using legacy migration anymore... + FLevelDBStorageEngine *levelDBEngine = + [[FLevelDBStorageEngine alloc] initWithPath:persistencePrefix]; + // We need the repo info to run the legacy migration. Future + // migrations will be managed by the database itself Remove this + // once we are confident that no-one is using legacy migration + // anymore... [levelDBEngine runLegacyMigration:self.repoInfo]; engine = levelDBEngine; } - self.persistenceManager = [[FPersistenceManager alloc] initWithStorageEngine:engine cachePolicy:cachePolicy]; + self.persistenceManager = + [[FPersistenceManager alloc] initWithStorageEngine:engine + cachePolicy:cachePolicy]; } else { self.persistenceManager = nil; } @@ -145,43 +163,49 @@ - (void)deferredInit { self.infoData = [[FSnapshotHolder alloc] init]; FListenProvider *infoListenProvider = [[FListenProvider alloc] init]; - infoListenProvider.startListening = ^(FQuerySpec *query, - NSNumber *tagId, - id hash, - fbt_nsarray_nsstring onComplete) { - NSArray *infoEvents = @[]; - FRepo *strongSelf = weakSelf; - id node = [strongSelf.infoData getNode:query.path]; - // This is possibly a hack, but we have different semantics for .info endpoints. We don't raise null events - // on initial data... - if (![node isEmpty]) { - infoEvents = [strongSelf.infoSyncTree applyServerOverwriteAtPath:query.path newData:node]; - [strongSelf.eventRaiser raiseCallback:^{ + infoListenProvider.startListening = + ^(FQuerySpec *query, NSNumber *tagId, id hash, + fbt_nsarray_nsstring onComplete) { + NSArray *infoEvents = @[]; + FRepo *strongSelf = weakSelf; + id node = [strongSelf.infoData getNode:query.path]; + // This is possibly a hack, but we have different semantics for .info + // endpoints. We don't raise null events on initial data... + if (![node isEmpty]) { + infoEvents = + [strongSelf.infoSyncTree applyServerOverwriteAtPath:query.path + newData:node]; + [strongSelf.eventRaiser raiseCallback:^{ onComplete(kFWPResponseForActionStatusOk); - }]; - } - return infoEvents; + }]; + } + return infoEvents; + }; + infoListenProvider.stopListening = ^(FQuerySpec *query, NSNumber *tagId) { }; - infoListenProvider.stopListening = ^(FQuerySpec *query, NSNumber *tagId) {}; - self.infoSyncTree = [[FSyncTree alloc] initWithListenProvider:infoListenProvider]; + self.infoSyncTree = + [[FSyncTree alloc] initWithListenProvider:infoListenProvider]; FListenProvider *serverListenProvider = [[FListenProvider alloc] init]; - serverListenProvider.startListening = ^(FQuerySpec *query, - NSNumber *tagId, - id hash, - fbt_nsarray_nsstring onComplete) { - [weakSelf.connection listen:query tagId:tagId hash:hash onComplete:^(NSString *status) { - NSArray *events = onComplete(status); - [weakSelf.eventRaiser raiseEvents:events]; - }]; - // No synchronous events for network-backed sync trees - return @[]; - }; + serverListenProvider.startListening = + ^(FQuerySpec *query, NSNumber *tagId, id hash, + fbt_nsarray_nsstring onComplete) { + [weakSelf.connection listen:query + tagId:tagId + hash:hash + onComplete:^(NSString *status) { + NSArray *events = onComplete(status); + [weakSelf.eventRaiser raiseEvents:events]; + }]; + // No synchronous events for network-backed sync trees + return @[]; + }; serverListenProvider.stopListening = ^(FQuerySpec *query, NSNumber *tag) { - [weakSelf.connection unlisten:query tagId:tag]; + [weakSelf.connection unlisten:query tagId:tag]; }; - self.serverSyncTree = [[FSyncTree alloc] initWithPersistenceManager:self.persistenceManager - listenProvider:serverListenProvider]; + self.serverSyncTree = + [[FSyncTree alloc] initWithPersistenceManager:self.persistenceManager + listenProvider:serverListenProvider]; [self restoreWrites]; @@ -190,61 +214,80 @@ - (void)deferredInit { [self setupNotifications]; } - -- (void) restoreWrites { +- (void)restoreWrites { NSArray *writes = self.persistenceManager.userWrites; - NSDictionary *serverValues = [FServerValues generateServerValues:self.serverClock]; + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; __block NSInteger lastWriteId = NSIntegerMin; - [writes enumerateObjectsUsingBlock:^(FWriteRecord *write, NSUInteger idx, BOOL *stop) { - NSInteger writeId = write.writeId; - fbt_void_nsstring_nsstring callback = ^(NSString *status, NSString *errorReason) { - [self warnIfWriteFailedAtPath:write.path status:status message:@"Persisted write"]; - [self ackWrite:writeId rerunTransactionsAtPath:write.path status:status]; - }; - if (lastWriteId >= writeId) { - [NSException raise:NSInternalInconsistencyException format:@"Restored writes were not in order!"]; - } - lastWriteId = writeId; - self.writeIdCounter = writeId + 1; - if ([write isOverwrite]) { - FFLog(@"I-RDB038001", @"Restoring overwrite with id %ld", (long)write.writeId); - [self.connection putData:[write.overwrite valForExport:YES] + [writes enumerateObjectsUsingBlock:^(FWriteRecord *write, NSUInteger idx, + BOOL *stop) { + NSInteger writeId = write.writeId; + fbt_void_nsstring_nsstring callback = + ^(NSString *status, NSString *errorReason) { + [self warnIfWriteFailedAtPath:write.path + status:status + message:@"Persisted write"]; + [self ackWrite:writeId + rerunTransactionsAtPath:write.path + status:status]; + }; + if (lastWriteId >= writeId) { + [NSException raise:NSInternalInconsistencyException + format:@"Restored writes were not in order!"]; + } + lastWriteId = writeId; + self.writeIdCounter = writeId + 1; + if ([write isOverwrite]) { + FFLog(@"I-RDB038001", @"Restoring overwrite with id %ld", + (long)write.writeId); + [self.connection putData:[write.overwrite valForExport:YES] + forPath:[write.path toString] + withHash:nil + withCallback:callback]; + id resolved = + [FServerValues resolveDeferredValueSnapshot:write.overwrite + withServerValues:serverValues]; + [self.serverSyncTree applyUserOverwriteAtPath:write.path + newData:resolved + writeId:writeId + isVisible:YES]; + } else { + FFLog(@"I-RDB038002", @"Restoring merge with id %ld", + (long)write.writeId); + [self.connection mergeData:[write.merge valForExport:YES] forPath:[write.path toString] - withHash:nil withCallback:callback]; - id resolved = [FServerValues resolveDeferredValueSnapshot:write.overwrite withServerValues:serverValues]; - [self.serverSyncTree applyUserOverwriteAtPath:write.path newData:resolved writeId:writeId isVisible:YES]; - } else { - FFLog(@"I-RDB038002", @"Restoring merge with id %ld", (long)write.writeId); - [self.connection mergeData:[write.merge valForExport:YES] - forPath:[write.path toString] - withCallback:callback]; - FCompoundWrite *resolved = [FServerValues resolveDeferredValueCompoundWrite:write.merge withServerValues:serverValues]; - [self.serverSyncTree applyUserMergeAtPath:write.path changedChildren:resolved writeId:writeId]; - } + FCompoundWrite *resolved = + [FServerValues resolveDeferredValueCompoundWrite:write.merge + withServerValues:serverValues]; + [self.serverSyncTree applyUserMergeAtPath:write.path + changedChildren:resolved + writeId:writeId]; + } }]; } -- (NSString*)name { +- (NSString *)name { return self.repoInfo.namespace; } -- (NSString *) description { +- (NSString *)description { return [self.repoInfo description]; } -- (void) interrupt { +- (void)interrupt { [self.connection interruptForReason:kFInterruptReasonRepoInterrupt]; } -- (void) resume { +- (void)resume { [self.connection resumeForReason:kFInterruptReasonRepoInterrupt]; } -// NOTE: Typically if you're calling this, you should be in an @autoreleasepool block to make sure that ARC kicks -// in and cleans up things no longer referenced (i.e. pendingPutsDB). -- (void) dispose { +// NOTE: Typically if you're calling this, you should be in an @autoreleasepool +// block to make sure that ARC kicks in and cleans up things no longer +// referenced (i.e. pendingPutsDB). +- (void)dispose { [self.connection interruptForReason:kFInterruptReasonRepoInterrupt]; // We need to nil out any references to LevelDB, to make sure the @@ -252,120 +295,205 @@ - (void) dispose { [self.persistenceManager close]; } -- (NSInteger) nextWriteId { +- (NSInteger)nextWriteId { return self->_writeIdCounter++; } -- (NSTimeInterval) serverTime { +- (NSTimeInterval)serverTime { return [self.serverClock currentTime]; } -- (void) set:(FPath *)path withNode:(id)node withCallback:(fbt_void_nserror_ref)onComplete { +- (void)set:(FPath *)path + withNode:(id)node + withCallback:(fbt_void_nserror_ref)onComplete { id value = [node valForExport:YES]; - FFLog(@"I-RDB038003", @"Setting: %@ with %@ pri: %@", [path toString], [value description], [[node getPriority] val]); + FFLog(@"I-RDB038003", @"Setting: %@ with %@ pri: %@", [path toString], + [value description], [[node getPriority] val]); - // TODO: Optimize this behavior to either (a) store flag to skip resolving where possible and / or - // (b) store unresolved paths on JSON parse - NSDictionary* serverValues = [FServerValues generateServerValues:self.serverClock]; - id newNode = [FServerValues resolveDeferredValueSnapshot:node withServerValues:serverValues]; + // TODO: Optimize this behavior to either (a) store flag to skip resolving + // where possible and / or (b) store unresolved paths on JSON parse + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + id newNode = + [FServerValues resolveDeferredValueSnapshot:node + withServerValues:serverValues]; NSInteger writeId = [self nextWriteId]; - [self.persistenceManager saveUserOverwrite:node atPath:path writeId:writeId]; - NSArray *events = [self.serverSyncTree applyUserOverwriteAtPath:path newData:newNode writeId:writeId isVisible:YES]; + [self.persistenceManager saveUserOverwrite:node + atPath:path + writeId:writeId]; + NSArray *events = [self.serverSyncTree applyUserOverwriteAtPath:path + newData:newNode + writeId:writeId + isVisible:YES]; [self.eventRaiser raiseEvents:events]; - [self.connection putData:value forPath:[path toString] withHash:nil withCallback:^(NSString *status, NSString *errorReason) { - [self warnIfWriteFailedAtPath:path status:status message:@"setValue: or removeValue:"]; - [self ackWrite:writeId rerunTransactionsAtPath:path status:status]; - [self callOnComplete:onComplete withStatus:status errorReason:errorReason andPath:path]; - }]; + [self.connection putData:value + forPath:[path toString] + withHash:nil + withCallback:^(NSString *status, NSString *errorReason) { + [self warnIfWriteFailedAtPath:path + status:status + message:@"setValue: or removeValue:"]; + [self ackWrite:writeId + rerunTransactionsAtPath:path + status:status]; + [self callOnComplete:onComplete + withStatus:status + errorReason:errorReason + andPath:path]; + }]; - FPath* affectedPath = [self abortTransactionsAtPath:path error:kFTransactionSet]; + FPath *affectedPath = [self abortTransactionsAtPath:path + error:kFTransactionSet]; [self rerunTransactionsForPath:affectedPath]; } -- (void) update:(FPath *)path withNodes:(FCompoundWrite *)nodes withCallback:(fbt_void_nserror_ref)callback { +- (void)update:(FPath *)path + withNodes:(FCompoundWrite *)nodes + withCallback:(fbt_void_nserror_ref)callback { NSDictionary *values = [nodes valForExport:YES]; - FFLog(@"I-RDB038004", @"Updating: %@ with %@", [path toString], [values description]); - NSDictionary* serverValues = [FServerValues generateServerValues:self.serverClock]; - FCompoundWrite *resolved = [FServerValues resolveDeferredValueCompoundWrite:nodes withServerValues:serverValues]; + FFLog(@"I-RDB038004", @"Updating: %@ with %@", [path toString], + [values description]); + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + FCompoundWrite *resolved = + [FServerValues resolveDeferredValueCompoundWrite:nodes + withServerValues:serverValues]; if (!resolved.isEmpty) { NSInteger writeId = [self nextWriteId]; - [self.persistenceManager saveUserMerge:nodes atPath:path writeId:writeId]; - NSArray *events = [self.serverSyncTree applyUserMergeAtPath:path changedChildren:resolved writeId:writeId]; + [self.persistenceManager saveUserMerge:nodes + atPath:path + writeId:writeId]; + NSArray *events = [self.serverSyncTree applyUserMergeAtPath:path + changedChildren:resolved + writeId:writeId]; [self.eventRaiser raiseEvents:events]; - [self.connection mergeData:values forPath:[path description] withCallback:^(NSString *status, NSString *errorReason) { - [self warnIfWriteFailedAtPath:path status:status message:@"updateChildValues:"]; - [self ackWrite:writeId rerunTransactionsAtPath:path status:status]; - [self callOnComplete:callback withStatus:status errorReason:errorReason andPath:path]; - }]; + [self.connection mergeData:values + forPath:[path description] + withCallback:^(NSString *status, NSString *errorReason) { + [self warnIfWriteFailedAtPath:path + status:status + message:@"updateChildValues:"]; + [self ackWrite:writeId + rerunTransactionsAtPath:path + status:status]; + [self callOnComplete:callback + withStatus:status + errorReason:errorReason + andPath:path]; + }]; [nodes enumerateWrites:^(FPath *childPath, id node, BOOL *stop) { - FPath* pathFromRoot = [path child:childPath]; - FFLog(@"I-RDB038005", @"Cancelling transactions at path: %@", pathFromRoot); - FPath *affectedPath = [self abortTransactionsAtPath:pathFromRoot error:kFTransactionSet]; - [self rerunTransactionsForPath:affectedPath]; + FPath *pathFromRoot = [path child:childPath]; + FFLog(@"I-RDB038005", @"Cancelling transactions at path: %@", + pathFromRoot); + FPath *affectedPath = [self abortTransactionsAtPath:pathFromRoot + error:kFTransactionSet]; + [self rerunTransactionsForPath:affectedPath]; }]; } else { FFLog(@"I-RDB038006", @"update called with empty data. Doing nothing"); // Do nothing, just call the callback - [self callOnComplete:callback withStatus:@"ok" errorReason:nil andPath:path]; + [self callOnComplete:callback + withStatus:@"ok" + errorReason:nil + andPath:path]; } } -- (void) onDisconnectCancel:(FPath *)path withCallback:(fbt_void_nserror_ref)callback { - [self.connection onDisconnectCancelPath:path withCallback:^(NSString *status, NSString *errorReason) { - BOOL success = [status isEqualToString:kFWPResponseForActionStatusOk]; - if (success) { - [self.onDisconnect forgetPath:path]; - } else { - FFLog(@"I-RDB038007", @"cancelDisconnectOperations: at %@ failed: %@", path, status); - } +- (void)onDisconnectCancel:(FPath *)path + withCallback:(fbt_void_nserror_ref)callback { + [self.connection + onDisconnectCancelPath:path + withCallback:^(NSString *status, NSString *errorReason) { + BOOL success = + [status isEqualToString:kFWPResponseForActionStatusOk]; + if (success) { + [self.onDisconnect forgetPath:path]; + } else { + FFLog(@"I-RDB038007", + @"cancelDisconnectOperations: at %@ failed: %@", + path, status); + } - [self callOnComplete:callback withStatus:status errorReason:errorReason andPath:path]; - }]; + [self callOnComplete:callback + withStatus:status + errorReason:errorReason + andPath:path]; + }]; } -- (void) onDisconnectSet:(FPath *)path withNode:(id)node withCallback:(fbt_void_nserror_ref)callback { - [self.connection onDisconnectPutData:[node valForExport:YES] forPath:path withCallback:^(NSString *status, NSString *errorReason) { - BOOL success = [status isEqualToString:kFWPResponseForActionStatusOk]; - if (success) { - [self.onDisconnect rememberData:node onPath:path]; - } else { - FFWarn(@"I-RDB038008", @"onDisconnectSetValue: or onDisconnectRemoveValue: at %@ failed: %@", path, status); - } - - [self callOnComplete:callback withStatus:status errorReason:errorReason andPath:path]; - }]; +- (void)onDisconnectSet:(FPath *)path + withNode:(id)node + withCallback:(fbt_void_nserror_ref)callback { + [self.connection + onDisconnectPutData:[node valForExport:YES] + forPath:path + withCallback:^(NSString *status, NSString *errorReason) { + BOOL success = + [status isEqualToString:kFWPResponseForActionStatusOk]; + if (success) { + [self.onDisconnect rememberData:node onPath:path]; + } else { + FFWarn(@"I-RDB038008", + @"onDisconnectSetValue: or " + @"onDisconnectRemoveValue: at %@ failed: %@", + path, status); + } + + [self callOnComplete:callback + withStatus:status + errorReason:errorReason + andPath:path]; + }]; } -- (void) onDisconnectUpdate:(FPath *)path withNodes:(FCompoundWrite *)nodes withCallback:(fbt_void_nserror_ref)callback { +- (void)onDisconnectUpdate:(FPath *)path + withNodes:(FCompoundWrite *)nodes + withCallback:(fbt_void_nserror_ref)callback { if (!nodes.isEmpty) { NSDictionary *values = [nodes valForExport:YES]; - [self.connection onDisconnectMergeData:values forPath:path withCallback:^(NSString *status, NSString *errorReason) { - BOOL success = [status isEqualToString:kFWPResponseForActionStatusOk]; - if (success) { - [nodes enumerateWrites:^(FPath *relativePath, id nodeUnresolved, BOOL *stop) { - FPath* childPath = [path child:relativePath]; - [self.onDisconnect rememberData:nodeUnresolved onPath:childPath]; - }]; - } else { - FFWarn(@"I-RDB038009", @"onDisconnectUpdateChildValues: at %@ failed %@", path, status); - } - - [self callOnComplete:callback withStatus:status errorReason:errorReason andPath:path]; - }]; + [self.connection + onDisconnectMergeData:values + forPath:path + withCallback:^(NSString *status, NSString *errorReason) { + BOOL success = [status + isEqualToString:kFWPResponseForActionStatusOk]; + if (success) { + [nodes enumerateWrites:^(FPath *relativePath, + id nodeUnresolved, + BOOL *stop) { + FPath *childPath = [path child:relativePath]; + [self.onDisconnect rememberData:nodeUnresolved + onPath:childPath]; + }]; + } else { + FFWarn(@"I-RDB038009", + @"onDisconnectUpdateChildValues: at %@ " + @"failed %@", + path, status); + } + + [self callOnComplete:callback + withStatus:status + errorReason:errorReason + andPath:path]; + }]; } else { // Do nothing, just call the callback - [self callOnComplete:callback withStatus:@"ok" errorReason:nil andPath:path]; + [self callOnComplete:callback + withStatus:@"ok" + errorReason:nil + andPath:path]; } } -- (void) purgeOutstandingWrites { +- (void)purgeOutstandingWrites { FFLog(@"I-RDB038010", @"Purging outstanding writes"); NSArray *events = [self.serverSyncTree removeAllWrites]; [self.eventRaiser raiseEvents:events]; @@ -375,68 +503,95 @@ - (void) purgeOutstandingWrites { [self.connection purgeOutstandingWrites]; } -- (void) addEventRegistration:(id )eventRegistration forQuery:(FQuerySpec *)query { +- (void)addEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query { NSArray *events = nil; if ([[query.path getFront] isEqualToString:kDotInfoPrefix]) { - events = [self.infoSyncTree addEventRegistration:eventRegistration forQuery:query]; + events = [self.infoSyncTree addEventRegistration:eventRegistration + forQuery:query]; } else { - events = [self.serverSyncTree addEventRegistration:eventRegistration forQuery:query]; + events = [self.serverSyncTree addEventRegistration:eventRegistration + forQuery:query]; } [self.eventRaiser raiseEvents:events]; } -- (void) removeEventRegistration:(id)eventRegistration forQuery:(FQuerySpec *)query { - // These are guaranteed not to raise events, since we're not passing in a cancelError. However we can future-proof - // a little bit by handling the return values anyways. - FFLog(@"I-RDB038011", @"Removing event registration with hande: %lu", (unsigned long)eventRegistration.handle); +- (void)removeEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query { + // These are guaranteed not to raise events, since we're not passing in a + // cancelError. However we can future-proof a little bit by handling the + // return values anyways. + FFLog(@"I-RDB038011", @"Removing event registration with hande: %lu", + (unsigned long)eventRegistration.handle); NSArray *events = nil; if ([[query.path getFront] isEqualToString:kDotInfoPrefix]) { - events = [self.infoSyncTree removeEventRegistration:eventRegistration forQuery:query cancelError:nil]; + events = [self.infoSyncTree removeEventRegistration:eventRegistration + forQuery:query + cancelError:nil]; } else { - events = [self.serverSyncTree removeEventRegistration:eventRegistration forQuery:query cancelError:nil]; + events = [self.serverSyncTree removeEventRegistration:eventRegistration + forQuery:query + cancelError:nil]; } [self.eventRaiser raiseEvents:events]; } -- (void) keepQuery:(FQuerySpec *)query synced:(BOOL)synced { - NSAssert(![[query.path getFront] isEqualToString:kDotInfoPrefix], @"Can't keep .info tree synced!"); +- (void)keepQuery:(FQuerySpec *)query synced:(BOOL)synced { + NSAssert(![[query.path getFront] isEqualToString:kDotInfoPrefix], + @"Can't keep .info tree synced!"); [self.serverSyncTree keepQuery:query synced:synced]; } -- (void) updateInfo:(NSString *) pathString withValue:(id)value { - // hack to make serverTimeOffset available in a threadsafe way. Property is marked as atomic +- (void)updateInfo:(NSString *)pathString withValue:(id)value { + // hack to make serverTimeOffset available in a threadsafe way. Property is + // marked as atomic if ([pathString isEqualToString:kDotInfoServerTimeOffset]) { - NSTimeInterval offset = [(NSNumber *)value doubleValue]/1000.0; - self.serverClock = [[FOffsetClock alloc] initWithClock:[FSystemClock clock] offset:offset]; + NSTimeInterval offset = [(NSNumber *)value doubleValue] / 1000.0; + self.serverClock = + [[FOffsetClock alloc] initWithClock:[FSystemClock clock] + offset:offset]; } - FPath* path = [[FPath alloc] initWith:[NSString stringWithFormat:@"%@/%@", kDotInfoPrefix, pathString]]; + FPath *path = [[FPath alloc] + initWith:[NSString + stringWithFormat:@"%@/%@", kDotInfoPrefix, pathString]]; id newNode = [FSnapshotUtilities nodeFrom:value]; [self.infoData updateSnapshot:path withNewSnapshot:newNode]; - NSArray *events = [self.infoSyncTree applyServerOverwriteAtPath:path newData:newNode]; + NSArray *events = [self.infoSyncTree applyServerOverwriteAtPath:path + newData:newNode]; [self.eventRaiser raiseEvents:events]; } -- (void) callOnComplete:(fbt_void_nserror_ref)onComplete withStatus:(NSString *)status errorReason:(NSString *)errorReason andPath:(FPath *)path { +- (void)callOnComplete:(fbt_void_nserror_ref)onComplete + withStatus:(NSString *)status + errorReason:(NSString *)errorReason + andPath:(FPath *)path { if (onComplete) { - FIRDatabaseReference * ref = [[FIRDatabaseReference alloc] initWithRepo:self path:path]; + FIRDatabaseReference *ref = + [[FIRDatabaseReference alloc] initWithRepo:self path:path]; BOOL statusOk = [status isEqualToString:kFWPResponseForActionStatusOk]; - NSError* err = nil; + NSError *err = nil; if (!statusOk) { err = [FUtilities errorForStatus:status andReason:errorReason]; } [self.eventRaiser raiseCallback:^{ - onComplete(err, ref); + onComplete(err, ref); }]; } } -- (void)ackWrite:(NSInteger)writeId rerunTransactionsAtPath:(FPath *)path status:(NSString *)status { +- (void)ackWrite:(NSInteger)writeId + rerunTransactionsAtPath:(FPath *)path + status:(NSString *)status { if ([status isEqualToString:kFErrorWriteCanceled]) { // This write was already removed, we just need to ignore it... } else { BOOL success = [status isEqualToString:kFWPResponseForActionStatusOk]; - NSArray *clearEvents = [self.serverSyncTree ackUserWriteWithWriteId:writeId revert:!success persist:YES clock:self.serverClock]; + NSArray *clearEvents = + [self.serverSyncTree ackUserWriteWithWriteId:writeId + revert:!success + persist:YES + clock:self.serverClock]; if ([clearEvents count] > 0) { [self rerunTransactionsForPath:path]; } @@ -444,8 +599,11 @@ - (void)ackWrite:(NSInteger)writeId rerunTransactionsAtPath:(FPath *)path status } } -- (void) warnIfWriteFailedAtPath:(FPath *)path status:(NSString *)status message:(NSString *)message { - if (!([status isEqualToString:kFWPResponseForActionStatusOk] || [status isEqualToString:kFErrorWriteCanceled])) { +- (void)warnIfWriteFailedAtPath:(FPath *)path + status:(NSString *)status + message:(NSString *)message { + if (!([status isEqualToString:kFWPResponseForActionStatusOk] || + [status isEqualToString:kFErrorWriteCanceled])) { FFWarn(@"I-RDB038012", @"%@ at %@ failed: %@", message, path, status); } } @@ -453,59 +611,81 @@ - (void) warnIfWriteFailedAtPath:(FPath *)path status:(NSString *)status message #pragma mark - #pragma mark FPersistentConnectionDelegate methods -- (void) onDataUpdate:(FPersistentConnection *)fpconnection forPath:(NSString *)pathString message:(id)data isMerge:(BOOL)isMerge tagId:(NSNumber *)tagId { - FFLog(@"I-RDB038013", @"onDataUpdateForPath: %@ withMessage: %@", pathString, data); +- (void)onDataUpdate:(FPersistentConnection *)fpconnection + forPath:(NSString *)pathString + message:(id)data + isMerge:(BOOL)isMerge + tagId:(NSNumber *)tagId { + FFLog(@"I-RDB038013", @"onDataUpdateForPath: %@ withMessage: %@", + pathString, data); // For testing. self.dataUpdateCount++; - FPath* path = [[FPath alloc] initWith:pathString]; - data = self.interceptServerDataCallback ? self.interceptServerDataCallback(pathString, data) : data; + FPath *path = [[FPath alloc] initWith:pathString]; + data = self.interceptServerDataCallback + ? self.interceptServerDataCallback(pathString, data) + : data; NSArray *events = nil; if (tagId != nil) { if (isMerge) { NSDictionary *message = data; - FCompoundWrite *taggedChildren = [FCompoundWrite compoundWriteWithValueDictionary:message]; - events = [self.serverSyncTree applyTaggedQueryMergeAtPath:path changedChildren:taggedChildren tagId:tagId]; + FCompoundWrite *taggedChildren = + [FCompoundWrite compoundWriteWithValueDictionary:message]; + events = + [self.serverSyncTree applyTaggedQueryMergeAtPath:path + changedChildren:taggedChildren + tagId:tagId]; } else { id taggedSnap = [FSnapshotUtilities nodeFrom:data]; - events = [self.serverSyncTree applyTaggedQueryOverwriteAtPath:path newData:taggedSnap tagId:tagId]; + events = + [self.serverSyncTree applyTaggedQueryOverwriteAtPath:path + newData:taggedSnap + tagId:tagId]; } } else if (isMerge) { NSDictionary *message = data; - FCompoundWrite *changedChildren = [FCompoundWrite compoundWriteWithValueDictionary:message]; - events = [self.serverSyncTree applyServerMergeAtPath:path changedChildren:changedChildren]; + FCompoundWrite *changedChildren = + [FCompoundWrite compoundWriteWithValueDictionary:message]; + events = [self.serverSyncTree applyServerMergeAtPath:path + changedChildren:changedChildren]; } else { id snap = [FSnapshotUtilities nodeFrom:data]; - events = [self.serverSyncTree applyServerOverwriteAtPath:path newData:snap]; + events = [self.serverSyncTree applyServerOverwriteAtPath:path + newData:snap]; } if ([events count] > 0) { - // Since we have a listener outstanding for each transaction, receiving any events - // is a proxy for some change having occurred. + // Since we have a listener outstanding for each transaction, receiving + // any events is a proxy for some change having occurred. [self rerunTransactionsForPath:path]; } [self.eventRaiser raiseEvents:events]; } -- (void)onRangeMerge:(NSArray *)ranges forPath:(NSString *)pathString tagId:(NSNumber *)tag { +- (void)onRangeMerge:(NSArray *)ranges + forPath:(NSString *)pathString + tagId:(NSNumber *)tag { FFLog(@"I-RDB038014", @"onRangeMerge: %@ => %@", pathString, ranges); // For testing self.rangeMergeUpdateCount++; - FPath* path = [[FPath alloc] initWith:pathString]; + FPath *path = [[FPath alloc] initWith:pathString]; NSArray *events; if (tag != nil) { - events = [self.serverSyncTree applyTaggedServerRangeMergeAtPath:path updates:ranges tagId:tag]; + events = [self.serverSyncTree applyTaggedServerRangeMergeAtPath:path + updates:ranges + tagId:tag]; } else { - events = [self.serverSyncTree applyServerRangeMergeAtPath:path updates:ranges]; + events = [self.serverSyncTree applyServerRangeMergeAtPath:path + updates:ranges]; } if (events.count > 0) { - // Since we have a listener outstanding for each transaction, receiving any events - // is a proxy for some change having occurred. + // Since we have a listener outstanding for each transaction, receiving + // any events is a proxy for some change having occurred. [self rerunTransactionsForPath:path]; } @@ -521,77 +701,98 @@ - (void)onDisconnect:(FPersistentConnection *)fpconnection { [self runOnDisconnectEvents]; } -- (void)onServerInfoUpdate:(FPersistentConnection *)fpconnection updates:(NSDictionary *)updates { - for (NSString* key in updates) { +- (void)onServerInfoUpdate:(FPersistentConnection *)fpconnection + updates:(NSDictionary *)updates { + for (NSString *key in updates) { id val = [updates objectForKey:key]; [self updateInfo:key withValue:val]; } } -- (void) setupNotifications { - NSString * const *backgroundConstant = (NSString * const *) dlsym(RTLD_DEFAULT, "UIApplicationDidEnterBackgroundNotification"); +- (void)setupNotifications { + NSString *const *backgroundConstant = (NSString *const *)dlsym( + RTLD_DEFAULT, "UIApplicationDidEnterBackgroundNotification"); if (backgroundConstant) { FFLog(@"I-RDB038015", @"Registering for background notification."); - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(didEnterBackground) - name:*backgroundConstant - object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(didEnterBackground) + name:*backgroundConstant + object:nil]; } else { - FFLog(@"I-RDB038016", @"Skipped registering for background notification."); + FFLog(@"I-RDB038016", + @"Skipped registering for background notification."); } } -- (void) didEnterBackground { +- (void)didEnterBackground { if (!self.config.persistenceEnabled) return; - // Targetted compilation is ONLY for testing. UIKit is weak-linked in actual release build. - #if TARGET_OS_IOS || TARGET_OS_TV - // The idea is to wait until any outstanding sets get written to disk. Since the sets might still be in our - // dispatch queue, we wait for the dispatch queue to catch up and for persistence to catch up. - // This may be undesirable though. The dispatch queue might just be processing a bunch of incoming data or - // something. We might want to keep track of whether there are any unpersisted sets or something. - FFLog(@"I-RDB038017", @"Entering background. Starting background task to finish work."); +// Targetted compilation is ONLY for testing. UIKit is weak-linked in actual +// release build. +#if TARGET_OS_IOS || TARGET_OS_TV + // The idea is to wait until any outstanding sets get written to disk. Since + // the sets might still be in our dispatch queue, we wait for the dispatch + // queue to catch up and for persistence to catch up. This may be + // undesirable though. The dispatch queue might just be processing a bunch + // of incoming data or something. We might want to keep track of whether + // there are any unpersisted sets or something. + FFLog(@"I-RDB038017", + @"Entering background. Starting background task to finish work."); Class uiApplicationClass = NSClassFromString(@"UIApplication"); - assert(uiApplicationClass); // If we are here, we should be on iOS and UIApplication should be available. + assert(uiApplicationClass); // If we are here, we should be on iOS and + // UIApplication should be available. UIApplication *application = [uiApplicationClass sharedApplication]; - __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{ - [application endBackgroundTask:bgTask]; - }]; + __block UIBackgroundTaskIdentifier bgTask = + [application beginBackgroundTaskWithExpirationHandler:^{ + [application endBackgroundTask:bgTask]; + }]; NSDate *start = [NSDate date]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - NSTimeInterval finishTime = [start timeIntervalSinceNow]*-1; - FFLog(@"I-RDB038018", @"Background task completed. Queue time: %f", finishTime); - [application endBackgroundTask:bgTask]; + NSTimeInterval finishTime = [start timeIntervalSinceNow] * -1; + FFLog(@"I-RDB038018", @"Background task completed. Queue time: %f", + finishTime); + [application endBackgroundTask:bgTask]; }); - #endif +#endif } #pragma mark - #pragma mark Internal methods /** -* Applies all the changes stored up in the onDisconnect tree -*/ -- (void) runOnDisconnectEvents { + * Applies all the changes stored up in the onDisconnect tree + */ +- (void)runOnDisconnectEvents { FFLog(@"I-RDB038019", @"Running onDisconnectEvents"); - NSDictionary* serverValues = [FServerValues generateServerValues:self.serverClock]; - FSparseSnapshotTree* resolvedTree = [FServerValues resolveDeferredValueTree:self.onDisconnect withServerValues:serverValues]; + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + FSparseSnapshotTree *resolvedTree = + [FServerValues resolveDeferredValueTree:self.onDisconnect + withServerValues:serverValues]; NSMutableArray *events = [[NSMutableArray alloc] init]; - [resolvedTree forEachTreeAtPath:[FPath empty] do:^(FPath *path, id node) { - [events addObjectsFromArray:[self.serverSyncTree applyServerOverwriteAtPath:path newData:node]]; - FPath* affectedPath = [self abortTransactionsAtPath:path error:kFTransactionSet]; - [self rerunTransactionsForPath:affectedPath]; - }]; + [resolvedTree + forEachTreeAtPath:[FPath empty] + do:^(FPath *path, id node) { + [events addObjectsFromArray: + [self.serverSyncTree + applyServerOverwriteAtPath:path + newData:node]]; + FPath *affectedPath = + [self abortTransactionsAtPath:path + error:kFTransactionSet]; + [self rerunTransactionsForPath:affectedPath]; + }]; self.onDisconnect = [[FSparseSnapshotTree alloc] init]; [self.eventRaiser raiseEvents:events]; } -- (NSDictionary *) dumpListens { +- (NSDictionary *)dumpListens { return [self.connection dumpListens]; } @@ -601,38 +802,55 @@ - (NSDictionary *) dumpListens { /** * Setup the transaction data structures */ -- (void) initTransactions { +- (void)initTransactions { self.transactionQueueTree = [[FTree alloc] init]; self.hijackHash = NO; self.loggedTransactionPersistenceWarning = NO; } /** - * Creates a new transaction, add its to the transactions we're tracking, and sends it to the server if possible + * Creates a new transaction, add its to the transactions we're tracking, and + * sends it to the server if possible */ -- (void) startTransactionOnPath:(FPath *)path update:(fbt_transactionresult_mutabledata)update onComplete:(fbt_void_nserror_bool_datasnapshot)onComplete withLocalEvents:(BOOL)applyLocally { - if (self.config.persistenceEnabled && !self.loggedTransactionPersistenceWarning) { +- (void)startTransactionOnPath:(FPath *)path + update:(fbt_transactionresult_mutabledata)update + onComplete:(fbt_void_nserror_bool_datasnapshot)onComplete + withLocalEvents:(BOOL)applyLocally { + if (self.config.persistenceEnabled && + !self.loggedTransactionPersistenceWarning) { self.loggedTransactionPersistenceWarning = YES; - FFInfo(@"I-RDB038020", @"runTransactionBlock: usage detected while persistence is enabled. Please be aware that transactions " + FFInfo(@"I-RDB038020", + @"runTransactionBlock: usage detected while persistence is " + @"enabled. Please be aware that transactions " @"*will not* be persisted across app restarts. " - @"See https://www.firebase.com/docs/ios/guide/offline-capabilities.html#section-handling-transactions-offline for more details."); + @"See " + @"https://www.firebase.com/docs/ios/guide/" + @"offline-capabilities.html#section-handling-transactions-" + @"offline for more details."); } - FIRDatabaseReference * watchRef = [[FIRDatabaseReference alloc] initWithRepo:self path:path]; + FIRDatabaseReference *watchRef = + [[FIRDatabaseReference alloc] initWithRepo:self path:path]; // make sure we're listening on this node - // Note: we can't do this asynchronously. To preserve event ordering, it has to be done in this block. - // This is ok, this block is guaranteed to be our own event loop + // Note: we can't do this asynchronously. To preserve event ordering, it has + // to be done in this block. This is ok, this block is guaranteed to be our + // own event loop NSUInteger handle = [[FUtilities LUIDGenerator] integerValue]; - fbt_void_datasnapshot cb = ^(FIRDataSnapshot *snapshot) {}; - FValueEventRegistration *registration = [[FValueEventRegistration alloc] initWithRepo:self - handle:handle - callback:cb - cancelCallback:nil]; - [watchRef.repo addEventRegistration:registration forQuery:watchRef.querySpec]; - fbt_void_void unwatcher = ^{ [watchRef removeObserverWithHandle:handle]; }; + fbt_void_datasnapshot cb = ^(FIRDataSnapshot *snapshot) { + }; + FValueEventRegistration *registration = + [[FValueEventRegistration alloc] initWithRepo:self + handle:handle + callback:cb + cancelCallback:nil]; + [watchRef.repo addEventRegistration:registration + forQuery:watchRef.querySpec]; + fbt_void_void unwatcher = ^{ + [watchRef removeObserverWithHandle:handle]; + }; // Save all the data that represents this transaction - FTupleTransaction* transaction = [[FTupleTransaction alloc] init]; + FTupleTransaction *transaction = [[FTupleTransaction alloc] init]; transaction.path = path; transaction.update = update; transaction.onComplete = onComplete; @@ -649,8 +867,9 @@ - (void) startTransactionOnPath:(FPath *)path update:(fbt_transactionresult_muta // Run transaction initially id currentState = [self latestStateAtPath:path excludeWriteIds:nil]; transaction.currentInputSnapshot = currentState; - FIRMutableData * mutableCurrent = [[FIRMutableData alloc] initWithNode:currentState]; - FIRTransactionResult * result = transaction.update(mutableCurrent); + FIRMutableData *mutableCurrent = + [[FIRMutableData alloc] initWithNode:currentState]; + FIRTransactionResult *result = transaction.update(mutableCurrent); if (!result.isSuccess) { // Abort the transaction @@ -658,19 +877,25 @@ - (void) startTransactionOnPath:(FPath *)path update:(fbt_transactionresult_muta transaction.currentOutputSnapshotRaw = nil; transaction.currentOutputSnapshotResolved = nil; if (transaction.onComplete) { - FIRDatabaseReference *ref = [[FIRDatabaseReference alloc] initWithRepo:self path:transaction.path]; - FIndexedNode *indexedNode = [FIndexedNode indexedNodeWithNode:transaction.currentInputSnapshot]; - FIRDataSnapshot *snap = [[FIRDataSnapshot alloc] initWithRef:ref indexedNode:indexedNode]; + FIRDatabaseReference *ref = + [[FIRDatabaseReference alloc] initWithRepo:self + path:transaction.path]; + FIndexedNode *indexedNode = [FIndexedNode + indexedNodeWithNode:transaction.currentInputSnapshot]; + FIRDataSnapshot *snap = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:indexedNode]; [self.eventRaiser raiseCallback:^{ - transaction.onComplete(nil, NO, snap); + transaction.onComplete(nil, NO, snap); }]; } } else { - // Note: different from js. We don't need to validate, FIRMutableData does validation. - // We also don't have to worry about priorities. Just mark as run and add to queue. + // Note: different from js. We don't need to validate, FIRMutableData + // does validation. We also don't have to worry about priorities. Just + // mark as run and add to queue. transaction.status = FTransactionRun; - FTree* queueNode = [self.transactionQueueTree subTree:transaction.path]; - NSMutableArray* nodeQueue = [queueNode getValue]; + FTree *queueNode = [self.transactionQueueTree subTree:transaction.path]; + NSMutableArray *nodeQueue = [queueNode getValue]; if (nodeQueue == nil) { nodeQueue = [[NSMutableArray alloc] init]; } @@ -678,18 +903,25 @@ - (void) startTransactionOnPath:(FPath *)path update:(fbt_transactionresult_muta [queueNode setValue:nodeQueue]; // Update visibleData and raise events - // Note: We intentionally raise events after updating all of our transaction state, since the user could - // start new transactions from the event callbacks - NSDictionary* serverValues = [FServerValues generateServerValues:self.serverClock]; + // Note: We intentionally raise events after updating all of our + // transaction state, since the user could start new transactions from + // the event callbacks + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; id newValUnresolved = [result.update nodeValue]; - id newVal = [FServerValues resolveDeferredValueSnapshot:newValUnresolved withServerValues:serverValues]; + id newVal = + [FServerValues resolveDeferredValueSnapshot:newValUnresolved + withServerValues:serverValues]; transaction.currentOutputSnapshotRaw = newValUnresolved; transaction.currentOutputSnapshotResolved = newVal; - transaction.currentWriteId = [NSNumber numberWithInteger:[self nextWriteId]]; - - NSArray *events = [self.serverSyncTree applyUserOverwriteAtPath:path newData:newVal - writeId:[transaction.currentWriteId integerValue] - isVisible:transaction.applyLocally]; + transaction.currentWriteId = + [NSNumber numberWithInteger:[self nextWriteId]]; + + NSArray *events = [self.serverSyncTree + applyUserOverwriteAtPath:path + newData:newVal + writeId:[transaction.currentWriteId integerValue] + isVisible:transaction.applyLocally]; [self.eventRaiser raiseEvents:events]; [self sendAllReadyTransactions]; @@ -699,65 +931,79 @@ - (void) startTransactionOnPath:(FPath *)path update:(fbt_transactionresult_muta /** * @param writeIdsToExclude A specific set to exclude */ -- (id) latestStateAtPath:(FPath *)path excludeWriteIds:(NSArray *)writeIdsToExclude { - id latestState = [self.serverSyncTree calcCompleteEventCacheAtPath:path excludeWriteIds:writeIdsToExclude]; +- (id)latestStateAtPath:(FPath *)path + excludeWriteIds:(NSArray *)writeIdsToExclude { + id latestState = + [self.serverSyncTree calcCompleteEventCacheAtPath:path + excludeWriteIds:writeIdsToExclude]; return latestState ? latestState : [FEmptyNode emptyNode]; } /** - * Sends any already-run transactions that aren't waiting for outstanding transactions to complete. + * Sends any already-run transactions that aren't waiting for outstanding + * transactions to complete. * * Externally, call the version with no arguments. - * Internally, calls itself recursively with a particular transactionQueueTree node to recurse through the tree + * Internally, calls itself recursively with a particular transactionQueueTree + * node to recurse through the tree */ -- (void) sendAllReadyTransactions { - FTree* node = self.transactionQueueTree; +- (void)sendAllReadyTransactions { + FTree *node = self.transactionQueueTree; [self pruneCompletedTransactionsBelowNode:node]; [self sendReadyTransactionsForTree:node]; } -- (void) sendReadyTransactionsForTree:(FTree *)node { - NSMutableArray* queue = [node getValue]; +- (void)sendReadyTransactionsForTree:(FTree *)node { + NSMutableArray *queue = [node getValue]; if (queue != nil) { queue = [self buildTransactionQueueAtNode:node]; NSAssert([queue count] > 0, @"Sending zero length transaction queue"); - NSUInteger notRunIndex = [queue indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { - return ((FTupleTransaction*)obj).status != FTransactionRun; - }]; + NSUInteger notRunIndex = [queue + indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { + return ((FTupleTransaction *)obj).status != FTransactionRun; + }]; - // If they're all run (and not sent), we can send them. Else, we must wait. + // If they're all run (and not sent), we can send them. Else, we must + // wait. if (notRunIndex == NSNotFound) { [self sendTransactionQueue:queue atPath:node.path]; } } else if ([node hasChildren]) { [node forEachChild:^(FTree *child) { - [self sendReadyTransactionsForTree:child]; + [self sendReadyTransactionsForTree:child]; }]; } } /** - * Given a list of run transactions, send them to the server and then handle the result (success or failure). + * Given a list of run transactions, send them to the server and then handle the + * result (success or failure). */ -- (void) sendTransactionQueue:(NSMutableArray *)queue atPath:(FPath *)path { +- (void)sendTransactionQueue:(NSMutableArray *)queue atPath:(FPath *)path { // Mark transactions as sent and bump the retry count NSMutableArray *writeIdsToExclude = [[NSMutableArray alloc] init]; for (FTupleTransaction *transaction in queue) { [writeIdsToExclude addObject:transaction.currentWriteId]; } - id latestState = [self latestStateAtPath:path excludeWriteIds:writeIdsToExclude]; + id latestState = [self latestStateAtPath:path + excludeWriteIds:writeIdsToExclude]; id snapToSend = latestState; NSString *latestHash = [latestState dataHash]; - for (FTupleTransaction* transaction in queue) { - NSAssert(transaction.status == FTransactionRun, @"[FRepo sendTransactionQueue:] items in queue should all be run."); - FFLog(@"I-RDB038021", @"Transaction at %@ set to SENT", transaction.path); + for (FTupleTransaction *transaction in queue) { + NSAssert( + transaction.status == FTransactionRun, + @"[FRepo sendTransactionQueue:] items in queue should all be run."); + FFLog(@"I-RDB038021", @"Transaction at %@ set to SENT", + transaction.path); transaction.status = FTransactionSent; transaction.retryCount++; FPath *relativePath = [FPath relativePathFrom:path to:transaction.path]; // If we've gotten to this point, the output snapshot must be defined. - snapToSend = [snapToSend updateChild:relativePath withNewChild:transaction.currentOutputSnapshotRaw]; + snapToSend = + [snapToSend updateChild:relativePath + withNewChild:transaction.currentOutputSnapshotRaw]; } id dataToSend = [snapToSend valForExport:YES]; @@ -765,63 +1011,85 @@ - (void) sendTransactionQueue:(NSMutableArray *)queue atPath:(FPath *)path { latestHash = self.hijackHash ? @"badhash" : latestHash; // Send the put - [self.connection putData:dataToSend forPath:pathToSend withHash:latestHash withCallback:^(NSString *status, NSString *errorReason) { - FFLog(@"I-RDB038022", @"Transaction put response: %@ : %@", pathToSend, status); - - NSMutableArray *events = [[NSMutableArray alloc] init]; - if ([status isEqualToString:kFWPResponseForActionStatusOk]) { - // Queue up the callbacks and fire them after cleaning up all of our transaction state, since - // the callback could trigger more transactions or sets. - NSMutableArray *callbacks = [[NSMutableArray alloc] init]; - for (FTupleTransaction *transaction in queue) { - transaction.status = FTransactionCompleted; - [events addObjectsFromArray:[self.serverSyncTree ackUserWriteWithWriteId:[transaction.currentWriteId integerValue] - revert:NO - persist:NO - clock:self.serverClock]]; - if (transaction.onComplete) { - // We never unset the output snapshot, and given that this transaction is complete, it should be set - id node = transaction.currentOutputSnapshotResolved; - FIndexedNode *indexedNode = [FIndexedNode indexedNodeWithNode:node]; - FIRDatabaseReference *ref = [[FIRDatabaseReference alloc] initWithRepo:self path:transaction.path]; - FIRDataSnapshot *snapshot = [[FIRDataSnapshot alloc] initWithRef:ref indexedNode:indexedNode]; - fbt_void_void cb = ^{ + [self.connection + putData:dataToSend + forPath:pathToSend + withHash:latestHash + withCallback:^(NSString *status, NSString *errorReason) { + FFLog(@"I-RDB038022", @"Transaction put response: %@ : %@", + pathToSend, status); + + NSMutableArray *events = [[NSMutableArray alloc] init]; + if ([status isEqualToString:kFWPResponseForActionStatusOk]) { + // Queue up the callbacks and fire them after cleaning up all of + // our transaction state, since the callback could trigger more + // transactions or sets. + NSMutableArray *callbacks = [[NSMutableArray alloc] init]; + for (FTupleTransaction *transaction in queue) { + transaction.status = FTransactionCompleted; + [events addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId: + [transaction.currentWriteId integerValue] + revert:NO + persist:NO + clock:self.serverClock]]; + if (transaction.onComplete) { + // We never unset the output snapshot, and given that this + // transaction is complete, it should be set + id node = + transaction.currentOutputSnapshotResolved; + FIndexedNode *indexedNode = + [FIndexedNode indexedNodeWithNode:node]; + FIRDatabaseReference *ref = [[FIRDatabaseReference alloc] + initWithRepo:self + path:transaction.path]; + FIRDataSnapshot *snapshot = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:indexedNode]; + fbt_void_void cb = ^{ transaction.onComplete(nil, YES, snapshot); - }; - [callbacks addObject:[cb copy]]; - } - transaction.unwatcher(); - } - - // Now remove the completed transactions. - [self pruneCompletedTransactionsBelowNode:[self.transactionQueueTree subTree:path]]; - // There may be pending transactions that we can now send. - [self sendAllReadyTransactions]; - - // Finally, trigger onComplete callbacks - [self.eventRaiser raiseCallbacks:callbacks]; - } else { - // transactions are no longer sent. Update their status appropriately. - if ([status isEqualToString:kFWPResponseForActionStatusDataStale]) { - for (FTupleTransaction *transaction in queue) { - if (transaction.status == FTransactionSentNeedsAbort) { - transaction.status = FTransactionNeedsAbort; - } else { - transaction.status = FTransactionRun; - } - } - } else { - FFWarn(@"I-RDB038023", @"runTransactionBlock: at %@ failed: %@", path, status); - for (FTupleTransaction *transaction in queue) { - transaction.status = FTransactionNeedsAbort; - [transaction setAbortStatus:status reason:errorReason]; - } - } - } - - [self rerunTransactionsForPath:path]; - [self.eventRaiser raiseEvents:events]; - }]; + }; + [callbacks addObject:[cb copy]]; + } + transaction.unwatcher(); + } + + // Now remove the completed transactions. + [self + pruneCompletedTransactionsBelowNode:[self.transactionQueueTree + subTree:path]]; + // There may be pending transactions that we can now send. + [self sendAllReadyTransactions]; + + // Finally, trigger onComplete callbacks + [self.eventRaiser raiseCallbacks:callbacks]; + } else { + // transactions are no longer sent. Update their status + // appropriately. + if ([status + isEqualToString:kFWPResponseForActionStatusDataStale]) { + for (FTupleTransaction *transaction in queue) { + if (transaction.status == FTransactionSentNeedsAbort) { + transaction.status = FTransactionNeedsAbort; + } else { + transaction.status = FTransactionRun; + } + } + } else { + FFWarn(@"I-RDB038023", + @"runTransactionBlock: at %@ failed: %@", path, + status); + for (FTupleTransaction *transaction in queue) { + transaction.status = FTransactionNeedsAbort; + [transaction setAbortStatus:status reason:errorReason]; + } + } + } + + [self rerunTransactionsForPath:path]; + [self.eventRaiser raiseEvents:events]; + }]; } /** @@ -829,18 +1097,21 @@ - (void) sendTransactionQueue:(NSMutableArray *)queue atPath:(FPath *)path { * * Should be called any time cached data changes. * - * Return the highest path that was affected by rerunning transactions. This is the path at which events need to - * be raised for. + * Return the highest path that was affected by rerunning transactions. This is + * the path at which events need to be raised for. */ -- (FPath *) rerunTransactionsForPath:(FPath *)changedPath { - // For the common case that there are no transactions going on, skip all this! +- (FPath *)rerunTransactionsForPath:(FPath *)changedPath { + // For the common case that there are no transactions going on, skip all + // this! if ([self.transactionQueueTree isEmpty]) { return changedPath; } else { - FTree* rootMostTransactionNode = [self getAncestorTransactionNodeForPath:changedPath]; - FPath* path = rootMostTransactionNode.path; + FTree *rootMostTransactionNode = + [self getAncestorTransactionNodeForPath:changedPath]; + FPath *path = rootMostTransactionNode.path; - NSArray* queue = [self buildTransactionQueueAtNode:rootMostTransactionNode]; + NSArray *queue = + [self buildTransactionQueueAtNode:rootMostTransactionNode]; [self rerunTransactionQueue:queue atPath:path]; return path; @@ -848,83 +1119,121 @@ - (FPath *) rerunTransactionsForPath:(FPath *)changedPath { } /** - * Does all the work of rerunning transactions (as well as cleans up aborted transactions and whatnot). + * Does all the work of rerunning transactions (as well as cleans up aborted + * transactions and whatnot). */ -- (void) rerunTransactionQueue:(NSArray *)queue atPath:(FPath *)path { +- (void)rerunTransactionQueue:(NSArray *)queue atPath:(FPath *)path { if (queue.count == 0) { return; // nothing to do } - // Queue up the callbacks and fire them after cleaning up all of our transaction state, since - // the callback could trigger more transactions or sets. + // Queue up the callbacks and fire them after cleaning up all of our + // transaction state, since the callback could trigger more transactions or + // sets. NSMutableArray *events = [[NSMutableArray alloc] init]; NSMutableArray *callbacks = [[NSMutableArray alloc] init]; - // Ignore, by default, all of the sets in this queue, since we're re-running all of them. However, we want to include - // the results of new sets triggered as part of this re-run, so we don't want to ignore a range, just these specific - // sets. + // Ignore, by default, all of the sets in this queue, since we're re-running + // all of them. However, we want to include the results of new sets + // triggered as part of this re-run, so we don't want to ignore a range, + // just these specific sets. NSMutableArray *writeIdsToExclude = [[NSMutableArray alloc] init]; for (FTupleTransaction *transaction in queue) { [writeIdsToExclude addObject:transaction.currentWriteId]; } - for (FTupleTransaction* transaction in queue) { - FPath* relativePath __unused = [FPath relativePathFrom:path to:transaction.path]; + for (FTupleTransaction *transaction in queue) { + FPath *relativePath __unused = + [FPath relativePathFrom:path to:transaction.path]; BOOL abortTransaction = NO; - NSAssert(relativePath != nil, @"[FRepo rerunTransactionsQueue:] relativePath should not be null."); + NSAssert(relativePath != nil, @"[FRepo rerunTransactionsQueue:] " + @"relativePath should not be null."); if (transaction.status == FTransactionNeedsAbort) { abortTransaction = YES; - if (![transaction.abortStatus isEqualToString:kFErrorWriteCanceled]) { - NSArray *ackEvents = [self.serverSyncTree ackUserWriteWithWriteId:[transaction.currentWriteId integerValue] - revert:YES - persist:NO - clock:self.serverClock]; + if (![transaction.abortStatus + isEqualToString:kFErrorWriteCanceled]) { + NSArray *ackEvents = [self.serverSyncTree + ackUserWriteWithWriteId:[transaction.currentWriteId + integerValue] + revert:YES + persist:NO + clock:self.serverClock]; [events addObjectsFromArray:ackEvents]; } } else if (transaction.status == FTransactionRun) { if (transaction.retryCount >= kFTransactionMaxRetries) { abortTransaction = YES; - [transaction setAbortStatus:kFTransactionTooManyRetries reason:nil]; - [events addObjectsFromArray:[self.serverSyncTree ackUserWriteWithWriteId:[transaction.currentWriteId integerValue] - revert:YES - persist:NO - clock:self.serverClock]]; + [transaction setAbortStatus:kFTransactionTooManyRetries + reason:nil]; + [events + addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId:[transaction.currentWriteId + integerValue] + revert:YES + persist:NO + clock:self.serverClock]]; } else { // This code reruns a transaction - id currentNode = [self latestStateAtPath:transaction.path excludeWriteIds:writeIdsToExclude]; + id currentNode = + [self latestStateAtPath:transaction.path + excludeWriteIds:writeIdsToExclude]; transaction.currentInputSnapshot = currentNode; - FIRMutableData * mutableCurrent = [[FIRMutableData alloc] initWithNode:currentNode]; - FIRTransactionResult * result = transaction.update(mutableCurrent); + FIRMutableData *mutableCurrent = + [[FIRMutableData alloc] initWithNode:currentNode]; + FIRTransactionResult *result = + transaction.update(mutableCurrent); if (result.isSuccess) { NSNumber *oldWriteId = transaction.currentWriteId; - NSDictionary* serverValues = [FServerValues generateServerValues:self.serverClock]; + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; id newVal = [result.update nodeValue]; - id newValResolved = [FServerValues resolveDeferredValueSnapshot:newVal withServerValues:serverValues]; + id newValResolved = [FServerValues + resolveDeferredValueSnapshot:newVal + withServerValues:serverValues]; transaction.currentOutputSnapshotRaw = newVal; transaction.currentOutputSnapshotResolved = newValResolved; - transaction.currentWriteId = [NSNumber numberWithInteger:[self nextWriteId]]; + transaction.currentWriteId = + [NSNumber numberWithInteger:[self nextWriteId]]; // Mutates writeIdsToExclude in place [writeIdsToExclude removeObject:oldWriteId]; - [events addObjectsFromArray:[self.serverSyncTree applyUserOverwriteAtPath:transaction.path - newData:transaction.currentOutputSnapshotResolved - writeId:[transaction.currentWriteId integerValue] - isVisible:transaction.applyLocally]]; - [events addObjectsFromArray:[self.serverSyncTree ackUserWriteWithWriteId:[oldWriteId integerValue] - revert:YES - persist:NO - clock:self.serverClock]]; + [events + addObjectsFromArray: + [self.serverSyncTree + applyUserOverwriteAtPath:transaction.path + newData: + transaction + .currentOutputSnapshotResolved + writeId: + [transaction.currentWriteId + integerValue] + isVisible:transaction + .applyLocally]]; + [events addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId:[oldWriteId + integerValue] + revert:YES + persist:NO + clock:self.serverClock]]; } else { abortTransaction = YES; - // The user aborted the transaction. JS treats ths as a "nodata" abort, but it's not an error, so we don't send them an error. + // The user aborted the transaction. JS treats ths as a + // "nodata" abort, but it's not an error, so we don't send + // them an error. [transaction setAbortStatus:nil reason:nil]; - [events addObjectsFromArray:[self.serverSyncTree ackUserWriteWithWriteId:[transaction.currentWriteId integerValue] - revert:YES - persist:NO - clock:self.serverClock]]; + [events + addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId: + [transaction.currentWriteId integerValue] + revert:YES + persist:NO + clock:self.serverClock]]; } } } @@ -937,19 +1246,26 @@ - (void) rerunTransactionQueue:(NSArray *)queue atPath:(FPath *)path { transaction.status = FTransactionCompleted; transaction.unwatcher(); if (transaction.onComplete) { - FIRDatabaseReference * ref = [[FIRDatabaseReference alloc] initWithRepo:self path:transaction.path]; - FIndexedNode *lastInput = [FIndexedNode indexedNodeWithNode:transaction.currentInputSnapshot]; - FIRDataSnapshot * snap = [[FIRDataSnapshot alloc] initWithRef:ref indexedNode:lastInput]; + FIRDatabaseReference *ref = [[FIRDatabaseReference alloc] + initWithRepo:self + path:transaction.path]; + FIndexedNode *lastInput = [FIndexedNode + indexedNodeWithNode:transaction.currentInputSnapshot]; + FIRDataSnapshot *snap = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:lastInput]; fbt_void_void cb = ^{ - // Unlike JS, no need to check for "nodata" because ObjC has abortError = nil - transaction.onComplete(transaction.abortError, NO, snap); + // Unlike JS, no need to check for "nodata" because ObjC has + // abortError = nil + transaction.onComplete(transaction.abortError, NO, snap); }; [callbacks addObject:[cb copy]]; } } } - // Note: unlike current js client, we don't need to preserve priority. Users can set priority via FIRMutableData + // Note: unlike current js client, we don't need to preserve priority. Users + // can set priority via FIRMutableData // Clean up completed transactions. [self pruneCompletedTransactionsBelowNode:self.transactionQueueTree]; @@ -961,48 +1277,52 @@ - (void) rerunTransactionQueue:(NSArray *)queue atPath:(FPath *)path { [self sendAllReadyTransactions]; } -- (FTree *) getAncestorTransactionNodeForPath:(FPath *)path { - FTree* transactionNode = self.transactionQueueTree; +- (FTree *)getAncestorTransactionNodeForPath:(FPath *)path { + FTree *transactionNode = self.transactionQueueTree; while (![path isEmpty] && [transactionNode getValue] == nil) { - NSString* front = [path getFront]; - transactionNode = [transactionNode subTree:[[FPath alloc] initWith:front]]; + NSString *front = [path getFront]; + transactionNode = + [transactionNode subTree:[[FPath alloc] initWith:front]]; path = [path popFront]; } return transactionNode; } -- (NSMutableArray *) buildTransactionQueueAtNode:(FTree *)node { - NSMutableArray* queue = [[NSMutableArray alloc] init]; +- (NSMutableArray *)buildTransactionQueueAtNode:(FTree *)node { + NSMutableArray *queue = [[NSMutableArray alloc] init]; [self aggregateTransactionQueuesForNode:node andQueue:queue]; - [queue sortUsingComparator:^NSComparisonResult(FTupleTransaction* obj1, FTupleTransaction* obj2) { - return [obj1.order compare:obj2.order]; + [queue sortUsingComparator:^NSComparisonResult(FTupleTransaction *obj1, + FTupleTransaction *obj2) { + return [obj1.order compare:obj2.order]; }]; return queue; } -- (void) aggregateTransactionQueuesForNode:(FTree *)node andQueue:(NSMutableArray *)queue { - NSArray* nodeQueue = [node getValue]; +- (void)aggregateTransactionQueuesForNode:(FTree *)node + andQueue:(NSMutableArray *)queue { + NSArray *nodeQueue = [node getValue]; [queue addObjectsFromArray:nodeQueue]; [node forEachChild:^(FTree *child) { - [self aggregateTransactionQueuesForNode:child andQueue:queue]; + [self aggregateTransactionQueuesForNode:child andQueue:queue]; }]; } /** - * Remove COMPLETED transactions at or below this node in the transactionQueueTree + * Remove COMPLETED transactions at or below this node in the + * transactionQueueTree */ -- (void) pruneCompletedTransactionsBelowNode:(FTree *)node { - NSMutableArray* queue = [node getValue]; +- (void)pruneCompletedTransactionsBelowNode:(FTree *)node { + NSMutableArray *queue = [node getValue]; if (queue != nil) { int i = 0; // remove all of the completed transactions from the queue while (i < queue.count) { - FTupleTransaction* transaction = [queue objectAtIndex:i]; + FTupleTransaction *transaction = [queue objectAtIndex:i]; if (transaction.status == FTransactionCompleted) { [queue removeObjectAtIndex:i]; } else { @@ -1017,33 +1337,36 @@ - (void) pruneCompletedTransactionsBelowNode:(FTree *)node { } [node forEachChildMutationSafe:^(FTree *child) { - [self pruneCompletedTransactionsBelowNode:child]; + [self pruneCompletedTransactionsBelowNode:child]; }]; } /** - * Aborts all transactions on ancestors or descendants of the specified path. Called when doing a setValue: or - * updateChildValues: since we consider them incompatible with transactions + * Aborts all transactions on ancestors or descendants of the specified path. + * Called when doing a setValue: or updateChildValues: since we consider them + * incompatible with transactions * * @param path path for which we want to abort related transactions. */ -- (FPath *) abortTransactionsAtPath:(FPath *)path error:(NSString *)error { - // For the common case that there are no transactions going on, skip all this! +- (FPath *)abortTransactionsAtPath:(FPath *)path error:(NSString *)error { + // For the common case that there are no transactions going on, skip all + // this! if ([self.transactionQueueTree isEmpty]) { return path; } else { - FPath* affectedPath = [self getAncestorTransactionNodeForPath:path].path; + FPath *affectedPath = + [self getAncestorTransactionNodeForPath:path].path; - FTree* transactionNode = [self.transactionQueueTree subTree:path]; + FTree *transactionNode = [self.transactionQueueTree subTree:path]; [transactionNode forEachAncestor:^BOOL(FTree *ancestor) { - [self abortTransactionsAtNode:ancestor error:error]; - return NO; + [self abortTransactionsAtNode:ancestor error:error]; + return NO; }]; [self abortTransactionsAtNode:transactionNode error:error]; [transactionNode forEachDescendant:^(FTree *child) { - [self abortTransactionsAtNode:child error:error]; + [self abortTransactionsAtNode:child error:error]; }]; return affectedPath; @@ -1055,20 +1378,21 @@ - (FPath *) abortTransactionsAtPath:(FPath *)path error:(NSString *)error { * * @param node Node to abort transactions for. */ -- (void) abortTransactionsAtNode:(FTree *)node error:(NSString *)error { - NSMutableArray* queue = [node getValue]; +- (void)abortTransactionsAtNode:(FTree *)node error:(NSString *)error { + NSMutableArray *queue = [node getValue]; if (queue != nil) { - // Queue up the callbacks and fire them after cleaning up all of our transaction state, since - // can be immediately aborted and removed. - NSMutableArray* callbacks = [[NSMutableArray alloc] init]; + // Queue up the callbacks and fire them after cleaning up all of our + // transaction state, since can be immediately aborted and removed. + NSMutableArray *callbacks = [[NSMutableArray alloc] init]; - // Go through queue. Any already-sent transactions must be marked for abort, while the unsent ones - // can be immediately aborted and removed + // Go through queue. Any already-sent transactions must be marked for + // abort, while the unsent ones can be immediately aborted and removed NSMutableArray *events = [[NSMutableArray alloc] init]; int lastSent = -1; - // Note: all of the sent transactions will be at the front of the queue, so safe to increment lastSent - for (FTupleTransaction* transaction in queue) { + // Note: all of the sent transactions will be at the front of the queue, + // so safe to increment lastSent + for (FTupleTransaction *transaction in queue) { if (transaction.status == FTransactionSentNeedsAbort) { // No-op. already marked. } else if (transaction.status == FTransactionSent) { @@ -1080,27 +1404,34 @@ - (void) abortTransactionsAtNode:(FTree *)node error:(NSString *)error { // we can abort this immediately transaction.unwatcher(); if ([error isEqualToString:kFTransactionSet]) { - [events addObjectsFromArray:[self.serverSyncTree ackUserWriteWithWriteId:[transaction.currentWriteId integerValue] - revert:YES - persist:NO - clock:self.serverClock]]; + [events + addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId: + [transaction.currentWriteId integerValue] + revert:YES + persist:NO + clock:self.serverClock]]; } else { - // If it was cancelled it was already removed from the sync tree, no need to ack + // If it was cancelled it was already removed from the sync + // tree, no need to ack NSAssert([error isEqualToString:kFErrorWriteCanceled], nil); } if (transaction.onComplete) { - NSError* abortReason = [FUtilities errorForStatus:error andReason:nil]; - FIRDataSnapshot * snapshot = nil; + NSError *abortReason = [FUtilities errorForStatus:error + andReason:nil]; + FIRDataSnapshot *snapshot = nil; fbt_void_void cb = ^{ - transaction.onComplete(abortReason, NO, snapshot); + transaction.onComplete(abortReason, NO, snapshot); }; [callbacks addObject:[cb copy]]; } } } if (lastSent == -1) { - // We're not waiting for any sent transactions. We can clear the queue. + // We're not waiting for any sent transactions. We can clear the + // queue. [node setValue:nil]; } else { // Remove the transactions we aborted diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoInfo.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoInfo.h index 433bf35..46e9b8b 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoInfo.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoInfo.h @@ -18,18 +18,20 @@ @interface FRepoInfo : NSObject -@property (nonatomic, readonly, strong) NSString* host; -@property (nonatomic, readonly, strong) NSString* namespace; -@property (nonatomic, strong) NSString* internalHost; -@property (nonatomic, readonly) bool secure; +@property(nonatomic, readonly, strong) NSString *host; +@property(nonatomic, readonly, strong) NSString *namespace; +@property(nonatomic, strong) NSString *internalHost; +@property(nonatomic, readonly) bool secure; -- (id) initWithHost:(NSString*)host isSecure:(bool)secure withNamespace:(NSString*)namespace; +- (id)initWithHost:(NSString *)host + isSecure:(bool)secure + withNamespace:(NSString *)namespace; -- (NSString *) connectionURLWithLastSessionID:(NSString*)lastSessionID; -- (NSString *) connectionURL; -- (void) clearInternalHostCache; -- (BOOL) isDemoHost; -- (BOOL) isCustomHost; +- (NSString *)connectionURLWithLastSessionID:(NSString *)lastSessionID; +- (NSString *)connectionURL; +- (void)clearInternalHostCache; +- (BOOL)isDemoHost; +- (BOOL)isCustomHost; - (id)copyWithZone:(NSZone *)zone; - (NSUInteger)hash; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoInfo.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoInfo.m index 925163e..b2dd2e2 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoInfo.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoInfo.m @@ -19,11 +19,10 @@ @interface FRepoInfo () -@property (nonatomic, strong) NSString *domain; +@property(nonatomic, strong) NSString *domain; @end - @implementation FRepoInfo @synthesize namespace; @@ -32,17 +31,25 @@ @implementation FRepoInfo @synthesize secure; @synthesize domain; -- (id) initWithHost:(NSString*)aHost isSecure:(bool)isSecure withNamespace:(NSString*)aNamespace { +- (id)initWithHost:(NSString *)aHost + isSecure:(bool)isSecure + withNamespace:(NSString *)aNamespace { self = [super init]; if (self) { host = aHost; - domain = [host substringFromIndex:[host rangeOfString:@"."].location+1]; + domain = + [host containsString:@"."] + ? [host + substringFromIndex:[host rangeOfString:@"."].location + 1] + : host; secure = isSecure; namespace = aNamespace; // Get cached internal host if it exists - NSString* internalHostKey = [NSString stringWithFormat:@"firebase:host:%@", self.host]; - NSString* cachedInternalHost = [[NSUserDefaults standardUserDefaults] stringForKey:internalHostKey]; + NSString *internalHostKey = + [NSString stringWithFormat:@"firebase:host:%@", self.host]; + NSString *cachedInternalHost = [[NSUserDefaults standardUserDefaults] + stringForKey:internalHostKey]; if (cachedInternalHost != nil) { internalHost = cachedInternalHost; } else { @@ -54,57 +61,58 @@ - (id) initWithHost:(NSString*)aHost isSecure:(bool)isSecure withNamespace:(NSSt - (NSString *)description { // The namespace is encoded in the hostname, so we can just return this. - return [NSString stringWithFormat:@"http%@://%@", (self.secure ? @"s" : @""), self.host]; + return [NSString + stringWithFormat:@"http%@://%@", (self.secure ? @"s" : @""), self.host]; } -- (void) setInternalHost:(NSString *)newHost { +- (void)setInternalHost:(NSString *)newHost { if (![internalHost isEqualToString:newHost]) { internalHost = newHost; // Cache the internal host so we don't need to redirect later on - NSString* internalHostKey = [NSString stringWithFormat:@"firebase:host:%@", self.host]; - NSUserDefaults* cache = [NSUserDefaults standardUserDefaults]; + NSString *internalHostKey = + [NSString stringWithFormat:@"firebase:host:%@", self.host]; + NSUserDefaults *cache = [NSUserDefaults standardUserDefaults]; [cache setObject:internalHost forKey:internalHostKey]; [cache synchronize]; } } -- (void) clearInternalHostCache { +- (void)clearInternalHostCache { internalHost = self.host; // Remove the cached entry - NSString* internalHostKey = [NSString stringWithFormat:@"firebase:host:%@", self.host]; - NSUserDefaults* cache = [NSUserDefaults standardUserDefaults]; + NSString *internalHostKey = + [NSString stringWithFormat:@"firebase:host:%@", self.host]; + NSUserDefaults *cache = [NSUserDefaults standardUserDefaults]; [cache removeObjectForKey:internalHostKey]; [cache synchronize]; } -- (BOOL) isDemoHost { +- (BOOL)isDemoHost { return [self.domain isEqualToString:@"firebaseio-demo.com"]; } -- (BOOL) isCustomHost { - return ![self.domain isEqualToString:@"firebaseio-demo.com"] && ![self.domain isEqualToString:@"firebaseio.com"]; +- (BOOL)isCustomHost { + return ![self.domain isEqualToString:@"firebaseio-demo.com"] && + ![self.domain isEqualToString:@"firebaseio.com"]; } - -- (NSString *) connectionURL { +- (NSString *)connectionURL { return [self connectionURLWithLastSessionID:nil]; } -- (NSString *) connectionURLWithLastSessionID:(NSString*)lastSessionID { +- (NSString *)connectionURLWithLastSessionID:(NSString *)lastSessionID { NSString *scheme; if (self.secure) { scheme = @"wss"; } else { scheme = @"ws"; } - NSString *url = [NSString stringWithFormat:@"%@://%@/.ws?%@=%@&ns=%@", - scheme, - self.internalHost, - kWireProtocolVersionParam, - kWebsocketProtocolVersion, - self.namespace]; + NSString *url = + [NSString stringWithFormat:@"%@://%@/.ws?%@=%@&ns=%@", scheme, + self.internalHost, kWireProtocolVersionParam, + kWebsocketProtocolVersion, self.namespace]; if (lastSessionID != nil) { url = [NSString stringWithFormat:@"%@&ls=%@", url, lastSessionID]; @@ -112,7 +120,8 @@ - (NSString *) connectionURLWithLastSessionID:(NSString*)lastSessionID { return url; } -- (id)copyWithZone:(NSZone *)zone; { +- (id)copyWithZone:(NSZone *)zone; +{ return self; // Immutable } @@ -125,7 +134,8 @@ - (NSUInteger)hash { } - (BOOL)isEqual:(id)anObject { - if (![anObject isKindOfClass:[FRepoInfo class]]) return NO; + if (![anObject isKindOfClass:[FRepoInfo class]]) + return NO; FRepoInfo *other = (FRepoInfo *)anObject; return secure == other.secure && [host isEqualToString:other.host] && [namespace isEqualToString:other.namespace]; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoManager.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoManager.h index c492861..ba8d1fc 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoManager.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoManager.h @@ -14,19 +14,21 @@ * limitations under the License. */ -#import -#import "FRepoInfo.h" -#import "FRepo.h" #import "FIRDatabaseConfig.h" +#import "FRepo.h" +#import "FRepoInfo.h" +#import @interface FRepoManager : NSObject -+ (FRepo *) getRepo:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config; -+ (FRepo *) createRepo:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config database:(FIRDatabase *)database; -+ (void) interruptAll; -+ (void) interrupt:(FIRDatabaseConfig *)config; -+ (void) resumeAll; -+ (void) resume:(FIRDatabaseConfig *)config; -+ (void) disposeRepos:(FIRDatabaseConfig *)config; ++ (FRepo *)getRepo:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config; ++ (FRepo *)createRepo:(FRepoInfo *)repoInfo + config:(FIRDatabaseConfig *)config + database:(FIRDatabase *)database; ++ (void)interruptAll; ++ (void)interrupt:(FIRDatabaseConfig *)config; ++ (void)resumeAll; ++ (void)resume:(FIRDatabaseConfig *)config; ++ (void)disposeRepos:(FIRDatabaseConfig *)config; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoManager.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoManager.m index 31c3efc..54ad196 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoManager.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepoManager.m @@ -14,13 +14,13 @@ * limitations under the License. */ -#import #import "FRepoManager.h" -#import "FRepo.h" -#import "FIRDatabaseQuery_Private.h" #import "FAtomicNumber.h" #import "FIRDatabaseConfig_Private.h" +#import "FIRDatabaseQuery_Private.h" #import "FIRDatabase_Private.h" +#import "FRepo.h" +#import @implementation FRepoManager @@ -32,20 +32,21 @@ + (FRepoDictionary *)configs { static dispatch_once_t pred = 0; static FRepoDictionary *configs; dispatch_once(&pred, ^{ - configs = [NSMutableDictionary dictionary]; + configs = [NSMutableDictionary dictionary]; }); return configs; } /** - * Used for legacy unit tests. The public API should go through FirebaseDatabase which - * calls createRepo. + * Used for legacy unit tests. The public API should go through + * FirebaseDatabase which calls createRepo. */ -+ (FRepo *) getRepo:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config { ++ (FRepo *)getRepo:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config { [config freeze]; FRepoDictionary *configs = [FRepoManager configs]; @synchronized(configs) { - NSMutableDictionary *repos = configs[config.sessionIdentifier]; + NSMutableDictionary *repos = + configs[config.sessionIdentifier]; if (!repos || repos[repoInfo] == nil) { // Calling this should create the repo. [FIRDatabase createDatabaseForTests:repoInfo config:config]; @@ -55,7 +56,9 @@ + (FRepo *) getRepo:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config { } } -+ (FRepo *) createRepo:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config database:(FIRDatabase *)database { ++ (FRepo *)createRepo:(FRepoInfo *)repoInfo + config:(FIRDatabaseConfig *)config + database:(FIRDatabase *)database { [config freeze]; FRepoDictionary *configs = [FRepoManager configs]; @synchronized(configs) { @@ -67,68 +70,78 @@ + (FRepo *) createRepo:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config } FRepo *repo = repos[repoInfo]; if (repo == nil) { - repo = [[FRepo alloc] initWithRepoInfo:repoInfo config:config database:database]; + repo = [[FRepo alloc] initWithRepoInfo:repoInfo + config:config + database:database]; repos[repoInfo] = repo; return repo; } else { - [NSException raise:@"RepoExists" format:@"createRepo called for Repo that already exists."]; + [NSException + raise:@"RepoExists" + format:@"createRepo called for Repo that already exists."]; return nil; } } } -+ (void) interrupt:(FIRDatabaseConfig *)config { ++ (void)interrupt:(FIRDatabaseConfig *)config { dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - FRepoDictionary *configs = [FRepoManager configs]; - NSMutableDictionary *repos = configs[config.sessionIdentifier]; - for (FRepo *repo in [repos allValues]) { - [repo interrupt]; - } + FRepoDictionary *configs = [FRepoManager configs]; + NSMutableDictionary *repos = + configs[config.sessionIdentifier]; + for (FRepo *repo in [repos allValues]) { + [repo interrupt]; + } }); } -+ (void) interruptAll { ++ (void)interruptAll { dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - FRepoDictionary *configs = [FRepoManager configs]; - for (NSMutableDictionary *repos in [configs allValues]) { - for (FRepo *repo in [repos allValues]) { - [repo interrupt]; - } - } + FRepoDictionary *configs = [FRepoManager configs]; + for (NSMutableDictionary *repos in + [configs allValues]) { + for (FRepo *repo in [repos allValues]) { + [repo interrupt]; + } + } }); } -+ (void) resume:(FIRDatabaseConfig *)config { ++ (void)resume:(FIRDatabaseConfig *)config { dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - FRepoDictionary *configs = [FRepoManager configs]; - NSMutableDictionary *repos = configs[config.sessionIdentifier]; - for (FRepo *repo in [repos allValues]) { - [repo resume]; - } + FRepoDictionary *configs = [FRepoManager configs]; + NSMutableDictionary *repos = + configs[config.sessionIdentifier]; + for (FRepo *repo in [repos allValues]) { + [repo resume]; + } }); } -+ (void) resumeAll { ++ (void)resumeAll { dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - FRepoDictionary *configs = [FRepoManager configs]; - for (NSMutableDictionary *repos in [configs allValues]) { - for (FRepo *repo in [repos allValues]) { - [repo resume]; - } - } + FRepoDictionary *configs = [FRepoManager configs]; + for (NSMutableDictionary *repos in + [configs allValues]) { + for (FRepo *repo in [repos allValues]) { + [repo resume]; + } + } }); } + (void)disposeRepos:(FIRDatabaseConfig *)config { - // Do this synchronously to make sure we release our references to LevelDB before returning, allowing LevelDB - // to close and release its exclusive locks. + // Do this synchronously to make sure we release our references to LevelDB + // before returning, allowing LevelDB to close and release its exclusive + // locks. dispatch_sync([FIRDatabaseQuery sharedQueue], ^{ - FFLog(@"I-RDB040001", @"Disposing all repos for Config with name %@", config.sessionIdentifier); - NSMutableDictionary *configs = [FRepoManager configs]; - for (FRepo* repo in [configs[config.sessionIdentifier] allValues]) { - [repo dispose]; - } - [configs removeObjectForKey:config.sessionIdentifier]; + FFLog(@"I-RDB040001", @"Disposing all repos for Config with name %@", + config.sessionIdentifier); + NSMutableDictionary *configs = [FRepoManager configs]; + for (FRepo *repo in [configs[config.sessionIdentifier] allValues]) { + [repo dispose]; + } + [configs removeObjectForKey:config.sessionIdentifier]; }); } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepo_Private.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepo_Private.h index 109edac..8dc1350 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepo_Private.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FRepo_Private.h @@ -24,18 +24,18 @@ @interface FRepo () -- (void) runOnDisconnectEvents; +- (void)runOnDisconnectEvents; -@property (nonatomic, strong) FRepoInfo* repoInfo; -@property (nonatomic, strong) FPersistentConnection* connection; -@property (nonatomic, strong) FSnapshotHolder* infoData; -@property (nonatomic, strong) FSparseSnapshotTree* onDisconnect; -@property (nonatomic, strong) FEventRaiser *eventRaiser; -@property (nonatomic, strong) FSyncTree *serverSyncTree; +@property(nonatomic, strong) FRepoInfo *repoInfo; +@property(nonatomic, strong) FPersistentConnection *connection; +@property(nonatomic, strong) FSnapshotHolder *infoData; +@property(nonatomic, strong) FSparseSnapshotTree *onDisconnect; +@property(nonatomic, strong) FEventRaiser *eventRaiser; +@property(nonatomic, strong) FSyncTree *serverSyncTree; // For testing. -@property (nonatomic) long dataUpdateCount; -@property (nonatomic) long rangeMergeUpdateCount; +@property(nonatomic) long dataUpdateCount; +@property(nonatomic) long rangeMergeUpdateCount; - (NSInteger)nextWriteId; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FServerValues.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FServerValues.h index 2540c12..33d1e57 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FServerValues.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FServerValues.h @@ -14,17 +14,20 @@ * limitations under the License. */ -#import -#import "FSparseSnapshotTree.h" -#import "FNode.h" -#import "FCompoundWrite.h" #import "FClock.h" +#import "FCompoundWrite.h" +#import "FNode.h" +#import "FSparseSnapshotTree.h" +#import @interface FServerValues : NSObject -+ (NSDictionary*) generateServerValues:(id)clock; -+ (id) resolveDeferredValueCompoundWrite:(FCompoundWrite*)write withServerValues:(NSDictionary*)serverValues; -+ (id) resolveDeferredValueSnapshot:(id)node withServerValues:(NSDictionary*)serverValues; -+ (id) resolveDeferredValueTree:(FSparseSnapshotTree*)tree withServerValues:(NSDictionary*)serverValues; ++ (NSDictionary *)generateServerValues:(id)clock; ++ (id)resolveDeferredValueCompoundWrite:(FCompoundWrite *)write + withServerValues:(NSDictionary *)serverValues; ++ (id)resolveDeferredValueSnapshot:(id)node + withServerValues:(NSDictionary *)serverValues; ++ (id)resolveDeferredValueTree:(FSparseSnapshotTree *)tree + withServerValues:(NSDictionary *)serverValues; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FServerValues.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FServerValues.m index 89ee5d0..5519862 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FServerValues.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FServerValues.m @@ -15,23 +15,24 @@ */ #import "FServerValues.h" +#import "FChildrenNode.h" #import "FConstants.h" #import "FLeafNode.h" -#import "FChildrenNode.h" #import "FSnapshotUtilities.h" @implementation FServerValues -+ (NSDictionary*) generateServerValues:(id)clock { ++ (NSDictionary *)generateServerValues:(id)clock { long long millis = (long long)([clock currentTime] * 1000); - return @{ @"timestamp": [NSNumber numberWithLongLong:millis] }; + return @{@"timestamp" : [NSNumber numberWithLongLong:millis]}; } -+ (id) resolveDeferredValue:(id)val withServerValues:(NSDictionary*)serverValues { ++ (id)resolveDeferredValue:(id)val + withServerValues:(NSDictionary *)serverValues { if ([val isKindOfClass:[NSDictionary class]]) { - NSDictionary* dict = val; + NSDictionary *dict = val; if (dict[kServerValueSubKey] != nil) { - NSString* serverValueType = [dict objectForKey:kServerValueSubKey]; + NSString *serverValueType = [dict objectForKey:kServerValueSubKey]; if (serverValues[serverValueType] != nil) { return [serverValues objectForKey:serverValueType]; } else { @@ -42,52 +43,73 @@ + (id) resolveDeferredValue:(id)val withServerValues:(NSDictionary*)serverValues return val; } -+ (FCompoundWrite *) resolveDeferredValueCompoundWrite:(FCompoundWrite *)write withServerValues:(NSDictionary *)serverValues { ++ (FCompoundWrite *)resolveDeferredValueCompoundWrite:(FCompoundWrite *)write + withServerValues: + (NSDictionary *)serverValues { __block FCompoundWrite *resolved = write; [write enumerateWrites:^(FPath *path, id node, BOOL *stop) { - id resolvedNode = [FServerValues resolveDeferredValueSnapshot:node withServerValues:serverValues]; - // Node actually changed, use pointer inequality here - if (resolvedNode != node) { - resolved = [resolved addWrite:resolvedNode atPath:path]; - } + id resolvedNode = + [FServerValues resolveDeferredValueSnapshot:node + withServerValues:serverValues]; + // Node actually changed, use pointer inequality here + if (resolvedNode != node) { + resolved = [resolved addWrite:resolvedNode atPath:path]; + } }]; return resolved; } -+ (id) resolveDeferredValueTree:(FSparseSnapshotTree*)tree withServerValues:(NSDictionary*)serverValues { - FSparseSnapshotTree* resolvedTree = [[FSparseSnapshotTree alloc] init]; - [tree forEachTreeAtPath:[FPath empty] do:^(FPath* path, id node) { - [resolvedTree rememberData:[FServerValues resolveDeferredValueSnapshot:node withServerValues:serverValues] onPath:path]; - }]; ++ (id)resolveDeferredValueTree:(FSparseSnapshotTree *)tree + withServerValues:(NSDictionary *)serverValues { + FSparseSnapshotTree *resolvedTree = [[FSparseSnapshotTree alloc] init]; + [tree + forEachTreeAtPath:[FPath empty] + do:^(FPath *path, id node) { + [resolvedTree + rememberData: + [FServerValues + resolveDeferredValueSnapshot:node + withServerValues:serverValues] + onPath:path]; + }]; return resolvedTree; } -+ (id) resolveDeferredValueSnapshot:(id)node withServerValues:(NSDictionary*)serverValues { - id priorityVal = [FServerValues resolveDeferredValue:[[node getPriority] val] withServerValues:serverValues]; ++ (id)resolveDeferredValueSnapshot:(id)node + withServerValues:(NSDictionary *)serverValues { + id priorityVal = + [FServerValues resolveDeferredValue:[[node getPriority] val] + withServerValues:serverValues]; id priority = [FSnapshotUtilities nodeFrom:priorityVal]; if ([node isLeafNode]) { - id value = [self resolveDeferredValue:[node val] withServerValues:serverValues]; - if (![value isEqual:[node val]] || ![priority isEqual:[node getPriority]]) { - return [[FLeafNode alloc] initWithValue:value withPriority:priority]; + id value = [self resolveDeferredValue:[node val] + withServerValues:serverValues]; + if (![value isEqual:[node val]] || + ![priority isEqual:[node getPriority]]) { + return [[FLeafNode alloc] initWithValue:value + withPriority:priority]; } else { return node; } } else { - __block FChildrenNode* newNode = node; + __block FChildrenNode *newNode = node; if (![priority isEqual:[node getPriority]]) { - newNode = [newNode updatePriority:priority]; + newNode = [newNode updatePriority:priority]; } - [node enumerateChildrenUsingBlock:^(NSString *childKey, id childNode, BOOL *stop) { - id newChildNode = [FServerValues resolveDeferredValueSnapshot:childNode withServerValues:serverValues]; - if (![newChildNode isEqual:childNode]) { - newNode = [newNode updateImmediateChild:childKey withNewChild:newChildNode]; - } + [node enumerateChildrenUsingBlock:^(NSString *childKey, + id childNode, BOOL *stop) { + id newChildNode = + [FServerValues resolveDeferredValueSnapshot:childNode + withServerValues:serverValues]; + if (![newChildNode isEqual:childNode]) { + newNode = [newNode updateImmediateChild:childKey + withNewChild:newChildNode]; + } }]; return newNode; } } @end - diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSnapshotHolder.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSnapshotHolder.h index 9a1d871..d682a8e 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSnapshotHolder.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSnapshotHolder.h @@ -14,14 +14,14 @@ * limitations under the License. */ -#import #import "FNode.h" +#import @interface FSnapshotHolder : NSObject -- (id) getNode:(FPath *)path; -- (void) updateSnapshot:(FPath *)path withNewSnapshot:(id)newSnapshotNode; +- (id)getNode:(FPath *)path; +- (void)updateSnapshot:(FPath *)path withNewSnapshot:(id)newSnapshotNode; -@property (nonatomic, strong) id rootNode; +@property(nonatomic, strong) id rootNode; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSnapshotHolder.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSnapshotHolder.m index 25c4625..59a7b52 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSnapshotHolder.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSnapshotHolder.m @@ -17,8 +17,7 @@ #import "FSnapshotHolder.h" #import "FEmptyNode.h" -@interface FSnapshotHolder() - +@interface FSnapshotHolder () @end @@ -26,8 +25,7 @@ @implementation FSnapshotHolder @synthesize rootNode; -- (id)init -{ +- (id)init { self = [super init]; if (self) { self.rootNode = [FEmptyNode emptyNode]; @@ -35,12 +33,14 @@ - (id)init return self; } -- (id) getNode:(FPath *)path { +- (id)getNode:(FPath *)path { return [self.rootNode getChild:path]; } -- (void) updateSnapshot:(FPath *)path withNewSnapshot:(id)newSnapshotNode { - self.rootNode = [self.rootNode updateChild:path withNewChild:newSnapshotNode]; +- (void)updateSnapshot:(FPath *)path + withNewSnapshot:(id)newSnapshotNode { + self.rootNode = [self.rootNode updateChild:path + withNewChild:newSnapshotNode]; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSparseSnapshotTree.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSparseSnapshotTree.h index b860c9d..dab5406 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSparseSnapshotTree.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSparseSnapshotTree.h @@ -14,21 +14,21 @@ * limitations under the License. */ -#import #import "FNode.h" #import "FPath.h" #import "FTypedefs_Private.h" +#import @class FSparseSnapshotTree; -typedef void (^fbt_void_nsstring_sstree) (NSString*, FSparseSnapshotTree*); +typedef void (^fbt_void_nsstring_sstree)(NSString *, FSparseSnapshotTree *); @interface FSparseSnapshotTree : NSObject -- (id) findPath:(FPath *)path; -- (void) rememberData:(id)data onPath:(FPath *)path; -- (BOOL) forgetPath:(FPath *)path; -- (void) forEachTreeAtPath:(FPath *)prefixPath do:(fbt_void_path_node)func; -- (void) forEachChild:(fbt_void_nsstring_sstree)func; +- (id)findPath:(FPath *)path; +- (void)rememberData:(id)data onPath:(FPath *)path; +- (BOOL)forgetPath:(FPath *)path; +- (void)forEachTreeAtPath:(FPath *)prefixPath do:(fbt_void_path_node)func; +- (void)forEachChild:(fbt_void_nsstring_sstree)func; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSparseSnapshotTree.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSparseSnapshotTree.m index 1f16888..6219309 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSparseSnapshotTree.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSparseSnapshotTree.m @@ -19,14 +19,14 @@ @interface FSparseSnapshotTree () { id value; - NSMutableDictionary* children; + NSMutableDictionary *children; } @end @implementation FSparseSnapshotTree -- (id) init { +- (id)init { self = [super init]; if (self) { value = nil; @@ -35,13 +35,13 @@ - (id) init { return self; } -- (id) findPath:(FPath *)path { +- (id)findPath:(FPath *)path { if (value != nil) { return [value getChild:path]; } else if (![path isEmpty] && children != nil) { - NSString* childKey = [path getFront]; + NSString *childKey = [path getFront]; path = [path popFront]; - FSparseSnapshotTree* childTree = children[childKey]; + FSparseSnapshotTree *childTree = children[childKey]; if (childTree != nil) { return [childTree findPath:path]; } else { @@ -52,7 +52,7 @@ - (id) init { } } -- (void) rememberData:(id)data onPath:(FPath *)path { +- (void)rememberData:(id)data onPath:(FPath *)path { if ([path isEmpty]) { value = data; children = nil; @@ -63,18 +63,18 @@ - (void) rememberData:(id)data onPath:(FPath *)path { children = [[NSMutableDictionary alloc] init]; } - NSString* childKey = [path getFront]; + NSString *childKey = [path getFront]; if (children[childKey] == nil) { children[childKey] = [[FSparseSnapshotTree alloc] init]; } - FSparseSnapshotTree* child = children[childKey]; + FSparseSnapshotTree *child = children[childKey]; path = [path popFront]; [child rememberData:data onPath:path]; } } -- (BOOL) forgetPath:(FPath *)path { +- (BOOL)forgetPath:(FPath *)path { if ([path isEmpty]) { value = nil; children = nil; @@ -88,19 +88,21 @@ - (BOOL) forgetPath:(FPath *)path { id tmp = value; value = nil; - [tmp enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - [self rememberData:node onPath:[[FPath alloc] initWith:key]]; + [tmp enumerateChildrenUsingBlock:^(NSString *key, + id node, BOOL *stop) { + [self rememberData:node onPath:[[FPath alloc] initWith:key]]; }]; - // we've cleared out the value and set children. Call ourself again to hit the next case + // we've cleared out the value and set children. Call ourself + // again to hit the next case return [self forgetPath:path]; } } else if (children != nil) { - NSString* childKey = [path getFront]; + NSString *childKey = [path getFront]; path = [path popFront]; if (children[childKey] != nil) { - FSparseSnapshotTree* child = children[childKey]; + FSparseSnapshotTree *child = children[childKey]; BOOL safeToRemove = [child forgetPath:path]; if (safeToRemove) { [children removeObjectForKey:childKey]; @@ -119,26 +121,24 @@ - (BOOL) forgetPath:(FPath *)path { } } -- (void) forEachTreeAtPath:(FPath *)prefixPath do:(fbt_void_path_node)func { +- (void)forEachTreeAtPath:(FPath *)prefixPath do:(fbt_void_path_node)func { if (value != nil) { func(prefixPath, value); } else { - [self forEachChild:^(NSString* key, FSparseSnapshotTree* tree) { - FPath* path = [prefixPath childFromString:key]; - [tree forEachTreeAtPath:path do:func]; + [self forEachChild:^(NSString *key, FSparseSnapshotTree *tree) { + FPath *path = [prefixPath childFromString:key]; + [tree forEachTreeAtPath:path do:func]; }]; } } - -- (void) forEachChild:(fbt_void_nsstring_sstree)func { +- (void)forEachChild:(fbt_void_nsstring_sstree)func { if (children != nil) { - for (NSString* key in children) { - FSparseSnapshotTree* tree = [children objectForKey:key]; + for (NSString *key in children) { + FSparseSnapshotTree *tree = [children objectForKey:key]; func(key, tree); } } } - @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncPoint.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncPoint.h index 4e5a4e2..a9bd4d9 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncPoint.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncPoint.h @@ -32,35 +32,38 @@ - (id)initWithPersistenceManager:(FPersistenceManager *)persistence; -- (BOOL) isEmpty; +- (BOOL)isEmpty; /** -* Returns array of FEvent -*/ -- (NSArray *) applyOperation:(id)operation writesCache:(FWriteTreeRef *)writesCache serverCache:(id)optCompleteServerCache; + * Returns array of FEvent + */ +- (NSArray *)applyOperation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache; /** -* Returns array of FEvent -*/ -- (NSArray *) addEventRegistration:(id )eventRegistration - forNonExistingViewForQuery:(FQuerySpec *)query - writesCache:(FWriteTreeRef *)writesCache - serverCache:(FCacheNode *)serverCache; + * Returns array of FEvent + */ +- (NSArray *)addEventRegistration:(id)eventRegistration + forNonExistingViewForQuery:(FQuerySpec *)query + writesCache:(FWriteTreeRef *)writesCache + serverCache:(FCacheNode *)serverCache; -- (NSArray *) addEventRegistration:(id )eventRegistration - forExistingViewForQuery:(FQuerySpec *)query; +- (NSArray *)addEventRegistration:(id)eventRegistration + forExistingViewForQuery:(FQuerySpec *)query; -- (FTupleRemovedQueriesEvents *) removeEventRegistration:(id )eventRegistration - forQuery:(FQuerySpec *)query - cancelError:(NSError *)cancelError; +- (FTupleRemovedQueriesEvents *)removeEventRegistration: + (id)eventRegistration + forQuery:(FQuerySpec *)query + cancelError:(NSError *)cancelError; /** -* Returns array of FViews -*/ -- (NSArray *) queryViews; -- (id) completeServerCacheAtPath:(FPath *)path; -- (FView *) viewForQuery:(FQuerySpec *)query; -- (BOOL) viewExistsForQuery:(FQuerySpec *)query; -- (BOOL) hasCompleteView; -- (FView *) completeView; + * Returns array of FViews + */ +- (NSArray *)queryViews; +- (id)completeServerCacheAtPath:(FPath *)path; +- (FView *)viewForQuery:(FQuerySpec *)query; +- (BOOL)viewExistsForQuery:(FQuerySpec *)query; +- (BOOL)hasCompleteView; +- (FView *)completeView; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncPoint.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncPoint.m index cd429f1..6496ae8 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncPoint.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncPoint.m @@ -15,51 +15,54 @@ */ #import "FSyncPoint.h" -#import "FOperation.h" -#import "FWriteTreeRef.h" -#import "FNode.h" +#import "FCacheNode.h" +#import "FChildrenNode.h" +#import "FDataEvent.h" +#import "FEmptyNode.h" #import "FEventRegistration.h" #import "FIRDatabaseQuery.h" -#import "FChildrenNode.h" -#import "FTupleRemovedQueriesEvents.h" -#import "FView.h" +#import "FNode.h" +#import "FOperation.h" #import "FOperationSource.h" -#import "FQuerySpec.h" -#import "FQueryParams.h" #import "FPath.h" -#import "FEmptyNode.h" -#import "FViewCache.h" -#import "FCacheNode.h" #import "FPersistenceManager.h" -#import "FDataEvent.h" +#import "FQueryParams.h" +#import "FQuerySpec.h" +#import "FTupleRemovedQueriesEvents.h" +#import "FView.h" +#import "FViewCache.h" +#import "FWriteTreeRef.h" /** -* SyncPoint represents a single location in a SyncTree with 1 or more event registrations, meaning we need to -* maintain 1 or more Views at this location to cache server data and raise appropriate events for server changes -* and user writes (set, transaction, update). -* -* It's responsible for: -* - Maintaining the set of 1 or more views necessary at this location (a SyncPoint with 0 views should be removed). -* - Proxying user / server operations to the views as appropriate (i.e. applyServerOverwrite, -* applyUserOverwrite, etc.) -*/ + * SyncPoint represents a single location in a SyncTree with 1 or more event + * registrations, meaning we need to maintain 1 or more Views at this location + * to cache server data and raise appropriate events for server changes and user + * writes (set, transaction, update). + * + * It's responsible for: + * - Maintaining the set of 1 or more views necessary at this location (a + * SyncPoint with 0 views should be removed). + * - Proxying user / server operations to the views as appropriate (i.e. + * applyServerOverwrite, applyUserOverwrite, etc.) + */ @interface FSyncPoint () /** -* The Views being tracked at this location in the tree, stored as a map where the key is a -* queryParams and the value is the View for that query. -* -* NOTE: This list will be quite small (usually 1, but perhaps 2 or 3; any more is an odd use case). -* -* Maps NSString -> FView -*/ -@property (nonatomic, strong) NSMutableDictionary *views; + * The Views being tracked at this location in the tree, stored as a map where + * the key is a queryParams and the value is the View for that query. + * + * NOTE: This list will be quite small (usually 1, but perhaps 2 or 3; any more + * is an odd use case). + * + * Maps NSString -> FView + */ +@property(nonatomic, strong) NSMutableDictionary *views; -@property (nonatomic, strong) FPersistenceManager *persistenceManager; +@property(nonatomic, strong) FPersistenceManager *persistenceManager; @end @implementation FSyncPoint -- (id) initWithPersistenceManager:(FPersistenceManager *)persistence { +- (id)initWithPersistenceManager:(FPersistenceManager *)persistence { self = [super init]; if (self) { self.persistenceManager = persistence; @@ -68,83 +71,111 @@ - (id) initWithPersistenceManager:(FPersistenceManager *)persistence { return self; } -- (BOOL) isEmpty { +- (BOOL)isEmpty { return [self.views count] == 0; } -- (NSArray *) applyOperation:(id)operation - toView:(FView *)view - writesCache:(FWriteTreeRef *)writesCache - serverCache:(id)optCompleteServerCache { - FViewOperationResult *result = [view applyOperation:operation writesCache:writesCache serverCache:optCompleteServerCache]; +- (NSArray *)applyOperation:(id)operation + toView:(FView *)view + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache { + FViewOperationResult *result = [view applyOperation:operation + writesCache:writesCache + serverCache:optCompleteServerCache]; if (!view.query.loadsAllData) { NSMutableSet *removed = [NSMutableSet set]; NSMutableSet *added = [NSMutableSet set]; - [result.changes enumerateObjectsUsingBlock:^(FChange *change, NSUInteger idx, BOOL *stop) { - if (change.type == FIRDataEventTypeChildAdded) { - [added addObject:change.childKey]; - } else if (change.type == FIRDataEventTypeChildRemoved) { - [removed addObject:change.childKey]; - } + [result.changes enumerateObjectsUsingBlock:^( + FChange *change, NSUInteger idx, BOOL *stop) { + if (change.type == FIRDataEventTypeChildAdded) { + [added addObject:change.childKey]; + } else if (change.type == FIRDataEventTypeChildRemoved) { + [removed addObject:change.childKey]; + } }]; if ([removed count] > 0 || [added count] > 0) { - [self.persistenceManager updateTrackedQueryKeysWithAddedKeys:added removedKeys:removed forQuery:view.query]; + [self.persistenceManager + updateTrackedQueryKeysWithAddedKeys:added + removedKeys:removed + forQuery:view.query]; } } return result.events; } -- (NSArray *) applyOperation:(id )operation writesCache:(FWriteTreeRef *)writesCache serverCache:(id )optCompleteServerCache { +- (NSArray *)applyOperation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache { FQueryParams *queryParams = operation.source.queryParams; if (queryParams != nil) { FView *view = [self.views objectForKey:queryParams]; NSAssert(view != nil, @"SyncTree gave us an op for an invalid query."); - return [self applyOperation:operation toView:view writesCache:writesCache serverCache:optCompleteServerCache]; + return [self applyOperation:operation + toView:view + writesCache:writesCache + serverCache:optCompleteServerCache]; } else { NSMutableArray *events = [[NSMutableArray alloc] init]; - [self.views enumerateKeysAndObjectsUsingBlock:^(FQueryParams *key, FView *view, BOOL *stop) { - NSArray *eventsForView = [self applyOperation:operation toView:view writesCache:writesCache serverCache:optCompleteServerCache]; - [events addObjectsFromArray:eventsForView]; + [self.views enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *key, FView *view, BOOL *stop) { + NSArray *eventsForView = [self applyOperation:operation + toView:view + writesCache:writesCache + serverCache:optCompleteServerCache]; + [events addObjectsFromArray:eventsForView]; }]; return events; } } /** -* Add an event callback for the specified query -* Returns Array of FEvent events to raise. -*/ -- (NSArray *) addEventRegistration:(id )eventRegistration - forNonExistingViewForQuery:(FQuerySpec *)query - writesCache:(FWriteTreeRef *)writesCache - serverCache:(FCacheNode *)serverCache { - NSAssert(self.views[query.params] == nil, @"Found view for query: %@", query.params); + * Add an event callback for the specified query + * Returns Array of FEvent events to raise. + */ +- (NSArray *)addEventRegistration:(id)eventRegistration + forNonExistingViewForQuery:(FQuerySpec *)query + writesCache:(FWriteTreeRef *)writesCache + serverCache:(FCacheNode *)serverCache { + NSAssert(self.views[query.params] == nil, @"Found view for query: %@", + query.params); // TODO: make writesCache take flag for complete server node - id eventCache = [writesCache calculateCompleteEventCacheWithCompleteServerCache:serverCache.isFullyInitialized ? serverCache.node : nil]; + id eventCache = [writesCache + calculateCompleteEventCacheWithCompleteServerCache: + serverCache.isFullyInitialized ? serverCache.node : nil]; BOOL eventCacheComplete; if (eventCache != nil) { eventCacheComplete = YES; } else { - eventCache = [writesCache calculateCompleteEventChildrenWithCompleteServerChildren:serverCache.node]; + eventCache = [writesCache + calculateCompleteEventChildrenWithCompleteServerChildren:serverCache + .node]; eventCacheComplete = NO; } - FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:eventCache index:query.index]; - FCacheNode *eventCacheNode = [[FCacheNode alloc] initWithIndexedNode:indexed - isFullyInitialized:eventCacheComplete - isFiltered:NO]; - FViewCache *viewCache = [[FViewCache alloc] initWithEventCache:eventCacheNode serverCache:serverCache]; - FView *view = [[FView alloc] initWithQuery:query initialViewCache:viewCache]; - // If this is a non-default query we need to tell persistence our current view of the data + FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:eventCache + index:query.index]; + FCacheNode *eventCacheNode = + [[FCacheNode alloc] initWithIndexedNode:indexed + isFullyInitialized:eventCacheComplete + isFiltered:NO]; + FViewCache *viewCache = + [[FViewCache alloc] initWithEventCache:eventCacheNode + serverCache:serverCache]; + FView *view = [[FView alloc] initWithQuery:query + initialViewCache:viewCache]; + // If this is a non-default query we need to tell persistence our current + // view of the data if (!query.loadsAllData) { NSMutableSet *allKeys = [NSMutableSet set]; - [view.eventCache enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - [allKeys addObject:key]; + [view.eventCache enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + [allKeys addObject:key]; }]; [self.persistenceManager setTrackedQueryKeys:allKeys forQuery:query]; } self.views[query.params] = view; - return [self addEventRegistration:eventRegistration forExistingViewForQuery:query]; + return [self addEventRegistration:eventRegistration + forExistingViewForQuery:query]; } - (NSArray *)addEventRegistration:(id)eventRegistration @@ -156,37 +187,47 @@ - (NSArray *)addEventRegistration:(id)eventRegistration } /** -* Remove event callback(s). Return cancelEvents if a cancelError is specified. -* -* If query is the default query, we'll check all views for the specified eventRegistration. -* If eventRegistration is nil, we'll remove all callbacks for the specified view(s). -* -* @return FTupleRemovedQueriesEvents removed queries and any cancel events -*/ -- (FTupleRemovedQueriesEvents *) removeEventRegistration:(id )eventRegistration - forQuery:(FQuerySpec *)query - cancelError:(NSError *)cancelError { + * Remove event callback(s). Return cancelEvents if a cancelError is specified. + * + * If query is the default query, we'll check all views for the specified + * eventRegistration. If eventRegistration is nil, we'll remove all callbacks + * for the specified view(s). + * + * @return FTupleRemovedQueriesEvents removed queries and any cancel events + */ +- (FTupleRemovedQueriesEvents *)removeEventRegistration: + (id)eventRegistration + forQuery:(FQuerySpec *)query + cancelError:(NSError *)cancelError { NSMutableArray *removedQueries = [[NSMutableArray alloc] init]; __block NSMutableArray *cancelEvents = [[NSMutableArray alloc] init]; BOOL hadCompleteView = [self hasCompleteView]; if ([query isDefault]) { - // When you do [ref removeObserverWithHandle:], we search all views for the registration to remove. - [self.views enumerateKeysAndObjectsUsingBlock:^(FQueryParams *viewQueryParams, FView *view, BOOL *stop) { - [cancelEvents addObjectsFromArray:[view removeEventRegistration:eventRegistration cancelError:cancelError]]; - if ([view isEmpty]) { - [self.views removeObjectForKey:viewQueryParams]; + // When you do [ref removeObserverWithHandle:], we search all views for + // the registration to remove. + [self.views enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *viewQueryParams, FView *view, + BOOL *stop) { + [cancelEvents + addObjectsFromArray:[view + removeEventRegistration:eventRegistration + cancelError:cancelError]]; + if ([view isEmpty]) { + [self.views removeObjectForKey:viewQueryParams]; - // We'll deal with complete views later - if (![view.query loadsAllData]) { - [removedQueries addObject:view.query]; - } - } + // We'll deal with complete views later + if (![view.query loadsAllData]) { + [removedQueries addObject:view.query]; + } + } }]; } else { // remove the callback from the specific view FView *view = [self.views objectForKey:query.params]; if (view != nil) { - [cancelEvents addObjectsFromArray:[view removeEventRegistration:eventRegistration cancelError:cancelError]]; + [cancelEvents addObjectsFromArray: + [view removeEventRegistration:eventRegistration + cancelError:cancelError]]; if ([view isEmpty]) { [self.views removeObjectForKey:query.params]; @@ -204,54 +245,58 @@ - (FTupleRemovedQueriesEvents *) removeEventRegistration:(id ) completeServerCacheAtPath:(FPath *)path { +- (id)completeServerCacheAtPath:(FPath *)path { __block id serverCache = nil; - [self.views enumerateKeysAndObjectsUsingBlock:^(FQueryParams *key, FView *view, BOOL *stop) { - serverCache = [view completeServerCacheFor:path]; - *stop = (serverCache != nil); + [self.views enumerateKeysAndObjectsUsingBlock:^(FQueryParams *key, + FView *view, BOOL *stop) { + serverCache = [view completeServerCacheFor:path]; + *stop = (serverCache != nil); }]; return serverCache; } -- (FView *) viewForQuery:(FQuerySpec *)query { +- (FView *)viewForQuery:(FQuerySpec *)query { return [self.views objectForKey:query.params]; } -- (BOOL) viewExistsForQuery:(FQuerySpec *)query { +- (BOOL)viewExistsForQuery:(FQuerySpec *)query { return [self viewForQuery:query] != nil; } -- (BOOL) hasCompleteView { +- (BOOL)hasCompleteView { return [self completeView] != nil; } -- (FView *) completeView { +- (FView *)completeView { __block FView *completeView = nil; - [self.views enumerateKeysAndObjectsUsingBlock:^(FQueryParams *key, FView *view, BOOL *stop) { - if ([view.query loadsAllData]) { - completeView = view; - *stop = YES; - } + [self.views enumerateKeysAndObjectsUsingBlock:^(FQueryParams *key, + FView *view, BOOL *stop) { + if ([view.query loadsAllData]) { + completeView = view; + *stop = YES; + } }]; return completeView; } - @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncTree.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncTree.h index 887f721..ef89774 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncTree.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncTree.h @@ -37,25 +37,46 @@ @interface FSyncTree : NSObject -- (id) initWithListenProvider:(FListenProvider *)provider; -- (id) initWithPersistenceManager:(FPersistenceManager *)persistenceManager - listenProvider:(FListenProvider *)provider; +- (id)initWithListenProvider:(FListenProvider *)provider; +- (id)initWithPersistenceManager:(FPersistenceManager *)persistenceManager + listenProvider:(FListenProvider *)provider; // These methods all return NSArray of FEvent -- (NSArray *) applyUserOverwriteAtPath:(FPath *)path newData:(id )newData writeId:(NSInteger)writeId isVisible:(BOOL)visible; -- (NSArray *) applyUserMergeAtPath:(FPath *)path changedChildren:(FCompoundWrite *)changedChildren writeId:(NSInteger)writeId; -- (NSArray *) ackUserWriteWithWriteId:(NSInteger)writeId revert:(BOOL)revert persist:(BOOL)persist clock:(id)clock; -- (NSArray *) applyServerOverwriteAtPath:(FPath *)path newData:(id)newData; -- (NSArray *) applyServerMergeAtPath:(FPath *)path changedChildren:(FCompoundWrite *)changedChildren; -- (NSArray *) applyServerRangeMergeAtPath:(FPath *)path updates:(NSArray *)ranges; -- (NSArray *) applyTaggedQueryOverwriteAtPath:(FPath *)path newData:(id )newData tagId:(NSNumber *)tagId; -- (NSArray *) applyTaggedQueryMergeAtPath:(FPath *)path changedChildren:(FCompoundWrite *)changedChildren tagId:(NSNumber *)tagId; -- (NSArray *) applyTaggedServerRangeMergeAtPath:(FPath *)path updates:(NSArray *)ranges tagId:(NSNumber *)tagId; -- (NSArray *) addEventRegistration:(id)eventRegistration forQuery:(FQuerySpec *)query; -- (NSArray *) removeEventRegistration:(id )eventRegistration forQuery:(FQuerySpec *)query cancelError:(NSError *)cancelError; +- (NSArray *)applyUserOverwriteAtPath:(FPath *)path + newData:(id)newData + writeId:(NSInteger)writeId + isVisible:(BOOL)visible; +- (NSArray *)applyUserMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writeId:(NSInteger)writeId; +- (NSArray *)ackUserWriteWithWriteId:(NSInteger)writeId + revert:(BOOL)revert + persist:(BOOL)persist + clock:(id)clock; +- (NSArray *)applyServerOverwriteAtPath:(FPath *)path + newData:(id)newData; +- (NSArray *)applyServerMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren; +- (NSArray *)applyServerRangeMergeAtPath:(FPath *)path + updates:(NSArray *)ranges; +- (NSArray *)applyTaggedQueryOverwriteAtPath:(FPath *)path + newData:(id)newData + tagId:(NSNumber *)tagId; +- (NSArray *)applyTaggedQueryMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + tagId:(NSNumber *)tagId; +- (NSArray *)applyTaggedServerRangeMergeAtPath:(FPath *)path + updates:(NSArray *)ranges + tagId:(NSNumber *)tagId; +- (NSArray *)addEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query; +- (NSArray *)removeEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query + cancelError:(NSError *)cancelError; - (void)keepQuery:(FQuerySpec *)query synced:(BOOL)keepSynced; -- (NSArray *) removeAllWrites; +- (NSArray *)removeAllWrites; -- (id) calcCompleteEventCacheAtPath:(FPath *)path excludeWriteIds:(NSArray *)writeIdsToExclude; +- (id)calcCompleteEventCacheAtPath:(FPath *)path + excludeWriteIds:(NSArray *)writeIdsToExclude; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncTree.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncTree.m index 688a43b..e7fa3dc 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncTree.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FSyncTree.m @@ -14,55 +14,56 @@ * limitations under the License. */ -#import #import "FSyncTree.h" -#import "FListenProvider.h" -#import "FWriteTree.h" -#import "FNode.h" -#import "FPath.h" +#import "FAckUserWrite.h" +#import "FAtomicNumber.h" +#import "FCacheNode.h" +#import "FChildrenNode.h" +#import "FCompoundHash.h" +#import "FCompoundWrite.h" +#import "FEmptyNode.h" +#import "FEventRaiser.h" #import "FEventRegistration.h" #import "FImmutableTree.h" +#import "FKeepSyncedEventRegistration.h" +#import "FListenComplete.h" +#import "FListenProvider.h" +#import "FMerge.h" +#import "FNode.h" #import "FOperation.h" -#import "FWriteTreeRef.h" -#import "FOverwrite.h" #import "FOperationSource.h" -#import "FMerge.h" -#import "FAckUserWrite.h" -#import "FView.h" -#import "FSyncPoint.h" -#import "FEmptyNode.h" +#import "FOverwrite.h" +#import "FPath.h" +#import "FPersistenceManager.h" #import "FQueryParams.h" #import "FQuerySpec.h" +#import "FRangeMerge.h" +#import "FServerValues.h" #import "FSnapshotHolder.h" -#import "FChildrenNode.h" -#import "FTupleRemovedQueriesEvents.h" -#import "FAtomicNumber.h" -#import "FEventRaiser.h" -#import "FListenComplete.h" #import "FSnapshotUtilities.h" -#import "FCacheNode.h" +#import "FSyncPoint.h" +#import "FTupleRemovedQueriesEvents.h" #import "FUtilities.h" -#import "FCompoundWrite.h" +#import "FView.h" #import "FWriteRecord.h" -#import "FPersistenceManager.h" -#import "FKeepSyncedEventRegistration.h" -#import "FServerValues.h" -#import "FCompoundHash.h" -#import "FRangeMerge.h" +#import "FWriteTree.h" +#import "FWriteTreeRef.h" +#import // Size after which we start including the compound hash static const NSUInteger kFSizeThresholdForCompoundHash = 1024; -@interface FListenContainer : NSObject +@interface FListenContainer : NSObject -@property (nonatomic, strong) FView *view; -@property (nonatomic, copy) fbt_nsarray_nsstring onComplete; +@property(nonatomic, strong) FView *view; +@property(nonatomic, copy) fbt_nsarray_nsstring onComplete; @end @implementation FListenContainer -- (instancetype)initWithView:(FView *)view onComplete:(fbt_nsarray_nsstring)onComplete { +- (instancetype)initWithView:(FView *)view + onComplete:(fbt_nsarray_nsstring)onComplete { self = [super init]; if (self != nil) { self->_view = view; @@ -84,7 +85,8 @@ - (NSString *)simpleHash { } - (BOOL)includeCompoundHash { - return [FSnapshotUtilities estimateSerializedNodeSize:[self serverCache]] > kFSizeThresholdForCompoundHash; + return [FSnapshotUtilities estimateSerializedNodeSize:[self serverCache]] > + kFSizeThresholdForCompoundHash; } @end @@ -92,54 +94,62 @@ - (BOOL)includeCompoundHash { @interface FSyncTree () /** -* Tree of SyncPoints. There's a SyncPoint at any location that has 1 or more views. -*/ -@property (nonatomic, strong) FImmutableTree *syncPointTree; + * Tree of SyncPoints. There's a SyncPoint at any location that has 1 or more + * views. + */ +@property(nonatomic, strong) FImmutableTree *syncPointTree; /** -* A tree of all pending user writes (user-initiated set, transactions, updates, etc) -*/ -@property (nonatomic, strong) FWriteTree *pendingWriteTree; + * A tree of all pending user writes (user-initiated set, transactions, updates, + * etc) + */ +@property(nonatomic, strong) FWriteTree *pendingWriteTree; /** -* Maps tagId -> FTuplePathQueryParams -*/ -@property (nonatomic, strong) NSMutableDictionary *tagToQueryMap; -@property (nonatomic, strong) NSMutableDictionary *queryToTagMap; -@property (nonatomic, strong) FListenProvider *listenProvider; -@property (nonatomic, strong) FPersistenceManager *persistenceManager; -@property (nonatomic, strong) FAtomicNumber *queryTagCounter; -@property (nonatomic, strong) NSMutableSet *keepSyncedQueries; + * Maps tagId -> FTuplePathQueryParams + */ +@property(nonatomic, strong) NSMutableDictionary *tagToQueryMap; +@property(nonatomic, strong) NSMutableDictionary *queryToTagMap; +@property(nonatomic, strong) FListenProvider *listenProvider; +@property(nonatomic, strong) FPersistenceManager *persistenceManager; +@property(nonatomic, strong) FAtomicNumber *queryTagCounter; +@property(nonatomic, strong) NSMutableSet *keepSyncedQueries; @end /** -* SyncTree is the central class for managing event callback registration, data caching, views -* (query processing), and event generation. There are typically two SyncTree instances for -* each Repo, one for the normal Firebase data, and one for the .info data. -* -* It has a number of responsibilities, including: -* - Tracking all user event callbacks (registered via addEventRegistration: and removeEventRegistration:). -* - Applying and caching data changes for user setValue:, runTransactionBlock:, and updateChildValues: calls -* (applyUserOverwriteAtPath:, applyUserMergeAtPath:). -* - Applying and caching data changes for server data changes (applyServerOverwriteAtPath:, -* applyServerMergeAtPath:). -* - Generating user-facing events for server and user changes (all of the apply* methods -* return the set of events that need to be raised as a result). -* - Maintaining the appropriate set of server listens to ensure we are always subscribed -* to the correct set of paths and queries to satisfy the current set of user event -* callbacks (listens are started/stopped using the provided listenProvider). -* -* NOTE: Although SyncTree tracks event callbacks and calculates events to raise, the actual -* events are returned to the caller rather than raised synchronously. -*/ + * SyncTree is the central class for managing event callback registration, data + * caching, views (query processing), and event generation. There are typically + * two SyncTree instances for each Repo, one for the normal Firebase data, and + * one for the .info data. + * + * It has a number of responsibilities, including: + * - Tracking all user event callbacks (registered via addEventRegistration: + * and removeEventRegistration:). + * - Applying and caching data changes for user setValue:, + * runTransactionBlock:, and updateChildValues: calls + * (applyUserOverwriteAtPath:, applyUserMergeAtPath:). + * - Applying and caching data changes for server data changes + * (applyServerOverwriteAtPath:, applyServerMergeAtPath:). + * - Generating user-facing events for server and user changes (all of the + * apply* methods return the set of events that need to be raised as a result). + * - Maintaining the appropriate set of server listens to ensure we are always + * subscribed to the correct set of paths and queries to satisfy the current set + * of user event callbacks (listens are started/stopped using the provided + * listenProvider). + * + * NOTE: Although SyncTree tracks event callbacks and calculates events to + * raise, the actual events are returned to the caller rather than raised + * synchronously. + */ @implementation FSyncTree -- (id) initWithListenProvider:(FListenProvider *)provider { +- (id)initWithListenProvider:(FListenProvider *)provider { return [self initWithPersistenceManager:nil listenProvider:provider]; } -- (id) initWithPersistenceManager:(FPersistenceManager *)persistenceManager listenProvider:(FListenProvider *)provider { +- (id)initWithPersistenceManager:(FPersistenceManager *)persistenceManager + listenProvider:(FListenProvider *)provider { self = [super init]; if (self) { self.syncPointTree = [FImmutableTree empty]; @@ -158,38 +168,60 @@ - (id) initWithPersistenceManager:(FPersistenceManager *)persistenceManager list #pragma mark Apply Operations /** -* Apply data changes for a user-generated setValue: runTransactionBlock: updateChildValues:, etc. -* @return NSArray of FEvent to raise. -*/ -- (NSArray *) applyUserOverwriteAtPath:(FPath *)path newData:(id )newData writeId:(NSInteger)writeId isVisible:(BOOL)visible { + * Apply data changes for a user-generated setValue: runTransactionBlock: + * updateChildValues:, etc. + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyUserOverwriteAtPath:(FPath *)path + newData:(id)newData + writeId:(NSInteger)writeId + isVisible:(BOOL)visible { // Record pending write - [self.pendingWriteTree addOverwriteAtPath:path newData:newData writeId:writeId isVisible:visible]; + [self.pendingWriteTree addOverwriteAtPath:path + newData:newData + writeId:writeId + isVisible:visible]; if (!visible) { return @[]; } else { - FOverwrite *operation = [[FOverwrite alloc] initWithSource:[FOperationSource userInstance] path:path snap:newData]; + FOverwrite *operation = + [[FOverwrite alloc] initWithSource:[FOperationSource userInstance] + path:path + snap:newData]; return [self applyOperationToSyncPoints:operation]; } } /** -* Apply the data from a user-generated updateChildValues: call -* @return NSArray of FEvent to raise. -*/ -- (NSArray *) applyUserMergeAtPath:(FPath *)path changedChildren:(FCompoundWrite *)changedChildren writeId:(NSInteger)writeId { + * Apply the data from a user-generated updateChildValues: call + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyUserMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writeId:(NSInteger)writeId { // Record pending merge - [self.pendingWriteTree addMergeAtPath:path changedChildren:changedChildren writeId:writeId]; - - FMerge *operation = [[FMerge alloc] initWithSource:[FOperationSource userInstance] path:path children:changedChildren]; + [self.pendingWriteTree addMergeAtPath:path + changedChildren:changedChildren + writeId:writeId]; + + FMerge *operation = + [[FMerge alloc] initWithSource:[FOperationSource userInstance] + path:path + children:changedChildren]; return [self applyOperationToSyncPoints:operation]; } /** - * Acknowledge a pending user write that was previously registered with applyUserOverwriteAtPath: or applyUserMergeAtPath: - * TODO[offline]: Taking a serverClock here is awkward, but server values are awkward. :-( + * Acknowledge a pending user write that was previously registered with + * applyUserOverwriteAtPath: or applyUserMergeAtPath: + * TODO[offline]: Taking a serverClock here is awkward, but server values are + * awkward. :-( * @return NSArray of FEvent to raise. */ -- (NSArray *) ackUserWriteWithWriteId:(NSInteger)writeId revert:(BOOL)revert persist:(BOOL)persist clock:(id)clock { +- (NSArray *)ackUserWriteWithWriteId:(NSInteger)writeId + revert:(BOOL)revert + persist:(BOOL)persist + clock:(id)clock { FWriteRecord *write = [self.pendingWriteTree writeForId:writeId]; BOOL needToReevaluate = [self.pendingWriteTree removeWriteId:writeId]; if (write.visible) { @@ -197,13 +229,20 @@ - (NSArray *) ackUserWriteWithWriteId:(NSInteger)writeId revert:(BOOL)revert per [self.persistenceManager removeUserWrite:writeId]; } if (!revert) { - NSDictionary *serverValues = [FServerValues generateServerValues:clock]; + NSDictionary *serverValues = + [FServerValues generateServerValues:clock]; if ([write isOverwrite]) { - id resolvedNode = [FServerValues resolveDeferredValueSnapshot:write.overwrite withServerValues:serverValues]; - [self.persistenceManager applyUserWrite:resolvedNode toServerCacheAtPath:write.path]; + id resolvedNode = + [FServerValues resolveDeferredValueSnapshot:write.overwrite + withServerValues:serverValues]; + [self.persistenceManager applyUserWrite:resolvedNode + toServerCacheAtPath:write.path]; } else { - FCompoundWrite *resolvedMerge = [FServerValues resolveDeferredValueCompoundWrite:write.merge withServerValues:serverValues]; - [self.persistenceManager applyUserMerge:resolvedMerge toServerCacheAtPath:write.path]; + FCompoundWrite *resolvedMerge = [FServerValues + resolveDeferredValueCompoundWrite:write.merge + withServerValues:serverValues]; + [self.persistenceManager applyUserMerge:resolvedMerge + toServerCacheAtPath:write.path]; } } } @@ -214,43 +253,60 @@ - (NSArray *) ackUserWriteWithWriteId:(NSInteger)writeId revert:(BOOL)revert per if (write.isOverwrite) { affectedTree = [affectedTree setValue:@YES atPath:[FPath empty]]; } else { - [write.merge enumerateWrites:^(FPath *path, id node, BOOL *stop) { - affectedTree = [affectedTree setValue:@YES atPath:path]; - }]; + [write.merge + enumerateWrites:^(FPath *path, id node, BOOL *stop) { + affectedTree = [affectedTree setValue:@YES atPath:path]; + }]; } - FAckUserWrite *operation = [[FAckUserWrite alloc] initWithPath:write.path affectedTree:affectedTree revert:revert]; + FAckUserWrite *operation = + [[FAckUserWrite alloc] initWithPath:write.path + affectedTree:affectedTree + revert:revert]; return [self applyOperationToSyncPoints:operation]; } } /** -* Apply new server data for the specified path -* @return NSArray of FEvent to raise. -*/ -- (NSArray *) applyServerOverwriteAtPath:(FPath *)path newData:(id )newData { - [self.persistenceManager updateServerCacheWithNode:newData forQuery:[FQuerySpec defaultQueryAtPath:path]]; - FOverwrite *operation = [[FOverwrite alloc] initWithSource:[FOperationSource serverInstance] path:path snap:newData]; + * Apply new server data for the specified path + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyServerOverwriteAtPath:(FPath *)path + newData:(id)newData { + [self.persistenceManager + updateServerCacheWithNode:newData + forQuery:[FQuerySpec defaultQueryAtPath:path]]; + FOverwrite *operation = + [[FOverwrite alloc] initWithSource:[FOperationSource serverInstance] + path:path + snap:newData]; return [self applyOperationToSyncPoints:operation]; } /** -* Applied new server data to be merged in at the specified path -* @return NSArray of FEvent to raise. -*/ -- (NSArray *) applyServerMergeAtPath:(FPath *)path changedChildren:(FCompoundWrite *)changedChildren { - [self.persistenceManager updateServerCacheWithMerge:changedChildren atPath:path]; - FMerge *operation = [[FMerge alloc] initWithSource:[FOperationSource serverInstance] path:path children:changedChildren]; + * Applied new server data to be merged in at the specified path + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyServerMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren { + [self.persistenceManager updateServerCacheWithMerge:changedChildren + atPath:path]; + FMerge *operation = + [[FMerge alloc] initWithSource:[FOperationSource serverInstance] + path:path + children:changedChildren]; return [self applyOperationToSyncPoints:operation]; } -- (NSArray *) applyServerRangeMergeAtPath:(FPath *)path updates:(NSArray *)ranges { +- (NSArray *)applyServerRangeMergeAtPath:(FPath *)path + updates:(NSArray *)ranges { FSyncPoint *syncPoint = [self.syncPointTree valueAtPath:path]; if (syncPoint == nil) { // Removed view, so it's safe to just ignore this update return @[]; } else { - // This could be for any "complete" (unfiltered) view, and if there is more than one complete view, they should - // each have the same cache so it doesn't matter which one we use. + // This could be for any "complete" (unfiltered) view, and if there is + // more than one complete view, they should each have the same cache so + // it doesn't matter which one we use. FView *view = [syncPoint completeView]; if (view != nil) { id serverNode = [view serverCache]; @@ -259,34 +315,39 @@ - (NSArray *) applyServerRangeMergeAtPath:(FPath *)path updates:(NSArray *)range } return [self applyServerOverwriteAtPath:path newData:serverNode]; } else { - // There doesn't exist a view for this update, so it was removed and it's safe to just ignore this range - // merge + // There doesn't exist a view for this update, so it was removed and + // it's safe to just ignore this range merge return @[]; } } } /** -* Apply a listen complete to a path -* @return NSArray of FEvent to raise. -*/ -- (NSArray *) applyListenCompleteAtPath:(FPath *)path { - [self.persistenceManager setQueryComplete:[FQuerySpec defaultQueryAtPath:path]]; - id operation = [[FListenComplete alloc] initWithSource:[FOperationSource serverInstance] path:path]; + * Apply a listen complete to a path + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyListenCompleteAtPath:(FPath *)path { + [self.persistenceManager + setQueryComplete:[FQuerySpec defaultQueryAtPath:path]]; + id operation = [[FListenComplete alloc] + initWithSource:[FOperationSource serverInstance] + path:path]; return [self applyOperationToSyncPoints:operation]; } /** -* Apply a listen complete to a path -* @return NSArray of FEvent to raise. -*/ -- (NSArray *) applyTaggedListenCompleteAtPath:(FPath *)path tagId:(NSNumber *)tagId { + * Apply a listen complete to a path + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyTaggedListenCompleteAtPath:(FPath *)path + tagId:(NSNumber *)tagId { FQuerySpec *query = [self queryForTag:tagId]; if (query != nil) { [self.persistenceManager setQueryComplete:query]; FPath *relativePath = [FPath relativePathFrom:query.path to:path]; - id op = [[FListenComplete alloc] initWithSource:[FOperationSource forServerTaggedQuery:query.params] - path:relativePath]; + id op = [[FListenComplete alloc] + initWithSource:[FOperationSource forServerTaggedQuery:query.params] + path:relativePath]; return [self applyTaggedOperation:op atPath:query.path]; } else { // We've already removed the query. No big deal, ignore the update. @@ -295,27 +356,38 @@ - (NSArray *) applyTaggedListenCompleteAtPath:(FPath *)path tagId:(NSNumber *)ta } /** -* Internal helper method to apply tagged operation -*/ -- (NSArray *) applyTaggedOperation:(id)operation atPath:(FPath *)path { + * Internal helper method to apply tagged operation + */ +- (NSArray *)applyTaggedOperation:(id)operation + atPath:(FPath *)path { FSyncPoint *syncPoint = [self.syncPointTree valueAtPath:path]; - NSAssert(syncPoint != nil, @"Missing sync point for query tag that we're tracking."); - FWriteTreeRef *writesCache = [self.pendingWriteTree childWritesForPath:path]; - return [syncPoint applyOperation:operation writesCache:writesCache serverCache:nil]; + NSAssert(syncPoint != nil, + @"Missing sync point for query tag that we're tracking."); + FWriteTreeRef *writesCache = + [self.pendingWriteTree childWritesForPath:path]; + return [syncPoint applyOperation:operation + writesCache:writesCache + serverCache:nil]; } /** -* Apply new server data for the specified tagged query -* @return NSArray of FEvent to raise. -*/ -- (NSArray *) applyTaggedQueryOverwriteAtPath:(FPath *)path newData:(id )newData tagId:(NSNumber *)tagId { + * Apply new server data for the specified tagged query + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyTaggedQueryOverwriteAtPath:(FPath *)path + newData:(id)newData + tagId:(NSNumber *)tagId { FQuerySpec *query = [self queryForTag:tagId]; if (query != nil) { FPath *relativePath = [FPath relativePathFrom:query.path to:path]; - FQuerySpec *queryToOverwrite = relativePath.isEmpty ? query : [FQuerySpec defaultQueryAtPath:path]; - [self.persistenceManager updateServerCacheWithNode:newData forQuery:queryToOverwrite]; - FOverwrite *operation = [[FOverwrite alloc] initWithSource:[FOperationSource forServerTaggedQuery:query.params] - path:relativePath snap:newData]; + FQuerySpec *queryToOverwrite = + relativePath.isEmpty ? query : [FQuerySpec defaultQueryAtPath:path]; + [self.persistenceManager updateServerCacheWithNode:newData + forQuery:queryToOverwrite]; + FOverwrite *operation = [[FOverwrite alloc] + initWithSource:[FOperationSource forServerTaggedQuery:query.params] + path:relativePath + snap:newData]; return [self applyTaggedOperation:operation atPath:query.path]; } else { // Query must have been removed already @@ -324,17 +396,21 @@ - (NSArray *) applyTaggedQueryOverwriteAtPath:(FPath *)path newData:(id ) } /** -* Apply server data to be merged in for the specified tagged query -* @return NSArray of FEvent to raise. -*/ -- (NSArray *) applyTaggedQueryMergeAtPath:(FPath *)path changedChildren:(FCompoundWrite *)changedChildren tagId:(NSNumber *)tagId { + * Apply server data to be merged in for the specified tagged query + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyTaggedQueryMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + tagId:(NSNumber *)tagId { FQuerySpec *query = [self queryForTag:tagId]; if (query != nil) { FPath *relativePath = [FPath relativePathFrom:query.path to:path]; - [self.persistenceManager updateServerCacheWithMerge:changedChildren atPath:path]; - FMerge *operation = [[FMerge alloc] initWithSource:[FOperationSource forServerTaggedQuery:query.params] - path:relativePath - children:changedChildren]; + [self.persistenceManager updateServerCacheWithMerge:changedChildren + atPath:path]; + FMerge *operation = [[FMerge alloc] + initWithSource:[FOperationSource forServerTaggedQuery:query.params] + path:relativePath + children:changedChildren]; return [self applyTaggedOperation:operation atPath:query.path]; } else { // We've already removed the query. No big deal, ignore the update. @@ -342,19 +418,26 @@ - (NSArray *) applyTaggedQueryMergeAtPath:(FPath *)path changedChildren:(FCompou } } -- (NSArray *) applyTaggedServerRangeMergeAtPath:(FPath *)path updates:(NSArray *)ranges tagId:(NSNumber *)tagId { +- (NSArray *)applyTaggedServerRangeMergeAtPath:(FPath *)path + updates:(NSArray *)ranges + tagId:(NSNumber *)tagId { FQuerySpec *query = [self queryForTag:tagId]; if (query != nil) { - NSAssert([path isEqual:query.path], @"Tagged update path and query path must match"); + NSAssert([path isEqual:query.path], + @"Tagged update path and query path must match"); FSyncPoint *syncPoint = [self.syncPointTree valueAtPath:path]; - NSAssert(syncPoint != nil, @"Missing sync point for query tag that we're tracking."); + NSAssert(syncPoint != nil, + @"Missing sync point for query tag that we're tracking."); FView *view = [syncPoint viewForQuery:query]; - NSAssert(view != nil, @"Missing view for query tag that we're tracking"); + NSAssert(view != nil, + @"Missing view for query tag that we're tracking"); id serverNode = [view serverCache]; for (FRangeMerge *merge in ranges) { serverNode = [merge applyToNode:serverNode]; } - return [self applyTaggedQueryOverwriteAtPath:path newData:serverNode tagId:tagId]; + return [self applyTaggedQueryOverwriteAtPath:path + newData:serverNode + tagId:tagId]; } else { // We've already removed the query. No big deal, ignore the update. return @[]; @@ -362,40 +445,49 @@ - (NSArray *) applyTaggedServerRangeMergeAtPath:(FPath *)path updates:(NSArray * } /** -* Add an event callback for the specified query -* @return NSArray of FEvent to raise. -*/ -- (NSArray *) addEventRegistration:(id)eventRegistration forQuery:(FQuerySpec *)query { + * Add an event callback for the specified query + * @return NSArray of FEvent to raise. + */ +- (NSArray *)addEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query { FPath *path = query.path; __block BOOL foundAncestorDefaultView = NO; - [self.syncPointTree forEachOnPath:query.path whileBlock:^BOOL(FPath *pathToSyncPoint, FSyncPoint *syncPoint) { - foundAncestorDefaultView = foundAncestorDefaultView || [syncPoint hasCompleteView]; - return !foundAncestorDefaultView; - }]; + [self.syncPointTree + forEachOnPath:query.path + whileBlock:^BOOL(FPath *pathToSyncPoint, FSyncPoint *syncPoint) { + foundAncestorDefaultView = + foundAncestorDefaultView || [syncPoint hasCompleteView]; + return !foundAncestorDefaultView; + }]; [self.persistenceManager setQueryActive:query]; FSyncPoint *syncPoint = [self.syncPointTree valueAtPath:path]; if (syncPoint == nil) { - syncPoint = [[FSyncPoint alloc] initWithPersistenceManager:self.persistenceManager]; - self.syncPointTree = [self.syncPointTree setValue:syncPoint atPath:path]; + syncPoint = [[FSyncPoint alloc] + initWithPersistenceManager:self.persistenceManager]; + self.syncPointTree = [self.syncPointTree setValue:syncPoint + atPath:path]; } BOOL viewAlreadyExists = [syncPoint viewExistsForQuery:query]; NSArray *events; if (viewAlreadyExists) { - events = [syncPoint addEventRegistration:eventRegistration forExistingViewForQuery:query]; + events = [syncPoint addEventRegistration:eventRegistration + forExistingViewForQuery:query]; } else { if (![query loadsAllData]) { // We need to track a tag for this query - NSAssert(self.queryToTagMap[query] == nil, @"View does not exist, but we have a tag"); + NSAssert(self.queryToTagMap[query] == nil, + @"View does not exist, but we have a tag"); NSNumber *tagId = [self.queryTagCounter getAndIncrement]; self.queryToTagMap[query] = tagId; self.tagToQueryMap[tagId] = query; } - FWriteTreeRef *writesCache = [self.pendingWriteTree childWritesForPath:path]; + FWriteTreeRef *writesCache = + [self.pendingWriteTree childWritesForPath:path]; FCacheNode *serverCache = [self serverCacheForQuery:query]; events = [syncPoint addEventRegistration:eventRegistration forNonExistingViewForQuery:query @@ -406,7 +498,9 @@ - (NSArray *) addEventRegistration:(id)eventRegistration for if (!foundAncestorDefaultView) { FView *view = [syncPoint viewForQuery:query]; NSMutableArray *mutableEvents = [events mutableCopy]; - [mutableEvents addObjectsFromArray:[self setupListenerOnQuery:query view:view]]; + [mutableEvents + addObjectsFromArray:[self setupListenerOnQuery:query + view:view]]; events = mutableEvents; } } @@ -417,38 +511,60 @@ - (NSArray *) addEventRegistration:(id)eventRegistration for - (FCacheNode *)serverCacheForQuery:(FQuerySpec *)query { __block id serverCacheNode = nil; - [self.syncPointTree forEachOnPath:query.path whileBlock:^BOOL(FPath *pathToSyncPoint, FSyncPoint *syncPoint) { - FPath *relativePath = [FPath relativePathFrom:pathToSyncPoint to:query.path]; - serverCacheNode = [syncPoint completeServerCacheAtPath:relativePath]; - return serverCacheNode == nil; - }]; + [self.syncPointTree + forEachOnPath:query.path + whileBlock:^BOOL(FPath *pathToSyncPoint, FSyncPoint *syncPoint) { + FPath *relativePath = [FPath relativePathFrom:pathToSyncPoint + to:query.path]; + serverCacheNode = + [syncPoint completeServerCacheAtPath:relativePath]; + return serverCacheNode == nil; + }]; FCacheNode *serverCache; if (serverCacheNode != nil) { - FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:serverCacheNode index:query.index]; - serverCache = [[FCacheNode alloc] initWithIndexedNode:indexed isFullyInitialized:YES isFiltered:NO]; + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:serverCacheNode + index:query.index]; + serverCache = [[FCacheNode alloc] initWithIndexedNode:indexed + isFullyInitialized:YES + isFiltered:NO]; } else { - FCacheNode *persistenceServerCache = [self.persistenceManager serverCacheForQuery:query]; + FCacheNode *persistenceServerCache = + [self.persistenceManager serverCacheForQuery:query]; if (persistenceServerCache.isFullyInitialized) { serverCache = persistenceServerCache; } else { serverCacheNode = [FEmptyNode emptyNode]; - FImmutableTree *subtree = [self.syncPointTree subtreeAtPath:query.path]; - [subtree forEachChild:^(NSString *childKey, FSyncPoint *childSyncPoint) { - id completeCache = [childSyncPoint completeServerCacheAtPath:[FPath empty]]; - if (completeCache) { - serverCacheNode = [serverCacheNode updateImmediateChild:childKey withNewChild:completeCache]; - } - }]; + FImmutableTree *subtree = + [self.syncPointTree subtreeAtPath:query.path]; + [subtree + forEachChild:^(NSString *childKey, FSyncPoint *childSyncPoint) { + id completeCache = + [childSyncPoint completeServerCacheAtPath:[FPath empty]]; + if (completeCache) { + serverCacheNode = + [serverCacheNode updateImmediateChild:childKey + withNewChild:completeCache]; + } + }]; // Fill the node with any available children we have - [persistenceServerCache.node enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - if (![serverCacheNode hasChild:key]) { - serverCacheNode = [serverCacheNode updateImmediateChild:key withNewChild:node]; - } - }]; - FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:serverCacheNode index:query.index]; - serverCache = [[FCacheNode alloc] initWithIndexedNode:indexed isFullyInitialized:NO isFiltered:NO]; + [persistenceServerCache.node + enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + if (![serverCacheNode hasChild:key]) { + serverCacheNode = + [serverCacheNode updateImmediateChild:key + withNewChild:node]; + } + }]; + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:serverCacheNode + index:query.index]; + serverCache = [[FCacheNode alloc] initWithIndexedNode:indexed + isFullyInitialized:NO + isFiltered:NO]; } } @@ -456,85 +572,115 @@ - (FCacheNode *)serverCacheForQuery:(FQuerySpec *)query { } /** -* Remove event callback(s). -* -* If query is the default query, we'll check all queries for the specified eventRegistration. -* If eventRegistration is null, we'll remove all callbacks for the specified query/queries. -* -* @param eventRegistration if nil, all callbacks are removed -* @param cancelError If provided, appropriate cancel events will be returned -* @return NSArray of FEvent to raise. -*/ -- (NSArray *) removeEventRegistration:(id )eventRegistration - forQuery:(FQuerySpec *)query - cancelError:(NSError *)cancelError { - // Find the syncPoint first. Then deal with whether or not it has matching listeners + * Remove event callback(s). + * + * If query is the default query, we'll check all queries for the specified + * eventRegistration. If eventRegistration is null, we'll remove all callbacks + * for the specified query/queries. + * + * @param eventRegistration if nil, all callbacks are removed + * @param cancelError If provided, appropriate cancel events will be returned + * @return NSArray of FEvent to raise. + */ +- (NSArray *)removeEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query + cancelError:(NSError *)cancelError { + // Find the syncPoint first. Then deal with whether or not it has matching + // listeners FPath *path = query.path; FSyncPoint *maybeSyncPoint = [self.syncPointTree valueAtPath:path]; NSArray *cancelEvents = @[]; - // A removal on a default query affects all queries at that location. A removal on an indexed query, even one without - // other query constraints, does *not* affect all queries at that location. So this check must be for 'default', and - // not loadsAllData: - if (maybeSyncPoint && ([query isDefault] || [maybeSyncPoint viewExistsForQuery:query])) { - FTupleRemovedQueriesEvents *removedAndEvents = [maybeSyncPoint removeEventRegistration:eventRegistration forQuery:query cancelError:cancelError]; + // A removal on a default query affects all queries at that location. A + // removal on an indexed query, even one without other query constraints, + // does *not* affect all queries at that location. So this check must be for + // 'default', and not loadsAllData: + if (maybeSyncPoint && + ([query isDefault] || [maybeSyncPoint viewExistsForQuery:query])) { + FTupleRemovedQueriesEvents *removedAndEvents = + [maybeSyncPoint removeEventRegistration:eventRegistration + forQuery:query + cancelError:cancelError]; if ([maybeSyncPoint isEmpty]) { self.syncPointTree = [self.syncPointTree removeValueAtPath:path]; } NSArray *removed = removedAndEvents.removedQueries; cancelEvents = removedAndEvents.cancelEvents; - // We may have just removed one of many listeners and can short-circuit this whole process - // We may also not have removed a default listener, in which case all of the descendant listeners should already - // be properly set up. + // We may have just removed one of many listeners and can short-circuit + // this whole process We may also not have removed a default listener, + // in which case all of the descendant listeners should already be + // properly set up. // - // Since indexed queries can shadow if they don't have other query constraints, check for loadsAllData: instead - // of isDefault: - NSUInteger defaultQueryIndex = [removed indexOfObjectPassingTest:^BOOL(FQuerySpec *q, NSUInteger idx, BOOL *stop) { - return [q loadsAllData]; - }]; + // Since indexed queries can shadow if they don't have other query + // constraints, check for loadsAllData: instead of isDefault: + NSUInteger defaultQueryIndex = [removed + indexOfObjectPassingTest:^BOOL(FQuerySpec *q, NSUInteger idx, + BOOL *stop) { + return [q loadsAllData]; + }]; BOOL removingDefault = defaultQueryIndex != NSNotFound; - [removed enumerateObjectsUsingBlock:^(FQuerySpec *query, NSUInteger idx, BOOL *stop) { - [self.persistenceManager setQueryInactive:query]; - }]; - NSNumber *covered = [self.syncPointTree findOnPath:path andApplyBlock:^id(FPath *relativePath, FSyncPoint *parentSyncPoint) { - return [NSNumber numberWithBool:[parentSyncPoint hasCompleteView]]; + [removed enumerateObjectsUsingBlock:^(FQuerySpec *query, NSUInteger idx, + BOOL *stop) { + [self.persistenceManager setQueryInactive:query]; }]; + NSNumber *covered = [self.syncPointTree + findOnPath:path + andApplyBlock:^id(FPath *relativePath, + FSyncPoint *parentSyncPoint) { + return + [NSNumber numberWithBool:[parentSyncPoint hasCompleteView]]; + }]; if (removingDefault && ![covered boolValue]) { FImmutableTree *subtree = [self.syncPointTree subtreeAtPath:path]; - // There are potentially child listeners. Determine what if any listens we need to send before executing - // the removal + // There are potentially child listeners. Determine what if any + // listens we need to send before executing the removal if (![subtree isEmpty]) { - // We need to fold over our subtree and collect the listeners to send - NSArray *newViews = [self collectDistinctViewsForSubTree:subtree]; + // We need to fold over our subtree and collect the listeners to + // send + NSArray *newViews = + [self collectDistinctViewsForSubTree:subtree]; // Ok, we've collected all the listens we need. Set them up. - [newViews enumerateObjectsUsingBlock:^(FView *view, NSUInteger idx, BOOL *stop) { - FQuerySpec *newQuery = view.query; - FListenContainer *listenContainer = [self createListenerForView:view]; - self.listenProvider.startListening([self queryForListening:newQuery], [self tagForQuery:newQuery], - listenContainer, listenContainer.onComplete); + [newViews enumerateObjectsUsingBlock:^( + FView *view, NSUInteger idx, BOOL *stop) { + FQuerySpec *newQuery = view.query; + FListenContainer *listenContainer = + [self createListenerForView:view]; + self.listenProvider.startListening( + [self queryForListening:newQuery], + [self tagForQuery:newQuery], listenContainer, + listenContainer.onComplete); }]; } else { - // There's nothing below us, so nothing we need to start listening on + // There's nothing below us, so nothing we need to start + // listening on } } - // If we removed anything and we're not covered by a higher up listen, we need to stop listening on this query. - // The above block has us covered in terms of making sure we're set up on listens lower in the tree. - // Also, note that if we have a cancelError, it's already been removed at the provider level. + // If we removed anything and we're not covered by a higher up listen, + // we need to stop listening on this query. The above block has us + // covered in terms of making sure we're set up on listens lower in the + // tree. Also, note that if we have a cancelError, it's already been + // removed at the provider level. if (![covered boolValue] && [removed count] > 0 && cancelError == nil) { - // If we removed a default, then we weren't listening on any of the other queries here. Just cancel the one - // default. Otherwise, we need to iterate through and cancel each individual query + // If we removed a default, then we weren't listening on any of the + // other queries here. Just cancel the one default. Otherwise, we + // need to iterate through and cancel each individual query if (removingDefault) { // We don't tag default listeners - self.listenProvider.stopListening([self queryForListening:query], nil); + self.listenProvider.stopListening( + [self queryForListening:query], nil); } else { - [removed enumerateObjectsUsingBlock:^(FQuerySpec *queryToRemove, NSUInteger idx, BOOL *stop) { - NSNumber *tagToRemove = [self.queryToTagMap objectForKey:queryToRemove]; - self.listenProvider.stopListening([self queryForListening:queryToRemove], tagToRemove); - }]; + [removed + enumerateObjectsUsingBlock:^(FQuerySpec *queryToRemove, + NSUInteger idx, BOOL *stop) { + NSNumber *tagToRemove = + [self.queryToTagMap objectForKey:queryToRemove]; + self.listenProvider.stopListening( + [self queryForListening:queryToRemove], tagToRemove); + }]; } } // Now, clear all the tags we're tracking for the removed listens. @@ -548,90 +694,109 @@ - (NSArray *) removeEventRegistration:(id )eventRegistration - (void)keepQuery:(FQuerySpec *)query synced:(BOOL)keepSynced { // Only do something if we actually need to add/remove an event registration if (keepSynced && ![self.keepSyncedQueries containsObject:query]) { - [self addEventRegistration:[FKeepSyncedEventRegistration instance] forQuery:query]; + [self addEventRegistration:[FKeepSyncedEventRegistration instance] + forQuery:query]; [self.keepSyncedQueries addObject:query]; } else if (!keepSynced && [self.keepSyncedQueries containsObject:query]) { - [self removeEventRegistration:[FKeepSyncedEventRegistration instance] forQuery:query cancelError:nil]; + [self removeEventRegistration:[FKeepSyncedEventRegistration instance] + forQuery:query + cancelError:nil]; [self.keepSyncedQueries removeObject:query]; } } -- (NSArray *) removeAllWrites { +- (NSArray *)removeAllWrites { [self.persistenceManager removeAllUserWrites]; NSArray *removedWrites = [self.pendingWriteTree removeAllWrites]; if (removedWrites.count > 0) { - FImmutableTree *affectedTree = [[FImmutableTree empty] setValue:@YES atPath:[FPath empty]]; - return [self applyOperationToSyncPoints:[[FAckUserWrite alloc] initWithPath:[FPath empty] - affectedTree:affectedTree revert:YES]]; + FImmutableTree *affectedTree = + [[FImmutableTree empty] setValue:@YES atPath:[FPath empty]]; + return [self applyOperationToSyncPoints:[[FAckUserWrite alloc] + initWithPath:[FPath empty] + affectedTree:affectedTree + revert:YES]]; } else { return @[]; } } /** -* Returns a complete cache, if we have one, of the data at a particular path. The location must have a listener above -* it, but as this is only used by transaction code, that should always be the case anyways. -* -* Note: this method will *include* hidden writes from transaction with applyLocally set to false. -* @param path The path to the data we want -* @param writeIdsToExclude A specific set to be excluded -*/ -- (id ) calcCompleteEventCacheAtPath:(FPath *)path excludeWriteIds:(NSArray *)writeIdsToExclude { + * Returns a complete cache, if we have one, of the data at a particular path. + * The location must have a listener above it, but as this is only used by + * transaction code, that should always be the case anyways. + * + * Note: this method will *include* hidden writes from transaction with + * applyLocally set to false. + * @param path The path to the data we want + * @param writeIdsToExclude A specific set to be excluded + */ +- (id)calcCompleteEventCacheAtPath:(FPath *)path + excludeWriteIds:(NSArray *)writeIdsToExclude { BOOL includeHiddenSets = YES; FWriteTree *writeTree = self.pendingWriteTree; - id serverCache = [self.syncPointTree findOnPath:path andApplyBlock:^id(FPath *pathSoFar, FSyncPoint *syncPoint) { - FPath *relativePath = [FPath relativePathFrom:pathSoFar to:path]; - id serverCache = [syncPoint completeServerCacheAtPath:relativePath]; - if (serverCache) { - return serverCache; - } else { - return nil; - } - }]; - return [writeTree calculateCompleteEventCacheAtPath:path completeServerCache:serverCache excludeWriteIds:writeIdsToExclude includeHiddenWrites:includeHiddenSets]; + id serverCache = [self.syncPointTree + findOnPath:path + andApplyBlock:^id(FPath *pathSoFar, FSyncPoint *syncPoint) { + FPath *relativePath = [FPath relativePathFrom:pathSoFar to:path]; + id serverCache = + [syncPoint completeServerCacheAtPath:relativePath]; + if (serverCache) { + return serverCache; + } else { + return nil; + } + }]; + return [writeTree calculateCompleteEventCacheAtPath:path + completeServerCache:serverCache + excludeWriteIds:writeIdsToExclude + includeHiddenWrites:includeHiddenSets]; } #pragma mark - #pragma mark Private Methods /** -* This collapses multiple unfiltered views into a single view, since we only need a single -* listener for them. -* @return NSArray of FView -*/ -- (NSArray *) collectDistinctViewsForSubTree:(FImmutableTree *)subtree { - return [subtree foldWithBlock:^NSArray *(FPath *relativePath, FSyncPoint *maybeChildSyncPoint, NSDictionary *childMap) { - if (maybeChildSyncPoint && [maybeChildSyncPoint hasCompleteView]) { - FView *completeView = [maybeChildSyncPoint completeView]; - return @[completeView]; - } else { - // No complete view here, flatten any deeper listens into an array - NSMutableArray *views = [[NSMutableArray alloc] init]; - if (maybeChildSyncPoint) { - views = [[maybeChildSyncPoint queryViews] mutableCopy]; - } - [childMap enumerateKeysAndObjectsUsingBlock:^(NSString *childKey, NSArray *childViews, BOOL *stop) { - [views addObjectsFromArray:childViews]; - }]; - return views; - } + * This collapses multiple unfiltered views into a single view, since we only + * need a single listener for them. + * @return NSArray of FView + */ +- (NSArray *)collectDistinctViewsForSubTree:(FImmutableTree *)subtree { + return [subtree foldWithBlock:^NSArray *(FPath *relativePath, + FSyncPoint *maybeChildSyncPoint, + NSDictionary *childMap) { + if (maybeChildSyncPoint && [maybeChildSyncPoint hasCompleteView]) { + FView *completeView = [maybeChildSyncPoint completeView]; + return @[ completeView ]; + } else { + // No complete view here, flatten any deeper listens into an array + NSMutableArray *views = [[NSMutableArray alloc] init]; + if (maybeChildSyncPoint) { + views = [[maybeChildSyncPoint queryViews] mutableCopy]; + } + [childMap enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, NSArray *childViews, BOOL *stop) { + [views addObjectsFromArray:childViews]; + }]; + return views; + } }]; } /** -* @param queries NSArray of FQuerySpec -*/ -- (void) removeTags:(NSArray *)queries { - [queries enumerateObjectsUsingBlock:^(FQuerySpec *removedQuery, NSUInteger idx, BOOL *stop) { - if (![removedQuery loadsAllData]) { - // We should have a tag for this - NSNumber *removedQueryTag = self.queryToTagMap[removedQuery]; - [self.queryToTagMap removeObjectForKey:removedQuery]; - [self.tagToQueryMap removeObjectForKey:removedQueryTag]; - } + * @param queries NSArray of FQuerySpec + */ +- (void)removeTags:(NSArray *)queries { + [queries enumerateObjectsUsingBlock:^(FQuerySpec *removedQuery, + NSUInteger idx, BOOL *stop) { + if (![removedQuery loadsAllData]) { + // We should have a tag for this + NSNumber *removedQueryTag = self.queryToTagMap[removedQuery]; + [self.queryToTagMap removeObjectForKey:removedQuery]; + [self.tagToQueryMap removeObjectForKey:removedQueryTag]; + } }]; } -- (FQuerySpec *) queryForListening:(FQuerySpec *)query { +- (FQuerySpec *)queryForListening:(FQuerySpec *)query { if (query.loadsAllData && !query.isDefault) { // We treat queries that load all data as default queries return [FQuerySpec defaultQueryAtPath:query.path]; @@ -641,83 +806,105 @@ - (FQuerySpec *) queryForListening:(FQuerySpec *)query { } /** -* For a given new listen, manage the de-duplication of outstanding subscriptions. -* @return NSArray of FEvent events to support synchronous data sources -*/ -- (NSArray *) setupListenerOnQuery:(FQuerySpec *)query view:(FView *)view { + * For a given new listen, manage the de-duplication of outstanding + * subscriptions. + * @return NSArray of FEvent events to support synchronous data sources + */ +- (NSArray *)setupListenerOnQuery:(FQuerySpec *)query view:(FView *)view { FPath *path = query.path; NSNumber *tagId = [self tagForQuery:query]; FListenContainer *listenContainer = [self createListenerForView:view]; - NSArray *events = self.listenProvider.startListening([self queryForListening:query], tagId, listenContainer, - listenContainer.onComplete); + NSArray *events = self.listenProvider.startListening( + [self queryForListening:query], tagId, listenContainer, + listenContainer.onComplete); FImmutableTree *subtree = [self.syncPointTree subtreeAtPath:path]; - // The root of this subtree has our query. We're here because we definitely need to send a listen for that, but we - // may need to shadow other listens as well. + // The root of this subtree has our query. We're here because we definitely + // need to send a listen for that, but we may need to shadow other listens + // as well. if (tagId != nil) { - NSAssert(![subtree.value hasCompleteView], @"If we're adding a query, it shouldn't be shadowed"); + NSAssert(![subtree.value hasCompleteView], + @"If we're adding a query, it shouldn't be shadowed"); } else { - // Shadow everything at or below this location, this is a default listener. - NSArray *queriesToStop = [subtree foldWithBlock:^id(FPath *relativePath, FSyncPoint *maybeChildSyncPoint, NSDictionary *childMap) { - if (![relativePath isEmpty] && maybeChildSyncPoint != nil && [maybeChildSyncPoint hasCompleteView]) { - return @[[maybeChildSyncPoint completeView].query]; - } else { - // No default listener here, flatten any deeper queries into an array - NSMutableArray *queries = [[NSMutableArray alloc] init]; - if (maybeChildSyncPoint != nil) { - for (FView *view in [maybeChildSyncPoint queryViews]) { - [queries addObject:view.query]; - } - } - [childMap enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSArray *childQueries, BOOL *stop) { - [queries addObjectsFromArray:childQueries]; - }]; - return queries; - } - }]; + // Shadow everything at or below this location, this is a default + // listener. + NSArray *queriesToStop = + [subtree foldWithBlock:^id(FPath *relativePath, + FSyncPoint *maybeChildSyncPoint, + NSDictionary *childMap) { + if (![relativePath isEmpty] && maybeChildSyncPoint != nil && + [maybeChildSyncPoint hasCompleteView]) { + return @[ [maybeChildSyncPoint completeView].query ]; + } else { + // No default listener here, flatten any deeper queries into + // an array + NSMutableArray *queries = [[NSMutableArray alloc] init]; + if (maybeChildSyncPoint != nil) { + for (FView *view in [maybeChildSyncPoint queryViews]) { + [queries addObject:view.query]; + } + } + [childMap + enumerateKeysAndObjectsUsingBlock:^( + NSString *key, NSArray *childQueries, BOOL *stop) { + [queries addObjectsFromArray:childQueries]; + }]; + return queries; + } + }]; for (FQuerySpec *queryToStop in queriesToStop) { - self.listenProvider.stopListening([self queryForListening:queryToStop], [self tagForQuery:queryToStop]); + self.listenProvider.stopListening( + [self queryForListening:queryToStop], + [self tagForQuery:queryToStop]); } } return events; } -- (FListenContainer *) createListenerForView:(FView *)view { +- (FListenContainer *)createListenerForView:(FView *)view { FQuerySpec *query = view.query; NSNumber *tagId = [self tagForQuery:query]; - FListenContainer *listenContainer = [[FListenContainer alloc] initWithView:view - onComplete:^(NSString *status) { - if ([status isEqualToString:@"ok"]) { - if (tagId != nil) { - return [self applyTaggedListenCompleteAtPath:query.path tagId:tagId]; + FListenContainer *listenContainer = [[FListenContainer alloc] + initWithView:view + onComplete:^(NSString *status) { + if ([status isEqualToString:@"ok"]) { + if (tagId != nil) { + return [self applyTaggedListenCompleteAtPath:query.path + tagId:tagId]; + } else { + return [self applyListenCompleteAtPath:query.path]; + } } else { - return [self applyListenCompleteAtPath:query.path]; + // If a listen failed, kill all of the listeners here, not just + // the one that triggered the error. Note that this may need to + // be scoped to just this listener if we change permissions on + // filtered children + NSError *error = [FUtilities errorForStatus:status + andReason:nil]; + FFWarn(@"I-RDB038012", @"Listener at %@ failed: %@", query.path, + status); + return [self removeEventRegistration:nil + forQuery:query + cancelError:error]; } - } else { - // If a listen failed, kill all of the listeners here, not just the one that triggered the error. - // Note that this may need to be scoped to just this listener if we change permissions on filtered children - NSError *error = [FUtilities errorForStatus:status andReason:nil]; - FFWarn(@"I-RDB038012", @"Listener at %@ failed: %@", query.path, status); - return [self removeEventRegistration:nil forQuery:query cancelError:error]; - } - }]; + }]; return listenContainer; } /** -* @return The query associated with the given tag, if we have one -*/ -- (FQuerySpec *) queryForTag:(NSNumber *)tagId { + * @return The query associated with the given tag, if we have one + */ +- (FQuerySpec *)queryForTag:(NSNumber *)tagId { return self.tagToQueryMap[tagId]; } /** -* @return The tag associated with the given query -*/ -- (NSNumber *) tagForQuery:(FQuerySpec *)query { + * @return The tag associated with the given query + */ +- (NSNumber *)tagForQuery:(FQuerySpec *)query { return self.queryToTagMap[query]; } @@ -725,36 +912,49 @@ - (NSNumber *) tagForQuery:(FQuerySpec *)query { #pragma mark applyOperation Helpers /** -* A helper method that visits all descendant and ancestor SyncPoints, applying the operation. +* A helper method that visits all descendant and ancestor SyncPoints, applying +the operation. * * NOTES: -* - Descendant SyncPoints will be visited first (since we raise events depth-first). +* - Descendant SyncPoints will be visited first (since we raise events +depth-first). * - We call applyOperation: on each SyncPoint passing three things: -* 1. A version of the Operation that has been made relative to the SyncPoint location. +* 1. A version of the Operation that has been made relative to the SyncPoint +location. * 2. A WriteTreeRef of any writes we have cached at the SyncPoint location. * 3. A snapshot Node with cached server data, if we have it. -* - We concatenate all of the events returned by each SyncPoint and return the result. +* - We concatenate all of the events returned by each SyncPoint and return the +result. * * @return Array of FEvent */ -- (NSArray *) applyOperationToSyncPoints:(id)operation { - return [self applyOperationHelper:operation syncPointTree:self.syncPointTree serverCache:nil - writesCache:[self.pendingWriteTree childWritesForPath:[FPath empty]]]; +- (NSArray *)applyOperationToSyncPoints:(id)operation { + return [self applyOperationHelper:operation + syncPointTree:self.syncPointTree + serverCache:nil + writesCache:[self.pendingWriteTree + childWritesForPath:[FPath empty]]]; } /** -* Recursive helper for applyOperationToSyncPoints_ -*/ -- (NSArray *) applyOperationHelper:(id)operation syncPointTree:(FImmutableTree *)syncPointTree - serverCache:(id)serverCache writesCache:(FWriteTreeRef *)writesCache { + * Recursive helper for applyOperationToSyncPoints_ + */ +- (NSArray *)applyOperationHelper:(id)operation + syncPointTree:(FImmutableTree *)syncPointTree + serverCache:(id)serverCache + writesCache:(FWriteTreeRef *)writesCache { if ([operation.path isEmpty]) { - return [self applyOperationDescendantsHelper:operation syncPointTree:syncPointTree serverCache:serverCache writesCache:writesCache]; + return [self applyOperationDescendantsHelper:operation + syncPointTree:syncPointTree + serverCache:serverCache + writesCache:writesCache]; } else { FSyncPoint *syncPoint = syncPointTree.value; - // If we don't have cached server data, see if we can get it from this SyncPoint + // If we don't have cached server data, see if we can get it from this + // SyncPoint if (serverCache == nil && syncPoint != nil) { serverCache = [syncPoint completeServerCacheAtPath:[FPath empty]]; } @@ -764,13 +964,22 @@ - (NSArray *) applyOperationHelper:(id)operation syncPointTree:(FImm id childOperation = [operation operationForChild:childKey]; FImmutableTree *childTree = [syncPointTree.children get:childKey]; if (childTree != nil && childOperation != nil) { - id childServerCache = serverCache ? [serverCache getImmediateChild:childKey] : nil; - FWriteTreeRef *childWritesCache = [writesCache childWriteTreeRef:childKey]; - [events addObjectsFromArray:[self applyOperationHelper:childOperation syncPointTree:childTree serverCache:childServerCache writesCache:childWritesCache]]; + id childServerCache = + serverCache ? [serverCache getImmediateChild:childKey] : nil; + FWriteTreeRef *childWritesCache = + [writesCache childWriteTreeRef:childKey]; + [events + addObjectsFromArray:[self + applyOperationHelper:childOperation + syncPointTree:childTree + serverCache:childServerCache + writesCache:childWritesCache]]; } if (syncPoint) { - [events addObjectsFromArray:[syncPoint applyOperation:operation writesCache:writesCache serverCache:serverCache]]; + [events addObjectsFromArray:[syncPoint applyOperation:operation + writesCache:writesCache + serverCache:serverCache]]; } return events; @@ -778,38 +987,49 @@ - (NSArray *) applyOperationHelper:(id)operation syncPointTree:(FImm } /** -* Recursive helper for applyOperationToSyncPoints: -*/ -- (NSArray *) applyOperationDescendantsHelper:(id)operation syncPointTree:(FImmutableTree *)syncPointTree - serverCache:(id)serverCache writesCache:(FWriteTreeRef *)writesCache { + * Recursive helper for applyOperationToSyncPoints: + */ +- (NSArray *)applyOperationDescendantsHelper:(id)operation + syncPointTree:(FImmutableTree *)syncPointTree + serverCache:(id)serverCache + writesCache:(FWriteTreeRef *)writesCache { FSyncPoint *syncPoint = syncPointTree.value; - // If we don't have cached server data, see if we can get it from this SyncPoint + // If we don't have cached server data, see if we can get it from this + // SyncPoint id resolvedServerCache; if (serverCache == nil & syncPoint != nil) { - resolvedServerCache = [syncPoint completeServerCacheAtPath:[FPath empty]]; + resolvedServerCache = + [syncPoint completeServerCacheAtPath:[FPath empty]]; } else { resolvedServerCache = serverCache; } NSMutableArray *events = [[NSMutableArray alloc] init]; - [syncPointTree.children enumerateKeysAndObjectsUsingBlock:^(NSString *childKey, FImmutableTree *childTree, BOOL *stop) { - id childServerCache = nil; - if (resolvedServerCache != nil) { - childServerCache = [resolvedServerCache getImmediateChild:childKey]; - } - FWriteTreeRef *childWritesCache = [writesCache childWriteTreeRef:childKey]; - id childOperation = [operation operationForChild:childKey]; - if (childOperation != nil) { - [events addObjectsFromArray:[self applyOperationDescendantsHelper:childOperation - syncPointTree:childTree - serverCache:childServerCache - writesCache:childWritesCache]]; - } + [syncPointTree.children enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, + BOOL *stop) { + id childServerCache = nil; + if (resolvedServerCache != nil) { + childServerCache = [resolvedServerCache getImmediateChild:childKey]; + } + FWriteTreeRef *childWritesCache = + [writesCache childWriteTreeRef:childKey]; + id childOperation = [operation operationForChild:childKey]; + if (childOperation != nil) { + [events addObjectsFromArray: + [self applyOperationDescendantsHelper:childOperation + syncPointTree:childTree + serverCache:childServerCache + writesCache:childWritesCache]]; + } }]; if (syncPoint) { - [events addObjectsFromArray:[syncPoint applyOperation:operation writesCache:writesCache serverCache:resolvedServerCache]]; + [events + addObjectsFromArray:[syncPoint applyOperation:operation + writesCache:writesCache + serverCache:resolvedServerCache]]; } return events; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteRecord.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteRecord.h index a9b53fe..435fb6a 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteRecord.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteRecord.h @@ -22,17 +22,22 @@ @interface FWriteRecord : NSObject -- initWithPath:(FPath *)path overwrite:(id)overwrite writeId:(NSInteger)writeId visible:(BOOL)isVisible; -- initWithPath:(FPath *)path merge:(FCompoundWrite *)merge writeId:(NSInteger)writeId; +- initWithPath:(FPath *)path + overwrite:(id)overwrite + writeId:(NSInteger)writeId + visible:(BOOL)isVisible; +- initWithPath:(FPath *)path + merge:(FCompoundWrite *)merge + writeId:(NSInteger)writeId; -@property (nonatomic, readonly) NSInteger writeId; -@property (nonatomic, strong, readonly) FPath *path; -@property (nonatomic, strong, readonly) id overwrite; +@property(nonatomic, readonly) NSInteger writeId; +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) id overwrite; /** -* Maps NSString -> id -*/ -@property (nonatomic, strong, readonly) FCompoundWrite *merge; -@property (nonatomic, readonly) BOOL visible; + * Maps NSString -> id + */ +@property(nonatomic, strong, readonly) FCompoundWrite *merge; +@property(nonatomic, readonly) BOOL visible; - (BOOL)isMerge; - (BOOL)isOverwrite; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteRecord.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteRecord.m index 47c952c..be1816e 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteRecord.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteRecord.m @@ -15,26 +15,31 @@ */ #import "FWriteRecord.h" -#import "FPath.h" -#import "FNode.h" #import "FCompoundWrite.h" +#import "FNode.h" +#import "FPath.h" @interface FWriteRecord () -@property (nonatomic, readwrite) NSInteger writeId; -@property (nonatomic, strong, readwrite) FPath *path; -@property (nonatomic, strong, readwrite) id overwrite; -@property (nonatomic, strong, readwrite) FCompoundWrite *merge; -@property (nonatomic, readwrite) BOOL visible; +@property(nonatomic, readwrite) NSInteger writeId; +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, strong, readwrite) id overwrite; +@property(nonatomic, strong, readwrite) FCompoundWrite *merge; +@property(nonatomic, readwrite) BOOL visible; @end @implementation FWriteRecord -- (id)initWithPath:(FPath *)path overwrite:(id)overwrite writeId:(NSInteger)writeId visible:(BOOL)isVisible { +- (id)initWithPath:(FPath *)path + overwrite:(id)overwrite + writeId:(NSInteger)writeId + visible:(BOOL)isVisible { self = [super init]; if (self) { self.path = path; if (overwrite == nil) { - [NSException raise:NSInvalidArgumentException format:@"Can't pass nil as overwrite parameter to an overwrite write record"]; + [NSException raise:NSInvalidArgumentException + format:@"Can't pass nil as overwrite parameter to an " + @"overwrite write record"]; } self.overwrite = overwrite; self.merge = nil; @@ -44,12 +49,16 @@ - (id)initWithPath:(FPath *)path overwrite:(id)overwrite writeId:(NSInteg return self; } -- (id)initWithPath:(FPath *)path merge:(FCompoundWrite *)merge writeId:(NSInteger)writeId { +- (id)initWithPath:(FPath *)path + merge:(FCompoundWrite *)merge + writeId:(NSInteger)writeId { self = [super init]; if (self) { self.path = path; if (merge == nil) { - [NSException raise:NSInvalidArgumentException format:@"Can't pass nil as merge parameter to an merge write record"]; + [NSException raise:NSInvalidArgumentException + format:@"Can't pass nil as merge parameter to an merge " + @"write record"]; } self.overwrite = nil; self.merge = merge; @@ -61,14 +70,16 @@ - (id)initWithPath:(FPath *)path merge:(FCompoundWrite *)merge writeId:(NSIntege - (id)overwrite { if (self->_overwrite == nil) { - [NSException raise:NSInvalidArgumentException format:@"Can't get overwrite for merge write record!"]; + [NSException raise:NSInvalidArgumentException + format:@"Can't get overwrite for merge write record!"]; } return self->_overwrite; } - (FCompoundWrite *)compoundWrite { if (self->_merge == nil) { - [NSException raise:NSInvalidArgumentException format:@"Can't get merge for overwrite write record!"]; + [NSException raise:NSInvalidArgumentException + format:@"Can't get merge for overwrite write record!"]; } return self->_merge; } @@ -83,10 +94,15 @@ - (BOOL)isOverwrite { - (NSString *)description { if (self.isOverwrite) { - return [NSString stringWithFormat:@"FWriteRecord { writeId = %lu, path = %@, overwrite = %@, visible = %d }", - (unsigned long)self.writeId, self.path, self.overwrite, self.visible]; + return + [NSString stringWithFormat:@"FWriteRecord { writeId = %lu, path = " + @"%@, overwrite = %@, visible = %d }", + (unsigned long)self.writeId, self.path, + self.overwrite, self.visible]; } else { - return [NSString stringWithFormat:@"FWriteRecord { writeId = %lu, path = %@, merge = %@ }", + return [NSString + stringWithFormat: + @"FWriteRecord { writeId = %lu, path = %@, merge = %@ }", (unsigned long)self.writeId, self.path, self.merge]; } } @@ -96,11 +112,17 @@ - (BOOL)isEqual:(id)object { return NO; } FWriteRecord *other = (FWriteRecord *)object; - if (self->_writeId != other->_writeId) return NO; - if (self->_path != other->_path && ![self->_path isEqual:other->_path]) return NO; - if (self->_overwrite != other->_overwrite && ![self->_overwrite isEqual:other->_overwrite]) return NO; - if (self->_merge != other->_merge && ![self->_merge isEqual:other->_merge]) return NO; - if (self->_visible != other->_visible) return NO; + if (self->_writeId != other->_writeId) + return NO; + if (self->_path != other->_path && ![self->_path isEqual:other->_path]) + return NO; + if (self->_overwrite != other->_overwrite && + ![self->_overwrite isEqual:other->_overwrite]) + return NO; + if (self->_merge != other->_merge && ![self->_merge isEqual:other->_merge]) + return NO; + if (self->_visible != other->_visible) + return NO; return YES; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTree.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTree.h index 243bc9f..178946b 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTree.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTree.h @@ -28,36 +28,43 @@ @interface FWriteTree : NSObject -- (FWriteTreeRef *) childWritesForPath:(FPath *)path; -- (void) addOverwriteAtPath:(FPath *)path newData:(id)newData writeId:(NSInteger)writeId isVisible:(BOOL)visible; -- (void) addMergeAtPath:(FPath *)path changedChildren:(FCompoundWrite *)changedChildren writeId:(NSInteger)writeId; -- (BOOL) removeWriteId:(NSInteger)writeId; -- (NSArray *) removeAllWrites; +- (FWriteTreeRef *)childWritesForPath:(FPath *)path; +- (void)addOverwriteAtPath:(FPath *)path + newData:(id)newData + writeId:(NSInteger)writeId + isVisible:(BOOL)visible; +- (void)addMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writeId:(NSInteger)writeId; +- (BOOL)removeWriteId:(NSInteger)writeId; +- (NSArray *)removeAllWrites; - (FWriteRecord *)writeForId:(NSInteger)writeId; -- (id) calculateCompleteEventCacheAtPath:(FPath *)treePath - completeServerCache:(id)completeServerCache - excludeWriteIds:(NSArray *)writeIdsToExclude - includeHiddenWrites:(BOOL)includeHiddenWrites; +- (id)calculateCompleteEventCacheAtPath:(FPath *)treePath + completeServerCache:(id)completeServerCache + excludeWriteIds:(NSArray *)writeIdsToExclude + includeHiddenWrites:(BOOL)includeHiddenWrites; -- (id) calculateCompleteEventChildrenAtPath:(FPath *)treePath - completeServerChildren:(id)completeServerChildren; +- (id)calculateCompleteEventChildrenAtPath:(FPath *)treePath + completeServerChildren: + (id)completeServerChildren; -- (id) calculateEventCacheAfterServerOverwriteAtPath:(FPath *)treePath - childPath:(FPath *)childPath - existingEventSnap:(id)existingEventSnap - existingServerSnap:(id)existingServerSnap; +- (id) + calculateEventCacheAfterServerOverwriteAtPath:(FPath *)treePath + childPath:(FPath *)childPath + existingEventSnap:(id)existingEventSnap + existingServerSnap:(id)existingServerSnap; -- (id) calculateCompleteChildAtPath:(FPath *)treePath - childKey:(NSString *)childKey - cache:(FCacheNode *)existingServerCache; +- (id)calculateCompleteChildAtPath:(FPath *)treePath + childKey:(NSString *)childKey + cache:(FCacheNode *)existingServerCache; -- (id) shadowingWriteAtPath:(FPath *)path; +- (id)shadowingWriteAtPath:(FPath *)path; -- (FNamedNode *) calculateNextNodeAfterPost:(FNamedNode *)post - atPath:(FPath *)path - completeServerData:(id)completeServerData - reverse:(BOOL)reverse - index:(id)index; +- (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post + atPath:(FPath *)path + completeServerData:(id)completeServerData + reverse:(BOOL)reverse + index:(id)index; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTree.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTree.m index c5b08ea..d8592c0 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTree.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTree.m @@ -15,46 +15,47 @@ */ #import "FWriteTree.h" -#import "FImmutableTree.h" -#import "FPath.h" -#import "FNode.h" -#import "FWriteTreeRef.h" +#import "FCacheNode.h" #import "FChildrenNode.h" -#import "FNamedNode.h" -#import "FWriteRecord.h" +#import "FCompoundWrite.h" #import "FEmptyNode.h" +#import "FImmutableTree.h" #import "FIndex.h" -#import "FCompoundWrite.h" -#import "FCacheNode.h" +#import "FNamedNode.h" +#import "FNode.h" +#import "FPath.h" +#import "FWriteRecord.h" +#import "FWriteTreeRef.h" @interface FWriteTree () /** -* A tree tracking the results of applying all visible writes. This does not include transactions with -* applyLocally=false or writes that are completely shadowed by other writes. -* Contains id as values. -*/ -@property (nonatomic, strong) FCompoundWrite *visibleWrites; + * A tree tracking the results of applying all visible writes. This does not + * include transactions with applyLocally=false or writes that are completely + * shadowed by other writes. Contains id as values. + */ +@property(nonatomic, strong) FCompoundWrite *visibleWrites; /** -* A list of pending writes, regardless of visibility and shadowed-ness. Used to calcuate arbitrary -* sets of the changed data, such as hidden writes (from transactions) or changes with certain writes excluded (also -* used by transactions). -* Contains FWriteRecords. -*/ -@property (nonatomic, strong) NSMutableArray *allWrites; -@property (nonatomic) NSInteger lastWriteId; + * A list of pending writes, regardless of visibility and shadowed-ness. Used to + * calcuate arbitrary sets of the changed data, such as hidden writes (from + * transactions) or changes with certain writes excluded (also used by + * transactions). Contains FWriteRecords. + */ +@property(nonatomic, strong) NSMutableArray *allWrites; +@property(nonatomic) NSInteger lastWriteId; @end /** -* FWriteTree tracks all pending user-initiated writes and has methods to calcuate the result of merging them with -* underlying server data (to create "event cache" data). Pending writes are added with addOverwriteAtPath: and -* addMergeAtPath: and removed with removeWriteId:. -*/ + * FWriteTree tracks all pending user-initiated writes and has methods to + * calcuate the result of merging them with underlying server data (to create + * "event cache" data). Pending writes are added with addOverwriteAtPath: and + * addMergeAtPath: and removed with removeWriteId:. + */ @implementation FWriteTree @synthesize allWrites; @synthesize lastWriteId; -- (id) init { +- (id)init { self = [super init]; if (self) { self.visibleWrites = [FCompoundWrite emptyWrite]; @@ -65,19 +66,28 @@ - (id) init { } /** -* Create a new WriteTreeRef for the given path. For use with a new sync point at the given path. -*/ -- (FWriteTreeRef *) childWritesForPath:(FPath *)path { + * Create a new WriteTreeRef for the given path. For use with a new sync point + * at the given path. + */ +- (FWriteTreeRef *)childWritesForPath:(FPath *)path { return [[FWriteTreeRef alloc] initWithPath:path writeTree:self]; } /** -* Record a new overwrite from user code. -* @param visible Is set to false by some transactions. It should be excluded from event caches. -*/ -- (void) addOverwriteAtPath:(FPath *)path newData:(id )newData writeId:(NSInteger)writeId isVisible:(BOOL)visible { - NSAssert(writeId > self.lastWriteId, @"Stacking an older write on top of a newer one"); - FWriteRecord *record = [[FWriteRecord alloc] initWithPath:path overwrite:newData writeId:writeId visible:visible]; + * Record a new overwrite from user code. + * @param visible Is set to false by some transactions. It should be excluded + * from event caches. + */ +- (void)addOverwriteAtPath:(FPath *)path + newData:(id)newData + writeId:(NSInteger)writeId + isVisible:(BOOL)visible { + NSAssert(writeId > self.lastWriteId, + @"Stacking an older write on top of a newer one"); + FWriteRecord *record = [[FWriteRecord alloc] initWithPath:path + overwrite:newData + writeId:writeId + visible:visible]; [self.allWrites addObject:record]; if (visible) { @@ -88,41 +98,54 @@ - (void) addOverwriteAtPath:(FPath *)path newData:(id )newData writeId:(N } /** -* Record a new merge from user code. -* @param changedChildren maps NSString -> id -*/ -- (void) addMergeAtPath:(FPath *)path changedChildren:(FCompoundWrite *)changedChildren writeId:(NSInteger)writeId { - NSAssert(writeId > self.lastWriteId, @"Stacking an older merge on top of newer one"); - FWriteRecord *record = [[FWriteRecord alloc] initWithPath:path merge:changedChildren writeId:writeId]; + * Record a new merge from user code. + * @param changedChildren maps NSString -> id + */ +- (void)addMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writeId:(NSInteger)writeId { + NSAssert(writeId > self.lastWriteId, + @"Stacking an older merge on top of newer one"); + FWriteRecord *record = [[FWriteRecord alloc] initWithPath:path + merge:changedChildren + writeId:writeId]; [self.allWrites addObject:record]; - self.visibleWrites = [self.visibleWrites addCompoundWrite:changedChildren atPath:path]; + self.visibleWrites = [self.visibleWrites addCompoundWrite:changedChildren + atPath:path]; self.lastWriteId = writeId; } - (FWriteRecord *)writeForId:(NSInteger)writeId { - NSUInteger index = [self.allWrites indexOfObjectPassingTest:^BOOL(FWriteRecord *write, NSUInteger idx, BOOL *stop) { - return write.writeId == writeId; - }]; + NSUInteger index = [self.allWrites + indexOfObjectPassingTest:^BOOL(FWriteRecord *write, NSUInteger idx, + BOOL *stop) { + return write.writeId == writeId; + }]; return (index == NSNotFound) ? nil : self.allWrites[index]; } /** -* Remove a write (either an overwrite or merge) that has been successfully acknowledged by the server. Recalculates the -* tree if necessary. We return the path of the write and whether it may have been visible, meaning views need to -* reevaluate. -* -* @return YES if the write may have been visible (meaning we'll need to reevaluate / raise events as a result). -*/ -- (BOOL) removeWriteId:(NSInteger)writeId { - NSUInteger index = [self.allWrites indexOfObjectPassingTest:^BOOL(FWriteRecord *record, NSUInteger idx, BOOL *stop) { - if (record.writeId == writeId) { - return YES; - } else { - return NO; - } - }]; - NSAssert(index != NSNotFound, @"[FWriteTree removeWriteId:] called with nonexistent writeId."); + * Remove a write (either an overwrite or merge) that has been successfully + * acknowledged by the server. Recalculates the tree if necessary. We return the + * path of the write and whether it may have been visible, meaning views need to + * reevaluate. + * + * @return YES if the write may have been visible (meaning we'll need to + * reevaluate / raise events as a result). + */ +- (BOOL)removeWriteId:(NSInteger)writeId { + NSUInteger index = [self.allWrites + indexOfObjectPassingTest:^BOOL(FWriteRecord *record, NSUInteger idx, + BOOL *stop) { + if (record.writeId == writeId) { + return YES; + } else { + return NO; + } + }]; + NSAssert(index != NSNotFound, + @"[FWriteTree removeWriteId:] called with nonexistent writeId."); FWriteRecord *writeToRemove = self.allWrites[index]; [self.allWrites removeObjectAtIndex:index]; @@ -133,11 +156,14 @@ - (BOOL) removeWriteId:(NSInteger)writeId { while (removedWriteWasVisible && i >= 0) { FWriteRecord *currentWrite = [self.allWrites objectAtIndex:i]; if (currentWrite.visible) { - if (i >= index && [self record:currentWrite containsPath:writeToRemove.path]) { - // The removed write was completely shadowed by a subsequent write. + if (i >= index && [self record:currentWrite + containsPath:writeToRemove.path]) { + // The removed write was completely shadowed by a subsequent + // write. removedWriteWasVisible = NO; } else if ([writeToRemove.path contains:currentWrite.path]) { - // Either we're covering some writes or they're covering part of us (depending on which came first). + // Either we're covering some writes or they're covering part of + // us (depending on which came first). removedWriteOverlapsWithOtherWrites = YES; } } @@ -147,24 +173,28 @@ - (BOOL) removeWriteId:(NSInteger)writeId { if (!removedWriteWasVisible) { return NO; } else if (removedWriteOverlapsWithOtherWrites) { - // There's some shadowing going on. Just rebuild the visible writes from scratch. + // There's some shadowing going on. Just rebuild the visible writes from + // scratch. [self resetTree]; return YES; } else { - // There's no shadowing. We can safely just remove the write(s) from visibleWrites. + // There's no shadowing. We can safely just remove the write(s) from + // visibleWrites. if ([writeToRemove isOverwrite]) { - self.visibleWrites = [self.visibleWrites removeWriteAtPath:writeToRemove.path]; + self.visibleWrites = + [self.visibleWrites removeWriteAtPath:writeToRemove.path]; } else { FCompoundWrite *merge = writeToRemove.merge; [merge enumerateWrites:^(FPath *path, id node, BOOL *stop) { - self.visibleWrites = [self.visibleWrites removeWriteAtPath:[writeToRemove.path child:path]]; + self.visibleWrites = [self.visibleWrites + removeWriteAtPath:[writeToRemove.path child:path]]; }]; } return YES; } } -- (NSArray *) removeAllWrites { +- (NSArray *)removeAllWrites { NSArray *writes = self.allWrites; self.visibleWrites = [FCompoundWrite emptyWrite]; self.allWrites = [NSMutableArray array]; @@ -172,53 +202,76 @@ - (NSArray *) removeAllWrites { } /** -* @return A complete snapshot for the given path if there's visible write data at that path, else nil. -* No server data is considered. -*/ -- (id ) completeWriteDataAtPath:(FPath *)path { + * @return A complete snapshot for the given path if there's visible write data + * at that path, else nil. No server data is considered. + */ +- (id)completeWriteDataAtPath:(FPath *)path { return [self.visibleWrites completeNodeAtPath:path]; } /** -* Given optional, underlying server data, and an optional set of constraints (exclude some sets, include hidden -* writes), attempt to calculate a complete snapshot for the given path -* @param includeHiddenWrites Defaults to false, whether or not to layer on writes with visible set to false -*/ -- (id ) calculateCompleteEventCacheAtPath:(FPath *)treePath completeServerCache:(id )completeServerCache - excludeWriteIds:(NSArray *)writeIdsToExclude includeHiddenWrites:(BOOL)includeHiddenWrites { + * Given optional, underlying server data, and an optional set of constraints + * (exclude some sets, include hidden writes), attempt to calculate a complete + * snapshot for the given path + * @param includeHiddenWrites Defaults to false, whether or not to layer on + * writes with visible set to false + */ +- (id)calculateCompleteEventCacheAtPath:(FPath *)treePath + completeServerCache:(id)completeServerCache + excludeWriteIds:(NSArray *)writeIdsToExclude + includeHiddenWrites:(BOOL)includeHiddenWrites { if (writeIdsToExclude == nil && !includeHiddenWrites) { - id shadowingNode = [self.visibleWrites completeNodeAtPath:treePath]; + id shadowingNode = + [self.visibleWrites completeNodeAtPath:treePath]; if (shadowingNode != nil) { return shadowingNode; } else { // No cache here. Can't claim complete knowledge. - FCompoundWrite *subMerge = [self.visibleWrites childCompoundWriteAtPath:treePath]; + FCompoundWrite *subMerge = + [self.visibleWrites childCompoundWriteAtPath:treePath]; if (subMerge.isEmpty) { return completeServerCache; - } else if (completeServerCache == nil && ![subMerge hasCompleteWriteAtPath:[FPath empty]]) { - // We wouldn't have a complete snapshot since there's no underlying data and no complete shadow + } else if (completeServerCache == nil && + ![subMerge hasCompleteWriteAtPath:[FPath empty]]) { + // We wouldn't have a complete snapshot since there's no + // underlying data and no complete shadow return nil; } else { - id layeredCache = completeServerCache != nil ? completeServerCache : [FEmptyNode emptyNode]; + id layeredCache = completeServerCache != nil + ? completeServerCache + : [FEmptyNode emptyNode]; return [subMerge applyToNode:layeredCache]; } } } else { - FCompoundWrite *merge = [self.visibleWrites childCompoundWriteAtPath:treePath]; + FCompoundWrite *merge = + [self.visibleWrites childCompoundWriteAtPath:treePath]; if (!includeHiddenWrites && merge.isEmpty) { return completeServerCache; } else { - // If the server cache is null and we don't have a complete cache, we need to return nil - if (!includeHiddenWrites && completeServerCache == nil && ![merge hasCompleteWriteAtPath:[FPath empty]]) { + // If the server cache is null and we don't have a complete cache, + // we need to return nil + if (!includeHiddenWrites && completeServerCache == nil && + ![merge hasCompleteWriteAtPath:[FPath empty]]) { return nil; } else { - BOOL (^filter) (FWriteRecord *) = ^(FWriteRecord *record) { - return (BOOL) ((record.visible || includeHiddenWrites) && - (writeIdsToExclude == nil || ![writeIdsToExclude containsObject:[NSNumber numberWithInteger:record.writeId]]) && - ([record.path contains:treePath] || [treePath contains:record.path])); + BOOL (^filter)(FWriteRecord *) = ^(FWriteRecord *record) { + return (BOOL)( + (record.visible || includeHiddenWrites) && + (writeIdsToExclude == nil || + ![writeIdsToExclude + containsObject: + [NSNumber numberWithInteger:record.writeId]]) && + ([record.path contains:treePath] || + [treePath contains:record.path])); }; - FCompoundWrite *mergeAtPath = [FWriteTree layerTreeFromWrites:self.allWrites filter:filter treeRoot:treePath]; - id layeredCache = completeServerCache ? completeServerCache : [FEmptyNode emptyNode]; + FCompoundWrite *mergeAtPath = + [FWriteTree layerTreeFromWrites:self.allWrites + filter:filter + treeRoot:treePath]; + id layeredCache = completeServerCache + ? completeServerCache + : [FEmptyNode emptyNode]; return [mergeAtPath applyToNode:layeredCache]; } } @@ -226,91 +279,119 @@ - (NSArray *) removeAllWrites { } /** -* With optional, underlying server data, attempt to return a children node of children that we have complete data for. -* Used when creating new views, to pre-fill their complete event children snapshot. -*/ -- (FChildrenNode *) calculateCompleteEventChildrenAtPath:(FPath *)treePath - completeServerChildren:(id)completeServerChildren { + * With optional, underlying server data, attempt to return a children node of + * children that we have complete data for. Used when creating new views, to + * pre-fill their complete event children snapshot. + */ +- (FChildrenNode *)calculateCompleteEventChildrenAtPath:(FPath *)treePath + completeServerChildren: + (id)completeServerChildren { __block id completeChildren = [FEmptyNode emptyNode]; id topLevelSet = [self.visibleWrites completeNodeAtPath:treePath]; if (topLevelSet != nil) { if (![topLevelSet isLeafNode]) { // We're shadowing everything. Return the children. FChildrenNode *topChildrenNode = topLevelSet; - [topChildrenNode enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - completeChildren = [completeChildren updateImmediateChild:key withNewChild:node]; + [topChildrenNode enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + completeChildren = [completeChildren updateImmediateChild:key + withNewChild:node]; }]; } return completeChildren; } else { // Layer any children we have on top of this - // We know we don't have a top-level set, so just enumerate existing children, and apply any updates - FCompoundWrite *merge = [self.visibleWrites childCompoundWriteAtPath:treePath]; - [completeServerChildren enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - FCompoundWrite *childMerge = [merge childCompoundWriteAtPath:[[FPath alloc] initWith:key]]; - id newChildNode = [childMerge applyToNode:node]; - completeChildren = [completeChildren updateImmediateChild:key withNewChild:newChildNode]; + // We know we don't have a top-level set, so just enumerate existing + // children, and apply any updates + FCompoundWrite *merge = + [self.visibleWrites childCompoundWriteAtPath:treePath]; + [completeServerChildren enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + FCompoundWrite *childMerge = + [merge childCompoundWriteAtPath:[[FPath alloc] initWith:key]]; + id newChildNode = [childMerge applyToNode:node]; + completeChildren = + [completeChildren updateImmediateChild:key + withNewChild:newChildNode]; }]; // Add any complete children we have from the set. for (FNamedNode *node in merge.completeChildren) { - completeChildren = [completeChildren updateImmediateChild:node.name withNewChild:node.node]; + completeChildren = + [completeChildren updateImmediateChild:node.name + withNewChild:node.node]; } return completeChildren; } } /** -* Given that the underlying server data has updated, determine what, if anything, needs to be applied to the event cache. -* -* Possibilities -* -* 1. No write are shadowing. Events should be raised, the snap to be applied comes from the server data. -* -* 2. Some write is completely shadowing. No events to be raised. -* -* 3. Is partially shadowed. Events .. -* -* Either existingEventSnap or existingServerSnap must exist. -*/ -- (id ) calculateEventCacheAfterServerOverwriteAtPath:(FPath *)treePath childPath:(FPath *)childPath existingEventSnap:(id )existingEventSnap existingServerSnap:(id )existingServerSnap { + * Given that the underlying server data has updated, determine what, if + * anything, needs to be applied to the event cache. + * + * Possibilities + * + * 1. No write are shadowing. Events should be raised, the snap to be applied + * comes from the server data. + * + * 2. Some write is completely shadowing. No events to be raised. + * + * 3. Is partially shadowed. Events .. + * + * Either existingEventSnap or existingServerSnap must exist. + */ +- (id)calculateEventCacheAfterServerOverwriteAtPath:(FPath *)treePath + childPath:(FPath *)childPath + existingEventSnap: + (id)existingEventSnap + existingServerSnap: + (id)existingServerSnap { NSAssert(existingEventSnap != nil || existingServerSnap != nil, - @"Either existingEventSnap or existingServerSanp must exist."); + @"Either existingEventSnap or existingServerSanp must exist."); FPath *path = [treePath child:childPath]; if ([self.visibleWrites hasCompleteWriteAtPath:path]) { - // At this point we can probably guarantee that we're in case 2, meaning no events - // May need to check visibility while doing the findRootMostValueAndPath call + // At this point we can probably guarantee that we're in case 2, meaning + // no events May need to check visibility while doing the + // findRootMostValueAndPath call return nil; } else { - // This could be more efficient if the serverNode + updates doesn't change the eventSnap - // However this is tricky to find out, since user updates don't necessary change the server - // snap, e.g. priority updates on empty nodes, or deep deletes. Another special case is if the server - // adds nodes, but doesn't change any existing writes. It is therefore not enough to - // only check if the updates change the serverNode. - // Maybe check if the merge tree contains these special cases and only do a full overwrite in that case? - FCompoundWrite *childMerge = [self.visibleWrites childCompoundWriteAtPath:path]; + // This could be more efficient if the serverNode + updates doesn't + // change the eventSnap However this is tricky to find out, since user + // updates don't necessary change the server snap, e.g. priority updates + // on empty nodes, or deep deletes. Another special case is if the + // server adds nodes, but doesn't change any existing writes. It is + // therefore not enough to only check if the updates change the + // serverNode. Maybe check if the merge tree contains these special + // cases and only do a full overwrite in that case? + FCompoundWrite *childMerge = + [self.visibleWrites childCompoundWriteAtPath:path]; if (childMerge.isEmpty) { // We're not shadowing at all. Case 1 return [existingServerSnap getChild:childPath]; } else { - return [childMerge applyToNode:[existingServerSnap getChild:childPath]]; + return [childMerge + applyToNode:[existingServerSnap getChild:childPath]]; } } } /** -* Returns a complete child for a given server snap after applying all user writes or nil if there is no complete child -* for this child key. -*/ -- (id) calculateCompleteChildAtPath:(FPath *)treePath childKey:(NSString *)childKey cache:(FCacheNode *)existingServerCache { + * Returns a complete child for a given server snap after applying all user + * writes or nil if there is no complete child for this child key. + */ +- (id)calculateCompleteChildAtPath:(FPath *)treePath + childKey:(NSString *)childKey + cache:(FCacheNode *)existingServerCache { FPath *path = [treePath childFromString:childKey]; id shadowingNode = [self.visibleWrites completeNodeAtPath:path]; if (shadowingNode != nil) { return shadowingNode; } else { if ([existingServerCache isCompleteForChild:childKey]) { - FCompoundWrite *childMerge = [self.visibleWrites childCompoundWriteAtPath:path]; - return [childMerge applyToNode:[existingServerCache.node getImmediateChild:childKey]]; + FCompoundWrite *childMerge = + [self.visibleWrites childCompoundWriteAtPath:path]; + return [childMerge applyToNode:[existingServerCache.node + getImmediateChild:childKey]]; } else { return nil; } @@ -318,26 +399,28 @@ - (FChildrenNode *) calculateCompleteEventChildrenAtPath:(FPath *)treePath } /** -* Returns a node if there is a complete overwrite for this path. More specifically, if there is a write at -* a higher path, this will return the child of that write relative to the write and this path. -* Returns null if there is no write at this path. -*/ -- (id) shadowingWriteAtPath:(FPath *)path { + * Returns a node if there is a complete overwrite for this path. More + * specifically, if there is a write at a higher path, this will return the + * child of that write relative to the write and this path. Returns null if + * there is no write at this path. + */ +- (id)shadowingWriteAtPath:(FPath *)path { return [self.visibleWrites completeNodeAtPath:path]; } /** -* This method is used when processing child remove events on a query. If we can, we pull in children that were outside -* the window, but may now be in the window. -*/ + * This method is used when processing child remove events on a query. If we + * can, we pull in children that were outside the window, but may now be in the + * window. + */ - (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post atPath:(FPath *)treePath completeServerData:(id)completeServerData reverse:(BOOL)reverse - index:(id)index -{ + index:(id)index { __block id toIterate; - FCompoundWrite *merge = [self.visibleWrites childCompoundWriteAtPath:treePath]; + FCompoundWrite *merge = + [self.visibleWrites childCompoundWriteAtPath:treePath]; id shadowingNode = [merge completeNodeAtPath:[FPath empty]]; if (shadowingNode != nil) { toIterate = shadowingNode; @@ -349,12 +432,21 @@ - (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post __block NSString *currentNextKey = nil; __block id currentNextNode = nil; - [toIterate enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - if ([index compareKey:key andNode:node toOtherKey:post.name andNode:post.node reverse:reverse] > NSOrderedSame && - (!currentNextKey || [index compareKey:key andNode:node toOtherKey:currentNextKey andNode:currentNextNode reverse:reverse] < NSOrderedSame)) { - currentNextKey = key; - currentNextNode = node; - } + [toIterate enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + if ([index compareKey:key + andNode:node + toOtherKey:post.name + andNode:post.node + reverse:reverse] > NSOrderedSame && + (!currentNextKey || [index compareKey:key + andNode:node + toOtherKey:currentNextKey + andNode:currentNextNode + reverse:reverse] < NSOrderedSame)) { + currentNextKey = key; + currentNextNode = node; + } }]; if (currentNextKey != nil) { @@ -367,24 +459,29 @@ - (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post #pragma mark - #pragma mark Private Methods -- (BOOL) record:(FWriteRecord *)record containsPath:(FPath *)path { +- (BOOL)record:(FWriteRecord *)record containsPath:(FPath *)path { if ([record isOverwrite]) { return [record.path contains:path]; } else { __block BOOL contains = NO; - [record.merge enumerateWrites:^(FPath *childPath, id node, BOOL *stop) { - contains = [[record.path child:childPath] contains:path]; - *stop = contains; - }]; + [record.merge + enumerateWrites:^(FPath *childPath, id node, BOOL *stop) { + contains = [[record.path child:childPath] contains:path]; + *stop = contains; + }]; return contains; } } /** -* Re-layer the writes and merges into a tree so we can efficiently calculate event snapshots -*/ -- (void) resetTree { - self.visibleWrites = [FWriteTree layerTreeFromWrites:self.allWrites filter:[FWriteTree defaultFilter] treeRoot:[FPath empty]]; + * Re-layer the writes and merges into a tree so we can efficiently calculate + * event snapshots + */ +- (void)resetTree { + self.visibleWrites = + [FWriteTree layerTreeFromWrites:self.allWrites + filter:[FWriteTree defaultFilter] + treeRoot:[FPath empty]]; if ([self.allWrites count] > 0) { FWriteRecord *lastRecord = self.allWrites[[self.allWrites count] - 1]; self.lastWriteId = lastRecord.writeId; @@ -394,63 +491,85 @@ - (void) resetTree { } /** -* The default filter used when constructing the tree. Keep everything that's visible. -*/ -+ (BOOL (^)(FWriteRecord *record)) defaultFilter { + * The default filter used when constructing the tree. Keep everything that's + * visible. + */ ++ (BOOL (^)(FWriteRecord *record))defaultFilter { static BOOL (^filter)(FWriteRecord *); static dispatch_once_t filterToken; dispatch_once(&filterToken, ^{ - filter = ^(FWriteRecord *record) { - return YES; - }; + filter = ^(FWriteRecord *record) { + return YES; + }; }); return filter; } /** -* Static method. Given an array of WriteRecords, a filter for which ones to include, and a path, construct a merge -* at that path -* @return An FImmutableTree of ids. -*/ -+ (FCompoundWrite *) layerTreeFromWrites:(NSArray *)writes filter:(BOOL (^)(FWriteRecord *record))filter treeRoot:(FPath *)treeRoot { + * Static method. Given an array of WriteRecords, a filter for which ones to + * include, and a path, construct a merge at that path + * @return An FImmutableTree of ids. + */ ++ (FCompoundWrite *)layerTreeFromWrites:(NSArray *)writes + filter:(BOOL (^)(FWriteRecord *record))filter + treeRoot:(FPath *)treeRoot { __block FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite]; - [writes enumerateObjectsUsingBlock:^(FWriteRecord *record, NSUInteger idx, BOOL *stop) { - // Theory, a later set will either: - // a) abort a relevant transaction, so no need to worry about excluding it from calculating that transaction - // b) not be relevant to a transaction (separate branch), so again will not affect the data for that transaction - if (filter(record)) { - FPath *writePath = record.path; - if ([record isOverwrite]) { - if ([treeRoot contains:writePath]) { - FPath *relativePath = [FPath relativePathFrom:treeRoot to:writePath]; - compoundWrite = [compoundWrite addWrite:record.overwrite atPath:relativePath]; - } else if ([writePath contains:treeRoot]) { - id child = [record.overwrite getChild:[FPath relativePathFrom:writePath to:treeRoot]]; - compoundWrite = [compoundWrite addWrite:child atPath:[FPath empty]]; - } else { - // There is no overlap between root path and write path, ignore write - } - } else { - if ([treeRoot contains:writePath]) { - FPath *relativePath = [FPath relativePathFrom:treeRoot to:writePath]; - compoundWrite = [compoundWrite addCompoundWrite:record.merge atPath:relativePath]; - } else if ([writePath contains:treeRoot]) { - FPath *relativePath = [FPath relativePathFrom:writePath to:treeRoot]; - if (relativePath.isEmpty) { - compoundWrite = [compoundWrite addCompoundWrite:record.merge atPath:[FPath empty]]; - } else { - id child = [record.merge completeNodeAtPath:relativePath]; - if (child != nil) { - // There exists a child in this node that matches the root path - id deepNode = [child getChild:[relativePath popFront]]; - compoundWrite = [compoundWrite addWrite:deepNode atPath:[FPath empty]]; - } - } - } else { - // There is no overlap between root path and write path, ignore write - } - } - } + [writes enumerateObjectsUsingBlock:^(FWriteRecord *record, NSUInteger idx, + BOOL *stop) { + // Theory, a later set will either: + // a) abort a relevant transaction, so no need to worry about excluding it + // from calculating that transaction b) not be relevant to a transaction + // (separate branch), so again will not affect the data for that + // transaction + if (filter(record)) { + FPath *writePath = record.path; + if ([record isOverwrite]) { + if ([treeRoot contains:writePath]) { + FPath *relativePath = [FPath relativePathFrom:treeRoot + to:writePath]; + compoundWrite = [compoundWrite addWrite:record.overwrite + atPath:relativePath]; + } else if ([writePath contains:treeRoot]) { + id child = [record.overwrite + getChild:[FPath relativePathFrom:writePath to:treeRoot]]; + compoundWrite = [compoundWrite addWrite:child + atPath:[FPath empty]]; + } else { + // There is no overlap between root path and write path, + // ignore write + } + } else { + if ([treeRoot contains:writePath]) { + FPath *relativePath = [FPath relativePathFrom:treeRoot + to:writePath]; + compoundWrite = [compoundWrite addCompoundWrite:record.merge + atPath:relativePath]; + } else if ([writePath contains:treeRoot]) { + FPath *relativePath = [FPath relativePathFrom:writePath + to:treeRoot]; + if (relativePath.isEmpty) { + compoundWrite = + [compoundWrite addCompoundWrite:record.merge + atPath:[FPath empty]]; + } else { + id child = + [record.merge completeNodeAtPath:relativePath]; + if (child != nil) { + // There exists a child in this node that matches the + // root path + id deepNode = + [child getChild:[relativePath popFront]]; + compoundWrite = + [compoundWrite addWrite:deepNode + atPath:[FPath empty]]; + } + } + } else { + // There is no overlap between root path and write path, + // ignore write + } + } + } }]; return compoundWrite; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTreeRef.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTreeRef.h index 791dd26..962ad5c 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTreeRef.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTreeRef.h @@ -27,25 +27,31 @@ @interface FWriteTreeRef : NSObject -- (id) initWithPath:(FPath *)aPath writeTree:(FWriteTree *)tree; +- (id)initWithPath:(FPath *)aPath writeTree:(FWriteTree *)tree; -- (id ) calculateCompleteEventCacheWithCompleteServerCache:(id )completeServerCache; +- (id)calculateCompleteEventCacheWithCompleteServerCache: + (id)completeServerCache; -- (FChildrenNode *) calculateCompleteEventChildrenWithCompleteServerChildren:(FChildrenNode *)completeServerChildren; +- (FChildrenNode *)calculateCompleteEventChildrenWithCompleteServerChildren: + (FChildrenNode *)completeServerChildren; -- (id) calculateEventCacheAfterServerOverwriteWithChildPath:(FPath *)childPath - existingEventSnap:(id)existingEventSnap - existingServerSnap:(id)existingServerSnap; +- (id) + calculateEventCacheAfterServerOverwriteWithChildPath:(FPath *)childPath + existingEventSnap: + (id)existingEventSnap + existingServerSnap: + (id)existingServerSnap; -- (id) shadowingWriteAtPath:(FPath *)path; +- (id)shadowingWriteAtPath:(FPath *)path; -- (FNamedNode *) calculateNextNodeAfterPost:(FNamedNode *)post - completeServerData:(id)completeServerData - reverse:(BOOL)reverse - index:(id)index; +- (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post + completeServerData:(id)completeServerData + reverse:(BOOL)reverse + index:(id)index; -- (id) calculateCompleteChild:(NSString *)childKey cache:(FCacheNode *)existingServerCache; +- (id)calculateCompleteChild:(NSString *)childKey + cache:(FCacheNode *)existingServerCache; -- (FWriteTreeRef *) childWriteTreeRef:(NSString *)childKey; +- (FWriteTreeRef *)childWriteTreeRef:(NSString *)childKey; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTreeRef.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTreeRef.m index 392369b..809d1a9 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTreeRef.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/FWriteTreeRef.m @@ -15,37 +15,37 @@ */ #import "FWriteTreeRef.h" -#import "FPath.h" -#import "FNode.h" -#import "FWriteTree.h" +#import "FCacheNode.h" #import "FChildrenNode.h" +#import "FIndex.h" #import "FNamedNode.h" +#import "FNode.h" +#import "FPath.h" #import "FWriteRecord.h" -#import "FIndex.h" -#import "FCacheNode.h" +#import "FWriteTree.h" @interface FWriteTreeRef () /** -* The path to this particular FWriteTreeRef. Used for calling methods on writeTree while exposing a simpler interface -* to callers. -*/ -@property (nonatomic, strong) FPath *path; + * The path to this particular FWriteTreeRef. Used for calling methods on + * writeTree while exposing a simpler interface to callers. + */ +@property(nonatomic, strong) FPath *path; /** -* A reference to the actual tree of the write data. All methods are pass-through to the tree, but with the appropriate -* path prefixed. -* -* This lets us make cheap references to points in the tree for sync points without having to copy and maintain all of -* the data. -*/ -@property (nonatomic, strong) FWriteTree *writeTree; + * A reference to the actual tree of the write data. All methods are + * pass-through to the tree, but with the appropriate path prefixed. + * + * This lets us make cheap references to points in the tree for sync points + * without having to copy and maintain all of the data. + */ +@property(nonatomic, strong) FWriteTree *writeTree; @end /** -* A FWriteTreeRef wraps a FWriteTree and a FPath, for convenient access to a particular subtree. All the methods just -* proxy to the underlying FWriteTree. -*/ + * A FWriteTreeRef wraps a FWriteTree and a FPath, for convenient access to a + * particular subtree. All the methods just proxy to the underlying FWriteTree. + */ @implementation FWriteTreeRef -- (id) initWithPath:(FPath *)aPath writeTree:(FWriteTree *)tree { +- (id)initWithPath:(FPath *)aPath writeTree:(FWriteTree *)tree { self = [super init]; if (self) { self.path = aPath; @@ -55,58 +55,80 @@ - (id) initWithPath:(FPath *)aPath writeTree:(FWriteTree *)tree { } /** -* @return If possible, returns a complete event cache, using the underlying server data if possible. In addition, can -* be used to get a cache that includes hidden writes, and excludes arbitrary writes. Note that customizing the returned -* node can lead to a more expensive calculation. -*/ -- (id ) calculateCompleteEventCacheWithCompleteServerCache:(id)completeServerCache { - return [self.writeTree calculateCompleteEventCacheAtPath:self.path completeServerCache:completeServerCache excludeWriteIds:nil includeHiddenWrites:NO]; + * @return If possible, returns a complete event cache, using the underlying + * server data if possible. In addition, can be used to get a cache that + * includes hidden writes, and excludes arbitrary writes. Note that customizing + * the returned node can lead to a more expensive calculation. + */ +- (id)calculateCompleteEventCacheWithCompleteServerCache: + (id)completeServerCache { + return [self.writeTree calculateCompleteEventCacheAtPath:self.path + completeServerCache:completeServerCache + excludeWriteIds:nil + includeHiddenWrites:NO]; } /** -* @return If possible, returns a children node containing all of the complete children we have data for. The returned -* data is a mix of the given server data and write data. -*/ -- (FChildrenNode *) calculateCompleteEventChildrenWithCompleteServerChildren:(id)completeServerChildren { - return [self.writeTree calculateCompleteEventChildrenAtPath:self.path completeServerChildren:completeServerChildren]; + * @return If possible, returns a children node containing all of the complete + * children we have data for. The returned data is a mix of the given server + * data and write data. + */ +- (FChildrenNode *)calculateCompleteEventChildrenWithCompleteServerChildren: + (id)completeServerChildren { + return [self.writeTree + calculateCompleteEventChildrenAtPath:self.path + completeServerChildren:completeServerChildren]; } /** -* Given that either the underlying server data has updated or the outstanding writes have been updating, determine what, -* if anything, needs to be applied to the event cache. -* -* Possibilities: -* -* 1. No writes are shadowing. Events should be raised, the snap to be applied comes from the server data. -* -* 2. Some writes are completly shadowing. No events to be raised. -* -* 3. Is partially shadowed. Events should be raised. -* -* Either existingEventSnap or existingServerSnap must exist, this is validated via an assert. -*/ -- (id) calculateEventCacheAfterServerOverwriteWithChildPath:(FPath *)childPath existingEventSnap:(id )existingEventSnap existingServerSnap:(id )existingServerSnap { - return [self.writeTree calculateEventCacheAfterServerOverwriteAtPath:self.path childPath:childPath existingEventSnap:existingEventSnap existingServerSnap:existingServerSnap]; + * Given that either the underlying server data has updated or the outstanding + * writes have been updating, determine what, if anything, needs to be applied + * to the event cache. + * + * Possibilities: + * + * 1. No writes are shadowing. Events should be raised, the snap to be applied + * comes from the server data. + * + * 2. Some writes are completly shadowing. No events to be raised. + * + * 3. Is partially shadowed. Events should be raised. + * + * Either existingEventSnap or existingServerSnap must exist, this is validated + * via an assert. + */ +- (id) + calculateEventCacheAfterServerOverwriteWithChildPath:(FPath *)childPath + existingEventSnap: + (id)existingEventSnap + existingServerSnap: + (id)existingServerSnap { + return [self.writeTree + calculateEventCacheAfterServerOverwriteAtPath:self.path + childPath:childPath + existingEventSnap:existingEventSnap + existingServerSnap:existingServerSnap]; } /** -* Returns a node if there is a complete overwrite for this path. More specifically, if there is a write at a higher -* path, this will return the child of that write relative to the write and this path. -* Returns nil if there is no write at this path. -*/ -- (id) shadowingWriteAtPath:(FPath *)path { + * Returns a node if there is a complete overwrite for this path. More + * specifically, if there is a write at a higher path, this will return the + * child of that write relative to the write and this path. Returns nil if there + * is no write at this path. + */ +- (id)shadowingWriteAtPath:(FPath *)path { return [self.writeTree shadowingWriteAtPath:[self.path child:path]]; } /** -* This method is used when processing child remove events on a query. If we can, we pull in children that are outside -* the window, but may now be in the window. -*/ + * This method is used when processing child remove events on a query. If we + * can, we pull in children that are outside the window, but may now be in the + * window. + */ - (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post completeServerData:(id)completeServerData reverse:(BOOL)reverse - index:(id)index -{ + index:(id)index { return [self.writeTree calculateNextNodeAfterPost:post atPath:self.path completeServerData:completeServerData @@ -115,19 +137,23 @@ - (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post } /** -* Returns a complete child for a given server snap after applying all user writes or nil if there is no complete child -* for this child key. -*/ -- (id) calculateCompleteChild:(NSString *)childKey cache:(FCacheNode *)existingServerCache { - return [self.writeTree calculateCompleteChildAtPath:self.path childKey:childKey cache:existingServerCache]; + * Returns a complete child for a given server snap after applying all user + * writes or nil if there is no complete child for this child key. + */ +- (id)calculateCompleteChild:(NSString *)childKey + cache:(FCacheNode *)existingServerCache { + return [self.writeTree calculateCompleteChildAtPath:self.path + childKey:childKey + cache:existingServerCache]; } /** -* @return a WriteTreeref for a child. -*/ -- (FWriteTreeRef *) childWriteTreeRef:(NSString *)childKey { - return [[FWriteTreeRef alloc] initWithPath:[self.path childFromString:childKey] writeTree:self.writeTree]; + * @return a WriteTreeref for a child. + */ +- (FWriteTreeRef *)childWriteTreeRef:(NSString *)childKey { + return + [[FWriteTreeRef alloc] initWithPath:[self.path childFromString:childKey] + writeTree:self.writeTree]; } - @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FAckUserWrite.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FAckUserWrite.h index a337996..97a23bf 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FAckUserWrite.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FAckUserWrite.h @@ -20,16 +20,18 @@ @class FOperationSource; @class FImmutableTree; - @interface FAckUserWrite : NSObject -- initWithPath:(FPath *)operationPath affectedTree:(FImmutableTree *)affectedTree revert:(BOOL)shouldRevert; +- initWithPath:(FPath *)operationPath + affectedTree:(FImmutableTree *)affectedTree + revert:(BOOL)shouldRevert; -@property (nonatomic, strong, readonly) FOperationSource *source; -@property (nonatomic, readonly) FOperationType type; -@property (nonatomic, strong, readonly) FPath *path; -// A FImmutableTree, containing @YES for each affected path. Affected paths can't overlap. -@property (nonatomic, strong, readonly) FImmutableTree *affectedTree; -@property (nonatomic, readonly) BOOL revert; +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, readonly) FOperationType type; +@property(nonatomic, strong, readonly) FPath *path; +// A FImmutableTree, containing @YES for each affected path. Affected paths +// can't overlap. +@property(nonatomic, strong, readonly) FImmutableTree *affectedTree; +@property(nonatomic, readonly) BOOL revert; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FAckUserWrite.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FAckUserWrite.m index f81e7f5..2a1f287 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FAckUserWrite.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FAckUserWrite.m @@ -15,14 +15,15 @@ */ #import "FAckUserWrite.h" -#import "FPath.h" -#import "FOperationSource.h" #import "FImmutableTree.h" - +#import "FOperationSource.h" +#import "FPath.h" @implementation FAckUserWrite -- (id) initWithPath:(FPath *)operationPath affectedTree:(FImmutableTree *)tree revert:(BOOL)shouldRevert { +- (id)initWithPath:(FPath *)operationPath + affectedTree:(FImmutableTree *)tree + revert:(BOOL)shouldRevert { self = [super init]; if (self) { self->_source = [FOperationSource userInstance]; @@ -34,22 +35,32 @@ - (id) initWithPath:(FPath *)operationPath affectedTree:(FImmutableTree *)tree r return self; } -- (FAckUserWrite *) operationForChild:(NSString *)childKey { +- (FAckUserWrite *)operationForChild:(NSString *)childKey { if (![self.path isEmpty]) { - NSAssert([self.path.getFront isEqualToString:childKey], @"operationForChild called for unrelated child."); - return [[FAckUserWrite alloc] initWithPath:[self.path popFront] affectedTree:self.affectedTree revert:self.revert]; + NSAssert([self.path.getFront isEqualToString:childKey], + @"operationForChild called for unrelated child."); + return [[FAckUserWrite alloc] initWithPath:[self.path popFront] + affectedTree:self.affectedTree + revert:self.revert]; } else if (self.affectedTree.value != nil) { - NSAssert(self.affectedTree.children.isEmpty, @"affectedTree should not have overlapping affected paths."); + NSAssert(self.affectedTree.children.isEmpty, + @"affectedTree should not have overlapping affected paths."); // All child locations are affected as well; just return same operation. return self; } else { - FImmutableTree *childTree = [self.affectedTree subtreeAtPath:[[FPath alloc] initWith:childKey]]; - return [[FAckUserWrite alloc] initWithPath:[FPath empty] affectedTree:childTree revert:self.revert]; + FImmutableTree *childTree = + [self.affectedTree subtreeAtPath:[[FPath alloc] initWith:childKey]]; + return [[FAckUserWrite alloc] initWithPath:[FPath empty] + affectedTree:childTree + revert:self.revert]; } } -- (NSString *) description { - return [NSString stringWithFormat:@"FAckUserWrite { path=%@, revert=%d, affectedTree=%@ }", self.path, self.revert, self.affectedTree]; +- (NSString *)description { + return + [NSString stringWithFormat: + @"FAckUserWrite { path=%@, revert=%d, affectedTree=%@ }", + self.path, self.revert, self.affectedTree]; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FMerge.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FMerge.h index 4cab613..56fbec9 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FMerge.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FMerge.h @@ -20,11 +20,13 @@ @interface FMerge : NSObject -- (id) initWithSource:(FOperationSource *)aSource path:(FPath *)aPath children:(FCompoundWrite *)children; +- (id)initWithSource:(FOperationSource *)aSource + path:(FPath *)aPath + children:(FCompoundWrite *)children; -@property (nonatomic, strong, readonly) FOperationSource *source; -@property (nonatomic, readonly) FOperationType type; -@property (nonatomic, strong, readonly) FPath *path; -@property (nonatomic, strong, readonly) FCompoundWrite *children; +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, readonly) FOperationType type; +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) FCompoundWrite *children; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FMerge.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FMerge.m index 8e6d924..c344755 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FMerge.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FMerge.m @@ -15,17 +15,17 @@ */ #import "FMerge.h" -#import "FOperationSource.h" -#import "FPath.h" +#import "FCompoundWrite.h" #import "FNode.h" +#import "FOperationSource.h" #import "FOverwrite.h" -#import "FCompoundWrite.h" +#import "FPath.h" @interface FMerge () -@property (nonatomic, strong, readwrite) FOperationSource *source; -@property (nonatomic, readwrite) FOperationType type; -@property (nonatomic, strong, readwrite) FPath *path; -@property (nonatomic, strong) FCompoundWrite *children; +@property(nonatomic, strong, readwrite) FOperationSource *source; +@property(nonatomic, readwrite) FOperationType type; +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, strong) FCompoundWrite *children; @end @implementation FMerge @@ -35,7 +35,9 @@ @implementation FMerge @synthesize path; @synthesize children; -- (id) initWithSource:(FOperationSource *)aSource path:(FPath *)aPath children:(FCompoundWrite *)someChildren { +- (id)initWithSource:(FOperationSource *)aSource + path:(FPath *)aPath + children:(FCompoundWrite *)someChildren { self = [super init]; if (self) { self.source = aSource; @@ -46,26 +48,38 @@ - (id) initWithSource:(FOperationSource *)aSource path:(FPath *)aPath children:( return self; } -- (id) operationForChild:(NSString *)childKey { +- (id)operationForChild:(NSString *)childKey { if ([self.path isEmpty]) { - FCompoundWrite *childTree = [self.children childCompoundWriteAtPath:[[FPath alloc] initWith:childKey]]; + FCompoundWrite *childTree = [self.children + childCompoundWriteAtPath:[[FPath alloc] initWith:childKey]]; if (childTree.isEmpty) { return nil; } else if (childTree.rootWrite != nil) { - // We have a snapshot for the child in question. This becomes an overwrite of the child. - return [[FOverwrite alloc] initWithSource:self.source path:[FPath empty] snap:childTree.rootWrite]; + // We have a snapshot for the child in question. This becomes an + // overwrite of the child. + return [[FOverwrite alloc] initWithSource:self.source + path:[FPath empty] + snap:childTree.rootWrite]; } else { // This is a merge at a deeper level - return [[FMerge alloc] initWithSource:self.source path:[FPath empty] children:childTree]; + return [[FMerge alloc] initWithSource:self.source + path:[FPath empty] + children:childTree]; } } else { - NSAssert([self.path.getFront isEqualToString:childKey], @"Can't get a merge for a child not on the path of the operation"); - return [[FMerge alloc] initWithSource:self.source path:[self.path popFront] children:self.children]; + NSAssert( + [self.path.getFront isEqualToString:childKey], + @"Can't get a merge for a child not on the path of the operation"); + return [[FMerge alloc] initWithSource:self.source + path:[self.path popFront] + children:self.children]; } } -- (NSString *) description { - return [NSString stringWithFormat:@"FMerge { path=%@, soruce=%@ children=%@}", self.path, self.source, self.children]; +- (NSString *)description { + return + [NSString stringWithFormat:@"FMerge { path=%@, soruce=%@ children=%@}", + self.path, self.source, self.children]; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOperation.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOperation.h index 2bbbbd2..41f6054 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOperation.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOperation.h @@ -27,8 +27,8 @@ typedef NS_ENUM(NSInteger, FOperationType) { }; @protocol FOperation -@property (nonatomic, strong, readonly) FOperationSource *source; -@property (nonatomic, readonly) FOperationType type; -@property (nonatomic, strong, readonly) FPath *path; -- (id) operationForChild:(NSString *)childKey; +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, readonly) FOperationType type; +@property(nonatomic, strong, readonly) FPath *path; +- (id)operationForChild:(NSString *)childKey; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOperationSource.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOperationSource.h index a069c2f..747487b 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOperationSource.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOperationSource.h @@ -20,15 +20,18 @@ @interface FOperationSource : NSObject -@property (nonatomic, readonly) BOOL fromUser; -@property (nonatomic, readonly) BOOL fromServer; -@property (nonatomic, readonly) BOOL isTagged; -@property (nonatomic, strong, readonly) FQueryParams *queryParams; +@property(nonatomic, readonly) BOOL fromUser; +@property(nonatomic, readonly) BOOL fromServer; +@property(nonatomic, readonly) BOOL isTagged; +@property(nonatomic, strong, readonly) FQueryParams *queryParams; -- initWithFromUser:(BOOL)isFromUser fromServer:(BOOL)isFromServer queryParams:(FQueryParams *)params tagged:(BOOL)isTagged; +- initWithFromUser:(BOOL)isFromUser + fromServer:(BOOL)isFromServer + queryParams:(FQueryParams *)params + tagged:(BOOL)isTagged; -+ (FOperationSource *) userInstance; -+ (FOperationSource *) serverInstance; -+ (FOperationSource *) forServerTaggedQuery:(FQueryParams *)params; ++ (FOperationSource *)userInstance; ++ (FOperationSource *)serverInstance; ++ (FOperationSource *)forServerTaggedQuery:(FQueryParams *)params; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOperationSource.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOperationSource.m index 9a34a2e..92e3db8 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOperationSource.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOperationSource.m @@ -19,10 +19,10 @@ #import "FQueryParams.h" @interface FOperationSource () -@property (nonatomic, readwrite) BOOL fromUser; -@property (nonatomic, readwrite) BOOL fromServer; -@property (nonatomic, readwrite) BOOL isTagged; -@property (nonatomic, strong, readwrite) FQueryParams *queryParams; +@property(nonatomic, readwrite) BOOL fromUser; +@property(nonatomic, readwrite) BOOL fromServer; +@property(nonatomic, readwrite) BOOL isTagged; +@property(nonatomic, strong, readwrite) FQueryParams *queryParams; @end @implementation FOperationSource @@ -31,7 +31,10 @@ @implementation FOperationSource @synthesize fromServer; @synthesize queryParams; -- (id) initWithFromUser:(BOOL)isFromUser fromServer:(BOOL)isFromServer queryParams:(FQueryParams *)params tagged:(BOOL)tagged { +- (id)initWithFromUser:(BOOL)isFromUser + fromServer:(BOOL)isFromServer + queryParams:(FQueryParams *)params + tagged:(BOOL)tagged { self = [super init]; if (self) { self.fromUser = isFromUser; @@ -42,32 +45,42 @@ - (id) initWithFromUser:(BOOL)isFromUser fromServer:(BOOL)isFromServer queryPara return self; } -+ (FOperationSource *) userInstance { ++ (FOperationSource *)userInstance { static FOperationSource *user = nil; static dispatch_once_t userToken; dispatch_once(&userToken, ^{ - user = [[FOperationSource alloc] initWithFromUser:YES fromServer:NO queryParams:nil tagged:NO]; + user = [[FOperationSource alloc] initWithFromUser:YES + fromServer:NO + queryParams:nil + tagged:NO]; }); return user; } -+ (FOperationSource *) serverInstance { ++ (FOperationSource *)serverInstance { static FOperationSource *server = nil; static dispatch_once_t serverToken; dispatch_once(&serverToken, ^{ - server = [[FOperationSource alloc] initWithFromUser:NO fromServer:YES queryParams:nil tagged:NO]; + server = [[FOperationSource alloc] initWithFromUser:NO + fromServer:YES + queryParams:nil + tagged:NO]; }); return server; } -+ (FOperationSource *) forServerTaggedQuery:(FQueryParams *)params { - return [[FOperationSource alloc] initWithFromUser:NO fromServer:YES queryParams:params tagged:YES]; ++ (FOperationSource *)forServerTaggedQuery:(FQueryParams *)params { + return [[FOperationSource alloc] initWithFromUser:NO + fromServer:YES + queryParams:params + tagged:YES]; } -- (NSString *) description { - return [NSString stringWithFormat:@"FOperationSource { fromUser=%d, fromServer=%d, queryId=%@, tagged=%d }", - self.fromUser, self.fromServer, self.queryParams, self.isTagged]; +- (NSString *)description { + return [NSString stringWithFormat:@"FOperationSource { fromUser=%d, " + @"fromServer=%d, queryId=%@, tagged=%d }", + self.fromUser, self.fromServer, + self.queryParams, self.isTagged]; } - @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOverwrite.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOverwrite.h index e950bed..7d738ac 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOverwrite.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOverwrite.h @@ -20,11 +20,13 @@ @interface FOverwrite : NSObject -- (id) initWithSource:(FOperationSource *)aSource path:(FPath *)aPath snap:(id)aSnap; +- (id)initWithSource:(FOperationSource *)aSource + path:(FPath *)aPath + snap:(id)aSnap; -@property (nonatomic, strong, readonly) FOperationSource *source; -@property (nonatomic, readonly) FOperationType type; -@property (nonatomic, strong, readonly) FPath *path; -@property (nonatomic, strong, readonly) id snap; +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, readonly) FOperationType type; +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) id snap; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOverwrite.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOverwrite.m index b72d31a..ad4daec 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOverwrite.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Operation/FOverwrite.m @@ -19,10 +19,10 @@ #import "FOperationSource.h" @interface FOverwrite () -@property (nonatomic, strong, readwrite) FOperationSource *source; -@property (nonatomic, readwrite) FOperationType type; -@property (nonatomic, strong, readwrite) FPath *path; -@property (nonatomic, strong) id snap; +@property(nonatomic, strong, readwrite) FOperationSource *source; +@property(nonatomic, readwrite) FOperationType type; +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, strong) id snap; @end @implementation FOverwrite @@ -32,7 +32,9 @@ @implementation FOverwrite @synthesize path; @synthesize snap; -- (id) initWithSource:(FOperationSource *)aSource path:(FPath *)aPath snap:(id )aSnap { +- (id)initWithSource:(FOperationSource *)aSource + path:(FPath *)aPath + snap:(id)aSnap { self = [super init]; if (self) { self.source = aSource; @@ -43,11 +45,12 @@ - (id) initWithSource:(FOperationSource *)aSource path:(FPath *)aPath snap:(id < return self; } -- (FOverwrite *) operationForChild:(NSString *)childKey { +- (FOverwrite *)operationForChild:(NSString *)childKey { if ([self.path isEmpty]) { - return [[FOverwrite alloc] initWithSource:self.source - path:[FPath empty] - snap:[self.snap getImmediateChild:childKey]]; + return [[FOverwrite alloc] + initWithSource:self.source + path:[FPath empty] + snap:[self.snap getImmediateChild:childKey]]; } else { return [[FOverwrite alloc] initWithSource:self.source path:[self.path popFront] @@ -55,8 +58,10 @@ - (FOverwrite *) operationForChild:(NSString *)childKey { } } -- (NSString *) description { - return [NSString stringWithFormat:@"FOverwrite { path=%@, source=%@, snapshot=%@ }", self.path, self.source, self.snap]; +- (NSString *)description { + return [NSString + stringWithFormat:@"FOverwrite { path=%@, source=%@, snapshot=%@ }", + self.path, self.source, self.snap]; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FIRRetryHelper.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FIRRetryHelper.h index f83aad9..a63d0d8 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FIRRetryHelper.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FIRRetryHelper.h @@ -18,16 +18,16 @@ @interface FIRRetryHelper : NSObject -- (instancetype) initWithDispatchQueue:(dispatch_queue_t)dispatchQueue - minRetryDelayAfterFailure:(NSTimeInterval)minRetryDelayAfterFailure - maxRetryDelay:(NSTimeInterval)maxRetryDelay - retryExponent:(double)retryExponent - jitterFactor:(double)jitterFactor; +- (instancetype)initWithDispatchQueue:(dispatch_queue_t)dispatchQueue + minRetryDelayAfterFailure:(NSTimeInterval)minRetryDelayAfterFailure + maxRetryDelay:(NSTimeInterval)maxRetryDelay + retryExponent:(double)retryExponent + jitterFactor:(double)jitterFactor; -- (void) retry:(void (^)(void))block; +- (void)retry:(void (^)(void))block; -- (void) cancel; +- (void)cancel; -- (void) signalSuccess; +- (void)signalSuccess; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FIRRetryHelper.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FIRRetryHelper.m index fca02f5..ef24d12 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FIRRetryHelper.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FIRRetryHelper.m @@ -14,19 +14,19 @@ * limitations under the License. */ -#import #import "FIRRetryHelper.h" #import "FUtilities.h" +#import @interface FIRRetryHelperTask : NSObject -@property (nonatomic, strong) void (^block)(void); +@property(nonatomic, strong) void (^block)(void); @end @implementation FIRRetryHelperTask -- (instancetype) initWithBlock:(void (^)(void))block { +- (instancetype)initWithBlock:(void (^)(void))block { self = [super init]; if (self != nil) { self->_block = [block copy]; @@ -34,15 +34,15 @@ - (instancetype) initWithBlock:(void (^)(void))block { return self; } -- (BOOL) isCanceled { +- (BOOL)isCanceled { return self.block == nil; } -- (void) cancel { +- (void)cancel { self.block = nil; } -- (void) execute { +- (void)execute { if (self.block) { self.block(); } @@ -50,30 +50,28 @@ - (void) execute { @end - - @interface FIRRetryHelper () -@property (nonatomic, strong) dispatch_queue_t dispatchQueue; -@property (nonatomic) NSTimeInterval minRetryDelayAfterFailure; -@property (nonatomic) NSTimeInterval maxRetryDelay; -@property (nonatomic) double retryExponent; -@property (nonatomic) double jitterFactor; +@property(nonatomic, strong) dispatch_queue_t dispatchQueue; +@property(nonatomic) NSTimeInterval minRetryDelayAfterFailure; +@property(nonatomic) NSTimeInterval maxRetryDelay; +@property(nonatomic) double retryExponent; +@property(nonatomic) double jitterFactor; -@property (nonatomic) BOOL lastWasSuccess; -@property (nonatomic) NSTimeInterval currentRetryDelay; +@property(nonatomic) BOOL lastWasSuccess; +@property(nonatomic) NSTimeInterval currentRetryDelay; -@property (nonatomic, strong) FIRRetryHelperTask *scheduledRetry; +@property(nonatomic, strong) FIRRetryHelperTask *scheduledRetry; @end @implementation FIRRetryHelper -- (instancetype) initWithDispatchQueue:(dispatch_queue_t)dispatchQueue - minRetryDelayAfterFailure:(NSTimeInterval)minRetryDelayAfterFailure - maxRetryDelay:(NSTimeInterval)maxRetryDelay - retryExponent:(double)retryExponent - jitterFactor:(double)jitterFactor { +- (instancetype)initWithDispatchQueue:(dispatch_queue_t)dispatchQueue + minRetryDelayAfterFailure:(NSTimeInterval)minRetryDelayAfterFailure + maxRetryDelay:(NSTimeInterval)maxRetryDelay + retryExponent:(double)retryExponent + jitterFactor:(double)jitterFactor { self = [super init]; if (self != nil) { self->_dispatchQueue = dispatchQueue; @@ -86,7 +84,7 @@ - (instancetype) initWithDispatchQueue:(dispatch_queue_t)dispatchQueue return self; } -- (void) retry:(void (^)(void))block { +- (void)retry:(void (^)(void))block { if (self.scheduledRetry != nil) { FFLog(@"I-RDB054001", @"Canceling existing retry attempt"); [self.scheduledRetry cancel]; @@ -100,33 +98,35 @@ - (void) retry:(void (^)(void))block { if (self.currentRetryDelay == 0) { self.currentRetryDelay = self.minRetryDelayAfterFailure; } else { - NSTimeInterval newDelay = (self.currentRetryDelay * self.retryExponent); + NSTimeInterval newDelay = + (self.currentRetryDelay * self.retryExponent); self.currentRetryDelay = MIN(newDelay, self.maxRetryDelay); } delay = ((1 - self.jitterFactor) * self.currentRetryDelay) + - (self.jitterFactor * self.currentRetryDelay * [FUtilities randomDouble]); + (self.jitterFactor * self.currentRetryDelay * + [FUtilities randomDouble]); FFLog(@"I-RDB054002", @"Scheduling retry in %fs", delay); - } self.lastWasSuccess = NO; FIRRetryHelperTask *task = [[FIRRetryHelperTask alloc] initWithBlock:block]; self.scheduledRetry = task; - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (long long)(delay * NSEC_PER_SEC)); + dispatch_time_t popTime = + dispatch_time(DISPATCH_TIME_NOW, (long long)(delay * NSEC_PER_SEC)); dispatch_after(popTime, self.dispatchQueue, ^{ - if (![task isCanceled]) { - self.scheduledRetry = nil; - [task execute]; - } + if (![task isCanceled]) { + self.scheduledRetry = nil; + [task execute]; + } }); } -- (void) signalSuccess { +- (void)signalSuccess { self.lastWasSuccess = YES; self.currentRetryDelay = 0; } -- (void) cancel { +- (void)cancel { if (self.scheduledRetry != nil) { FFLog(@"I-RDB054003", @"Canceling existing retry attempt"); [self.scheduledRetry cancel]; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FImmutableTree.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FImmutableTree.h index 005a9f2..e6d4961 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FImmutableTree.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FImmutableTree.h @@ -20,32 +20,40 @@ @interface FImmutableTree : NSObject -- (id) initWithValue:(id)aValue; -- (id) initWithValue:(id)aValue children:(FImmutableSortedDictionary *)childrenMap; +- (id)initWithValue:(id)aValue; +- (id)initWithValue:(id)aValue + children:(FImmutableSortedDictionary *)childrenMap; -+ (FImmutableTree *) empty; -- (BOOL) isEmpty; ++ (FImmutableTree *)empty; +- (BOOL)isEmpty; -- (FTuplePathValue *) findRootMostMatchingPath:(FPath *)relativePath predicate:(BOOL (^)(id))predicate; -- (FTuplePathValue *) findRootMostValueAndPath:(FPath *)relativePath; -- (FImmutableTree *) subtreeAtPath:(FPath *)relativePath; -- (FImmutableTree *) setValue:(id)newValue atPath:(FPath *)relativePath; -- (FImmutableTree *) removeValueAtPath:(FPath *)relativePath; -- (id) valueAtPath:(FPath *)relativePath; -- (id) rootMostValueOnPath:(FPath *)path; -- (id) rootMostValueOnPath:(FPath *)path matching:(BOOL (^)(id))predicate; -- (id) leafMostValueOnPath:(FPath *)path; -- (id) leafMostValueOnPath:(FPath *)relativePath matching:(BOOL (^)(id))predicate; -- (BOOL) containsValueMatching:(BOOL (^)(id))predicate; -- (FImmutableTree *) setTree:(FImmutableTree *)newTree atPath:(FPath *)relativePath; -- (id) foldWithBlock:(id (^)(FPath *path, id value, NSDictionary *foldedChildren))block; -- (id) findOnPath:(FPath *)path andApplyBlock:(id (^)(FPath *path, id value))block; -- (FPath *) forEachOnPath:(FPath *)path whileBlock:(BOOL (^)(FPath *path, id value))block; -- (FImmutableTree *) forEachOnPath:(FPath *)path performBlock:(void (^)(FPath *path, id value))block; -- (void) forEach:(void (^)(FPath *path, id value))block; -- (void) forEachChild:(void (^)(NSString *childKey, id childValue))block; +- (FTuplePathValue *)findRootMostMatchingPath:(FPath *)relativePath + predicate:(BOOL (^)(id))predicate; +- (FTuplePathValue *)findRootMostValueAndPath:(FPath *)relativePath; +- (FImmutableTree *)subtreeAtPath:(FPath *)relativePath; +- (FImmutableTree *)setValue:(id)newValue atPath:(FPath *)relativePath; +- (FImmutableTree *)removeValueAtPath:(FPath *)relativePath; +- (id)valueAtPath:(FPath *)relativePath; +- (id)rootMostValueOnPath:(FPath *)path; +- (id)rootMostValueOnPath:(FPath *)path matching:(BOOL (^)(id))predicate; +- (id)leafMostValueOnPath:(FPath *)path; +- (id)leafMostValueOnPath:(FPath *)relativePath + matching:(BOOL (^)(id))predicate; +- (BOOL)containsValueMatching:(BOOL (^)(id))predicate; +- (FImmutableTree *)setTree:(FImmutableTree *)newTree + atPath:(FPath *)relativePath; +- (id)foldWithBlock:(id (^)(FPath *path, id value, + NSDictionary *foldedChildren))block; +- (id)findOnPath:(FPath *)path + andApplyBlock:(id (^)(FPath *path, id value))block; +- (FPath *)forEachOnPath:(FPath *)path + whileBlock:(BOOL (^)(FPath *path, id value))block; +- (FImmutableTree *)forEachOnPath:(FPath *)path + performBlock:(void (^)(FPath *path, id value))block; +- (void)forEach:(void (^)(FPath *path, id value))block; +- (void)forEachChild:(void (^)(NSString *childKey, id childValue))block; -@property (nonatomic, strong, readonly) id value; -@property (nonatomic, strong, readonly) FImmutableSortedDictionary *children; +@property(nonatomic, strong, readonly) id value; +@property(nonatomic, strong, readonly) FImmutableSortedDictionary *children; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FImmutableTree.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FImmutableTree.m index 57bf74d..34e62ae 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FImmutableTree.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FImmutableTree.m @@ -20,18 +20,18 @@ #import "FUtilities.h" @interface FImmutableTree () -@property (nonatomic, strong, readwrite) id value; +@property(nonatomic, strong, readwrite) id value; /** -* Maps NSString -> FImmutableTree, where is type of value. -*/ -@property (nonatomic, strong, readwrite) FImmutableSortedDictionary *children; + * Maps NSString -> FImmutableTree, where is type of value. + */ +@property(nonatomic, strong, readwrite) FImmutableSortedDictionary *children; @end @implementation FImmutableTree @synthesize value; @synthesize children; -- (id) initWithValue:(id)aValue { +- (id)initWithValue:(id)aValue { self = [super init]; if (self) { self.value = aValue; @@ -40,7 +40,8 @@ - (id) initWithValue:(id)aValue { return self; } -- (id) initWithValue:(id)aValue children:(FImmutableSortedDictionary *)childrenMap { +- (id)initWithValue:(id)aValue + children:(FImmutableSortedDictionary *)childrenMap { self = [super init]; if (self) { self.value = aValue; @@ -49,35 +50,40 @@ - (id) initWithValue:(id)aValue children:(FImmutableSortedDictionary *)childrenM return self; } -+ (FImmutableSortedDictionary *) emptyChildren { ++ (FImmutableSortedDictionary *)emptyChildren { static dispatch_once_t emptyChildrenToken; static FImmutableSortedDictionary *emptyChildren; dispatch_once(&emptyChildrenToken, ^{ - emptyChildren = [FImmutableSortedDictionary dictionaryWithComparator:[FUtilities stringComparator]]; + emptyChildren = [FImmutableSortedDictionary + dictionaryWithComparator:[FUtilities stringComparator]]; }); return emptyChildren; } -+ (FImmutableTree *) empty { ++ (FImmutableTree *)empty { static dispatch_once_t emptyImmutableTreeToken; static FImmutableTree *emptyTree = nil; dispatch_once(&emptyImmutableTreeToken, ^{ - emptyTree = [[FImmutableTree alloc] initWithValue:nil]; + emptyTree = [[FImmutableTree alloc] initWithValue:nil]; }); return emptyTree; } -- (BOOL) isEmpty { +- (BOOL)isEmpty { return self.value == nil && [self.children isEmpty]; } /** -* Given a path and a predicate, return the first node and the path to that node where the predicate returns true -* // TODO Do a perf test. If we're creating a bunch of FTuplePathValue objects on the way back out, it may be better to pass down a pathSoFar FPath -*/ -- (FTuplePathValue *) findRootMostMatchingPath:(FPath *)relativePath predicate:(BOOL (^)(id value))predicate { + * Given a path and a predicate, return the first node and the path to that node + * where the predicate returns true + * // TODO Do a perf test. If we're creating a bunch of FTuplePathValue objects + * on the way back out, it may be better to pass down a pathSoFar FPath + */ +- (FTuplePathValue *)findRootMostMatchingPath:(FPath *)relativePath + predicate:(BOOL (^)(id value))predicate { if (self.value != nil && predicate(self.value)) { - return [[FTuplePathValue alloc] initWithPath:[FPath empty] value:self.value]; + return [[FTuplePathValue alloc] initWithPath:[FPath empty] + value:self.value]; } else { if ([relativePath isEmpty]) { return nil; @@ -85,10 +91,15 @@ - (FTuplePathValue *) findRootMostMatchingPath:(FPath *)relativePath predicate:( NSString *front = [relativePath getFront]; FImmutableTree *child = [self.children get:front]; if (child != nil) { - FTuplePathValue *childExistingPathAndValue = [child findRootMostMatchingPath:[relativePath popFront] predicate:predicate]; + FTuplePathValue *childExistingPathAndValue = + [child findRootMostMatchingPath:[relativePath popFront] + predicate:predicate]; if (childExistingPathAndValue != nil) { - FPath *fullPath = [[[FPath alloc] initWith:front] child:childExistingPathAndValue.path]; - return [[FTuplePathValue alloc] initWithPath:fullPath value:childExistingPathAndValue.value]; + FPath *fullPath = [[[FPath alloc] initWith:front] + child:childExistingPathAndValue.path]; + return [[FTuplePathValue alloc] + initWithPath:fullPath + value:childExistingPathAndValue.value]; } else { return nil; } @@ -101,67 +112,76 @@ - (FTuplePathValue *) findRootMostMatchingPath:(FPath *)relativePath predicate:( } /** -* Find, if it exists, the shortest subpath of the given path that points a defined value in the tree -*/ -- (FTuplePathValue *) findRootMostValueAndPath:(FPath *)relativePath { - return [self findRootMostMatchingPath:relativePath predicate:^BOOL(__unsafe_unretained id value){ - return YES; - }]; + * Find, if it exists, the shortest subpath of the given path that points a + * defined value in the tree + */ +- (FTuplePathValue *)findRootMostValueAndPath:(FPath *)relativePath { + return [self findRootMostMatchingPath:relativePath + predicate:^BOOL(__unsafe_unretained id value) { + return YES; + }]; } -- (id) rootMostValueOnPath:(FPath *)path { - return [self rootMostValueOnPath:path matching:^BOOL(id value) { - return YES; - }]; +- (id)rootMostValueOnPath:(FPath *)path { + return [self rootMostValueOnPath:path + matching:^BOOL(id value) { + return YES; + }]; } -- (id) rootMostValueOnPath:(FPath *)path matching:(BOOL (^)(id))predicate { +- (id)rootMostValueOnPath:(FPath *)path matching:(BOOL (^)(id))predicate { if (self.value != nil && predicate(self.value)) { return self.value; } else if (path.isEmpty) { return nil; } else { - return [[self.children get:path.getFront] rootMostValueOnPath:[path popFront] matching:predicate]; + return [[self.children get:path.getFront] + rootMostValueOnPath:[path popFront] + matching:predicate]; } } -- (id) leafMostValueOnPath:(FPath *)path { - return [self leafMostValueOnPath:path matching:^BOOL(id value) { - return YES; - }]; +- (id)leafMostValueOnPath:(FPath *)path { + return [self leafMostValueOnPath:path + matching:^BOOL(id value) { + return YES; + }]; } -- (id) leafMostValueOnPath:(FPath *)relativePath matching:(BOOL (^)(id))predicate { +- (id)leafMostValueOnPath:(FPath *)relativePath + matching:(BOOL (^)(id))predicate { __block id currentValue = self.value; __block FImmutableTree *currentTree = self; [relativePath enumerateComponentsUsingBlock:^(NSString *key, BOOL *stop) { - currentTree = [currentTree.children get:key]; - if (currentTree == nil) { - *stop = YES; - } else { - id treeValue = currentTree.value; - if (treeValue != nil && predicate(treeValue)) { - currentValue = treeValue; - } - } + currentTree = [currentTree.children get:key]; + if (currentTree == nil) { + *stop = YES; + } else { + id treeValue = currentTree.value; + if (treeValue != nil && predicate(treeValue)) { + currentValue = treeValue; + } + } }]; return currentValue; } -- (BOOL) containsValueMatching:(BOOL (^)(id))predicate { +- (BOOL)containsValueMatching:(BOOL (^)(id))predicate { if (self.value != nil && predicate(self.value)) { return YES; } else { __block BOOL found = NO; - [self.children enumerateKeysAndObjectsUsingBlock:^(NSString *key, FImmutableTree *subtree, BOOL *stop) { - found = [subtree containsValueMatching:predicate]; - if (found) *stop = YES; + [self.children enumerateKeysAndObjectsUsingBlock:^( + NSString *key, FImmutableTree *subtree, BOOL *stop) { + found = [subtree containsValueMatching:predicate]; + if (found) + *stop = YES; }]; return found; } } -- (FImmutableTree *) subtreeAtPath:(FPath *)relativePath { +- (FImmutableTree *)subtreeAtPath:(FPath *)relativePath { if ([relativePath isEmpty]) { return self; } else { @@ -176,48 +196,56 @@ - (FImmutableTree *) subtreeAtPath:(FPath *)relativePath { } /** -* Sets a value at the specified path -*/ -- (FImmutableTree *) setValue:(id)newValue atPath:(FPath *)relativePath { + * Sets a value at the specified path + */ +- (FImmutableTree *)setValue:(id)newValue atPath:(FPath *)relativePath { if ([relativePath isEmpty]) { - return [[FImmutableTree alloc] initWithValue:newValue children:self.children]; + return [[FImmutableTree alloc] initWithValue:newValue + children:self.children]; } else { NSString *front = [relativePath getFront]; FImmutableTree *child = [self.children get:front]; if (child == nil) { child = [FImmutableTree empty]; } - FImmutableTree *newChild = [child setValue:newValue atPath:[relativePath popFront]]; - FImmutableSortedDictionary *newChildren = [self.children insertKey:front withValue:newChild]; - return [[FImmutableTree alloc] initWithValue:self.value children:newChildren]; + FImmutableTree *newChild = [child setValue:newValue + atPath:[relativePath popFront]]; + FImmutableSortedDictionary *newChildren = + [self.children insertKey:front withValue:newChild]; + return [[FImmutableTree alloc] initWithValue:self.value + children:newChildren]; } } /** -* Remove the value at the specified path -*/ -- (FImmutableTree *) removeValueAtPath:(FPath *)relativePath { + * Remove the value at the specified path + */ +- (FImmutableTree *)removeValueAtPath:(FPath *)relativePath { if ([relativePath isEmpty]) { if ([self.children isEmpty]) { return [FImmutableTree empty]; } else { - return [[FImmutableTree alloc] initWithValue:nil children:self.children]; + return [[FImmutableTree alloc] initWithValue:nil + children:self.children]; } } else { NSString *front = [relativePath getFront]; FImmutableTree *child = [self.children get:front]; if (child) { - FImmutableTree *newChild = [child removeValueAtPath:[relativePath popFront]]; + FImmutableTree *newChild = + [child removeValueAtPath:[relativePath popFront]]; FImmutableSortedDictionary *newChildren; if ([newChild isEmpty]) { newChildren = [self.children removeKey:front]; } else { - newChildren = [self.children insertKey:front withValue:newChild]; + newChildren = [self.children insertKey:front + withValue:newChild]; } if (self.value == nil && [newChildren isEmpty]) { return [FImmutableTree empty]; } else { - return [[FImmutableTree alloc] initWithValue:self.value children:newChildren]; + return [[FImmutableTree alloc] initWithValue:self.value + children:newChildren]; } } else { return self; @@ -226,9 +254,9 @@ - (FImmutableTree *) removeValueAtPath:(FPath *)relativePath { } /** -* Gets a value from the tree -*/ -- (id) valueAtPath:(FPath *)relativePath { + * Gets a value from the tree + */ +- (id)valueAtPath:(FPath *)relativePath { if ([relativePath isEmpty]) { return self.value; } else { @@ -243,9 +271,10 @@ - (id) valueAtPath:(FPath *)relativePath { } /** -* Replaces the subtree at the specified path with the given new tree -*/ -- (FImmutableTree *) setTree:(FImmutableTree *)newTree atPath:(FPath *)relativePath { + * Replaces the subtree at the specified path with the given new tree + */ +- (FImmutableTree *)setTree:(FImmutableTree *)newTree + atPath:(FPath *)relativePath { if ([relativePath isEmpty]) { return newTree; } else { @@ -254,44 +283,58 @@ - (FImmutableTree *) setTree:(FImmutableTree *)newTree atPath:(FPath *)relativeP if (child == nil) { child = [FImmutableTree empty]; } - FImmutableTree *newChild = [child setTree:newTree atPath:[relativePath popFront]]; + FImmutableTree *newChild = [child setTree:newTree + atPath:[relativePath popFront]]; FImmutableSortedDictionary *newChildren; if ([newChild isEmpty]) { newChildren = [self.children removeKey:front]; } else { newChildren = [self.children insertKey:front withValue:newChild]; } - return [[FImmutableTree alloc] initWithValue:self.value children:newChildren]; + return [[FImmutableTree alloc] initWithValue:self.value + children:newChildren]; } } /** -* Performs a depth first fold on this tree. Transforms a tree into a single value, given a function that operates on -* the path to a node, an optional current value, and a map of the child names to folded subtrees -*/ -- (id) foldWithBlock:(id (^)(FPath *path, id value, NSDictionary *foldedChildren))block { + * Performs a depth first fold on this tree. Transforms a tree into a single + * value, given a function that operates on the path to a node, an optional + * current value, and a map of the child names to folded subtrees + */ +- (id)foldWithBlock:(id (^)(FPath *path, id value, + NSDictionary *foldedChildren))block { return [self foldWithPathSoFar:[FPath empty] withBlock:block]; } /** -* Recursive helper for public facing foldWithBlock: method -*/ -- (id) foldWithPathSoFar:(FPath *)pathSoFar withBlock:(id (^)(FPath *path, id value, NSDictionary *foldedChildren))block { + * Recursive helper for public facing foldWithBlock: method + */ +- (id)foldWithPathSoFar:(FPath *)pathSoFar + withBlock:(id (^)(FPath *path, id value, + NSDictionary *foldedChildren))block { __block NSMutableDictionary *accum = [[NSMutableDictionary alloc] init]; - [self.children enumerateKeysAndObjectsUsingBlock:^(NSString *childKey, FImmutableTree *childTree, BOOL *stop) { - accum[childKey] = [childTree foldWithPathSoFar:[pathSoFar childFromString:childKey] withBlock:block]; - }]; + [self.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + accum[childKey] = + [childTree foldWithPathSoFar:[pathSoFar childFromString:childKey] + withBlock:block]; + }]; return block(pathSoFar, self.value, accum); } /** -* Find the first matching value on the given path. Return the result of applying block to it. -*/ -- (id) findOnPath:(FPath *)path andApplyBlock:(id (^)(FPath *path, id value))block { + * Find the first matching value on the given path. Return the result of + * applying block to it. + */ +- (id)findOnPath:(FPath *)path + andApplyBlock:(id (^)(FPath *path, id value))block { return [self findOnPath:path pathSoFar:[FPath empty] andApplyBlock:block]; } -- (id) findOnPath:(FPath *)pathToFollow pathSoFar:(FPath *)pathSoFar andApplyBlock:(id (^)(FPath *path, id value))block { +- (id)findOnPath:(FPath *)pathToFollow + pathSoFar:(FPath *)pathSoFar + andApplyBlock:(id (^)(FPath *path, id value))block { id result = self.value ? block(pathSoFar, self.value) : nil; if (result != nil) { return result; @@ -302,7 +345,9 @@ - (id) findOnPath:(FPath *)pathToFollow pathSoFar:(FPath *)pathSoFar andApplyBlo NSString *front = [pathToFollow getFront]; FImmutableTree *nextChild = [self.children get:front]; if (nextChild != nil) { - return [nextChild findOnPath:[pathToFollow popFront] pathSoFar:[pathSoFar childFromString:front] andApplyBlock:block]; + return [nextChild findOnPath:[pathToFollow popFront] + pathSoFar:[pathSoFar childFromString:front] + andApplyBlock:block]; } else { return nil; } @@ -310,14 +355,17 @@ - (id) findOnPath:(FPath *)pathToFollow pathSoFar:(FPath *)pathSoFar andApplyBlo } } /** -* Call the block on each value along the path for as long as that function returns true -* @return The path to the deepest location inspected -*/ -- (FPath *) forEachOnPath:(FPath *)path whileBlock:(BOOL (^)(FPath *, id))block { + * Call the block on each value along the path for as long as that function + * returns true + * @return The path to the deepest location inspected + */ +- (FPath *)forEachOnPath:(FPath *)path whileBlock:(BOOL (^)(FPath *, id))block { return [self forEachOnPath:path pathSoFar:[FPath empty] whileBlock:block]; } -- (FPath *) forEachOnPath:(FPath *)pathToFollow pathSoFar:(FPath *)pathSoFar whileBlock:(BOOL (^)(FPath *, id))block { +- (FPath *)forEachOnPath:(FPath *)pathToFollow + pathSoFar:(FPath *)pathSoFar + whileBlock:(BOOL (^)(FPath *, id))block { if ([pathToFollow isEmpty]) { if (self.value) { block(pathSoFar, self.value); @@ -332,7 +380,10 @@ - (FPath *) forEachOnPath:(FPath *)pathToFollow pathSoFar:(FPath *)pathSoFar whi NSString *front = [pathToFollow getFront]; FImmutableTree *nextChild = [self.children get:front]; if (nextChild) { - return [nextChild forEachOnPath:[pathToFollow popFront] pathSoFar:[pathSoFar childFromString:front] whileBlock:block]; + return + [nextChild forEachOnPath:[pathToFollow popFront] + pathSoFar:[pathSoFar childFromString:front] + whileBlock:block]; } else { return pathSoFar; } @@ -342,11 +393,14 @@ - (FPath *) forEachOnPath:(FPath *)pathToFollow pathSoFar:(FPath *)pathSoFar whi } } -- (FImmutableTree *) forEachOnPath:(FPath *)path performBlock:(void (^)(FPath *path, id value))block { +- (FImmutableTree *)forEachOnPath:(FPath *)path + performBlock:(void (^)(FPath *path, id value))block { return [self forEachOnPath:path pathSoFar:[FPath empty] performBlock:block]; } -- (FImmutableTree *) forEachOnPath:(FPath *)pathToFollow pathSoFar:(FPath *)pathSoFar performBlock:(void (^)(FPath *path, id value))block { +- (FImmutableTree *)forEachOnPath:(FPath *)pathToFollow + pathSoFar:(FPath *)pathSoFar + performBlock:(void (^)(FPath *path, id value))block { if ([pathToFollow isEmpty]) { return self; } else { @@ -356,34 +410,43 @@ - (FImmutableTree *) forEachOnPath:(FPath *)pathToFollow pathSoFar:(FPath *)path NSString *front = [pathToFollow getFront]; FImmutableTree *nextChild = [self.children get:front]; if (nextChild) { - return [nextChild forEachOnPath:[pathToFollow popFront] pathSoFar:[pathSoFar childFromString:front] performBlock:block]; + return [nextChild forEachOnPath:[pathToFollow popFront] + pathSoFar:[pathSoFar childFromString:front] + performBlock:block]; } else { return [FImmutableTree empty]; } } } /** -* Calls the given block for each node in the tree that has a value. Called in depth-first order -*/ -- (void) forEach:(void (^)(FPath *path, id value))block { + * Calls the given block for each node in the tree that has a value. Called in + * depth-first order + */ +- (void)forEach:(void (^)(FPath *path, id value))block { [self forEachPathSoFar:[FPath empty] withBlock:block]; } -- (void) forEachPathSoFar:(FPath *)pathSoFar withBlock:(void (^)(FPath *path, id value))block { - [self.children enumerateKeysAndObjectsUsingBlock:^(NSString *childKey, FImmutableTree *childTree, BOOL *stop) { - [childTree forEachPathSoFar:[pathSoFar childFromString:childKey] withBlock:block]; - }]; +- (void)forEachPathSoFar:(FPath *)pathSoFar + withBlock:(void (^)(FPath *path, id value))block { + [self.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + [childTree forEachPathSoFar:[pathSoFar childFromString:childKey] + withBlock:block]; + }]; if (self.value) { block(pathSoFar, self.value); } } -- (void) forEachChild:(void (^)(NSString *childKey, id childValue))block { - [self.children enumerateKeysAndObjectsUsingBlock:^(NSString *childKey, FImmutableTree *childTree, BOOL *stop) { - if (childTree.value) { - block(childKey, childTree.value); - } - }]; +- (void)forEachChild:(void (^)(NSString *childKey, id childValue))block { + [self.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + if (childTree.value) { + block(childKey, childTree.value); + } + }]; } - (BOOL)isEqual:(id)object { @@ -391,31 +454,33 @@ - (BOOL)isEqual:(id)object { return NO; } FImmutableTree *other = (FImmutableTree *)object; - return (self.value == other.value || [self.value isEqual:other.value]) && [self.children isEqual:other.children]; + return (self.value == other.value || [self.value isEqual:other.value]) && + [self.children isEqual:other.children]; } - (NSUInteger)hash { return self.children.hash * 31 + [self.value hash]; } -- (NSString *) description { +- (NSString *)description { NSMutableString *string = [[NSMutableString alloc] init]; [string appendString:@"FImmutableTree { value="]; [string appendString:(self.value ? [self.value description] : @"")]; [string appendString:@", children={"]; - [self.children enumerateKeysAndObjectsUsingBlock:^(NSString *childKey, FImmutableTree *childTree, BOOL *stop) { - [string appendString:@" "]; - [string appendString:childKey]; - [string appendString:@"="]; - [string appendString:[childTree.value description]]; - }]; + [self.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + [string appendString:@" "]; + [string appendString:childKey]; + [string appendString:@"="]; + [string appendString:[childTree.value description]]; + }]; [string appendString:@" } }"]; return [NSString stringWithString:string]; } -- (NSString *) debugDescription { +- (NSString *)debugDescription { return [self description]; } - @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FPath.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FPath.h index 71a7167..cfa86aa 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FPath.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FPath.h @@ -16,30 +16,31 @@ #import -@interface FPath : NSObject +@interface FPath : NSObject -+ (FPath *) relativePathFrom:(FPath *)outer to:(FPath *)inner; -+ (FPath *) empty; -+ (FPath *) pathWithString:(NSString *)string; ++ (FPath *)relativePathFrom:(FPath *)outer to:(FPath *)inner; ++ (FPath *)empty; ++ (FPath *)pathWithString:(NSString *)string; - (id)initWith:(NSString *)path; - (id)initWithPieces:(NSArray *)somePieces andPieceNum:(NSInteger)aPieceNum; - (id)copyWithZone:(NSZone *)zone; -- (void)enumerateComponentsUsingBlock:(void (^)(NSString *key, BOOL *stop))block; -- (NSString *) getFront; -- (NSUInteger) length; -- (FPath *) popFront; -- (NSString *) getBack; -- (NSString *) toString; -- (NSString *) toStringWithTrailingSlash; -- (NSString *) wireFormat; -- (FPath *) parent; -- (FPath *) child:(FPath *)childPathObj; -- (FPath *) childFromString:(NSString *)childPath; -- (BOOL) isEmpty; -- (BOOL) contains:(FPath *)other; -- (NSComparisonResult) compare:(FPath *)other; +- (void)enumerateComponentsUsingBlock:(void (^)(NSString *key, + BOOL *stop))block; +- (NSString *)getFront; +- (NSUInteger)length; +- (FPath *)popFront; +- (NSString *)getBack; +- (NSString *)toString; +- (NSString *)toStringWithTrailingSlash; +- (NSString *)wireFormat; +- (FPath *)parent; +- (FPath *)child:(FPath *)childPathObj; +- (FPath *)childFromString:(NSString *)childPath; +- (BOOL)isEmpty; +- (BOOL)contains:(FPath *)other; +- (NSComparisonResult)compare:(FPath *)other; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FPath.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FPath.m index 5215596..f655240 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FPath.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FPath.m @@ -18,10 +18,10 @@ #import "FUtilities.h" -@interface FPath() +@interface FPath () -@property (nonatomic, readwrite, assign) NSInteger pieceNum; -@property (nonatomic, strong) NSArray * pieces; +@property(nonatomic, readwrite, assign) NSInteger pieceNum; +@property(nonatomic, strong) NSArray *pieces; @end @@ -30,25 +30,29 @@ @implementation FPath #pragma mark - #pragma mark Initializers -+ (FPath *) relativePathFrom:(FPath *)outer to:(FPath *)inner { - NSString* outerFront = [outer getFront]; - NSString* innerFront = [inner getFront]; ++ (FPath *)relativePathFrom:(FPath *)outer to:(FPath *)inner { + NSString *outerFront = [outer getFront]; + NSString *innerFront = [inner getFront]; if (outerFront == nil) { return inner; } else if ([outerFront isEqualToString:innerFront]) { return [self relativePathFrom:[outer popFront] to:[inner popFront]]; } else { - @throw [[NSException alloc] initWithName:@"FirebaseDatabaseInternalError" reason:[NSString stringWithFormat:@"innerPath (%@) is not within outerPath (%@)", inner, outer] userInfo:nil]; + @throw [[NSException alloc] + initWithName:@"FirebaseDatabaseInternalError" + reason:[NSString + stringWithFormat: + @"innerPath (%@) is not within outerPath (%@)", + inner, outer] + userInfo:nil]; } } -+ (FPath *)pathWithString:(NSString *)string -{ ++ (FPath *)pathWithString:(NSString *)string { return [[FPath alloc] initWith:string]; } -- (id)initWith:(NSString *)path -{ +- (id)initWith:(NSString *)path { self = [super init]; if (self) { NSArray *pathPieces = [path componentsSeparatedByString:@"/"]; @@ -75,8 +79,7 @@ - (id)initWithPieces:(NSArray *)somePieces andPieceNum:(NSInteger)aPieceNum { return self; } -- (id)copyWithZone:(NSZone *)zone -{ +- (id)copyWithZone:(NSZone *)zone { // Immutable, so it's safe to return self return self; } @@ -88,21 +91,21 @@ - (NSString *)description { #pragma mark - #pragma mark Public methods -- (NSString *) getFront { - if(self.pieceNum >= self.pieces.count) { +- (NSString *)getFront { + if (self.pieceNum >= self.pieces.count) { return nil; } return [self.pieces objectAtIndex:self.pieceNum]; } /** -* @return The number of segments in this path -*/ -- (NSUInteger) length { + * @return The number of segments in this path + */ +- (NSUInteger)length { return self.pieces.count - self.pieceNum; } -- (FPath *) popFront { +- (FPath *)popFront { NSInteger newPieceNum = self.pieceNum; if (newPieceNum < self.pieces.count) { newPieceNum++; @@ -110,26 +113,25 @@ - (FPath *) popFront { return [[FPath alloc] initWithPieces:self.pieces andPieceNum:newPieceNum]; } -- (NSString *) getBack { - if(self.pieceNum < self.pieces.count) { +- (NSString *)getBack { + if (self.pieceNum < self.pieces.count) { return [self.pieces lastObject]; - } - else { + } else { return nil; } } -- (NSString *) toString { +- (NSString *)toString { return [self toStringWithTrailingSlash:NO]; } -- (NSString *) toStringWithTrailingSlash { +- (NSString *)toStringWithTrailingSlash { return [self toStringWithTrailingSlash:YES]; } -- (NSString *) toStringWithTrailingSlash:(BOOL)trailingSlash { - NSMutableString* pathString = [[NSMutableString alloc] init]; - for(NSInteger i = self.pieceNum; i < self.pieces.count; i++) { +- (NSString *)toStringWithTrailingSlash:(BOOL)trailingSlash { + NSMutableString *pathString = [[NSMutableString alloc] init]; + for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { [pathString appendString:@"/"]; [pathString appendString:[self.pieces objectAtIndex:i]]; } @@ -147,7 +149,7 @@ - (NSString *)wireFormat { if ([self isEmpty]) { return @"/"; } else { - NSMutableString* pathString = [[NSMutableString alloc] init]; + NSMutableString *pathString = [[NSMutableString alloc] init]; for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { if (i > self.pieceNum) { [pathString appendString:@"/"]; @@ -158,11 +160,11 @@ - (NSString *)wireFormat { } } -- (FPath *) parent { - if(self.pieceNum >= self.pieces.count) { +- (FPath *)parent { + if (self.pieceNum >= self.pieces.count) { return nil; } else { - NSMutableArray* newPieces = [[NSMutableArray alloc] init]; + NSMutableArray *newPieces = [[NSMutableArray alloc] init]; for (NSInteger i = self.pieceNum; i < self.pieces.count - 1; i++) { [newPieces addObject:[self.pieces objectAtIndex:i]]; } @@ -170,13 +172,14 @@ - (FPath *) parent { } } -- (FPath *) child:(FPath *)childPathObj { - NSMutableArray* newPieces = [[NSMutableArray alloc] init]; +- (FPath *)child:(FPath *)childPathObj { + NSMutableArray *newPieces = [[NSMutableArray alloc] init]; for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { [newPieces addObject:[self.pieces objectAtIndex:i]]; } - for (NSInteger i = childPathObj.pieceNum; i < childPathObj.pieces.count; i++) { + for (NSInteger i = childPathObj.pieceNum; i < childPathObj.pieces.count; + i++) { [newPieces addObject:[childPathObj.pieces objectAtIndex:i]]; } @@ -184,7 +187,7 @@ - (FPath *) child:(FPath *)childPathObj { } - (FPath *)childFromString:(NSString *)childPath { - NSMutableArray* newPieces = [[NSMutableArray alloc] init]; + NSMutableArray *newPieces = [[NSMutableArray alloc] init]; for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { [newPieces addObject:[self.pieces objectAtIndex:i]]; } @@ -201,25 +204,25 @@ - (FPath *)childFromString:(NSString *)childPath { } /** -* @return True if there are no segments in this path -*/ -- (BOOL) isEmpty { + * @return True if there are no segments in this path + */ +- (BOOL)isEmpty { return self.pieceNum >= self.pieces.count; } /** -* @return Singleton to represent an empty path -*/ -+ (FPath *) empty { + * @return Singleton to represent an empty path + */ ++ (FPath *)empty { static dispatch_once_t oneEmptyPath; static FPath *emptyPath; dispatch_once(&oneEmptyPath, ^{ - emptyPath = [[FPath alloc] initWith:@""]; + emptyPath = [[FPath alloc] initWith:@""]; }); return emptyPath; } -- (BOOL) contains:(FPath *)other { +- (BOOL)contains:(FPath *)other { if (self.length > other.length) { return NO; } @@ -227,8 +230,8 @@ - (BOOL) contains:(FPath *)other { NSInteger i = self.pieceNum; NSInteger j = other.pieceNum; while (i < self.pieces.count) { - NSString* thisSeg = [self.pieces objectAtIndex:i]; - NSString* otherSeg = [other.pieces objectAtIndex:j]; + NSString *thisSeg = [self.pieces objectAtIndex:i]; + NSString *otherSeg = [other.pieces objectAtIndex:j]; if (![thisSeg isEqualToString:otherSeg]) { return NO; } @@ -238,18 +241,20 @@ - (BOOL) contains:(FPath *)other { return YES; } -- (void) enumerateComponentsUsingBlock:(void (^)(NSString *, BOOL *))block { +- (void)enumerateComponentsUsingBlock:(void (^)(NSString *, BOOL *))block { BOOL stop = NO; for (NSInteger i = self.pieceNum; !stop && i < self.pieces.count; i++) { block(self.pieces[i], &stop); } } -- (NSComparisonResult) compare:(FPath *)other { +- (NSComparisonResult)compare:(FPath *)other { NSInteger myCount = self.pieces.count; NSInteger otherCount = other.pieces.count; - for (NSInteger i = self.pieceNum, j = other.pieceNum; i < myCount && j < otherCount; i++, j++) { - NSComparisonResult comparison = [FUtilities compareKey:self.pieces[i] toKey:other.pieces[j]]; + for (NSInteger i = self.pieceNum, j = other.pieceNum; + i < myCount && j < otherCount; i++, j++) { + NSComparisonResult comparison = [FUtilities compareKey:self.pieces[i] + toKey:other.pieces[j]]; if (comparison != NSOrderedSame) { return comparison; } @@ -259,16 +264,16 @@ - (NSComparisonResult) compare:(FPath *)other { } else if (other.length < self.length) { return NSOrderedDescending; } else { - NSAssert(self.length == other.length, @"Paths must be the same lengths"); + NSAssert(self.length == other.length, + @"Paths must be the same lengths"); return NSOrderedSame; } } /** -* @return YES if paths are the same -*/ -- (BOOL)isEqual:(id)other -{ + * @return YES if paths are the same + */ +- (BOOL)isEqual:(id)other { if (other == self) { return YES; } @@ -279,7 +284,8 @@ - (BOOL)isEqual:(id)other if (self.length != otherPath.length) { return NO; } - for (NSUInteger i = self.pieceNum, j = otherPath.pieceNum; i < self.pieces.count; i++, j++) { + for (NSUInteger i = self.pieceNum, j = otherPath.pieceNum; + i < self.pieces.count; i++, j++) { if (![self.pieces[i] isEqualToString:otherPath.pieces[j]]) { return NO; } @@ -287,7 +293,7 @@ - (BOOL)isEqual:(id)other return YES; } -- (NSUInteger) hash { +- (NSUInteger)hash { NSUInteger hashCode = 0; for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { hashCode = hashCode * 37 + [self.pieces[i] hash]; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTree.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTree.h index 8528526..d5c77ab 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTree.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTree.h @@ -14,35 +14,39 @@ * limitations under the License. */ -#import -#import "FTreeNode.h" #import "FPath.h" +#import "FTreeNode.h" +#import @interface FTree : NSObject - (id)init; -- (id)initWithName:(NSString*)aName withParent:(FTree *)aParent withNode:(FTreeNode *)aNode; +- (id)initWithName:(NSString *)aName + withParent:(FTree *)aParent + withNode:(FTreeNode *)aNode; -- (FTree *) subTree:(FPath*)path; +- (FTree *)subTree:(FPath *)path; - (id)getValue; - (void)setValue:(id)value; -- (void) clear; -- (BOOL) hasChildren; -- (BOOL) isEmpty; -- (void) forEachChildMutationSafe:(void (^)(FTree *))action; -- (void) forEachChild:(void (^)(FTree *))action; -- (void) forEachDescendant:(void (^)(FTree *))action; -- (void) forEachDescendant:(void (^)(FTree *))action includeSelf:(BOOL)incSelf childrenFirst:(BOOL)childFirst; -- (BOOL) forEachAncestor:(BOOL (^)(FTree *))action; -- (BOOL) forEachAncestor:(BOOL (^)(FTree *))action includeSelf:(BOOL)incSelf; -- (void) forEachImmediateDescendantWithValue:(void (^)(FTree *))action; -- (BOOL) valueExistsAtOrAbove:(FPath *)path; +- (void)clear; +- (BOOL)hasChildren; +- (BOOL)isEmpty; +- (void)forEachChildMutationSafe:(void (^)(FTree *))action; +- (void)forEachChild:(void (^)(FTree *))action; +- (void)forEachDescendant:(void (^)(FTree *))action; +- (void)forEachDescendant:(void (^)(FTree *))action + includeSelf:(BOOL)incSelf + childrenFirst:(BOOL)childFirst; +- (BOOL)forEachAncestor:(BOOL (^)(FTree *))action; +- (BOOL)forEachAncestor:(BOOL (^)(FTree *))action includeSelf:(BOOL)incSelf; +- (void)forEachImmediateDescendantWithValue:(void (^)(FTree *))action; +- (BOOL)valueExistsAtOrAbove:(FPath *)path; - (FPath *)path; -- (void) updateParents; -- (void) updateChild:(NSString*)childName withNode:(FTree *)child; +- (void)updateParents; +- (void)updateChild:(NSString *)childName withNode:(FTree *)child; -@property (nonatomic, strong) NSString* name; -@property (nonatomic, strong) FTree* parent; -@property (nonatomic, strong) FTreeNode* node; +@property(nonatomic, strong) NSString *name; +@property(nonatomic, strong) FTree *parent; +@property(nonatomic, strong) FTreeNode *node; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTree.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTree.m index 8e7a334..209b59f 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTree.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTree.m @@ -15,8 +15,8 @@ */ #import "FTree.h" -#import "FTreeNode.h" #import "FPath.h" +#import "FTreeNode.h" #import "FUtilities.h" @implementation FTree @@ -25,8 +25,7 @@ @implementation FTree @synthesize parent; @synthesize node; -- (id)init -{ +- (id)init { self = [super init]; if (self) { self.name = @""; @@ -36,9 +35,9 @@ - (id)init return self; } - -- (id)initWithName:(NSString*)aName withParent:(FTree *)aParent withNode:(FTreeNode *)aNode -{ +- (id)initWithName:(NSString *)aName + withParent:(FTree *)aParent + withNode:(FTreeNode *)aNode { self = [super init]; if (self) { self.name = aName != nil ? aName : @""; @@ -48,15 +47,17 @@ - (id)initWithName:(NSString*)aName withParent:(FTree *)aParent withNode:(FTreeN return self; } -- (FTree *) subTree:(FPath*)path { - FTree* child = self; - NSString* next = [path getFront]; - while(next != nil) { - FTreeNode* childNode = child.node.children[next]; +- (FTree *)subTree:(FPath *)path { + FTree *child = self; + NSString *next = [path getFront]; + while (next != nil) { + FTreeNode *childNode = child.node.children[next]; if (childNode == nil) { childNode = [[FTreeNode alloc] init]; } - child = [[FTree alloc] initWithName:next withParent:child withNode:childNode]; + child = [[FTree alloc] initWithName:next + withParent:child + withNode:childNode]; path = [path popFront]; next = [path getFront]; } @@ -72,59 +73,67 @@ - (void)setValue:(id)value { [self updateParents]; } -- (void) clear { +- (void)clear { self.node.value = nil; [self.node.children removeAllObjects]; self.node.childCount = 0; [self updateParents]; } -- (BOOL) hasChildren { +- (BOOL)hasChildren { return self.node.childCount > 0; } -- (BOOL) isEmpty { +- (BOOL)isEmpty { return [self getValue] == nil && ![self hasChildren]; } -- (void) forEachChild:(void (^)(FTree *))action { - for(NSString* key in self.node.children) { - action([[FTree alloc] initWithName:key withParent:self withNode:[self.node.children objectForKey:key]]); +- (void)forEachChild:(void (^)(FTree *))action { + for (NSString *key in self.node.children) { + action([[FTree alloc] + initWithName:key + withParent:self + withNode:[self.node.children objectForKey:key]]); } } -- (void) forEachChildMutationSafe:(void (^)(FTree *))action { - for(NSString* key in [self.node.children copy]) { - action([[FTree alloc] initWithName:key withParent:self withNode:[self.node.children objectForKey:key]]); +- (void)forEachChildMutationSafe:(void (^)(FTree *))action { + for (NSString *key in [self.node.children copy]) { + action([[FTree alloc] + initWithName:key + withParent:self + withNode:[self.node.children objectForKey:key]]); } } -- (void) forEachDescendant:(void (^)(FTree *))action { +- (void)forEachDescendant:(void (^)(FTree *))action { [self forEachDescendant:action includeSelf:NO childrenFirst:NO]; } -- (void) forEachDescendant:(void (^)(FTree *))action includeSelf:(BOOL)incSelf childrenFirst:(BOOL)childFirst { - if(incSelf && !childFirst) { +- (void)forEachDescendant:(void (^)(FTree *))action + includeSelf:(BOOL)incSelf + childrenFirst:(BOOL)childFirst { + if (incSelf && !childFirst) { action(self); } - [self forEachChild:^(FTree* child) { - [child forEachDescendant:action includeSelf:YES childrenFirst:childFirst]; + [self forEachChild:^(FTree *child) { + [child forEachDescendant:action includeSelf:YES childrenFirst:childFirst]; }]; - if(incSelf && childFirst) { + if (incSelf && childFirst) { action(self); } } -- (BOOL) forEachAncestor:(BOOL (^)(FTree *))action { +- (BOOL)forEachAncestor:(BOOL (^)(FTree *))action { return [self forEachAncestor:action includeSelf:NO]; } -- (BOOL) forEachAncestor:(BOOL (^)(FTree *))action includeSelf:(BOOL)incSelf { - FTree* aNode = (incSelf) ? self : self.parent; - while(aNode != nil) { - if(action(aNode)) { +- (BOOL)forEachAncestor:(BOOL (^)(FTree *))action includeSelf:(BOOL)incSelf { + FTree *aNode = (incSelf) ? self : self.parent; + while (aNode != nil) { + if (action(aNode)) { return YES; } aNode = aNode.parent; @@ -132,21 +141,20 @@ - (BOOL) forEachAncestor:(BOOL (^)(FTree *))action includeSelf:(BOOL)incSelf { return NO; } -- (void) forEachImmediateDescendantWithValue:(void (^)(FTree *))action { - [self forEachChild:^(FTree * child) { - if([child getValue] != nil) { - action(child); - } - else { - [child forEachImmediateDescendantWithValue:action]; - } +- (void)forEachImmediateDescendantWithValue:(void (^)(FTree *))action { + [self forEachChild:^(FTree *child) { + if ([child getValue] != nil) { + action(child); + } else { + [child forEachImmediateDescendantWithValue:action]; + } }]; } -- (BOOL) valueExistsAtOrAbove:(FPath *)path { - FTreeNode* aNode = self.node; - while(aNode != nil) { - if(aNode.value != nil) { +- (BOOL)valueExistsAtOrAbove:(FPath *)path { + FTreeNode *aNode = self.node; + while (aNode != nil) { + if (aNode.value != nil) { return YES; } aNode = [aNode.children objectForKey:path.getFront]; @@ -157,23 +165,25 @@ - (BOOL) valueExistsAtOrAbove:(FPath *)path { } - (FPath *)path { - return [[FPath alloc] initWith:(self.parent == nil) ? self.name : - [NSString stringWithFormat:@"%@/%@", [self.parent path], self.name ]]; + return [[FPath alloc] + initWith:(self.parent == nil) + ? self.name + : [NSString stringWithFormat:@"%@/%@", [self.parent path], + self.name]]; } -- (void) updateParents { +- (void)updateParents { [self.parent updateChild:self.name withNode:self]; } -- (void) updateChild:(NSString*)childName withNode:(FTree *)child { +- (void)updateChild:(NSString *)childName withNode:(FTree *)child { BOOL childEmpty = [child isEmpty]; BOOL childExists = self.node.children[childName] != nil; - if(childEmpty && childExists) { + if (childEmpty && childExists) { [self.node.children removeObjectForKey:childName]; self.node.childCount = self.node.childCount - 1; [self updateParents]; - } - else if(!childEmpty && !childExists) { + } else if (!childEmpty && !childExists) { [self.node.children setObject:child.node forKey:childName]; self.node.childCount = self.node.childCount + 1; [self updateParents]; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTreeNode.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTreeNode.h index 7e3497e..549f3b1 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTreeNode.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTreeNode.h @@ -18,8 +18,8 @@ @interface FTreeNode : NSObject -@property (nonatomic, strong) NSMutableDictionary* children; -@property (nonatomic, readwrite, assign) int childCount; -@property (nonatomic, strong) id value; +@property(nonatomic, strong) NSMutableDictionary *children; +@property(nonatomic, readwrite, assign) int childCount; +@property(nonatomic, strong) id value; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTreeNode.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTreeNode.m index 9cba9c5..bae6c62 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTreeNode.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/Utilities/FTreeNode.m @@ -22,8 +22,7 @@ @implementation FTreeNode @synthesize childCount; @synthesize value; -- (id)init -{ +- (id)init { self = [super init]; if (self) { self.children = [[NSMutableDictionary alloc] init]; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCacheNode.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCacheNode.h index b23869c..eff0cb0 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCacheNode.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCacheNode.h @@ -21,24 +21,26 @@ @class FPath; /** -* A cache node only stores complete children. Additionally it holds a flag whether the node can be considered fully -* initialized in the sense that we know at one point in time, this represented a valid state of the world, e.g. -* initialized with data from the server, or a complete overwrite by the client. It is not necessarily complete because -* it may have been from a tagged query. The filtered flag also tracks whether a node potentially had children removed -* due to a filter. -*/ + * A cache node only stores complete children. Additionally it holds a flag + * whether the node can be considered fully initialized in the sense that we + * know at one point in time, this represented a valid state of the world, e.g. + * initialized with data from the server, or a complete overwrite by the client. + * It is not necessarily complete because it may have been from a tagged query. + * The filtered flag also tracks whether a node potentially had children removed + * due to a filter. + */ @interface FCacheNode : NSObject -- (id) initWithIndexedNode:(FIndexedNode *)indexedNode - isFullyInitialized:(BOOL)fullyInitialized - isFiltered:(BOOL)filtered; +- (id)initWithIndexedNode:(FIndexedNode *)indexedNode + isFullyInitialized:(BOOL)fullyInitialized + isFiltered:(BOOL)filtered; -- (BOOL) isCompleteForPath:(FPath *)path; -- (BOOL) isCompleteForChild:(NSString *)childKey; +- (BOOL)isCompleteForPath:(FPath *)path; +- (BOOL)isCompleteForChild:(NSString *)childKey; -@property (nonatomic, readonly) BOOL isFullyInitialized; -@property (nonatomic, readonly) BOOL isFiltered; -@property (nonatomic, strong, readonly) FIndexedNode *indexedNode; -@property (nonatomic, strong, readonly) id node; +@property(nonatomic, readonly) BOOL isFullyInitialized; +@property(nonatomic, readonly) BOOL isFiltered; +@property(nonatomic, strong, readonly) FIndexedNode *indexedNode; +@property(nonatomic, strong, readonly) id node; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCacheNode.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCacheNode.m index 4767a25..a991d52 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCacheNode.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCacheNode.m @@ -15,22 +15,21 @@ */ #import "FCacheNode.h" -#import "FNode.h" -#import "FPath.h" #import "FEmptyNode.h" #import "FIndexedNode.h" +#import "FNode.h" +#import "FPath.h" @interface FCacheNode () -@property (nonatomic, readwrite) BOOL isFullyInitialized; -@property (nonatomic, readwrite) BOOL isFiltered; -@property (nonatomic, strong, readwrite) FIndexedNode *indexedNode; +@property(nonatomic, readwrite) BOOL isFullyInitialized; +@property(nonatomic, readwrite) BOOL isFiltered; +@property(nonatomic, strong, readwrite) FIndexedNode *indexedNode; @end @implementation FCacheNode -- (id) initWithIndexedNode:(FIndexedNode *)indexedNode - isFullyInitialized:(BOOL)fullyInitialized - isFiltered:(BOOL)filtered -{ +- (id)initWithIndexedNode:(FIndexedNode *)indexedNode + isFullyInitialized:(BOOL)fullyInitialized + isFiltered:(BOOL)filtered { self = [super init]; if (self) { self.indexedNode = indexedNode; @@ -50,7 +49,8 @@ - (BOOL)isCompleteForPath:(FPath *)path { } - (BOOL)isCompleteForChild:(NSString *)childKey { - return (self.isFullyInitialized && !self.isFiltered) || [self.node hasChild:childKey]; + return (self.isFullyInitialized && !self.isFiltered) || + [self.node hasChild:childKey]; } - (id)node { diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCancelEvent.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCancelEvent.h index 38277f7..dd58642 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCancelEvent.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCancelEvent.h @@ -14,17 +14,18 @@ * limitations under the License. */ -#import #import "FEvent.h" +#import @protocol FEventRegistration; +@interface FCancelEvent : NSObject -@interface FCancelEvent : NSObject - -- initWithEventRegistration:(id)eventRegistration error:(NSError *)error path:(FPath *)path; +- initWithEventRegistration:(id)eventRegistration + error:(NSError *)error + path:(FPath *)path; -@property (nonatomic, strong, readonly) NSError *error; -@property (nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) NSError *error; +@property(nonatomic, strong, readonly) FPath *path; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCancelEvent.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCancelEvent.m index fb73f17..b069a71 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCancelEvent.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FCancelEvent.m @@ -15,13 +15,13 @@ */ #import "FCancelEvent.h" -#import "FPath.h" #import "FEventRegistration.h" +#import "FPath.h" @interface FCancelEvent () -@property (nonatomic, strong) id eventRegistration; -@property (nonatomic, strong, readwrite) NSError *error; -@property (nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, strong) id eventRegistration; +@property(nonatomic, strong, readwrite) NSError *error; +@property(nonatomic, strong, readwrite) FPath *path; @end @implementation FCancelEvent @@ -30,7 +30,9 @@ @implementation FCancelEvent @synthesize error; @synthesize path; -- (id)initWithEventRegistration:(id )registration error:(NSError *)anError path:(FPath *)aPath { +- (id)initWithEventRegistration:(id)registration + error:(NSError *)anError + path:(FPath *)aPath { self = [super init]; if (self) { self.eventRegistration = registration; @@ -40,15 +42,15 @@ - (id)initWithEventRegistration:(id )registration error:(NSE return self; } -- (void) fireEventOnQueue:(dispatch_queue_t)queue { +- (void)fireEventOnQueue:(dispatch_queue_t)queue { [self.eventRegistration fireEvent:self queue:queue]; } -- (BOOL) isCancelEvent { +- (BOOL)isCancelEvent { return YES; } -- (NSString *) description { +- (NSString *)description { return [NSString stringWithFormat:@"%@: cancel", self.path]; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChange.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChange.h index d728fe0..101ec8f 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChange.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChange.h @@ -14,25 +14,28 @@ * limitations under the License. */ -#import #import "FIRDatabaseReference.h" -#import "FNode.h" #import "FIndexedNode.h" +#import "FNode.h" +#import @interface FChange : NSObject -@property (nonatomic, readonly) FIRDataEventType type; -@property (nonatomic, strong, readonly) FIndexedNode *indexedNode; -@property (nonatomic, strong, readonly) NSString *childKey; -@property (nonatomic, strong, readonly) NSString *prevKey; -@property (nonatomic, strong, readonly) FIndexedNode *oldIndexedNode; +@property(nonatomic, readonly) FIRDataEventType type; +@property(nonatomic, strong, readonly) FIndexedNode *indexedNode; +@property(nonatomic, strong, readonly) NSString *childKey; +@property(nonatomic, strong, readonly) NSString *prevKey; +@property(nonatomic, strong, readonly) FIndexedNode *oldIndexedNode; -- (id)initWithType:(FIRDataEventType)type indexedNode:(FIndexedNode *)indexedNode; -- (id)initWithType:(FIRDataEventType)type indexedNode:(FIndexedNode *)indexedNode childKey:(NSString *)childKey; +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode; +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode + childKey:(NSString *)childKey; - (id)initWithType:(FIRDataEventType)type indexedNode:(FIndexedNode *)indexedNode childKey:(NSString *)childKey oldIndexedNode:(FIndexedNode *)oldIndexedNode; -- (FChange *) changeWithPrevKey:(NSString *)prevKey; +- (FChange *)changeWithPrevKey:(NSString *)prevKey; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChange.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChange.m index 893fce4..8ad1cfc 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChange.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChange.m @@ -18,27 +18,33 @@ @interface FChange () -@property (nonatomic, strong, readwrite) NSString *prevKey; +@property(nonatomic, strong, readwrite) NSString *prevKey; @end @implementation FChange -- (id)initWithType:(FIRDataEventType)type indexedNode:(FIndexedNode *)indexedNode -{ - return [self initWithType:type indexedNode:indexedNode childKey:nil oldIndexedNode:nil]; +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode { + return [self initWithType:type + indexedNode:indexedNode + childKey:nil + oldIndexedNode:nil]; } -- (id)initWithType:(FIRDataEventType)type indexedNode:(FIndexedNode *)indexedNode childKey:(NSString *)childKey -{ - return [self initWithType:type indexedNode:indexedNode childKey:childKey oldIndexedNode:nil]; +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode + childKey:(NSString *)childKey { + return [self initWithType:type + indexedNode:indexedNode + childKey:childKey + oldIndexedNode:nil]; } - (id)initWithType:(FIRDataEventType)type indexedNode:(FIndexedNode *)indexedNode childKey:(NSString *)childKey - oldIndexedNode:(FIndexedNode *)oldIndexedNode -{ + oldIndexedNode:(FIndexedNode *)oldIndexedNode { self = [super init]; if (self != nil) { self->_type = type; @@ -49,7 +55,7 @@ - (id)initWithType:(FIRDataEventType)type return self; } -- (FChange *) changeWithPrevKey:(NSString *)prevKey { +- (FChange *)changeWithPrevKey:(NSString *)prevKey { FChange *newChange = [[FChange alloc] initWithType:self.type indexedNode:self.indexedNode childKey:self.childKey @@ -58,8 +64,9 @@ - (FChange *) changeWithPrevKey:(NSString *)prevKey { return newChange; } -- (NSString *) description { - return [NSString stringWithFormat:@"event: %d, data: %@", (int)self.type, [self.indexedNode.node val]]; +- (NSString *)description { + return [NSString stringWithFormat:@"event: %d, data: %@", (int)self.type, + [self.indexedNode.node val]]; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChildEventRegistration.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChildEventRegistration.h index 8da0b8f..0b0c633 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChildEventRegistration.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChildEventRegistration.h @@ -14,24 +14,24 @@ * limitations under the License. */ -#import #import "FEventRegistration.h" #import "FTypedefs.h" +#import @class FRepo; @interface FChildEventRegistration : NSObject -- (id) initWithRepo:(FRepo *)repo - handle:(FIRDatabaseHandle)fHandle - callbacks:(NSDictionary *)callbackBlocks - cancelCallback:(fbt_void_nserror)cancelCallbackBlock; +- (id)initWithRepo:(FRepo *)repo + handle:(FIRDatabaseHandle)fHandle + callbacks:(NSDictionary *)callbackBlocks + cancelCallback:(fbt_void_nserror)cancelCallbackBlock; /** -* Maps FIRDataEventType (as NSNumber) to fbt_void_datasnapshot_nsstring -*/ -@property (nonatomic, copy, readonly) NSDictionary *callbacks; -@property (nonatomic, copy, readonly) fbt_void_nserror cancelCallback; -@property (nonatomic, readonly) FIRDatabaseHandle handle; + * Maps FIRDataEventType (as NSNumber) to fbt_void_datasnapshot_nsstring + */ +@property(nonatomic, copy, readonly) NSDictionary *callbacks; +@property(nonatomic, copy, readonly) fbt_void_nserror cancelCallback; +@property(nonatomic, readonly) FIRDatabaseHandle handle; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChildEventRegistration.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChildEventRegistration.m index a98ea47..1b688c1 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChildEventRegistration.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FChildEventRegistration.m @@ -14,25 +14,28 @@ * limitations under the License. */ -#import #import "FChildEventRegistration.h" +#import "FCancelEvent.h" +#import "FDataEvent.h" +#import "FIRDataSnapshot_Private.h" #import "FIRDatabaseQuery_Private.h" #import "FQueryParams.h" #import "FQuerySpec.h" -#import "FIRDataSnapshot_Private.h" -#import "FDataEvent.h" -#import "FCancelEvent.h" +#import @interface FChildEventRegistration () -@property (nonatomic, strong) FRepo *repo; -@property (nonatomic, copy, readwrite) NSDictionary *callbacks; -@property (nonatomic, copy, readwrite) fbt_void_nserror cancelCallback; -@property (nonatomic, readwrite) FIRDatabaseHandle handle; +@property(nonatomic, strong) FRepo *repo; +@property(nonatomic, copy, readwrite) NSDictionary *callbacks; +@property(nonatomic, copy, readwrite) fbt_void_nserror cancelCallback; +@property(nonatomic, readwrite) FIRDatabaseHandle handle; @end @implementation FChildEventRegistration -- (id)initWithRepo:(id)repo handle:(FIRDatabaseHandle)fHandle callbacks:(NSDictionary *)callbackBlocks cancelCallback:(fbt_void_nserror)cancelCallbackBlock { +- (id)initWithRepo:(id)repo + handle:(FIRDatabaseHandle)fHandle + callbacks:(NSDictionary *)callbackBlocks + cancelCallback:(fbt_void_nserror)cancelCallbackBlock { self = [super init]; if (self) { self.repo = repo; @@ -43,51 +46,67 @@ - (id)initWithRepo:(id)repo handle:(FIRDatabaseHandle)fHandle callbacks:(NSDicti return self; } -- (BOOL) responseTo:(FIRDataEventType)eventType { - return self.callbacks != nil && [self.callbacks objectForKey:[NSNumber numberWithInteger:eventType]] != nil; +- (BOOL)responseTo:(FIRDataEventType)eventType { + return self.callbacks != nil && + [self.callbacks + objectForKey:[NSNumber numberWithInteger:eventType]] != nil; } -- (FDataEvent *) createEventFrom:(FChange *)change query:(FQuerySpec *)query { - FIRDatabaseReference *ref = [[FIRDatabaseReference alloc] initWithRepo:self.repo path:[query.path childFromString:change.childKey]]; - FIRDataSnapshot *snapshot = [[FIRDataSnapshot alloc] initWithRef:ref indexedNode:change.indexedNode]; +- (FDataEvent *)createEventFrom:(FChange *)change query:(FQuerySpec *)query { + FIRDatabaseReference *ref = [[FIRDatabaseReference alloc] + initWithRepo:self.repo + path:[query.path childFromString:change.childKey]]; + FIRDataSnapshot *snapshot = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:change.indexedNode]; - FDataEvent *eventData = [[FDataEvent alloc] initWithEventType:change.type eventRegistration:self - dataSnapshot:snapshot prevName:change.prevKey]; + FDataEvent *eventData = + [[FDataEvent alloc] initWithEventType:change.type + eventRegistration:self + dataSnapshot:snapshot + prevName:change.prevKey]; return eventData; } -- (void) fireEvent:(id )event queue:(dispatch_queue_t)queue { +- (void)fireEvent:(id)event queue:(dispatch_queue_t)queue { if ([event isCancelEvent]) { FCancelEvent *cancelEvent = event; FFLog(@"I-RDB061001", @"Raising cancel value event on %@", event.path); - NSAssert(self.cancelCallback != nil, @"Raising a cancel event on a listener with no cancel callback"); + NSAssert( + self.cancelCallback != nil, + @"Raising a cancel event on a listener with no cancel callback"); dispatch_async(queue, ^{ - self.cancelCallback(cancelEvent.error); + self.cancelCallback(cancelEvent.error); }); } else if (self.callbacks != nil) { FDataEvent *dataEvent = event; - FFLog(@"I-RDB061002", @"Raising event callback (%ld) on %@", (long)dataEvent.eventType, dataEvent.path); - fbt_void_datasnapshot_nsstring callback = [self.callbacks objectForKey:[NSNumber numberWithInteger:dataEvent.eventType]]; + FFLog(@"I-RDB061002", @"Raising event callback (%ld) on %@", + (long)dataEvent.eventType, dataEvent.path); + fbt_void_datasnapshot_nsstring callback = [self.callbacks + objectForKey:[NSNumber numberWithInteger:dataEvent.eventType]]; if (callback != nil) { dispatch_async(queue, ^{ - callback(dataEvent.snapshot, dataEvent.prevName); + callback(dataEvent.snapshot, dataEvent.prevName); }); } } } -- (FCancelEvent *) createCancelEventFromError:(NSError *)error path:(FPath *)path { +- (FCancelEvent *)createCancelEventFromError:(NSError *)error + path:(FPath *)path { if (self.cancelCallback != nil) { - return [[FCancelEvent alloc] initWithEventRegistration:self error:error path:path]; + return [[FCancelEvent alloc] initWithEventRegistration:self + error:error + path:path]; } else { return nil; } } -- (BOOL) matches:(id)other { - return self.handle == NSNotFound || other.handle == NSNotFound || self.handle == other.handle; +- (BOOL)matches:(id)other { + return self.handle == NSNotFound || other.handle == NSNotFound || + self.handle == other.handle; } - @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FDataEvent.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FDataEvent.h index da90b03..a0d28f9 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FDataEvent.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FDataEvent.h @@ -14,26 +14,28 @@ * limitations under the License. */ -#import +#import "FEvent.h" #import "FIRDataSnapshot.h" #import "FIRDatabaseReference.h" #import "FTupleUserCallback.h" -#import "FEvent.h" +#import @protocol FEventRegistration; @protocol FIndex; -@interface FDataEvent : NSObject - -- initWithEventType:(FIRDataEventType)type eventRegistration:(id)eventRegistration - dataSnapshot:(FIRDataSnapshot *)dataSnapshot; -- initWithEventType:(FIRDataEventType)type eventRegistration:(id)eventRegistration - dataSnapshot:(FIRDataSnapshot *)snapshot prevName:(NSString *)prevName; +@interface FDataEvent : NSObject +- initWithEventType:(FIRDataEventType)type + eventRegistration:(id)eventRegistration + dataSnapshot:(FIRDataSnapshot *)dataSnapshot; +- initWithEventType:(FIRDataEventType)type + eventRegistration:(id)eventRegistration + dataSnapshot:(FIRDataSnapshot *)snapshot + prevName:(NSString *)prevName; -@property (nonatomic, strong, readonly) id eventRegistration; -@property (nonatomic, strong, readonly) FIRDataSnapshot * snapshot; -@property (nonatomic, strong, readonly) NSString* prevName; -@property (nonatomic, readonly) FIRDataEventType eventType; +@property(nonatomic, strong, readonly) id eventRegistration; +@property(nonatomic, strong, readonly) FIRDataSnapshot *snapshot; +@property(nonatomic, strong, readonly) NSString *prevName; +@property(nonatomic, readonly) FIRDataEventType eventType; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FDataEvent.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FDataEvent.m index 6c97faf..886a21e 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FDataEvent.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FDataEvent.m @@ -16,14 +16,15 @@ #import "FDataEvent.h" #import "FEventRegistration.h" -#import "FIndex.h" #import "FIRDatabaseQuery_Private.h" +#import "FIndex.h" @interface FDataEvent () -@property (nonatomic, strong, readwrite) id eventRegistration; -@property (nonatomic, strong, readwrite) FIRDataSnapshot *snapshot; -@property (nonatomic, strong, readwrite) NSString *prevName; -@property (nonatomic, readwrite) FIRDataEventType eventType; +@property(nonatomic, strong, readwrite) id + eventRegistration; +@property(nonatomic, strong, readwrite) FIRDataSnapshot *snapshot; +@property(nonatomic, strong, readwrite) NSString *prevName; +@property(nonatomic, readwrite) FIRDataEventType eventType; @end @implementation FDataEvent @@ -33,11 +34,19 @@ @implementation FDataEvent @synthesize prevName; @synthesize eventType; -- (id)initWithEventType:(FIRDataEventType)type eventRegistration:(id )registration dataSnapshot:(FIRDataSnapshot *)dataSnapshot { - return [self initWithEventType:type eventRegistration:registration dataSnapshot:dataSnapshot prevName:nil]; +- (id)initWithEventType:(FIRDataEventType)type + eventRegistration:(id)registration + dataSnapshot:(FIRDataSnapshot *)dataSnapshot { + return [self initWithEventType:type + eventRegistration:registration + dataSnapshot:dataSnapshot + prevName:nil]; } -- (id)initWithEventType:(FIRDataEventType)type eventRegistration:(id )registration dataSnapshot:(FIRDataSnapshot *)dataSnapshot prevName:(NSString *)previousName { +- (id)initWithEventType:(FIRDataEventType)type + eventRegistration:(id)registration + dataSnapshot:(FIRDataSnapshot *)dataSnapshot + prevName:(NSString *)previousName { self = [super init]; if (self) { self.eventRegistration = registration; @@ -48,7 +57,7 @@ - (id)initWithEventType:(FIRDataEventType)type eventRegistration:(id #import "FIRDataEventType.h" +#import @class FPath; @protocol FEvent -- (FPath *) path; -- (void) fireEventOnQueue:(dispatch_queue_t)queue; -- (BOOL) isCancelEvent; -- (NSString *) description; +- (FPath *)path; +- (void)fireEventOnQueue:(dispatch_queue_t)queue; +- (BOOL)isCancelEvent; +- (NSString *)description; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FEventRaiser.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FEventRaiser.h index 01a0130..c46bff5 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FEventRaiser.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FEventRaiser.h @@ -21,15 +21,16 @@ @class FIRDatabaseConfig; /** -* Left as instance methods rather than class methods so that we could potentially callback on different queues for different repos. -* This is semi-parallel to JS's FEventQueue -*/ + * Left as instance methods rather than class methods so that we could + * potentially callback on different queues for different repos. This is + * semi-parallel to JS's FEventQueue + */ @interface FEventRaiser : NSObject - (id)initWithQueue:(dispatch_queue_t)queue; -- (void) raiseEvents:(NSArray *)eventDataList; -- (void) raiseCallback:(fbt_void_void)callback; -- (void) raiseCallbacks:(NSArray *)callbackList; +- (void)raiseEvents:(NSArray *)eventDataList; +- (void)raiseCallback:(fbt_void_void)callback; +- (void)raiseCallbacks:(NSArray *)callbackList; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FEventRaiser.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FEventRaiser.m index 94a0907..d745358 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FEventRaiser.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FEventRaiser.m @@ -16,26 +16,28 @@ #import "FEventRaiser.h" #import "FDataEvent.h" -#import "FTypedefs.h" -#import "FUtilities.h" -#import "FTupleUserCallback.h" #import "FRepo.h" #import "FRepoManager.h" +#import "FTupleUserCallback.h" +#import "FTypedefs.h" +#import "FUtilities.h" @interface FEventRaiser () -@property (nonatomic, strong) dispatch_queue_t queue; +@property(nonatomic, strong) dispatch_queue_t queue; @end /** -* This class exists for symmetry with other clients, but since events are async, we don't need to do the complicated -* stuff the JS client does to preserve event order. -*/ + * This class exists for symmetry with other clients, but since events are + * async, we don't need to do the complicated stuff the JS client does to + * preserve event order. + */ @implementation FEventRaiser - (id)init { - [NSException raise:NSInternalInconsistencyException format:@"Can't use default constructor"]; + [NSException raise:NSInternalInconsistencyException + format:@"Can't use default constructor"]; return nil; } @@ -47,23 +49,23 @@ - (id)initWithQueue:(dispatch_queue_t)queue { return self; } -- (void) raiseEvents:(NSArray *)eventDataList { +- (void)raiseEvents:(NSArray *)eventDataList { for (id event in eventDataList) { [event fireEventOnQueue:self.queue]; } } -- (void) raiseCallback:(fbt_void_void)callback { +- (void)raiseCallback:(fbt_void_void)callback { dispatch_async(self.queue, callback); } -- (void) raiseCallbacks:(NSArray *)callbackList { +- (void)raiseCallbacks:(NSArray *)callbackList { for (fbt_void_void callback in callbackList) { dispatch_async(self.queue, callback); } } -+ (void) raiseCallbacks:(NSArray *)callbackList queue:(dispatch_queue_t)queue { ++ (void)raiseCallbacks:(NSArray *)callbackList queue:(dispatch_queue_t)queue { for (fbt_void_void callback in callbackList) { dispatch_async(queue, callback); } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FEventRegistration.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FEventRegistration.h index 5b845ac..79a2eb0 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FEventRegistration.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FEventRegistration.h @@ -14,9 +14,9 @@ * limitations under the License. */ -#import #import "FChange.h" #import "FIRDataEventType.h" +#import @protocol FEvent; @class FDataEvent; @@ -24,13 +24,15 @@ @class FQuerySpec; @protocol FEventRegistration -- (BOOL) responseTo:(FIRDataEventType)eventType; -- (FDataEvent *) createEventFrom:(FChange *)change query:(FQuerySpec *)query; -- (void) fireEvent:(id)event queue:(dispatch_queue_t)queue; -- (FCancelEvent *) createCancelEventFromError:(NSError *)error path:(FPath *)path; +- (BOOL)responseTo:(FIRDataEventType)eventType; +- (FDataEvent *)createEventFrom:(FChange *)change query:(FQuerySpec *)query; +- (void)fireEvent:(id)event queue:(dispatch_queue_t)queue; +- (FCancelEvent *)createCancelEventFromError:(NSError *)error + path:(FPath *)path; /** -* Used to figure out what event registration match the event registration that needs to be removed. -*/ -- (BOOL) matches:(id)other; -@property (nonatomic, readonly) FIRDatabaseHandle handle; + * Used to figure out what event registration match the event registration that + * needs to be removed. + */ +- (BOOL)matches:(id)other; +@property(nonatomic, readonly) FIRDatabaseHandle handle; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FKeepSyncedEventRegistration.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FKeepSyncedEventRegistration.h index 669e012..d4dca60 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FKeepSyncedEventRegistration.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FKeepSyncedEventRegistration.h @@ -21,7 +21,7 @@ /** * A singleton event registration to mark a query as keep synced */ -@interface FKeepSyncedEventRegistration : NSObject +@interface FKeepSyncedEventRegistration : NSObject + (FKeepSyncedEventRegistration *)instance; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FKeepSyncedEventRegistration.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FKeepSyncedEventRegistration.m index 806d54f..1821829 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FKeepSyncedEventRegistration.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FKeepSyncedEventRegistration.m @@ -26,37 +26,43 @@ + (FKeepSyncedEventRegistration *)instance { static dispatch_once_t onceToken; static FKeepSyncedEventRegistration *keepSynced; dispatch_once(&onceToken, ^{ - keepSynced = [[FKeepSyncedEventRegistration alloc] init]; + keepSynced = [[FKeepSyncedEventRegistration alloc] init]; }); return keepSynced; } -- (BOOL) responseTo:(FIRDataEventType)eventType { +- (BOOL)responseTo:(FIRDataEventType)eventType { return NO; } -- (FDataEvent *) createEventFrom:(FChange *)change query:(FQuerySpec *)query { - [NSException raise:NSInternalInconsistencyException format:@"Should never create event for FKeepSyncedEventRegistration"]; +- (FDataEvent *)createEventFrom:(FChange *)change query:(FQuerySpec *)query { + [NSException + raise:NSInternalInconsistencyException + format:@"Should never create event for FKeepSyncedEventRegistration"]; return nil; } -- (void) fireEvent:(id)event queue:(dispatch_queue_t)queue { - [NSException raise:NSInternalInconsistencyException format:@"Should never raise event for FKeepSyncedEventRegistration"]; +- (void)fireEvent:(id)event queue:(dispatch_queue_t)queue { + [NSException + raise:NSInternalInconsistencyException + format:@"Should never raise event for FKeepSyncedEventRegistration"]; } -- (FCancelEvent *) createCancelEventFromError:(NSError *)error path:(FPath *)path { +- (FCancelEvent *)createCancelEventFromError:(NSError *)error + path:(FPath *)path { // Don't create cancel events.... return nil; } -- (FIRDatabaseHandle) handle { - // TODO[offline]: returning arbitray, can't return NSNotFound since that is used to match other event registrations - // We should really redo this to match on different kind of events (single observer, all observers, cancelled) - // rather than on a NSNotFound handle... +- (FIRDatabaseHandle)handle { + // TODO[offline]: returning arbitray, can't return NSNotFound since that is + // used to match other event registrations We should really redo this to + // match on different kind of events (single observer, all observers, + // cancelled) rather than on a NSNotFound handle... return NSNotFound - 1; } -- (BOOL) matches:(id)other { +- (BOOL)matches:(id)other { // Only matches singleton instance return self == other; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FValueEventRegistration.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FValueEventRegistration.h index 1220c60..819febe 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FValueEventRegistration.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FValueEventRegistration.h @@ -14,21 +14,21 @@ * limitations under the License. */ -#import #import "FEventRegistration.h" #import "FTypedefs.h" +#import @class FRepo; -@interface FValueEventRegistration : NSObject +@interface FValueEventRegistration : NSObject -- (id) initWithRepo:(FRepo *)repo - handle:(FIRDatabaseHandle)fHandle - callback:(fbt_void_datasnapshot)callbackBlock - cancelCallback:(fbt_void_nserror)cancelCallbackBlock; +- (id)initWithRepo:(FRepo *)repo + handle:(FIRDatabaseHandle)fHandle + callback:(fbt_void_datasnapshot)callbackBlock + cancelCallback:(fbt_void_nserror)cancelCallbackBlock; -@property (nonatomic, copy, readonly) fbt_void_datasnapshot callback; -@property (nonatomic, copy, readonly) fbt_void_nserror cancelCallback; -@property (nonatomic, readonly) FIRDatabaseHandle handle; +@property(nonatomic, copy, readonly) fbt_void_datasnapshot callback; +@property(nonatomic, copy, readonly) fbt_void_nserror cancelCallback; +@property(nonatomic, readonly) FIRDatabaseHandle handle; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FValueEventRegistration.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FValueEventRegistration.m index 6a98629..ad9368b 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FValueEventRegistration.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FValueEventRegistration.m @@ -14,28 +14,28 @@ * limitations under the License. */ -#import #import "FValueEventRegistration.h" +#import "FCancelEvent.h" +#import "FDataEvent.h" +#import "FIRDataSnapshot_Private.h" #import "FIRDatabaseQuery_Private.h" #import "FQueryParams.h" #import "FQuerySpec.h" -#import "FIRDataSnapshot_Private.h" -#import "FCancelEvent.h" -#import "FDataEvent.h" +#import @interface FValueEventRegistration () -@property (nonatomic, strong) FRepo* repo; -@property (nonatomic, copy, readwrite) fbt_void_datasnapshot callback; -@property (nonatomic, copy, readwrite) fbt_void_nserror cancelCallback; -@property (nonatomic, readwrite) FIRDatabaseHandle handle; +@property(nonatomic, strong) FRepo *repo; +@property(nonatomic, copy, readwrite) fbt_void_datasnapshot callback; +@property(nonatomic, copy, readwrite) fbt_void_nserror cancelCallback; +@property(nonatomic, readwrite) FIRDatabaseHandle handle; @end @implementation FValueEventRegistration -- (id) initWithRepo:(FRepo *)repo - handle:(FIRDatabaseHandle)fHandle - callback:(fbt_void_datasnapshot)callbackBlock - cancelCallback:(fbt_void_nserror)cancelCallbackBlock { +- (id)initWithRepo:(FRepo *)repo + handle:(FIRDatabaseHandle)fHandle + callback:(fbt_void_datasnapshot)callbackBlock + cancelCallback:(fbt_void_nserror)cancelCallbackBlock { self = [super init]; if (self) { self.repo = repo; @@ -46,45 +46,57 @@ - (id) initWithRepo:(FRepo *)repo return self; } -- (BOOL) responseTo:(FIRDataEventType)eventType { +- (BOOL)responseTo:(FIRDataEventType)eventType { return eventType == FIRDataEventTypeValue; } -- (FDataEvent *) createEventFrom:(FChange *)change query:(FQuerySpec *)query { - FIRDatabaseReference *ref = [[FIRDatabaseReference alloc] initWithRepo:self.repo path:query.path]; - FIRDataSnapshot *snapshot = [[FIRDataSnapshot alloc] initWithRef:ref indexedNode:change.indexedNode]; - FDataEvent *eventData = [[FDataEvent alloc] initWithEventType:FIRDataEventTypeValue eventRegistration:self - dataSnapshot:snapshot]; +- (FDataEvent *)createEventFrom:(FChange *)change query:(FQuerySpec *)query { + FIRDatabaseReference *ref = + [[FIRDatabaseReference alloc] initWithRepo:self.repo path:query.path]; + FIRDataSnapshot *snapshot = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:change.indexedNode]; + FDataEvent *eventData = + [[FDataEvent alloc] initWithEventType:FIRDataEventTypeValue + eventRegistration:self + dataSnapshot:snapshot]; return eventData; } -- (void) fireEvent:(id )event queue:(dispatch_queue_t)queue { +- (void)fireEvent:(id)event queue:(dispatch_queue_t)queue { if ([event isCancelEvent]) { FCancelEvent *cancelEvent = event; FFLog(@"I-RDB065001", @"Raising cancel value event on %@", event.path); - NSAssert(self.cancelCallback != nil, @"Raising a cancel event on a listener with no cancel callback"); + NSAssert( + self.cancelCallback != nil, + @"Raising a cancel event on a listener with no cancel callback"); dispatch_async(queue, ^{ - self.cancelCallback(cancelEvent.error); + self.cancelCallback(cancelEvent.error); }); } else if (self.callback != nil) { FDataEvent *dataEvent = event; - FFLog(@"I-RDB065002", @"Raising value event on %@", dataEvent.snapshot.key); + FFLog(@"I-RDB065002", @"Raising value event on %@", + dataEvent.snapshot.key); dispatch_async(queue, ^{ - self.callback(dataEvent.snapshot); + self.callback(dataEvent.snapshot); }); } } -- (FCancelEvent *) createCancelEventFromError:(NSError *)error path:(FPath *)path { +- (FCancelEvent *)createCancelEventFromError:(NSError *)error + path:(FPath *)path { if (self.cancelCallback != nil) { - return [[FCancelEvent alloc] initWithEventRegistration:self error:error path:path]; + return [[FCancelEvent alloc] initWithEventRegistration:self + error:error + path:path]; } else { return nil; } } -- (BOOL) matches:(id)other { - return self.handle == NSNotFound || other.handle == NSNotFound || self.handle == other.handle; +- (BOOL)matches:(id)other { + return self.handle == NSNotFound || other.handle == NSNotFound || + self.handle == other.handle; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FView.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FView.h index 2d0761a..0b4b9d8 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FView.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FView.h @@ -27,27 +27,30 @@ @interface FViewOperationResult : NSObject -@property (nonatomic, strong, readonly) NSArray* changes; -@property (nonatomic, strong, readonly) NSArray* events; +@property(nonatomic, strong, readonly) NSArray *changes; +@property(nonatomic, strong, readonly) NSArray *events; @end - @interface FView : NSObject -@property (nonatomic, strong, readonly) FQuerySpec *query; +@property(nonatomic, strong, readonly) FQuerySpec *query; -- (id) initWithQuery:(FQuerySpec *)query initialViewCache:(FViewCache *)initialViewCache; +- (id)initWithQuery:(FQuerySpec *)query + initialViewCache:(FViewCache *)initialViewCache; -- (id) eventCache; -- (id) serverCache; -- (id) completeServerCacheFor:(FPath*)path; -- (BOOL) isEmpty; +- (id)eventCache; +- (id)serverCache; +- (id)completeServerCacheFor:(FPath *)path; +- (BOOL)isEmpty; -- (void) addEventRegistration:(id)eventRegistration; -- (NSArray *) removeEventRegistration:(id)eventRegistration cancelError:(NSError *)cancelError; +- (void)addEventRegistration:(id)eventRegistration; +- (NSArray *)removeEventRegistration:(id)eventRegistration + cancelError:(NSError *)cancelError; -- (FViewOperationResult *) applyOperation:(id )operation writesCache:(FWriteTreeRef *)writesCache serverCache:(id )optCompleteServerCache; -- (NSArray *) initialEvents:(id)registration; +- (FViewOperationResult *)applyOperation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache; +- (NSArray *)initialEvents:(id)registration; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FView.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FView.m index 1aea4d7..a15e13d 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FView.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FView.m @@ -15,30 +15,30 @@ */ #import "FView.h" -#import "FNode.h" -#import "FWriteTreeRef.h" -#import "FOperation.h" +#import "FCacheNode.h" +#import "FCancelEvent.h" +#import "FEmptyNode.h" +#import "FEventGenerator.h" +#import "FEventRegistration.h" #import "FIRDatabaseQuery.h" #import "FIRDatabaseQuery_Private.h" -#import "FEventRegistration.h" +#import "FIndexedFilter.h" +#import "FIndexedNode.h" +#import "FNode.h" +#import "FOperation.h" +#import "FOperationSource.h" +#import "FPath.h" #import "FQueryParams.h" #import "FQuerySpec.h" #import "FViewCache.h" -#import "FPath.h" -#import "FEventGenerator.h" -#import "FOperationSource.h" -#import "FCancelEvent.h" -#import "FIndexedFilter.h" -#import "FCacheNode.h" -#import "FEmptyNode.h" #import "FViewProcessor.h" #import "FViewProcessorResult.h" -#import "FIndexedNode.h" +#import "FWriteTreeRef.h" @interface FViewOperationResult () -@property (nonatomic, strong, readwrite) NSArray *changes; -@property (nonatomic, strong, readwrite) NSArray *events; +@property(nonatomic, strong, readwrite) NSArray *changes; +@property(nonatomic, strong, readwrite) NSArray *events; @end @@ -56,52 +56,63 @@ - (id)initWithChanges:(NSArray *)changes events:(NSArray *)events { @end /** -* A view represents a specific location and query that has 1 or more event registrations. -* -* It does several things: -* - Maintains the list of event registration for this location/query. -* - Maintains a cache of the data visible for this location/query. -* - Applies new operations (via applyOperation), updates the cache, and based on the event -* registrations returns the set of events to be raised. -*/ + * A view represents a specific location and query that has 1 or more event + * registrations. + * + * It does several things: + * - Maintains the list of event registration for this location/query. + * - Maintains a cache of the data visible for this location/query. + * - Applies new operations (via applyOperation), updates the cache, and based + * on the event registrations returns the set of events to be raised. + */ @interface FView () -@property (nonatomic, strong, readwrite) FQuerySpec *query; -@property (nonatomic, strong) FViewProcessor *processor; -@property (nonatomic, strong) FViewCache *viewCache; -@property (nonatomic, strong) NSMutableArray *eventRegistrations; -@property (nonatomic, strong) FEventGenerator *eventGenerator; +@property(nonatomic, strong, readwrite) FQuerySpec *query; +@property(nonatomic, strong) FViewProcessor *processor; +@property(nonatomic, strong) FViewCache *viewCache; +@property(nonatomic, strong) NSMutableArray *eventRegistrations; +@property(nonatomic, strong) FEventGenerator *eventGenerator; @end @implementation FView -- (id) initWithQuery:(FQuerySpec *)query initialViewCache:(FViewCache *)initialViewCache { +- (id)initWithQuery:(FQuerySpec *)query + initialViewCache:(FViewCache *)initialViewCache { self = [super init]; if (self) { self.query = query; - FIndexedFilter *indexFilter = [[FIndexedFilter alloc] initWithIndex:query.index]; + FIndexedFilter *indexFilter = + [[FIndexedFilter alloc] initWithIndex:query.index]; id filter = query.params.nodeFilter; self.processor = [[FViewProcessor alloc] initWithFilter:filter]; FCacheNode *initialServerCache = initialViewCache.cachedServerSnap; FCacheNode *initialEventCache = initialViewCache.cachedEventSnap; - // Don't filter server node with other filter than index, wait for tagged listen - FIndexedNode *emptyIndexedNode = [FIndexedNode indexedNodeWithNode:[FEmptyNode emptyNode] index:query.index]; - FIndexedNode *serverSnap = [indexFilter updateFullNode:emptyIndexedNode - withNewNode:initialServerCache.indexedNode - accumulator:nil]; - FIndexedNode *eventSnap = [filter updateFullNode:emptyIndexedNode - withNewNode:initialEventCache.indexedNode - accumulator:nil]; - FCacheNode *newServerCache = [[FCacheNode alloc] initWithIndexedNode:serverSnap - isFullyInitialized:initialServerCache.isFullyInitialized - isFiltered:indexFilter.filtersNodes]; - FCacheNode *newEventCache = [[FCacheNode alloc] initWithIndexedNode:eventSnap - isFullyInitialized:initialEventCache.isFullyInitialized - isFiltered:filter.filtersNodes]; - - self.viewCache = [[FViewCache alloc] initWithEventCache:newEventCache serverCache:newServerCache]; + // Don't filter server node with other filter than index, wait for + // tagged listen + FIndexedNode *emptyIndexedNode = + [FIndexedNode indexedNodeWithNode:[FEmptyNode emptyNode] + index:query.index]; + FIndexedNode *serverSnap = + [indexFilter updateFullNode:emptyIndexedNode + withNewNode:initialServerCache.indexedNode + accumulator:nil]; + FIndexedNode *eventSnap = + [filter updateFullNode:emptyIndexedNode + withNewNode:initialEventCache.indexedNode + accumulator:nil]; + FCacheNode *newServerCache = [[FCacheNode alloc] + initWithIndexedNode:serverSnap + isFullyInitialized:initialServerCache.isFullyInitialized + isFiltered:indexFilter.filtersNodes]; + FCacheNode *newEventCache = [[FCacheNode alloc] + initWithIndexedNode:eventSnap + isFullyInitialized:initialEventCache.isFullyInitialized + isFiltered:filter.filtersNodes]; + + self.viewCache = [[FViewCache alloc] initWithEventCache:newEventCache + serverCache:newServerCache]; self.eventRegistrations = [[NSMutableArray alloc] init]; @@ -111,47 +122,53 @@ - (id) initWithQuery:(FQuerySpec *)query initialViewCache:(FViewCache *)initialV return self; } -- (id ) serverCache { +- (id)serverCache { return self.viewCache.cachedServerSnap.node; } -- (id ) eventCache { +- (id)eventCache { return self.viewCache.cachedEventSnap.node; } -- (id ) completeServerCacheFor:(FPath*)path { +- (id)completeServerCacheFor:(FPath *)path { id cache = self.viewCache.completeServerSnap; if (cache) { - // If this isn't a "loadsAllData" view, then cache isn't actually a complete cache and - // we need to see if it contains the child we're interested in. - if ([self.query loadsAllData] || - (!path.isEmpty && ![cache getImmediateChild:path.getFront].isEmpty)) { + // If this isn't a "loadsAllData" view, then cache isn't actually a + // complete cache and we need to see if it contains the child we're + // interested in. + if ([self.query loadsAllData] || + (!path.isEmpty && + ![cache getImmediateChild:path.getFront].isEmpty)) { return [cache getChild:path]; } } return nil; } -- (BOOL) isEmpty { +- (BOOL)isEmpty { return self.eventRegistrations.count == 0; } -- (void) addEventRegistration:(id )eventRegistration { +- (void)addEventRegistration:(id)eventRegistration { [self.eventRegistrations addObject:eventRegistration]; } /** -* @param eventRegistration If null, remove all callbacks. -* @param cancelError If a cancelError is provided, appropriate cancel events will be returned. -* @return Cancel events, if cancelError was provided. -*/ -- (NSArray *) removeEventRegistration:(id )eventRegistration cancelError:(NSError *)cancelError { + * @param eventRegistration If null, remove all callbacks. + * @param cancelError If a cancelError is provided, appropriate cancel events + * will be returned. + * @return Cancel events, if cancelError was provided. + */ +- (NSArray *)removeEventRegistration:(id)eventRegistration + cancelError:(NSError *)cancelError { NSMutableArray *cancelEvents = [[NSMutableArray alloc] init]; if (cancelError != nil) { - NSAssert(eventRegistration == nil, @"A cancel should cancel all event registrations."); + NSAssert(eventRegistration == nil, + @"A cancel should cancel all event registrations."); FPath *path = self.query.path; - for (id registration in self.eventRegistrations) { - FCancelEvent *maybeEvent = [registration createCancelEventFromError:cancelError path:path]; + for (id registration in self.eventRegistrations) { + FCancelEvent *maybeEvent = + [registration createCancelEventFromError:cancelError path:path]; if (maybeEvent) { [cancelEvents addObject:maybeEvent]; } @@ -175,49 +192,75 @@ - (NSArray *) removeEventRegistration:(id )eventRegistration } /** - * Applies the given Operation, updates our cache, and returns the appropriate events and changes + * Applies the given Operation, updates our cache, and returns the appropriate + * events and changes */ -- (FViewOperationResult *) applyOperation:(id )operation writesCache:(FWriteTreeRef *)writesCache serverCache:(id )optCompleteServerCache { - if (operation.type == FOperationTypeMerge && operation.source.queryParams != nil) { - NSAssert(self.viewCache.completeServerSnap != nil, @"We should always have a full cache before handling merges"); - NSAssert(self.viewCache.completeEventSnap != nil, @"Missing event cache, even though we have a server cache"); +- (FViewOperationResult *)applyOperation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache { + if (operation.type == FOperationTypeMerge && + operation.source.queryParams != nil) { + NSAssert(self.viewCache.completeServerSnap != nil, + @"We should always have a full cache before handling merges"); + NSAssert(self.viewCache.completeEventSnap != nil, + @"Missing event cache, even though we have a server cache"); } FViewCache *oldViewCache = self.viewCache; - FViewProcessorResult *result = [self.processor applyOperationOn:oldViewCache operation:operation writesCache:writesCache completeCache:optCompleteServerCache]; + FViewProcessorResult *result = + [self.processor applyOperationOn:oldViewCache + operation:operation + writesCache:writesCache + completeCache:optCompleteServerCache]; - NSAssert(result.viewCache.cachedServerSnap.isFullyInitialized || !oldViewCache.cachedServerSnap.isFullyInitialized, @"Once a server snap is complete, it should never go back."); + NSAssert(result.viewCache.cachedServerSnap.isFullyInitialized || + !oldViewCache.cachedServerSnap.isFullyInitialized, + @"Once a server snap is complete, it should never go back."); self.viewCache = result.viewCache; - NSArray *events = [self generateEventsForChanges:result.changes eventCache:result.viewCache.cachedEventSnap.indexedNode registration:nil]; - return [[FViewOperationResult alloc] initWithChanges:result.changes events:events]; + NSArray *events = [self + generateEventsForChanges:result.changes + eventCache:result.viewCache.cachedEventSnap.indexedNode + registration:nil]; + return [[FViewOperationResult alloc] initWithChanges:result.changes + events:events]; } -- (NSArray *) initialEvents:(id)registration { +- (NSArray *)initialEvents:(id)registration { FCacheNode *eventSnap = self.viewCache.cachedEventSnap; NSMutableArray *initialChanges = [[NSMutableArray alloc] init]; - [eventSnap.indexedNode.node enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:node]; - FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildAdded indexedNode:indexed childKey:key]; - [initialChanges addObject:change]; + [eventSnap.indexedNode.node enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:node]; + FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildAdded + indexedNode:indexed + childKey:key]; + [initialChanges addObject:change]; }]; if (eventSnap.isFullyInitialized) { - FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeValue indexedNode:eventSnap.indexedNode]; + FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeValue + indexedNode:eventSnap.indexedNode]; [initialChanges addObject:change]; } - return [self generateEventsForChanges:initialChanges eventCache:eventSnap.indexedNode registration:registration]; + return [self generateEventsForChanges:initialChanges + eventCache:eventSnap.indexedNode + registration:registration]; } -- (NSArray *) generateEventsForChanges:(NSArray *)changes eventCache:(FIndexedNode *)eventCache registration:(id)registration { +- (NSArray *)generateEventsForChanges:(NSArray *)changes + eventCache:(FIndexedNode *)eventCache + registration:(id)registration { NSArray *registrations; if (registration == nil) { registrations = [[NSArray alloc] initWithArray:self.eventRegistrations]; } else { registrations = [[NSArray alloc] initWithObjects:registration, nil]; } - return [self.eventGenerator generateEventsForChanges:changes eventCache:eventCache eventRegistrations:registrations]; + return [self.eventGenerator generateEventsForChanges:changes + eventCache:eventCache + eventRegistrations:registrations]; } -- (NSString *) description { +- (NSString *)description { return [NSString stringWithFormat:@"FView (%@)", self.query]; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FViewCache.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FViewCache.h index 4d01877..62618d2 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FViewCache.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FViewCache.h @@ -22,14 +22,19 @@ @interface FViewCache : NSObject -- (id) initWithEventCache:(FCacheNode *)eventCache serverCache:(FCacheNode *)serverCache; +- (id)initWithEventCache:(FCacheNode *)eventCache + serverCache:(FCacheNode *)serverCache; -- (FViewCache *) updateEventSnap:(FIndexedNode *)eventSnap isComplete:(BOOL)complete isFiltered:(BOOL)filtered; -- (FViewCache *) updateServerSnap:(FIndexedNode *)serverSnap isComplete:(BOOL)complete isFiltered:(BOOL)filtered; +- (FViewCache *)updateEventSnap:(FIndexedNode *)eventSnap + isComplete:(BOOL)complete + isFiltered:(BOOL)filtered; +- (FViewCache *)updateServerSnap:(FIndexedNode *)serverSnap + isComplete:(BOOL)complete + isFiltered:(BOOL)filtered; -@property (nonatomic, strong, readonly) FCacheNode *cachedEventSnap; -@property (nonatomic, strong, readonly) id completeEventSnap; -@property (nonatomic, strong, readonly) FCacheNode *cachedServerSnap; -@property (nonatomic, strong, readonly) id completeServerSnap; +@property(nonatomic, strong, readonly) FCacheNode *cachedEventSnap; +@property(nonatomic, strong, readonly) id completeEventSnap; +@property(nonatomic, strong, readonly) FCacheNode *cachedServerSnap; +@property(nonatomic, strong, readonly) id completeServerSnap; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FViewCache.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FViewCache.m index c6ec8b1..13e9283 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FViewCache.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/FViewCache.m @@ -16,17 +16,18 @@ #import "FViewCache.h" #import "FCacheNode.h" -#import "FNode.h" #import "FEmptyNode.h" +#import "FNode.h" @interface FViewCache () -@property (nonatomic, strong, readwrite) FCacheNode *cachedEventSnap; -@property (nonatomic, strong, readwrite) FCacheNode *cachedServerSnap; +@property(nonatomic, strong, readwrite) FCacheNode *cachedEventSnap; +@property(nonatomic, strong, readwrite) FCacheNode *cachedServerSnap; @end @implementation FViewCache -- (id) initWithEventCache:(FCacheNode *)eventCache serverCache:(FCacheNode *)serverCache { +- (id)initWithEventCache:(FCacheNode *)eventCache + serverCache:(FCacheNode *)serverCache { self = [super init]; if (self) { self.cachedEventSnap = eventCache; @@ -35,27 +36,37 @@ - (id) initWithEventCache:(FCacheNode *)eventCache serverCache:(FCacheNode *)ser return self; } -- (FViewCache *) updateEventSnap:(FIndexedNode *)eventSnap isComplete:(BOOL)complete isFiltered:(BOOL)filtered { - FCacheNode *updatedEventCache = [[FCacheNode alloc] initWithIndexedNode:eventSnap - isFullyInitialized:complete - isFiltered:filtered]; - return [[FViewCache alloc] initWithEventCache:updatedEventCache serverCache:self.cachedServerSnap]; +- (FViewCache *)updateEventSnap:(FIndexedNode *)eventSnap + isComplete:(BOOL)complete + isFiltered:(BOOL)filtered { + FCacheNode *updatedEventCache = + [[FCacheNode alloc] initWithIndexedNode:eventSnap + isFullyInitialized:complete + isFiltered:filtered]; + return [[FViewCache alloc] initWithEventCache:updatedEventCache + serverCache:self.cachedServerSnap]; } -- (FViewCache *) updateServerSnap:(FIndexedNode *)serverSnap isComplete:(BOOL)complete isFiltered:(BOOL)filtered { - FCacheNode *updatedServerCache = [[FCacheNode alloc] initWithIndexedNode:serverSnap - isFullyInitialized:complete - isFiltered:filtered]; - return [[FViewCache alloc] initWithEventCache:self.cachedEventSnap serverCache:updatedServerCache]; +- (FViewCache *)updateServerSnap:(FIndexedNode *)serverSnap + isComplete:(BOOL)complete + isFiltered:(BOOL)filtered { + FCacheNode *updatedServerCache = + [[FCacheNode alloc] initWithIndexedNode:serverSnap + isFullyInitialized:complete + isFiltered:filtered]; + return [[FViewCache alloc] initWithEventCache:self.cachedEventSnap + serverCache:updatedServerCache]; } -- (id) completeEventSnap { - return (self.cachedEventSnap.isFullyInitialized) ? self.cachedEventSnap.node : nil; +- (id)completeEventSnap { + return (self.cachedEventSnap.isFullyInitialized) ? self.cachedEventSnap.node + : nil; } -- (id) completeServerSnap { - return (self.cachedServerSnap.isFullyInitialized) ? self.cachedServerSnap.node : nil; +- (id)completeServerSnap { + return (self.cachedServerSnap.isFullyInitialized) + ? self.cachedServerSnap.node + : nil; } - @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FChildChangeAccumulator.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FChildChangeAccumulator.h index 59b0a85..bf25163 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FChildChangeAccumulator.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FChildChangeAccumulator.h @@ -18,11 +18,10 @@ @class FChange; - @interface FChildChangeAccumulator : NSObject -- (id) init; -- (void) trackChildChange:(FChange *)change; -- (NSArray *) changes; +- (id)init; +- (void)trackChildChange:(FChange *)change; +- (NSArray *)changes; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FChildChangeAccumulator.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FChildChangeAccumulator.m index e43fd7c..e35c2e2 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FChildChangeAccumulator.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FChildChangeAccumulator.m @@ -19,12 +19,12 @@ #import "FIndex.h" @interface FChildChangeAccumulator () -@property (nonatomic, strong) NSMutableDictionary *changeMap; +@property(nonatomic, strong) NSMutableDictionary *changeMap; @end @implementation FChildChangeAccumulator -- (id) init { +- (id)init { self = [super init]; if (self) { self.changeMap = [[NSMutableDictionary alloc] init]; @@ -32,48 +32,67 @@ - (id) init { return self; } -- (void) trackChildChange:(FChange *)change { +- (void)trackChildChange:(FChange *)change { FIRDataEventType type = change.type; NSString *childKey = change.childKey; - NSAssert(type == FIRDataEventTypeChildAdded || type == FIRDataEventTypeChildChanged || type == FIRDataEventTypeChildRemoved, @"Only child changes supported for tracking."); - NSAssert(![change.childKey isEqualToString:@".priority"], @"Changes not tracked on priority"); + NSAssert(type == FIRDataEventTypeChildAdded || + type == FIRDataEventTypeChildChanged || + type == FIRDataEventTypeChildRemoved, + @"Only child changes supported for tracking."); + NSAssert(![change.childKey isEqualToString:@".priority"], + @"Changes not tracked on priority"); if (self.changeMap[childKey] != nil) { FChange *oldChange = [self.changeMap objectForKey:childKey]; FIRDataEventType oldType = oldChange.type; - if (type == FIRDataEventTypeChildAdded && oldType == FIRDataEventTypeChildRemoved) { - FChange *newChange = [[FChange alloc] initWithType:FIRDataEventTypeChildChanged - indexedNode:change.indexedNode - childKey:childKey - oldIndexedNode:oldChange.indexedNode]; + if (type == FIRDataEventTypeChildAdded && + oldType == FIRDataEventTypeChildRemoved) { + FChange *newChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildChanged + indexedNode:change.indexedNode + childKey:childKey + oldIndexedNode:oldChange.indexedNode]; [self.changeMap setObject:newChange forKey:childKey]; - } else if (type == FIRDataEventTypeChildRemoved && oldType == FIRDataEventTypeChildAdded) { + } else if (type == FIRDataEventTypeChildRemoved && + oldType == FIRDataEventTypeChildAdded) { [self.changeMap removeObjectForKey:childKey]; - } else if (type == FIRDataEventTypeChildRemoved && oldType == FIRDataEventTypeChildChanged) { - FChange *newChange = [[FChange alloc] initWithType:FIRDataEventTypeChildRemoved - indexedNode:oldChange.oldIndexedNode - childKey:childKey]; + } else if (type == FIRDataEventTypeChildRemoved && + oldType == FIRDataEventTypeChildChanged) { + FChange *newChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildRemoved + indexedNode:oldChange.oldIndexedNode + childKey:childKey]; [self.changeMap setObject:newChange forKey:childKey]; - } else if (type == FIRDataEventTypeChildChanged && oldType == FIRDataEventTypeChildAdded) { - FChange *newChange = [[FChange alloc] initWithType:FIRDataEventTypeChildAdded - indexedNode:change.indexedNode - childKey:childKey]; + } else if (type == FIRDataEventTypeChildChanged && + oldType == FIRDataEventTypeChildAdded) { + FChange *newChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildAdded + indexedNode:change.indexedNode + childKey:childKey]; [self.changeMap setObject:newChange forKey:childKey]; - } else if (type == FIRDataEventTypeChildChanged && oldType == FIRDataEventTypeChildChanged) { - FChange *newChange = [[FChange alloc] initWithType:FIRDataEventTypeChildChanged - indexedNode:change.indexedNode - childKey:childKey - oldIndexedNode:oldChange.oldIndexedNode]; + } else if (type == FIRDataEventTypeChildChanged && + oldType == FIRDataEventTypeChildChanged) { + FChange *newChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildChanged + indexedNode:change.indexedNode + childKey:childKey + oldIndexedNode:oldChange.oldIndexedNode]; [self.changeMap setObject:newChange forKey:childKey]; } else { - NSString *reason = [NSString stringWithFormat:@"Illegal combination of changes: %@ occurred after %@", change, oldChange]; - @throw [[NSException alloc] initWithName:@"FirebaseDatabaseInternalError" reason:reason userInfo:nil]; + NSString *reason = [NSString + stringWithFormat: + @"Illegal combination of changes: %@ occurred after %@", + change, oldChange]; + @throw [[NSException alloc] + initWithName:@"FirebaseDatabaseInternalError" + reason:reason + userInfo:nil]; } } else { [self.changeMap setObject:change forKey:childKey]; } } -- (NSArray *) changes { +- (NSArray *)changes { return [self.changeMap allValues]; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FCompleteChildSource.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FCompleteChildSource.h index 4e99045..0c04bc1 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FCompleteChildSource.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FCompleteChildSource.h @@ -20,9 +20,11 @@ @class FNamedNode; @protocol FIndex; -@protocol FCompleteChildSource +@protocol FCompleteChildSource -- (id) completeChild:(NSString *)childKey; -- (FNamedNode *) childByIndex:(id)index afterChild:(FNamedNode *)child isReverse:(BOOL)reverse; +- (id)completeChild:(NSString *)childKey; +- (FNamedNode *)childByIndex:(id)index + afterChild:(FNamedNode *)child + isReverse:(BOOL)reverse; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FIndexedFilter.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FIndexedFilter.h index 5081a77..291e79a 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FIndexedFilter.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FIndexedFilter.h @@ -14,14 +14,13 @@ * limitations under the License. */ -#import #import "FNodeFilter.h" +#import @protocol FIndex; +@interface FIndexedFilter : NSObject -@interface FIndexedFilter : NSObject - -- (id) initWithIndex:(id)theIndex; +- (id)initWithIndex:(id)theIndex; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FIndexedFilter.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FIndexedFilter.m index 44c411c..f49af79 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FIndexedFilter.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FIndexedFilter.m @@ -14,22 +14,22 @@ * limitations under the License. */ -#import "FNode.h" #import "FIndexedFilter.h" -#import "FChildChangeAccumulator.h" -#import "FIndex.h" #import "FChange.h" +#import "FChildChangeAccumulator.h" #import "FChildrenNode.h" -#import "FKeyIndex.h" #import "FEmptyNode.h" +#import "FIndex.h" #import "FIndexedNode.h" +#import "FKeyIndex.h" +#import "FNode.h" @interface FIndexedFilter () -@property (nonatomic, strong, readwrite) id index; +@property(nonatomic, strong, readwrite) id index; @end @implementation FIndexedFilter -- (id) initWithIndex:(id)theIndex { +- (id)initWithIndex:(id)theIndex { self = [super init]; if (self) { self.index = theIndex; @@ -42,22 +42,26 @@ - (FIndexedNode *)updateChildIn:(FIndexedNode *)indexedNode newChild:(id)newChildSnap affectedPath:(FPath *)affectedPath fromSource:(id)source - accumulator:(FChildChangeAccumulator *)optChangeAccumulator -{ - NSAssert([indexedNode hasIndex:self.index], @"The index in FIndexedNode must match the index of the filter"); + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + NSAssert([indexedNode hasIndex:self.index], + @"The index in FIndexedNode must match the index of the filter"); id node = indexedNode.node; id oldChildSnap = [node getImmediateChild:childKey]; // Check if anything actually changed. - if ([[oldChildSnap getChild:affectedPath] isEqual:[newChildSnap getChild:affectedPath]]) { - // There's an edge case where a child can enter or leave the view because affectedPath was set to null. - // In this case, affectedPath will appear null in both the old and new snapshots. So we need - // to avoid treating these cases as "nothing changed." + if ([[oldChildSnap getChild:affectedPath] + isEqual:[newChildSnap getChild:affectedPath]]) { + // There's an edge case where a child can enter or leave the view + // because affectedPath was set to null. In this case, affectedPath will + // appear null in both the old and new snapshots. So we need to avoid + // treating these cases as "nothing changed." if (oldChildSnap.isEmpty == newChildSnap.isEmpty) { - // Nothing changed. - #ifdef DEBUG - NSAssert([oldChildSnap isEqual:newChildSnap], @"Old and new snapshots should be equal."); - #endif +// Nothing changed. +#ifdef DEBUG + NSAssert([oldChildSnap isEqual:newChildSnap], + @"Old and new snapshots should be equal."); +#endif return indexedNode; } @@ -65,23 +69,28 @@ - (FIndexedNode *)updateChildIn:(FIndexedNode *)indexedNode if (optChangeAccumulator) { if (newChildSnap.isEmpty) { if ([node hasChild:childKey]) { - FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildRemoved - indexedNode:[FIndexedNode indexedNodeWithNode:oldChildSnap] - childKey:childKey]; + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildRemoved + indexedNode:[FIndexedNode indexedNodeWithNode:oldChildSnap] + childKey:childKey]; [optChangeAccumulator trackChildChange:change]; } else { - NSAssert(node.isLeafNode, @"A child remove without an old child only makes sense on a leaf node."); + NSAssert(node.isLeafNode, + @"A child remove without an old child only makes " + @"sense on a leaf node."); } } else if (oldChildSnap.isEmpty) { - FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildAdded - indexedNode:[FIndexedNode indexedNodeWithNode:newChildSnap] - childKey:childKey]; + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildAdded + indexedNode:[FIndexedNode indexedNodeWithNode:newChildSnap] + childKey:childKey]; [optChangeAccumulator trackChildChange:change]; } else { - FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildChanged - indexedNode:[FIndexedNode indexedNodeWithNode:newChildSnap] - childKey:childKey - oldIndexedNode:[FIndexedNode indexedNodeWithNode:oldChildSnap]]; + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildChanged + indexedNode:[FIndexedNode indexedNodeWithNode:newChildSnap] + childKey:childKey + oldIndexedNode:[FIndexedNode indexedNodeWithNode:oldChildSnap]]; [optChangeAccumulator trackChildChange:change]; } } @@ -94,41 +103,49 @@ - (FIndexedNode *)updateChildIn:(FIndexedNode *)indexedNode - (FIndexedNode *)updateFullNode:(FIndexedNode *)oldSnap withNewNode:(FIndexedNode *)newSnap - accumulator:(FChildChangeAccumulator *)optChangeAccumulator -{ + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { if (optChangeAccumulator) { - [oldSnap.node enumerateChildrenUsingBlock:^(NSString *childKey, id childNode, BOOL *stop) { - if (![newSnap.node hasChild:childKey]) { - FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildRemoved - indexedNode:[FIndexedNode indexedNodeWithNode:childNode] - childKey:childKey]; - [optChangeAccumulator trackChildChange:change]; - } + [oldSnap.node enumerateChildrenUsingBlock:^( + NSString *childKey, id childNode, BOOL *stop) { + if (![newSnap.node hasChild:childKey]) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildRemoved + indexedNode:[FIndexedNode indexedNodeWithNode:childNode] + childKey:childKey]; + [optChangeAccumulator trackChildChange:change]; + } }]; - [newSnap.node enumerateChildrenUsingBlock:^(NSString *childKey, id childNode, BOOL *stop) { - if ([oldSnap.node hasChild:childKey]) { - id oldChildSnap = [oldSnap.node getImmediateChild:childKey]; - if (![oldChildSnap isEqual:childNode]) { - FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildChanged - indexedNode:[FIndexedNode indexedNodeWithNode:childNode] - childKey:childKey - oldIndexedNode:[FIndexedNode indexedNodeWithNode:oldChildSnap]]; - [optChangeAccumulator trackChildChange:change]; - } - } else { - FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildAdded - indexedNode:[FIndexedNode indexedNodeWithNode:childNode] - childKey:childKey]; - [optChangeAccumulator trackChildChange:change]; - } + [newSnap.node enumerateChildrenUsingBlock:^( + NSString *childKey, id childNode, BOOL *stop) { + if ([oldSnap.node hasChild:childKey]) { + id oldChildSnap = + [oldSnap.node getImmediateChild:childKey]; + if (![oldChildSnap isEqual:childNode]) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildChanged + indexedNode:[FIndexedNode + indexedNodeWithNode:childNode] + childKey:childKey + oldIndexedNode:[FIndexedNode + indexedNodeWithNode:oldChildSnap]]; + [optChangeAccumulator trackChildChange:change]; + } + } else { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildAdded + indexedNode:[FIndexedNode indexedNodeWithNode:childNode] + childKey:childKey]; + [optChangeAccumulator trackChildChange:change]; + } }]; } return newSnap; } -- (FIndexedNode *)updatePriority:(id)priority forNode:(FIndexedNode *)oldSnap -{ +- (FIndexedNode *)updatePriority:(id)priority + forNode:(FIndexedNode *)oldSnap { if ([oldSnap.node isEmpty]) { return oldSnap; } else { @@ -136,11 +153,11 @@ - (FIndexedNode *)updatePriority:(id)priority forNode:(FIndexedNode *)old } } -- (BOOL) filtersNodes { +- (BOOL)filtersNodes { return NO; } -- (id) indexedFilter { +- (id)indexedFilter { return self; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FLimitedFilter.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FLimitedFilter.h index 1690980..0642e72 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FLimitedFilter.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FLimitedFilter.h @@ -14,13 +14,12 @@ * limitations under the License. */ -#import #import "FNodeFilter.h" +#import @class FQueryParams; +@interface FLimitedFilter : NSObject -@interface FLimitedFilter : NSObject - -- (id) initWithQueryParams:(FQueryParams *)params; +- (id)initWithQueryParams:(FQueryParams *)params; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FLimitedFilter.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FLimitedFilter.m index 8bc6e87..fab9aab 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FLimitedFilter.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FLimitedFilter.m @@ -15,28 +15,27 @@ */ #import "FLimitedFilter.h" +#import "FChange.h" #import "FChildChangeAccumulator.h" -#import "FIndex.h" -#import "FRangedFilter.h" -#import "FQueryParams.h" -#import "FQueryParams.h" -#import "FNamedNode.h" -#import "FEmptyNode.h" #import "FChildrenNode.h" #import "FCompleteChildSource.h" -#import "FChange.h" +#import "FEmptyNode.h" +#import "FIndex.h" +#import "FNamedNode.h" +#import "FQueryParams.h" +#import "FRangedFilter.h" #import "FTreeSortedDictionary.h" @interface FLimitedFilter () -@property (nonatomic, strong) FRangedFilter *rangedFilter; -@property (nonatomic, strong, readwrite) id index; -@property (nonatomic) NSInteger limit; -@property (nonatomic) BOOL reverse; +@property(nonatomic, strong) FRangedFilter *rangedFilter; +@property(nonatomic, strong, readwrite) id index; +@property(nonatomic) NSInteger limit; +@property(nonatomic) BOOL reverse; @end @implementation FLimitedFilter -- (id) initWithQueryParams:(FQueryParams *)params { +- (id)initWithQueryParams:(FQueryParams *)params { self = [super init]; if (self) { self.rangedFilter = [[FRangedFilter alloc] initWithQueryParams:params]; @@ -47,14 +46,13 @@ - (id) initWithQueryParams:(FQueryParams *)params { return self; } - - (FIndexedNode *)updateChildIn:(FIndexedNode *)oldSnap forChildKey:(NSString *)childKey newChild:(id)newChildSnap affectedPath:(FPath *)affectedPath fromSource:(id)source - accumulator:(FChildChangeAccumulator *)optChangeAccumulator -{ + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { if (![self.rangedFilter matchesKey:childKey andNode:newChildSnap]) { newChildSnap = [FEmptyNode emptyNode]; } @@ -62,12 +60,13 @@ - (FIndexedNode *)updateChildIn:(FIndexedNode *)oldSnap // No change return oldSnap; } else if (oldSnap.node.numChildren < self.limit) { - return [[self.rangedFilter indexedFilter] updateChildIn:oldSnap - forChildKey:childKey - newChild:newChildSnap - affectedPath:affectedPath - fromSource:source - accumulator:optChangeAccumulator]; + return [[self.rangedFilter indexedFilter] + updateChildIn:oldSnap + forChildKey:childKey + newChild:newChildSnap + affectedPath:affectedPath + fromSource:source + accumulator:optChangeAccumulator]; } else { return [self fullLimitUpdateNode:oldSnap forChildKey:childKey @@ -81,67 +80,91 @@ - (FIndexedNode *)fullLimitUpdateNode:(FIndexedNode *)oldIndexed forChildKey:(NSString *)childKey newChild:(id)newChildSnap fromSource:(id)source - accumulator:(FChildChangeAccumulator *)optChangeAccumulator -{ - NSAssert(oldIndexed.node.numChildren == self.limit, @"Should have number of children equal to limit."); + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + NSAssert(oldIndexed.node.numChildren == self.limit, + @"Should have number of children equal to limit."); - FNamedNode *windowBoundary = self.reverse ? oldIndexed.firstChild : oldIndexed.lastChild; + FNamedNode *windowBoundary = + self.reverse ? oldIndexed.firstChild : oldIndexed.lastChild; BOOL inRange = [self.rangedFilter matchesKey:childKey andNode:newChildSnap]; if ([oldIndexed.node hasChild:childKey]) { - // `childKey` was already in `oldSnap`. Figure out if it remains in the window or needs to be replaced. + // `childKey` was already in `oldSnap`. Figure out if it remains in the + // window or needs to be replaced. id oldChildSnap = [oldIndexed.node getImmediateChild:childKey]; - // In case the `newChildSnap` falls outside the window, get the `nextChild` that might replace it. - FNamedNode *nextChild = [source childByIndex:self.index afterChild:windowBoundary isReverse:(BOOL)self.reverse]; + // In case the `newChildSnap` falls outside the window, get the + // `nextChild` that might replace it. + FNamedNode *nextChild = [source childByIndex:self.index + afterChild:windowBoundary + isReverse:(BOOL)self.reverse]; if (nextChild != nil && ([nextChild.name isEqualToString:childKey] || [oldIndexed.node hasChild:nextChild.name])) { - // There is a weird edge case where a node is updated as part of a merge in the write tree, but hasn't - // been applied to the limited filter yet. Ignore this next child which will be updated later in + // There is a weird edge case where a node is updated as part of a + // merge in the write tree, but hasn't been applied to the limited + // filter yet. Ignore this next child which will be updated later in // the limited filter... - nextChild = [source childByIndex:self.index afterChild:nextChild isReverse:self.reverse]; + nextChild = [source childByIndex:self.index + afterChild:nextChild + isReverse:self.reverse]; } - - - // Figure out if `newChildSnap` is in range and ordered before `nextChild` + // Figure out if `newChildSnap` is in range and ordered before + // `nextChild` BOOL remainsInWindow = inRange && !newChildSnap.isEmpty; - remainsInWindow = remainsInWindow && (!nextChild || [self.index compareKey:nextChild.name - andNode:nextChild.node - toOtherKey:childKey - andNode:newChildSnap - reverse:self.reverse] >= NSOrderedSame); + remainsInWindow = remainsInWindow && + (!nextChild || [self.index compareKey:nextChild.name + andNode:nextChild.node + toOtherKey:childKey + andNode:newChildSnap + reverse:self.reverse] >= + NSOrderedSame); if (remainsInWindow) { - // `newChildSnap` is ordered before `nextChild`, so it's a child changed event + // `newChildSnap` is ordered before `nextChild`, so it's a child + // changed event if (optChangeAccumulator != nil) { - FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildChanged - indexedNode:[FIndexedNode indexedNodeWithNode:newChildSnap] - childKey:childKey - oldIndexedNode:[FIndexedNode indexedNodeWithNode:oldChildSnap]]; + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildChanged + indexedNode:[FIndexedNode + indexedNodeWithNode:newChildSnap] + childKey:childKey + oldIndexedNode:[FIndexedNode + indexedNodeWithNode:oldChildSnap]]; [optChangeAccumulator trackChildChange:change]; } return [oldIndexed updateChild:childKey withNewChild:newChildSnap]; } else { - // `newChildSnap` is ordered after `nextChild`, so it's a child removed event + // `newChildSnap` is ordered after `nextChild`, so it's a child + // removed event if (optChangeAccumulator != nil) { - FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildRemoved - indexedNode:[FIndexedNode indexedNodeWithNode:oldChildSnap] - childKey:childKey]; + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildRemoved + indexedNode:[FIndexedNode indexedNodeWithNode:oldChildSnap] + childKey:childKey]; [optChangeAccumulator trackChildChange:change]; } - FIndexedNode *newIndexed = [oldIndexed updateChild:childKey withNewChild:[FEmptyNode emptyNode]]; + FIndexedNode *newIndexed = + [oldIndexed updateChild:childKey + withNewChild:[FEmptyNode emptyNode]]; - // We need to check if the `nextChild` is actually in range before adding it - BOOL nextChildInRange = (nextChild != nil) && [self.rangedFilter matchesKey:nextChild.name - andNode:nextChild.node]; + // We need to check if the `nextChild` is actually in range before + // adding it + BOOL nextChildInRange = + (nextChild != nil) && + [self.rangedFilter matchesKey:nextChild.name + andNode:nextChild.node]; if (nextChildInRange) { if (optChangeAccumulator != nil) { - FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildAdded - indexedNode:[FIndexedNode indexedNodeWithNode:nextChild.node] - childKey:nextChild.name]; + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildAdded + indexedNode:[FIndexedNode + indexedNodeWithNode:nextChild.node] + childKey:nextChild.name]; [optChangeAccumulator trackChildChange:change]; } - return [newIndexed updateChild:nextChild.name withNewChild:nextChild.node]; + return [newIndexed updateChild:nextChild.name + withNewChild:nextChild.node]; } else { return newIndexed; } @@ -150,42 +173,50 @@ - (FIndexedNode *)fullLimitUpdateNode:(FIndexedNode *)oldIndexed // We're deleting a node, but it was not in the window, so ignore it. return oldIndexed; } else if (inRange) { - // `newChildSnap` is in range, but was ordered after `windowBoundary`. If this has changed, we bump out the - // `windowBoundary` and add the `newChildSnap` + // `newChildSnap` is in range, but was ordered after `windowBoundary`. + // If this has changed, we bump out the `windowBoundary` and add the + // `newChildSnap` if ([self.index compareKey:windowBoundary.name andNode:windowBoundary.node toOtherKey:childKey andNode:newChildSnap reverse:self.reverse] >= NSOrderedSame) { if (optChangeAccumulator != nil) { - FChange *removedChange = [[FChange alloc] initWithType:FIRDataEventTypeChildRemoved - indexedNode:[FIndexedNode indexedNodeWithNode:windowBoundary.node] - childKey:windowBoundary.name]; - FChange *addedChange = [[FChange alloc] initWithType:FIRDataEventTypeChildAdded - indexedNode:[FIndexedNode indexedNodeWithNode:newChildSnap] - childKey:childKey]; + FChange *removedChange = [[FChange alloc] + initWithType:FIRDataEventTypeChildRemoved + indexedNode:[FIndexedNode + indexedNodeWithNode:windowBoundary.node] + childKey:windowBoundary.name]; + FChange *addedChange = [[FChange alloc] + initWithType:FIRDataEventTypeChildAdded + indexedNode:[FIndexedNode indexedNodeWithNode:newChildSnap] + childKey:childKey]; [optChangeAccumulator trackChildChange:removedChange]; [optChangeAccumulator trackChildChange:addedChange]; } - return [[oldIndexed updateChild:childKey withNewChild:newChildSnap] updateChild:windowBoundary.name - withNewChild:[FEmptyNode emptyNode]]; + return [[oldIndexed updateChild:childKey withNewChild:newChildSnap] + updateChild:windowBoundary.name + withNewChild:[FEmptyNode emptyNode]]; } else { return oldIndexed; } } else { - // `newChildSnap` was not in range and remains not in range, so ignore it. + // `newChildSnap` was not in range and remains not in range, so ignore + // it. return oldIndexed; } } - (FIndexedNode *)updateFullNode:(FIndexedNode *)oldSnap withNewNode:(FIndexedNode *)newSnap - accumulator:(FChildChangeAccumulator *)optChangeAccumulator -{ + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { __block FIndexedNode *filtered; if (newSnap.node.isLeafNode || newSnap.node.isEmpty) { - // Make sure we have a children node with the correct index, not a leaf node - filtered = [FIndexedNode indexedNodeWithNode:[FEmptyNode emptyNode] index:self.index]; + // Make sure we have a children node with the correct index, not a leaf + // node + filtered = [FIndexedNode indexedNodeWithNode:[FEmptyNode emptyNode] + index:self.index]; } else { filtered = newSnap; // Don't support priorities on queries. @@ -201,42 +232,53 @@ - (FIndexedNode *)updateFullNode:(FIndexedNode *)oldSnap } __block BOOL foundStartPost = NO; __block NSUInteger count = 0; - [newSnap enumerateChildrenReverse:self.reverse usingBlock:^(NSString *childKey, id childNode, BOOL *stop) { - if (!foundStartPost && [self.index compareKey:startPost.name - andNode:startPost.node - toOtherKey:childKey - andNode:childNode - reverse:self.reverse] <= NSOrderedSame) { - // Start adding - foundStartPost = YES; - } - BOOL inRange = foundStartPost && count < self.limit; - inRange = inRange && [self.index compareKey:childKey - andNode:childNode - toOtherKey:endPost.name - andNode:endPost.node - reverse:self.reverse] <= NSOrderedSame; - if (inRange) { - count++; - } else { - filtered = [filtered updateChild:childKey withNewChild:[FEmptyNode emptyNode]]; - } - }]; + [newSnap + enumerateChildrenReverse:self.reverse + usingBlock:^(NSString *childKey, id childNode, + BOOL *stop) { + if (!foundStartPost && + [self.index + compareKey:startPost.name + andNode:startPost.node + toOtherKey:childKey + andNode:childNode + reverse:self.reverse] <= NSOrderedSame) { + // Start adding + foundStartPost = YES; + } + BOOL inRange = foundStartPost && count < self.limit; + inRange = inRange && + [self.index compareKey:childKey + andNode:childNode + toOtherKey:endPost.name + andNode:endPost.node + reverse:self.reverse] <= + NSOrderedSame; + if (inRange) { + count++; + } else { + filtered = [filtered + updateChild:childKey + withNewChild:[FEmptyNode emptyNode]]; + } + }]; } - return [self.indexedFilter updateFullNode:oldSnap withNewNode:filtered accumulator:optChangeAccumulator]; + return [self.indexedFilter updateFullNode:oldSnap + withNewNode:filtered + accumulator:optChangeAccumulator]; } -- (FIndexedNode *)updatePriority:(id)priority forNode:(FIndexedNode *)oldSnap -{ +- (FIndexedNode *)updatePriority:(id)priority + forNode:(FIndexedNode *)oldSnap { // Don't support priorities on queries. return oldSnap; } -- (BOOL) filtersNodes { +- (BOOL)filtersNodes { return YES; } -- (id) indexedFilter { +- (id)indexedFilter { return self.rangedFilter.indexedFilter; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FNodeFilter.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FNodeFilter.h index f29a85a..d19c6fb 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FNodeFilter.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Core/View/Filter/FNodeFilter.h @@ -24,48 +24,54 @@ @class FPath; /** -* FNodeFilter is used to update nodes and complete children of nodes while applying queries on the fly and keeping -* track of any child changes. This class does not track value changes as value changes depend on more than just the -* node itself. Different kind of queries require different kind of implementations of this interface. -*/ -@protocol FNodeFilter + * FNodeFilter is used to update nodes and complete children of nodes while + * applying queries on the fly and keeping track of any child changes. This + * class does not track value changes as value changes depend on more than just + * the node itself. Different kind of queries require different kind of + * implementations of this interface. + */ +@protocol FNodeFilter /** -* Update a single complete child in the snap. If the child equals the old child in the snap, this is a no-op. -* The method expects an indexed snap. -*/ -- (FIndexedNode *) updateChildIn:(FIndexedNode *)oldSnap - forChildKey:(NSString *)childKey - newChild:(id)newChildSnap - affectedPath:(FPath *)affectedPath - fromSource:(id)source - accumulator:(FChildChangeAccumulator *)optChangeAccumulator; + * Update a single complete child in the snap. If the child equals the old child + * in the snap, this is a no-op. The method expects an indexed snap. + */ +- (FIndexedNode *)updateChildIn:(FIndexedNode *)oldSnap + forChildKey:(NSString *)childKey + newChild:(id)newChildSnap + affectedPath:(FPath *)affectedPath + fromSource:(id)source + accumulator:(FChildChangeAccumulator *)optChangeAccumulator; /** -* Update a node in full and output any resulting change from this complete update. -*/ -- (FIndexedNode *) updateFullNode:(FIndexedNode *)oldSnap - withNewNode:(FIndexedNode *)newSnap - accumulator:(FChildChangeAccumulator *)optChangeAccumulator; + * Update a node in full and output any resulting change from this complete + * update. + */ +- (FIndexedNode *)updateFullNode:(FIndexedNode *)oldSnap + withNewNode:(FIndexedNode *)newSnap + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator; /** -* Update the priority of the root node -*/ -- (FIndexedNode *) updatePriority:(id)priority forNode:(FIndexedNode *)oldSnap; + * Update the priority of the root node + */ +- (FIndexedNode *)updatePriority:(id)priority + forNode:(FIndexedNode *)oldSnap; /** -* Returns true if children might be filtered due to query critiera -*/ -- (BOOL) filtersNodes; + * Returns true if children might be filtered due to query critiera + */ +- (BOOL)filtersNodes; /** -* Returns the index filter that this filter uses to get a NodeFilter that doesn't filter any children. -*/ -@property (nonatomic, strong, readonly) id indexedFilter; + * Returns the index filter that this filter uses to get a NodeFilter that + * doesn't filter any children. + */ +@property(nonatomic, strong, readonly) id indexedFilter; /** -* Returns the index that this filter uses -*/ -@property (nonatomic, strong, readonly) id index; + * Returns the index that this filter uses + */ +@property(nonatomic, strong, readonly) id index; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FClock.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FClock.h index 1924ad4..e85cb2a 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FClock.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FClock.h @@ -22,13 +22,13 @@ @end -@interface FSystemClock : NSObject +@interface FSystemClock : NSObject + (FSystemClock *)clock; @end -@interface FOffsetClock : NSObject +@interface FOffsetClock : NSObject - (id)initWithClock:(id)clock offset:(NSTimeInterval)offset; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FClock.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FClock.m index 2464056..5d9a9ec 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FClock.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FClock.m @@ -26,7 +26,7 @@ + (FSystemClock *)clock { static dispatch_once_t onceToken; static FSystemClock *clock; dispatch_once(&onceToken, ^{ - clock = [[FSystemClock alloc] init]; + clock = [[FSystemClock alloc] init]; }); return clock; } @@ -35,8 +35,8 @@ + (FSystemClock *)clock { @interface FOffsetClock () -@property (nonatomic, strong) id clock; -@property (nonatomic) NSTimeInterval offset; +@property(nonatomic, strong) id clock; +@property(nonatomic) NSTimeInterval offset; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FEventGenerator.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FEventGenerator.h index 1bc011b..443664e 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FEventGenerator.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FEventGenerator.h @@ -21,7 +21,8 @@ @protocol FNode; @interface FEventGenerator : NSObject -- (id) initWithQuery:(FQuerySpec *)query; -- (NSArray*) generateEventsForChanges:(NSArray*)changes eventCache:(FIndexedNode *)eventCache - eventRegistrations:(NSArray*)registrations; +- (id)initWithQuery:(FQuerySpec *)query; +- (NSArray *)generateEventsForChanges:(NSArray *)changes + eventCache:(FIndexedNode *)eventCache + eventRegistrations:(NSArray *)registrations; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FEventGenerator.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FEventGenerator.m index f6e8f47..162b0ac 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FEventGenerator.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FEventGenerator.m @@ -15,25 +15,25 @@ */ #import "FEventGenerator.h" -#import "FNode.h" +#import "FChange.h" +#import "FDataEvent.h" +#import "FEvent.h" +#import "FEventRegistration.h" #import "FIRDatabaseQuery_Private.h" +#import "FNamedNode.h" +#import "FNode.h" #import "FQueryParams.h" #import "FQuerySpec.h" -#import "FChange.h" -#import "FNamedNode.h" -#import "FEventRegistration.h" -#import "FEvent.h" -#import "FDataEvent.h" @interface FEventGenerator () -@property (nonatomic, strong) FQuerySpec *query; +@property(nonatomic, strong) FQuerySpec *query; @end /** -* An EventGenerator is used to convert "raw" changes (fb.core.view.Change) as computed by the -* CacheDiffer into actual events (fb.core.view.Event) that can be raised. See generateEventsForChanges() -* for details. -*/ + * An EventGenerator is used to convert "raw" changes (fb.core.view.Change) as + * computed by the CacheDiffer into actual events (fb.core.view.Event) that can + * be raised. See generateEventsForChanges() for details. + */ @implementation FEventGenerator - (id)initWithQuery:(FQuerySpec *)query { @@ -45,52 +45,75 @@ - (id)initWithQuery:(FQuerySpec *)query { } /** -* Given a set of raw changes (no moved events, and prevName not specified yet), and a set of EventRegistrations that -* should be notified of these changes, generate the actual events to be raised. -* -* Notes: -* - child_moved events will be synthesized at this time for any child_changed events that affect our index -* - prevName will be calculated based on the index ordering -* -* @param changes NSArray of FChange, not necessarily in order. -* @param registrations is NSArray of FEventRegistration. -* @return NSArray of FEvent. -*/ -- (NSArray *) generateEventsForChanges:(NSArray *)changes - eventCache:(FIndexedNode *)eventCache - eventRegistrations:(NSArray *)registrations -{ + * Given a set of raw changes (no moved events, and prevName not specified yet), + * and a set of EventRegistrations that should be notified of these changes, + * generate the actual events to be raised. + * + * Notes: + * - child_moved events will be synthesized at this time for any child_changed + * events that affect our index + * - prevName will be calculated based on the index ordering + * + * @param changes NSArray of FChange, not necessarily in order. + * @param registrations is NSArray of FEventRegistration. + * @return NSArray of FEvent. + */ +- (NSArray *)generateEventsForChanges:(NSArray *)changes + eventCache:(FIndexedNode *)eventCache + eventRegistrations:(NSArray *)registrations { NSMutableArray *events = [[NSMutableArray alloc] init]; - // child_moved is index-specific, so check all our child_changed events to see if we need to materialize - // child_moved events with this view's index + // child_moved is index-specific, so check all our child_changed events to + // see if we need to materialize child_moved events with this view's index NSMutableArray *moves = [[NSMutableArray alloc] init]; for (FChange *change in changes) { - if (change.type == FIRDataEventTypeChildChanged && [self.query.index indexedValueChangedBetween:change.oldIndexedNode.node - and:change.indexedNode.node]) { - FChange *moveChange = [[FChange alloc] initWithType:FIRDataEventTypeChildMoved - indexedNode:change.indexedNode - childKey:change.childKey - oldIndexedNode:nil]; + if (change.type == FIRDataEventTypeChildChanged && + [self.query.index + indexedValueChangedBetween:change.oldIndexedNode.node + and:change.indexedNode.node]) { + FChange *moveChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildMoved + indexedNode:change.indexedNode + childKey:change.childKey + oldIndexedNode:nil]; [moves addObject:moveChange]; } } - [self generateEvents:events forType:FIRDataEventTypeChildRemoved changes:changes eventCache:eventCache eventRegistrations:registrations]; - [self generateEvents:events forType:FIRDataEventTypeChildAdded changes:changes eventCache:eventCache eventRegistrations:registrations]; - [self generateEvents:events forType:FIRDataEventTypeChildMoved changes:moves eventCache:eventCache eventRegistrations:registrations]; - [self generateEvents:events forType:FIRDataEventTypeChildChanged changes:changes eventCache:eventCache eventRegistrations:registrations]; - [self generateEvents:events forType:FIRDataEventTypeValue changes:changes eventCache:eventCache eventRegistrations:registrations]; + [self generateEvents:events + forType:FIRDataEventTypeChildRemoved + changes:changes + eventCache:eventCache + eventRegistrations:registrations]; + [self generateEvents:events + forType:FIRDataEventTypeChildAdded + changes:changes + eventCache:eventCache + eventRegistrations:registrations]; + [self generateEvents:events + forType:FIRDataEventTypeChildMoved + changes:moves + eventCache:eventCache + eventRegistrations:registrations]; + [self generateEvents:events + forType:FIRDataEventTypeChildChanged + changes:changes + eventCache:eventCache + eventRegistrations:registrations]; + [self generateEvents:events + forType:FIRDataEventTypeValue + changes:changes + eventCache:eventCache + eventRegistrations:registrations]; return events; } -- (void) generateEvents:(NSMutableArray *)events - forType:(FIRDataEventType)eventType - changes:(NSArray *)changes - eventCache:(FIndexedNode *)eventCache - eventRegistrations:(NSArray *)registrations -{ +- (void)generateEvents:(NSMutableArray *)events + forType:(FIRDataEventType)eventType + changes:(NSArray *)changes + eventCache:(FIndexedNode *)eventCache + eventRegistrations:(NSArray *)registrations { NSMutableArray *filteredChanges = [[NSMutableArray alloc] init]; for (FChange *change in changes) { if (change.type == eventType) { @@ -100,39 +123,44 @@ - (void) generateEvents:(NSMutableArray *)events id index = self.query.index; - [filteredChanges sortUsingComparator:^NSComparisonResult(FChange *one, FChange *two) { - if (one.childKey == nil || two.childKey == nil) { - @throw [[NSException alloc] initWithName:@"InternalInconsistencyError" - reason:@"Should only compare child_ events" - userInfo:nil]; - } - return [index compareKey:one.childKey - andNode:one.indexedNode.node - toOtherKey:two.childKey - andNode:two.indexedNode.node]; - }]; + [filteredChanges + sortUsingComparator:^NSComparisonResult(FChange *one, FChange *two) { + if (one.childKey == nil || two.childKey == nil) { + @throw [[NSException alloc] + initWithName:@"InternalInconsistencyError" + reason:@"Should only compare child_ events" + userInfo:nil]; + } + return [index compareKey:one.childKey + andNode:one.indexedNode.node + toOtherKey:two.childKey + andNode:two.indexedNode.node]; + }]; for (FChange *change in filteredChanges) { for (id registration in registrations) { if ([registration responseTo:eventType]) { - id event = [self generateEventForChange:change registration:registration eventCache:eventCache]; + id event = [self generateEventForChange:change + registration:registration + eventCache:eventCache]; [events addObject:event]; } } } } -- (id) generateEventForChange:(FChange *)change - registration:(id)registration - eventCache:(FIndexedNode *)eventCache -{ +- (id)generateEventForChange:(FChange *)change + registration:(id)registration + eventCache:(FIndexedNode *)eventCache { FChange *materializedChange; - if (change.type == FIRDataEventTypeValue || change.type == FIRDataEventTypeChildRemoved) { + if (change.type == FIRDataEventTypeValue || + change.type == FIRDataEventTypeChildRemoved) { materializedChange = change; } else { - NSString *prevChildKey = [eventCache predecessorForChildKey:change.childKey - childNode:change.indexedNode.node - index:self.query.index]; + NSString *prevChildKey = + [eventCache predecessorForChildKey:change.childKey + childNode:change.indexedNode.node + index:self.query.index]; materializedChange = [change changeWithPrevKey:prevChildKey]; } return [registration createEventFrom:materializedChange query:self.query]; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FIRDatabaseConfig_Private.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FIRDatabaseConfig_Private.h index ac37f2e..ca2f34b 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FIRDatabaseConfig_Private.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FIRDatabaseConfig_Private.h @@ -14,17 +14,17 @@ * limitations under the License. */ -#import "FIRDatabaseConfig.h" #import "FAuthTokenProvider.h" +#import "FIRDatabaseConfig.h" @protocol FStorageEngine; @interface FIRDatabaseConfig () -@property (nonatomic, readonly) BOOL isFrozen; -@property (nonatomic, strong, readonly) NSString *sessionIdentifier; -@property (nonatomic, strong) id authTokenProvider; -@property (nonatomic, strong) id forceStorageEngine; +@property(nonatomic, readonly) BOOL isFrozen; +@property(nonatomic, strong, readonly) NSString *sessionIdentifier; +@property(nonatomic, strong) id authTokenProvider; +@property(nonatomic, strong) id forceStorageEngine; - (void)freeze; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FIRDatabaseReference.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FIRDatabaseReference.m index 3ea5992..b3c0106 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FIRDatabaseReference.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FIRDatabaseReference.m @@ -14,33 +14,36 @@ * limitations under the License. */ -#import #import "FIRDatabaseReference.h" -#import -#import "FUtilities.h" -#import "FNextPushId.h" -#import "FIRDatabaseQuery_Private.h" -#import "FValidation.h" -#import "FIRDatabaseReference_Private.h" -#import "FStringUtilities.h" -#import "FSnapshotUtilities.h" +#import "FIRDatabase.h" #import "FIRDatabaseConfig.h" #import "FIRDatabaseConfig_Private.h" +#import "FIRDatabaseQuery_Private.h" +#import "FIRDatabaseReference_Private.h" +#import "FNextPushId.h" #import "FQueryParams.h" -#import "FIRDatabase.h" +#import "FSnapshotUtilities.h" +#import "FStringUtilities.h" +#import "FUtilities.h" +#import "FValidation.h" +#import +#import @implementation FIRDatabaseReference #pragma mark - #pragma mark Constructors -- (id) initWithConfig:(FIRDatabaseConfig *)config { - FParsedUrl* parsedUrl = [FUtilities parseUrl:[[FIRApp defaultApp] options].databaseURL]; +- (id)initWithConfig:(FIRDatabaseConfig *)config { + FParsedUrl *parsedUrl = + [FUtilities parseUrl:[[FIRApp defaultApp] options].databaseURL]; [FValidation validateFrom:@"initWithUrl:" validURL:parsedUrl]; - return [self initWithRepo:[FRepoManager getRepo:parsedUrl.repoInfo config:config] path:parsedUrl.path]; + return [self initWithRepo:[FRepoManager getRepo:parsedUrl.repoInfo + config:config] + path:parsedUrl.path]; } -- (id) initWithRepo:(FRepo *)repo path:(FPath *)path { +- (id)initWithRepo:(FRepo *)repo path:(FPath *)path { return [super initWithRepo:repo path:path params:[FQueryParams defaultInstance] @@ -48,52 +51,53 @@ - (id) initWithRepo:(FRepo *)repo path:(FPath *)path { priorityMethodCalled:NO]; } - #pragma mark - #pragma mark Ancillary methods -- (nullable NSString *) key { - if([self.path isEmpty]) { +- (nullable NSString *)key { + if ([self.path isEmpty]) { return nil; - } - else { + } else { return [self.path getBack]; } } -- (FIRDatabase *) database { +- (FIRDatabase *)database { return self.repo.database; } -- (FIRDatabaseReference *) parent { - FPath* parentPath = [self.path parent]; - FIRDatabaseReference * parent = nil; - if (parentPath != nil ) { - parent = [[FIRDatabaseReference alloc] initWithRepo:self.repo path:parentPath]; +- (FIRDatabaseReference *)parent { + FPath *parentPath = [self.path parent]; + FIRDatabaseReference *parent = nil; + if (parentPath != nil) { + parent = [[FIRDatabaseReference alloc] initWithRepo:self.repo + path:parentPath]; } return parent; } -- (NSString *) URL { - FIRDatabaseReference * parent = [self parent]; - return parent == nil ? [self.repo description] : [NSString stringWithFormat:@"%@/%@", [parent description], [FStringUtilities urlEncoded:self.key]]; +- (NSString *)URL { + FIRDatabaseReference *parent = [self parent]; + return parent == nil + ? [self.repo description] + : [NSString + stringWithFormat:@"%@/%@", [parent description], + [FStringUtilities urlEncoded:self.key]]; } -- (NSString *) description { +- (NSString *)description { return [self URL]; } -- (FIRDatabaseReference *) root { - return [[FIRDatabaseReference alloc] initWithRepo:self.repo path:[[FPath alloc] initWith:@""]]; +- (FIRDatabaseReference *)root { + return [[FIRDatabaseReference alloc] + initWithRepo:self.repo + path:[[FPath alloc] initWith:@""]]; } #pragma mark - #pragma mark Child methods -- (FIRDatabaseReference *)childByAppendingPath:(NSString *)pathString { - return [self child:pathString]; -} - - (FIRDatabaseReference *)child:(NSString *)pathString { if ([self.path getFront] == nil) { // we're at the root @@ -101,234 +105,344 @@ - (FIRDatabaseReference *)child:(NSString *)pathString { } else { [FValidation validateFrom:@"child:" validPathString:pathString]; } - FPath* path = [self.path childFromString:pathString]; - FIRDatabaseReference * firebaseRef = [[FIRDatabaseReference alloc] initWithRepo:self.repo path:path]; + FPath *path = [self.path childFromString:pathString]; + FIRDatabaseReference *firebaseRef = + [[FIRDatabaseReference alloc] initWithRepo:self.repo path:path]; return firebaseRef; } -- (FIRDatabaseReference *) childByAutoId { +- (FIRDatabaseReference *)childByAutoId { [FValidation validateFrom:@"childByAutoId:" writablePath:self.path]; - NSString* name = [FNextPushId get:self.repo.serverTime]; + NSString *name = [FNextPushId get:self.repo.serverTime]; return [self child:name]; } #pragma mark - #pragma mark Basic write methods -- (void) setValue:(id)value { - [self setValueInternal:value andPriority:nil withCompletionBlock:nil from:@"setValue:"]; +- (void)setValue:(id)value { + [self setValueInternal:value + andPriority:nil + withCompletionBlock:nil + from:@"setValue:"]; } -- (void) setValue:(id)value withCompletionBlock:(fbt_void_nserror_ref)block { - [self setValueInternal:value andPriority:nil withCompletionBlock:block from:@"setValue:withCompletionBlock:"]; +- (void)setValue:(id)value withCompletionBlock:(fbt_void_nserror_ref)block { + [self setValueInternal:value + andPriority:nil + withCompletionBlock:block + from:@"setValue:withCompletionBlock:"]; } -- (void) setValue:(id)value andPriority:(id)priority { - [self setValueInternal:value andPriority:priority withCompletionBlock:nil from:@"setValue:andPriority:"]; +- (void)setValue:(id)value andPriority:(id)priority { + [self setValueInternal:value + andPriority:priority + withCompletionBlock:nil + from:@"setValue:andPriority:"]; } -- (void) setValue:(id)value andPriority:(id)priority withCompletionBlock:(fbt_void_nserror_ref)block { - [self setValueInternal:value andPriority:priority withCompletionBlock:block from:@"setValue:andPriority:withCompletionBlock:"]; +- (void)setValue:(id)value + andPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block { + [self setValueInternal:value + andPriority:priority + withCompletionBlock:block + from:@"setValue:andPriority:withCompletionBlock:"]; } -- (void) setValueInternal:(id)value andPriority:(id)priority withCompletionBlock:(fbt_void_nserror_ref)block from:(NSString*)fn { +- (void)setValueInternal:(id)value + andPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { [FValidation validateFrom:fn writablePath:self.path]; fbt_void_nserror_ref userCallback = [block copy]; - id newNode = [FSnapshotUtilities nodeFrom:value priority:priority withValidationFrom:fn]; + id newNode = [FSnapshotUtilities nodeFrom:value + priority:priority + withValidationFrom:fn]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo set:self.path withNode:newNode withCallback:userCallback]; + [self.repo set:self.path withNode:newNode withCallback:userCallback]; }); } - -- (void) removeValue { - [self setValueInternal:nil andPriority:nil withCompletionBlock:nil from:@"removeValue:"]; +- (void)removeValue { + [self setValueInternal:nil + andPriority:nil + withCompletionBlock:nil + from:@"removeValue:"]; } -- (void) removeValueWithCompletionBlock:(fbt_void_nserror_ref)block { - [self setValueInternal:nil andPriority:nil withCompletionBlock:block from:@"removeValueWithCompletionBlock:"]; +- (void)removeValueWithCompletionBlock:(fbt_void_nserror_ref)block { + [self setValueInternal:nil + andPriority:nil + withCompletionBlock:block + from:@"removeValueWithCompletionBlock:"]; } - -- (void) setPriority:(id)priority { - [self setPriorityInternal:priority withCompletionBlock:nil from:@"setPriority:"]; +- (void)setPriority:(id)priority { + [self setPriorityInternal:priority + withCompletionBlock:nil + from:@"setPriority:"]; } -- (void) setPriority:(id)priority withCompletionBlock:(fbt_void_nserror_ref)block { +- (void)setPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block { - [self setPriorityInternal:priority withCompletionBlock:block from:@"setPriority:withCompletionBlock:"]; + [self setPriorityInternal:priority + withCompletionBlock:block + from:@"setPriority:withCompletionBlock:"]; } -- (void) setPriorityInternal:(id)priority withCompletionBlock:(fbt_void_nserror_ref)block from:(NSString*)fn { +- (void)setPriorityInternal:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { [FValidation validateFrom:fn writablePath:self.path]; fbt_void_nserror_ref userCallback = [block copy]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo set:[self.path childFromString:@".priority"] withNode:[FSnapshotUtilities nodeFrom:priority] withCallback:userCallback]; + [self.repo set:[self.path childFromString:@".priority"] + withNode:[FSnapshotUtilities nodeFrom:priority] + withCallback:userCallback]; }); } - -- (void) updateChildValues:(NSDictionary *)values { - [self updateChildValuesInternal:values withCompletionBlock:nil from:@"updateChildValues:"]; +- (void)updateChildValues:(NSDictionary *)values { + [self updateChildValuesInternal:values + withCompletionBlock:nil + from:@"updateChildValues:"]; } -- (void) updateChildValues:(NSDictionary *)values withCompletionBlock:(fbt_void_nserror_ref)block { - [self updateChildValuesInternal:values withCompletionBlock:block from:@"updateChildValues:withCompletionBlock:"]; +- (void)updateChildValues:(NSDictionary *)values + withCompletionBlock:(fbt_void_nserror_ref)block { + [self updateChildValuesInternal:values + withCompletionBlock:block + from:@"updateChildValues:withCompletionBlock:"]; } -- (void) updateChildValuesInternal:(NSDictionary *)values withCompletionBlock:(fbt_void_nserror_ref)block from:(NSString*)fn { +- (void)updateChildValuesInternal:(NSDictionary *)values + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { [FValidation validateFrom:fn writablePath:self.path]; - FCompoundWrite *merge = [FSnapshotUtilities compoundWriteFromDictionary:values withValidationFrom:fn]; + FCompoundWrite *merge = + [FSnapshotUtilities compoundWriteFromDictionary:values + withValidationFrom:fn]; fbt_void_nserror_ref userCallback = [block copy]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo update:self.path withNodes:merge withCallback:userCallback]; + [self.repo update:self.path withNodes:merge withCallback:userCallback]; }); } #pragma mark - #pragma mark Disconnect Operations -- (void) onDisconnectSetValue:(id)value { - [self onDisconnectSetValueInternal:value andPriority:nil withCompletionBlock:nil from:@"onDisconnectSetValue:"]; +- (void)onDisconnectSetValue:(id)value { + [self onDisconnectSetValueInternal:value + andPriority:nil + withCompletionBlock:nil + from:@"onDisconnectSetValue:"]; } -- (void) onDisconnectSetValue:(id)value withCompletionBlock:(fbt_void_nserror_ref)block { - [self onDisconnectSetValueInternal:value andPriority:nil withCompletionBlock:block from:@"onDisconnectSetValue:withCompletionBlock:"]; +- (void)onDisconnectSetValue:(id)value + withCompletionBlock:(fbt_void_nserror_ref)block { + [self onDisconnectSetValueInternal:value + andPriority:nil + withCompletionBlock:block + from:@"onDisconnectSetValue:" + @"withCompletionBlock:"]; } -- (void) onDisconnectSetValue:(id)value andPriority:(id)priority { - [self onDisconnectSetValueInternal:value andPriority:priority withCompletionBlock:nil from:@"onDisconnectSetValue:andPriority:"]; +- (void)onDisconnectSetValue:(id)value andPriority:(id)priority { + [self onDisconnectSetValueInternal:value + andPriority:priority + withCompletionBlock:nil + from:@"onDisconnectSetValue:andPriority:"]; } -- (void) onDisconnectSetValue:(id)value andPriority:(id)priority withCompletionBlock:(fbt_void_nserror_ref)block { - [self onDisconnectSetValueInternal:value andPriority:priority withCompletionBlock:block from:@"onDisconnectSetValue:andPriority:withCompletionBlock:"]; +- (void)onDisconnectSetValue:(id)value + andPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block { + [self onDisconnectSetValueInternal:value + andPriority:priority + withCompletionBlock:block + from:@"onDisconnectSetValue:andPriority:" + @"withCompletionBlock:"]; } -- (void) onDisconnectSetValueInternal:(id)value andPriority:(id)priority withCompletionBlock:(fbt_void_nserror_ref)block from:(NSString*)fn { +- (void)onDisconnectSetValueInternal:(id)value + andPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { [FValidation validateFrom:fn writablePath:self.path]; - id newNodeUnresolved = [FSnapshotUtilities nodeFrom:value priority:priority withValidationFrom:fn]; + id newNodeUnresolved = [FSnapshotUtilities nodeFrom:value + priority:priority + withValidationFrom:fn]; fbt_void_nserror_ref userCallback = [block copy]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo onDisconnectSet:self.path withNode:newNodeUnresolved withCallback:userCallback]; + [self.repo onDisconnectSet:self.path + withNode:newNodeUnresolved + withCallback:userCallback]; }); } - -- (void) onDisconnectRemoveValue { - [self onDisconnectSetValueInternal:nil andPriority:nil withCompletionBlock:nil from:@"onDisconnectRemoveValue:"]; +- (void)onDisconnectRemoveValue { + [self onDisconnectSetValueInternal:nil + andPriority:nil + withCompletionBlock:nil + from:@"onDisconnectRemoveValue:"]; } -- (void) onDisconnectRemoveValueWithCompletionBlock:(fbt_void_nserror_ref)block { - [self onDisconnectSetValueInternal:nil andPriority:nil withCompletionBlock:block from:@"onDisconnectRemoveValueWithCompletionBlock:"]; +- (void)onDisconnectRemoveValueWithCompletionBlock:(fbt_void_nserror_ref)block { + [self onDisconnectSetValueInternal:nil + andPriority:nil + withCompletionBlock:block + from:@"onDisconnectRemoveValueWithCompletionB" + @"lock:"]; } - -- (void) onDisconnectUpdateChildValues:(NSDictionary *)values { - [self onDisconnectUpdateChildValuesInternal:values withCompletionBlock:nil from:@"onDisconnectUpdateChildValues:"]; +- (void)onDisconnectUpdateChildValues:(NSDictionary *)values { + [self + onDisconnectUpdateChildValuesInternal:values + withCompletionBlock:nil + from: + @"onDisconnectUpdateChildValues:"]; } -- (void) onDisconnectUpdateChildValues:(NSDictionary *)values withCompletionBlock:(fbt_void_nserror_ref)block { - [self onDisconnectUpdateChildValuesInternal:values withCompletionBlock:block from:@"onDisconnectUpdateChildValues:withCompletionBlock:"]; +- (void)onDisconnectUpdateChildValues:(NSDictionary *)values + withCompletionBlock:(fbt_void_nserror_ref)block { + [self onDisconnectUpdateChildValuesInternal:values + withCompletionBlock:block + from:@"onDisconnectUpdateChildValues" + @":withCompletionBlock:"]; } -- (void) onDisconnectUpdateChildValuesInternal:(NSDictionary *)values withCompletionBlock:(fbt_void_nserror_ref)block from:(NSString*)fn { +- (void)onDisconnectUpdateChildValuesInternal:(NSDictionary *)values + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { [FValidation validateFrom:fn writablePath:self.path]; - FCompoundWrite *merge = [FSnapshotUtilities compoundWriteFromDictionary:values withValidationFrom:fn]; + FCompoundWrite *merge = + [FSnapshotUtilities compoundWriteFromDictionary:values + withValidationFrom:fn]; fbt_void_nserror_ref userCallback = [block copy]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo onDisconnectUpdate:self.path withNodes:merge withCallback:userCallback]; + [self.repo onDisconnectUpdate:self.path + withNodes:merge + withCallback:userCallback]; }); } - -- (void) cancelDisconnectOperations { +- (void)cancelDisconnectOperations { [self cancelDisconnectOperationsWithCompletionBlock:nil]; } -- (void) cancelDisconnectOperationsWithCompletionBlock:(fbt_void_nserror_ref)block { +- (void)cancelDisconnectOperationsWithCompletionBlock: + (fbt_void_nserror_ref)block { fbt_void_nserror_ref callback = nil; if (block != nil) { callback = [block copy]; } dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo onDisconnectCancel:self.path withCallback:callback]; + [self.repo onDisconnectCancel:self.path withCallback:callback]; }); } #pragma mark - #pragma mark Connection management methods -+ (void) goOffline { ++ (void)goOffline { [FRepoManager interruptAll]; } -+ (void) goOnline { ++ (void)goOnline { [FRepoManager resumeAll]; } - #pragma mark - #pragma mark Data reading methods deferred to FQuery -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(fbt_void_datasnapshot)block { - return [self observeEventType:eventType withBlock:block withCancelBlock:nil]; +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block { + return [self observeEventType:eventType + withBlock:block + withCancelBlock:nil]; } -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { - return [self observeEventType:eventType andPreviousSiblingKeyWithBlock:block withCancelBlock:nil]; +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { + return [self observeEventType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:nil]; } -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(fbt_void_datasnapshot)block withCancelBlock:(fbt_void_nserror)cancelBlock { - return [super observeEventType:eventType withBlock:block withCancelBlock:cancelBlock]; +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + return [super observeEventType:eventType + withBlock:block + withCancelBlock:cancelBlock]; } -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block withCancelBlock:(fbt_void_nserror)cancelBlock { - return [super observeEventType:eventType andPreviousSiblingKeyWithBlock:block withCancelBlock:cancelBlock]; +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + return [super observeEventType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:cancelBlock]; } - -- (void) removeObserverWithHandle:(FIRDatabaseHandle)handle { +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle { [super removeObserverWithHandle:handle]; } - -- (void) removeAllObservers { +- (void)removeAllObservers { [super removeAllObservers]; } -- (void) keepSynced:(BOOL)keepSynced { +- (void)keepSynced:(BOOL)keepSynced { [super keepSynced:keepSynced]; } -- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(fbt_void_datasnapshot)block { - [self observeSingleEventOfType:eventType withBlock:block withCancelBlock:nil]; +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block { + [self observeSingleEventOfType:eventType + withBlock:block + withCancelBlock:nil]; } -- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { - [self observeSingleEventOfType:eventType andPreviousSiblingKeyWithBlock:block withCancelBlock:nil]; +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { + [self observeSingleEventOfType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:nil]; } -- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(fbt_void_datasnapshot)block withCancelBlock:(fbt_void_nserror)cancelBlock { - [super observeSingleEventOfType:eventType withBlock:block withCancelBlock:cancelBlock]; +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + [super observeSingleEventOfType:eventType + withBlock:block + withCancelBlock:cancelBlock]; } -- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block withCancelBlock:(fbt_void_nserror)cancelBlock { - [super observeSingleEventOfType:eventType andPreviousSiblingKeyWithBlock:block withCancelBlock:cancelBlock]; +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + [super observeSingleEventOfType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:cancelBlock]; } #pragma mark - #pragma mark Query methods -// These methods suppress warnings from having method definitions in FIRDatabaseReference.h for docs generation. +// These methods suppress warnings from having method definitions in +// FIRDatabaseReference.h for docs generation. - (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit { return [super queryLimitedToFirst:limit]; @@ -342,11 +456,11 @@ - (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)key { return [super queryOrderedByChild:key]; } -- (FIRDatabaseQuery *) queryOrderedByKey { +- (FIRDatabaseQuery *)queryOrderedByKey { return [super queryOrderedByKey]; } -- (FIRDatabaseQuery *) queryOrderedByPriority { +- (FIRDatabaseQuery *)queryOrderedByPriority { return [super queryOrderedByPriority]; } @@ -354,7 +468,8 @@ - (FIRDatabaseQuery *)queryStartingAtValue:(id)startValue { return [super queryStartingAtValue:startValue]; } -- (FIRDatabaseQuery *)queryStartingAtValue:(id)startValue childKey:(NSString *)childKey { +- (FIRDatabaseQuery *)queryStartingAtValue:(id)startValue + childKey:(NSString *)childKey { return [super queryStartingAtValue:startValue childKey:childKey]; } @@ -362,7 +477,8 @@ - (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue { return [super queryEndingAtValue:endValue]; } -- (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue childKey:(NSString *)childKey { +- (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue + childKey:(NSString *)childKey { return [super queryEndingAtValue:endValue childKey:childKey]; } @@ -370,30 +486,42 @@ - (FIRDatabaseQuery *)queryEqualToValue:(id)value { return [super queryEqualToValue:value]; } -- (FIRDatabaseQuery *)queryEqualToValue:(id)value childKey:(NSString *)childKey { +- (FIRDatabaseQuery *)queryEqualToValue:(id)value + childKey:(NSString *)childKey { return [super queryEqualToValue:value childKey:childKey]; } - #pragma mark - #pragma mark Transaction methods -- (void) runTransactionBlock:(fbt_transactionresult_mutabledata)block { +- (void)runTransactionBlock:(fbt_transactionresult_mutabledata)block { [FValidation validateFrom:@"runTransactionBlock:" writablePath:self.path]; [self runTransactionBlock:block andCompletionBlock:nil withLocalEvents:YES]; } -- (void) runTransactionBlock:(fbt_transactionresult_mutabledata)update andCompletionBlock:(fbt_void_nserror_bool_datasnapshot)completionBlock { - [FValidation validateFrom:@"runTransactionBlock:andCompletionBlock:" writablePath:self.path]; - [self runTransactionBlock:update andCompletionBlock:completionBlock withLocalEvents:YES]; +- (void)runTransactionBlock:(fbt_transactionresult_mutabledata)update + andCompletionBlock: + (fbt_void_nserror_bool_datasnapshot)completionBlock { + [FValidation validateFrom:@"runTransactionBlock:andCompletionBlock:" + writablePath:self.path]; + [self runTransactionBlock:update + andCompletionBlock:completionBlock + withLocalEvents:YES]; } -- (void) runTransactionBlock:(fbt_transactionresult_mutabledata)block andCompletionBlock:(fbt_void_nserror_bool_datasnapshot)completionBlock withLocalEvents:(BOOL)localEvents { - [FValidation validateFrom:@"runTransactionBlock:andCompletionBlock:withLocalEvents:" writablePath:self.path]; +- (void)runTransactionBlock:(fbt_transactionresult_mutabledata)block + andCompletionBlock:(fbt_void_nserror_bool_datasnapshot)completionBlock + withLocalEvents:(BOOL)localEvents { + [FValidation + validateFrom:@"runTransactionBlock:andCompletionBlock:withLocalEvents:" + writablePath:self.path]; fbt_transactionresult_mutabledata updateCopy = [block copy]; fbt_void_nserror_bool_datasnapshot onCompleteCopy = [completionBlock copy]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo startTransactionOnPath:self.path update:updateCopy onComplete:onCompleteCopy withLocalEvents:localEvents]; + [self.repo startTransactionOnPath:self.path + update:updateCopy + onComplete:onCompleteCopy + withLocalEvents:localEvents]; }); } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FIndex.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FIndex.h index 8ab08c8..89bec76 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FIndex.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FIndex.h @@ -20,26 +20,27 @@ @class FNamedNode; @protocol FNode; -@protocol FIndex -- (NSComparisonResult) compareKey:(NSString *)key1 - andNode:(id)node1 - toOtherKey:(NSString *)key2 - andNode:(id)node2; - -- (NSComparisonResult) compareKey:(NSString *)key1 - andNode:(id)node1 - toOtherKey:(NSString *)key2 - andNode:(id)node2 - reverse:(BOOL)reverse; - -- (NSComparisonResult) compareNamedNode:(FNamedNode *)namedNode1 toNamedNode:(FNamedNode *)namedNode2; - -- (BOOL) isDefinedOn:(id)node; -- (BOOL) indexedValueChangedBetween:(id)oldNode and:(id)newNode; -- (FNamedNode*) minPost; -- (FNamedNode*) maxPost; -- (FNamedNode*) makePost:(id)indexValue name:(NSString*)name; -- (NSString*) queryDefinition; +@protocol FIndex +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2; + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse; + +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2; + +- (BOOL)isDefinedOn:(id)node; +- (BOOL)indexedValueChangedBetween:(id)oldNode and:(id)newNode; +- (FNamedNode *)minPost; +- (FNamedNode *)maxPost; +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name; +- (NSString *)queryDefinition; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FIndex.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FIndex.m index 61980c7..0366399 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FIndex.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FIndex.m @@ -17,9 +17,9 @@ #import "FIndex.h" #import "FKeyIndex.h" -#import "FValueIndex.h" #import "FPathIndex.h" #import "FPriorityIndex.h" +#import "FValueIndex.h" @implementation FIndex @@ -31,7 +31,8 @@ @implementation FIndex } else if ([string isEqualToString:@".priority"]) { return [FPriorityIndex priorityIndex]; } else { - return [[FPathIndex alloc] initWithPath:[[FPath alloc] initWith:string]]; + return + [[FPathIndex alloc] initWithPath:[[FPath alloc] initWith:string]]; } } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FKeyIndex.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FKeyIndex.h index a6bf787..281a5ac 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FKeyIndex.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FKeyIndex.h @@ -14,10 +14,9 @@ * limitations under the License. */ -#import #import "FIndex.h" +#import - -@interface FKeyIndex : NSObject -+ (id) keyIndex; +@interface FKeyIndex : NSObject ++ (id)keyIndex; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FKeyIndex.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FKeyIndex.m index 68ad461..ac10829 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FKeyIndex.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FKeyIndex.m @@ -15,14 +15,14 @@ */ #import "FKeyIndex.h" +#import "FEmptyNode.h" #import "FNamedNode.h" #import "FSnapshotUtilities.h" #import "FUtilities.h" -#import "FEmptyNode.h" @interface FKeyIndex () -@property (nonatomic, strong) FNamedNode *maxPost; +@property(nonatomic, strong) FNamedNode *maxPost; @end @@ -31,62 +31,71 @@ @implementation FKeyIndex - (id)init { self = [super init]; if (self) { - self.maxPost = [[FNamedNode alloc] initWithName:[FUtilities maxName] andNode:[FEmptyNode emptyNode]]; + self.maxPost = [[FNamedNode alloc] initWithName:[FUtilities maxName] + andNode:[FEmptyNode emptyNode]]; } return self; - } -- (NSComparisonResult) compareKey:(NSString *)key1 - andNode:(id)node1 - toOtherKey:(NSString *)key2 - andNode:(id)node2 -{ +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 { return [FUtilities compareKey:key1 toKey:key2]; } -- (NSComparisonResult) compareKey:(NSString *)key1 - andNode:(id)node1 - toOtherKey:(NSString *)key2 - andNode:(id)node2 - reverse:(BOOL)reverse -{ +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse { if (reverse) { - return [self compareKey:key2 andNode:node2 toOtherKey:key1 andNode:node1]; + return [self compareKey:key2 + andNode:node2 + toOtherKey:key1 + andNode:node1]; } else { - return [self compareKey:key1 andNode:node1 toOtherKey:key2 andNode:node2]; + return [self compareKey:key1 + andNode:node1 + toOtherKey:key2 + andNode:node2]; } } -- (NSComparisonResult) compareNamedNode:(FNamedNode *)namedNode1 toNamedNode:(FNamedNode *)namedNode2 -{ - return [self compareKey:namedNode1.name andNode:namedNode1.node toOtherKey:namedNode2.name andNode:namedNode2.node]; +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2 { + return [self compareKey:namedNode1.name + andNode:namedNode1.node + toOtherKey:namedNode2.name + andNode:namedNode2.node]; } -- (BOOL)isDefinedOn:(id )node { +- (BOOL)isDefinedOn:(id)node { return YES; } -- (BOOL)indexedValueChangedBetween:(id )oldNode and:(id )newNode { - return NO; // The key for a node never changes. +- (BOOL)indexedValueChangedBetween:(id)oldNode and:(id)newNode { + return NO; // The key for a node never changes. } - (FNamedNode *)minPost { return [FNamedNode min]; } -- (FNamedNode *)makePost:(id)indexValue name:(NSString*)name { +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name { NSString *key = indexValue.val; - NSAssert([key isKindOfClass:[NSString class]], @"KeyIndex indexValue must always be a string."); - // We just use empty node, but it'll never be compared, since our comparator only looks at name. + NSAssert([key isKindOfClass:[NSString class]], + @"KeyIndex indexValue must always be a string."); + // We just use empty node, but it'll never be compared, since our comparator + // only looks at name. return [[FNamedNode alloc] initWithName:key andNode:[FEmptyNode emptyNode]]; } -- (NSString *) queryDefinition { +- (NSString *)queryDefinition { return @".key"; } -- (NSString *) description { +- (NSString *)description { return @"FKeyIndex"; } @@ -94,21 +103,20 @@ - (id)copyWithZone:(NSZone *)zone { return self; } -- (BOOL) isEqual:(id)other { +- (BOOL)isEqual:(id)other { // since we're a singleton. return (other == self); } -- (NSUInteger) hash { +- (NSUInteger)hash { return [@".key" hash]; } - -+ (id) keyIndex { ++ (id)keyIndex { static id keyIndex; static dispatch_once_t once; dispatch_once(&once, ^{ - keyIndex = [[FKeyIndex alloc] init]; + keyIndex = [[FKeyIndex alloc] init]; }); return keyIndex; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FListenComplete.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FListenComplete.h index 914a3e4..99aabf8 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FListenComplete.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FListenComplete.h @@ -14,16 +14,15 @@ * limitations under the License. */ -#import #import "FOperation.h" - +#import @interface FListenComplete : NSObject -- (id) initWithSource:(FOperationSource *)aSource path:(FPath *)aPath; +- (id)initWithSource:(FOperationSource *)aSource path:(FPath *)aPath; -@property (nonatomic, strong, readonly) FOperationSource *source; -@property (nonatomic, strong, readonly) FPath *path; -@property (nonatomic, readonly) FOperationType type; +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, readonly) FOperationType type; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FListenComplete.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FListenComplete.m index 8573075..26370c6 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FListenComplete.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FListenComplete.m @@ -19,14 +19,15 @@ #import "FPath.h" @interface FListenComplete () -@property (nonatomic, strong, readwrite) FOperationSource *source; -@property (nonatomic, strong, readwrite) FPath *path; -@property (nonatomic, readwrite) FOperationType type; +@property(nonatomic, strong, readwrite) FOperationSource *source; +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, readwrite) FOperationType type; @end @implementation FListenComplete -- (id) initWithSource:(FOperationSource *)aSource path:(FPath *)aPath { - NSAssert(!aSource.fromUser, @"Can't have a listen complete from a user source"); +- (id)initWithSource:(FOperationSource *)aSource path:(FPath *)aPath { + NSAssert(!aSource.fromUser, + @"Can't have a listen complete from a user source"); self = [super init]; if (self) { self.source = aSource; @@ -36,16 +37,19 @@ - (id) initWithSource:(FOperationSource *)aSource path:(FPath *)aPath { return self; } -- (id ) operationForChild:(NSString *)childKey { +- (id)operationForChild:(NSString *)childKey { if ([self.path isEmpty]) { - return [[FListenComplete alloc] initWithSource:self.source path:[FPath empty]]; + return [[FListenComplete alloc] initWithSource:self.source + path:[FPath empty]]; } else { - return [[FListenComplete alloc] initWithSource:self.source path:[self.path popFront]]; + return [[FListenComplete alloc] initWithSource:self.source + path:[self.path popFront]]; } } -- (NSString *) description { - return [NSString stringWithFormat:@"FListenComplete { path=%@, source=%@ }", self.path, self.source]; +- (NSString *)description { + return [NSString stringWithFormat:@"FListenComplete { path=%@, source=%@ }", + self.path, self.source]; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FMaxNode.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FMaxNode.h index 6aff8c6..c68137e 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FMaxNode.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FMaxNode.h @@ -14,10 +14,9 @@ * limitations under the License. */ -#import #import "FChildrenNode.h" - +#import @interface FMaxNode : FChildrenNode - + (id) maxNode; ++ (id)maxNode; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FMaxNode.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FMaxNode.m index 3c93684..28e7672 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FMaxNode.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FMaxNode.m @@ -15,31 +15,28 @@ */ #import "FMaxNode.h" -#import "FUtilities.h" #import "FEmptyNode.h" - +#import "FUtilities.h" @implementation FMaxNode { - } -- (id) init { +- (id)init { self = [super init]; if (self) { - } return self; } -+ (id) maxNode { ++ (id)maxNode { static FMaxNode *maxNode = nil; static dispatch_once_t once; dispatch_once(&once, ^{ - maxNode = [[FMaxNode alloc] init]; + maxNode = [[FMaxNode alloc] init]; }); return maxNode; } -- (NSComparisonResult) compare:(id)other { +- (NSComparisonResult)compare:(id)other { if (other == self) { return NSOrderedSame; } else { @@ -51,11 +48,11 @@ - (BOOL)isEqual:(id)other { return other == self; } -- (id) getImmediateChild:(NSString *) childName { +- (id)getImmediateChild:(NSString *)childName { return [FEmptyNode emptyNode]; } -- (BOOL) isEmpty { +- (BOOL)isEmpty { return NO; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FNamedNode.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FNamedNode.h index ac9baa6..4414dfd 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FNamedNode.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FNamedNode.h @@ -14,19 +14,18 @@ * limitations under the License. */ -#import #import "FNode.h" +#import -@interface FNamedNode : NSObject - -@property (nonatomic, strong, readonly) NSString* name; -@property (nonatomic, strong, readonly) id node; +@interface FNamedNode : NSObject +@property(nonatomic, strong, readonly) NSString *name; +@property(nonatomic, strong, readonly) id node; --(id)initWithName:(NSString*)name andNode:(id)node; +- (id)initWithName:(NSString *)name andNode:(id)node; + (FNamedNode *)nodeWithName:(NSString *)name node:(id)node; -+ (FNamedNode*) min; -+ (FNamedNode*) max; ++ (FNamedNode *)min; ++ (FNamedNode *)max; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FNamedNode.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FNamedNode.m index d11787b..3b2eaf7 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FNamedNode.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FNamedNode.m @@ -15,24 +15,23 @@ */ #import "FNamedNode.h" -#import "FUtilities.h" #import "FEmptyNode.h" -#import "FMaxNode.h" #import "FIndex.h" +#import "FMaxNode.h" +#import "FUtilities.h" @interface FNamedNode () -@property (nonatomic, strong, readwrite) NSString* name; -@property (nonatomic, strong, readwrite) id node; +@property(nonatomic, strong, readwrite) NSString *name; +@property(nonatomic, strong, readwrite) id node; @end @implementation FNamedNode -+ (FNamedNode *)nodeWithName:(NSString *)name node:(id)node -{ ++ (FNamedNode *)nodeWithName:(NSString *)name node:(id)node { return [[FNamedNode alloc] initWithName:name andNode:node]; } -- (id)initWithName:(NSString *)name andNode:(id )node { +- (id)initWithName:(NSString *)name andNode:(id)node { self = [super init]; if (self) { self.name = name; @@ -41,13 +40,11 @@ - (id)initWithName:(NSString *)name andNode:(id )node { return self; } -- (id)copy -{ +- (id)copy { return self; } -- (id)copyWithZone:(NSZone *)zone -{ +- (id)copyWithZone:(NSZone *)zone { return self; } @@ -55,7 +52,8 @@ + (FNamedNode *)min { static FNamedNode *min = nil; static dispatch_once_t once; dispatch_once(&once, ^{ - min = [[FNamedNode alloc] initWithName:[FUtilities minName] andNode:[FEmptyNode emptyNode]]; + min = [[FNamedNode alloc] initWithName:[FUtilities minName] + andNode:[FEmptyNode emptyNode]]; }); return min; } @@ -64,27 +62,37 @@ + (FNamedNode *)max { static FNamedNode *max = nil; static dispatch_once_t once; dispatch_once(&once, ^{ - max = [[FNamedNode alloc] initWithName:[FUtilities maxName] andNode:[FMaxNode maxNode]]; + max = [[FNamedNode alloc] initWithName:[FUtilities maxName] + andNode:[FMaxNode maxNode]]; }); return max; } -- (NSString *) description { - return [NSString stringWithFormat:@"NamedNode[%@] %@", self.name, self.node]; +- (NSString *)description { + return + [NSString stringWithFormat:@"NamedNode[%@] %@", self.name, self.node]; } -- (BOOL) isEqual:(id)object { - if (self == object) { return YES; } - if (object == nil || ![object isKindOfClass:[FNamedNode class]]) { return NO; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (object == nil || ![object isKindOfClass:[FNamedNode class]]) { + return NO; + } FNamedNode *namedNode = object; - if (![self.name isEqualToString:namedNode.name]) { return NO; } - if (![self.node isEqual:namedNode.node]) { return NO; } + if (![self.name isEqualToString:namedNode.name]) { + return NO; + } + if (![self.node isEqual:namedNode.node]) { + return NO; + } return YES; } -- (NSUInteger) hash { +- (NSUInteger)hash { NSUInteger nameHash = [self.name hash]; NSUInteger nodeHash = [self.node hash]; NSUInteger result = 31 * nameHash + nodeHash; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FPathIndex.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FPathIndex.h index cf92ad1..6ab9151 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FPathIndex.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FPathIndex.h @@ -14,10 +14,10 @@ * limitations under the License. */ -#import #import "FIndex.h" #import "FPath.h" +#import -@interface FPathIndex : NSObject -- (id) initWithPath:(FPath *)path; +@interface FPathIndex : NSObject +- (id)initWithPath:(FPath *)path; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FPathIndex.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FPathIndex.m index 39913aa..214eab8 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FPathIndex.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FPathIndex.m @@ -15,35 +15,35 @@ */ #import "FPathIndex.h" -#import "FUtilities.h" -#import "FMaxNode.h" #import "FEmptyNode.h" -#import "FSnapshotUtilities.h" +#import "FMaxNode.h" #import "FNamedNode.h" #import "FPath.h" +#import "FSnapshotUtilities.h" +#import "FUtilities.h" @interface FPathIndex () - @property (nonatomic, strong) FPath *path; +@property(nonatomic, strong) FPath *path; @end @implementation FPathIndex -- (id) initWithPath:(FPath *)path { +- (id)initWithPath:(FPath *)path { self = [super init]; if (self) { if (path.isEmpty || [path.getFront isEqualToString:@".priority"]) { - [NSException raise:NSInvalidArgumentException format:@"Invalid path for PathIndex: %@", path]; + [NSException raise:NSInvalidArgumentException + format:@"Invalid path for PathIndex: %@", path]; } _path = path; } return self; } -- (NSComparisonResult) compareKey:(NSString *)key1 - andNode:(id)node1 - toOtherKey:(NSString *)key2 - andNode:(id)node2 -{ +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 { id child1 = [node1 getChild:self.path]; id child2 = [node2 getChild:self.path]; NSComparisonResult indexCmp = [child1 compare:child2]; @@ -54,29 +54,37 @@ - (NSComparisonResult) compareKey:(NSString *)key1 } } -- (NSComparisonResult) compareKey:(NSString *)key1 - andNode:(id)node1 - toOtherKey:(NSString *)key2 - andNode:(id)node2 - reverse:(BOOL)reverse -{ +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse { if (reverse) { - return [self compareKey:key2 andNode:node2 toOtherKey:key1 andNode:node1]; + return [self compareKey:key2 + andNode:node2 + toOtherKey:key1 + andNode:node1]; } else { - return [self compareKey:key1 andNode:node1 toOtherKey:key2 andNode:node2]; + return [self compareKey:key1 + andNode:node1 + toOtherKey:key2 + andNode:node2]; } } -- (NSComparisonResult) compareNamedNode:(FNamedNode *)namedNode1 toNamedNode:(FNamedNode *)namedNode2 -{ - return [self compareKey:namedNode1.name andNode:namedNode1.node toOtherKey:namedNode2.name andNode:namedNode2.node]; +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2 { + return [self compareKey:namedNode1.name + andNode:namedNode1.node + toOtherKey:namedNode2.name + andNode:namedNode2.node]; } -- (BOOL)isDefinedOn:(id )node { +- (BOOL)isDefinedOn:(id)node { return ![node getChild:self.path].isEmpty; } -- (BOOL)indexedValueChangedBetween:(id )oldNode and:(id )newNode { +- (BOOL)indexedValueChangedBetween:(id)oldNode and:(id)newNode { id oldValue = [oldNode getChild:self.path]; id newValue = [newNode getChild:self.path]; return [oldValue compare:newValue] != NSOrderedSame; @@ -90,11 +98,13 @@ - (FNamedNode *)maxPost { id maxNode = [[FEmptyNode emptyNode] updateChild:self.path withNewChild:[FMaxNode maxNode]]; - return [[FNamedNode alloc] initWithName:[FUtilities maxName] andNode:maxNode]; + return [[FNamedNode alloc] initWithName:[FUtilities maxName] + andNode:maxNode]; } -- (FNamedNode*)makePost:(id)indexValue name:(NSString*)name { - id node = [[FEmptyNode emptyNode] updateChild:self.path withNewChild:indexValue]; +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name { + id node = [[FEmptyNode emptyNode] updateChild:self.path + withNewChild:indexValue]; return [[FNamedNode alloc] initWithName:name andNode:node]; } @@ -111,14 +121,14 @@ - (id)copyWithZone:(NSZone *)zone { return self; } -- (BOOL) isEqual:(id)other { +- (BOOL)isEqual:(id)other { if (![other isKindOfClass:[FPathIndex class]]) { return NO; } - return ([self.path isEqual:((FPathIndex*)other).path]); + return ([self.path isEqual:((FPathIndex *)other).path]); } -- (NSUInteger) hash { +- (NSUInteger)hash { return [self.path hash]; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FPriorityIndex.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FPriorityIndex.h index 8b5904d..1b4534e 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FPriorityIndex.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FPriorityIndex.h @@ -18,6 +18,6 @@ #import "FIndex.h" -@interface FPriorityIndex : NSObject -+ (id) priorityIndex; +@interface FPriorityIndex : NSObject ++ (id)priorityIndex; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FPriorityIndex.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FPriorityIndex.m index 2d06ffa..0b33837 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FPriorityIndex.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FPriorityIndex.m @@ -16,22 +16,21 @@ #import "FPriorityIndex.h" -#import "FNode.h" -#import "FUtilities.h" -#import "FNamedNode.h" #import "FEmptyNode.h" #import "FLeafNode.h" #import "FMaxNode.h" +#import "FNamedNode.h" +#import "FNode.h" +#import "FUtilities.h" // TODO: Abstract into some common base class? @implementation FPriorityIndex -- (NSComparisonResult) compareKey:(NSString *)key1 - andNode:(id)node1 - toOtherKey:(NSString *)key2 - andNode:(id)node2 -{ +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 { id child1 = [node1 getPriority]; id child2 = [node2 getPriority]; NSComparisonResult indexCmp = [child1 compare:child2]; @@ -42,29 +41,37 @@ - (NSComparisonResult) compareKey:(NSString *)key1 } } -- (NSComparisonResult) compareKey:(NSString *)key1 - andNode:(id)node1 - toOtherKey:(NSString *)key2 - andNode:(id)node2 - reverse:(BOOL)reverse -{ +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse { if (reverse) { - return [self compareKey:key2 andNode:node2 toOtherKey:key1 andNode:node1]; + return [self compareKey:key2 + andNode:node2 + toOtherKey:key1 + andNode:node1]; } else { - return [self compareKey:key1 andNode:node1 toOtherKey:key2 andNode:node2]; + return [self compareKey:key1 + andNode:node1 + toOtherKey:key2 + andNode:node2]; } } -- (NSComparisonResult) compareNamedNode:(FNamedNode *)namedNode1 toNamedNode:(FNamedNode *)namedNode2 -{ - return [self compareKey:namedNode1.name andNode:namedNode1.node toOtherKey:namedNode2.name andNode:namedNode2.node]; +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2 { + return [self compareKey:namedNode1.name + andNode:namedNode1.node + toOtherKey:namedNode2.name + andNode:namedNode2.node]; } -- (BOOL)isDefinedOn:(id )node { +- (BOOL)isDefinedOn:(id)node { return !node.getPriority.isEmpty; } -- (BOOL)indexedValueChangedBetween:(id )oldNode and:(id )newNode { +- (BOOL)indexedValueChangedBetween:(id)oldNode and:(id)newNode { id oldValue = [oldNode getPriority]; id newValue = [newNode getPriority]; return ![oldValue isEqual:newValue]; @@ -78,8 +85,9 @@ - (FNamedNode *)maxPost { return [self makePost:[FMaxNode maxNode] name:[FUtilities maxName]]; } -- (FNamedNode*)makePost:(id)indexValue name:(NSString*)name { - id node = [[FLeafNode alloc] initWithValue:@"[PRIORITY-POST]" withPriority:indexValue]; +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name { + id node = [[FLeafNode alloc] initWithValue:@"[PRIORITY-POST]" + withPriority:indexValue]; return [[FNamedNode alloc] initWithName:name andNode:node]; } @@ -96,20 +104,20 @@ - (id)copyWithZone:(NSZone *)zone { return self; } -- (BOOL) isEqual:(id)other { +- (BOOL)isEqual:(id)other { return [other isKindOfClass:[FPriorityIndex class]]; } -- (NSUInteger) hash { +- (NSUInteger)hash { // chosen by a fair dice roll. Guaranteed to be random return 3155577; } -+ (id) priorityIndex { ++ (id)priorityIndex { static id index; static dispatch_once_t once; dispatch_once(&once, ^{ - index = [[FPriorityIndex alloc] init]; + index = [[FPriorityIndex alloc] init]; }); return index; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FRangedFilter.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FRangedFilter.h index 1457778..3c1aadd 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FRangedFilter.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FRangedFilter.h @@ -14,19 +14,18 @@ * limitations under the License. */ -#import #import "FNodeFilter.h" +#import @class FQueryParams; @class FNamedNode; -@interface FRangedFilter : NSObject - -- (id) initWithQueryParams:(FQueryParams *)params; -- (BOOL) matchesKey:(NSString *)key andNode:(id)node; +@interface FRangedFilter : NSObject +- (id)initWithQueryParams:(FQueryParams *)params; +- (BOOL)matchesKey:(NSString *)key andNode:(id)node; -@property (nonatomic, strong, readonly) FNamedNode *startPost; -@property (nonatomic, strong, readonly) FNamedNode *endPost; +@property(nonatomic, strong, readonly) FNamedNode *startPost; +@property(nonatomic, strong, readonly) FNamedNode *endPost; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FRangedFilter.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FRangedFilter.m index 5c4bbeb..bd8ef81 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FRangedFilter.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FRangedFilter.m @@ -16,26 +16,26 @@ #import "FRangedFilter.h" #import "FChildChangeAccumulator.h" -#import "FNamedNode.h" -#import "FQueryParams.h" -#import "FIndexedFilter.h" -#import "FQueryParams.h" -#import "FEmptyNode.h" #import "FChildrenNode.h" +#import "FEmptyNode.h" +#import "FIndexedFilter.h" #import "FIndexedNode.h" +#import "FNamedNode.h" +#import "FQueryParams.h" @interface FRangedFilter () -@property (nonatomic, strong, readwrite) id indexedFilter; -@property (nonatomic, strong, readwrite) id index; -@property (nonatomic, strong, readwrite) FNamedNode *startPost; -@property (nonatomic, strong, readwrite) FNamedNode *endPost; +@property(nonatomic, strong, readwrite) id indexedFilter; +@property(nonatomic, strong, readwrite) id index; +@property(nonatomic, strong, readwrite) FNamedNode *startPost; +@property(nonatomic, strong, readwrite) FNamedNode *endPost; @end @implementation FRangedFilter -- (id) initWithQueryParams:(FQueryParams *)params { +- (id)initWithQueryParams:(FQueryParams *)params { self = [super init]; if (self) { - self.indexedFilter = [[FIndexedFilter alloc] initWithIndex:params.index]; + self.indexedFilter = + [[FIndexedFilter alloc] initWithIndex:params.index]; self.index = params.index; self.startPost = [FRangedFilter startPostFromQueryParams:params]; self.endPost = [FRangedFilter endPostFromQueryParams:params]; @@ -43,8 +43,7 @@ - (id) initWithQueryParams:(FQueryParams *)params { return self; } - -+ (FNamedNode *) startPostFromQueryParams:(FQueryParams *)params { ++ (FNamedNode *)startPostFromQueryParams:(FQueryParams *)params { if ([params hasStart]) { NSString *startKey = params.indexStartKey; return [params.index makePost:params.indexStartValue name:startKey]; @@ -53,7 +52,7 @@ + (FNamedNode *) startPostFromQueryParams:(FQueryParams *)params { } } -+ (FNamedNode *) endPostFromQueryParams:(FQueryParams *)params { ++ (FNamedNode *)endPostFromQueryParams:(FQueryParams *)params { if ([params hasEnd]) { NSString *endKey = params.indexEndKey; return [params.index makePost:params.indexEndValue name:endKey]; @@ -62,9 +61,15 @@ + (FNamedNode *) endPostFromQueryParams:(FQueryParams *)params { } } -- (BOOL) matchesKey:(NSString *)key andNode:(id)node { - return ([self.index compareKey:self.startPost.name andNode:self.startPost.node toOtherKey:key andNode:node] <= NSOrderedSame && - [self.index compareKey:key andNode:node toOtherKey:self.endPost.name andNode:self.endPost.node] <= NSOrderedSame); +- (BOOL)matchesKey:(NSString *)key andNode:(id)node { + return ([self.index compareKey:self.startPost.name + andNode:self.startPost.node + toOtherKey:key + andNode:node] <= NSOrderedSame && + [self.index compareKey:key + andNode:node + toOtherKey:self.endPost.name + andNode:self.endPost.node] <= NSOrderedSame); } - (FIndexedNode *)updateChildIn:(FIndexedNode *)oldSnap @@ -72,8 +77,8 @@ - (FIndexedNode *)updateChildIn:(FIndexedNode *)oldSnap newChild:(id)newChildSnap affectedPath:(FPath *)affectedPath fromSource:(id)source - accumulator:(FChildChangeAccumulator *)optChangeAccumulator -{ + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { if (![self matchesKey:childKey andNode:newChildSnap]) { newChildSnap = [FEmptyNode emptyNode]; } @@ -85,33 +90,39 @@ - (FIndexedNode *)updateChildIn:(FIndexedNode *)oldSnap accumulator:optChangeAccumulator]; } -- (FIndexedNode *) updateFullNode:(FIndexedNode *)oldSnap - withNewNode:(FIndexedNode *)newSnap - accumulator:(FChildChangeAccumulator *)optChangeAccumulator -{ +- (FIndexedNode *)updateFullNode:(FIndexedNode *)oldSnap + withNewNode:(FIndexedNode *)newSnap + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { __block FIndexedNode *filtered; if (newSnap.node.isLeafNode) { - // Make sure we have a children node with the correct index, not a leaf node - filtered = [FIndexedNode indexedNodeWithNode:[FEmptyNode emptyNode] index:self.index]; + // Make sure we have a children node with the correct index, not a leaf + // node + filtered = [FIndexedNode indexedNodeWithNode:[FEmptyNode emptyNode] + index:self.index]; } else { // Dont' support priorities on queries filtered = [newSnap updatePriority:[FEmptyNode emptyNode]]; - [newSnap.node enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - if (![self matchesKey:key andNode:node]) { - filtered = [filtered updateChild:key withNewChild:[FEmptyNode emptyNode]]; - } + [newSnap.node enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + if (![self matchesKey:key andNode:node]) { + filtered = [filtered updateChild:key + withNewChild:[FEmptyNode emptyNode]]; + } }]; } - return [self.indexedFilter updateFullNode:oldSnap withNewNode:filtered accumulator:optChangeAccumulator]; + return [self.indexedFilter updateFullNode:oldSnap + withNewNode:filtered + accumulator:optChangeAccumulator]; } -- (FIndexedNode *) updatePriority:(id)priority forNode:(FIndexedNode *)oldSnap -{ +- (FIndexedNode *)updatePriority:(id)priority + forNode:(FIndexedNode *)oldSnap { // Don't support priorities on queries return oldSnap; } -- (BOOL) filtersNodes { +- (BOOL)filtersNodes { return YES; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FTransformedEnumerator.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FTransformedEnumerator.h index 75391a8..25a59b4 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FTransformedEnumerator.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FTransformedEnumerator.h @@ -16,9 +16,9 @@ #import - @interface FTransformedEnumerator : NSEnumerator -- (id)initWithEnumerator:(NSEnumerator*) enumerator andTransform:(id (^)(id))transform; +- (id)initWithEnumerator:(NSEnumerator *)enumerator + andTransform:(id (^)(id))transform; - (id)nextObject; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FTransformedEnumerator.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FTransformedEnumerator.m index bb36e94..567e100 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FTransformedEnumerator.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FTransformedEnumerator.m @@ -17,12 +17,13 @@ #import "FTransformedEnumerator.h" @interface FTransformedEnumerator () -@property (nonatomic, strong) NSEnumerator *enumerator; -@property (nonatomic, copy) id (^transform)(id); +@property(nonatomic, strong) NSEnumerator *enumerator; +@property(nonatomic, copy) id (^transform)(id); @end @implementation FTransformedEnumerator -- (id)initWithEnumerator:(NSEnumerator *)enumerator andTransform:(id (^)(id))transform { +- (id)initWithEnumerator:(NSEnumerator *)enumerator + andTransform:(id (^)(id))transform { self = [super init]; if (self) { self.enumerator = enumerator; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FValueIndex.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FValueIndex.h index 0f1c7f7..a79f202 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FValueIndex.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FValueIndex.h @@ -14,10 +14,9 @@ * limitations under the License. */ -#import #import "FIndex.h" +#import - -@interface FValueIndex : NSObject -+ (id) valueIndex; +@interface FValueIndex : NSObject ++ (id)valueIndex; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FValueIndex.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FValueIndex.m index 7ef9bff..61021c8 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FValueIndex.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FValueIndex.m @@ -15,18 +15,17 @@ */ #import "FValueIndex.h" +#import "FMaxNode.h" #import "FNamedNode.h" #import "FSnapshotUtilities.h" #import "FUtilities.h" -#import "FMaxNode.h" @implementation FValueIndex -- (NSComparisonResult) compareKey:(NSString *)key1 - andNode:(id)node1 - toOtherKey:(NSString *)key2 - andNode:(id)node2 -{ +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 { NSComparisonResult indexCmp = [node1 compare:node2]; if (indexCmp == NSOrderedSame) { return [FUtilities compareKey:key1 toKey:key2]; @@ -35,22 +34,30 @@ - (NSComparisonResult) compareKey:(NSString *)key1 } } -- (NSComparisonResult) compareKey:(NSString *)key1 - andNode:(id)node1 - toOtherKey:(NSString *)key2 - andNode:(id)node2 - reverse:(BOOL)reverse -{ +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse { if (reverse) { - return [self compareKey:key2 andNode:node2 toOtherKey:key1 andNode:node1]; + return [self compareKey:key2 + andNode:node2 + toOtherKey:key1 + andNode:node1]; } else { - return [self compareKey:key1 andNode:node1 toOtherKey:key2 andNode:node2]; + return [self compareKey:key1 + andNode:node1 + toOtherKey:key2 + andNode:node2]; } } -- (NSComparisonResult) compareNamedNode:(FNamedNode *)namedNode1 toNamedNode:(FNamedNode *)namedNode2 -{ - return [self compareKey:namedNode1.name andNode:namedNode1.node toOtherKey:namedNode2.name andNode:namedNode2.node]; +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2 { + return [self compareKey:namedNode1.name + andNode:namedNode1.node + toOtherKey:namedNode2.name + andNode:namedNode2.node]; } - (BOOL)isDefinedOn:(id)node { @@ -69,7 +76,7 @@ - (FNamedNode *)maxPost { return FNamedNode.max; } -- (FNamedNode *)makePost:(id)indexValue name:(NSString*)name { +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name { return [[FNamedNode alloc] initWithName:name andNode:indexValue]; } @@ -77,7 +84,7 @@ - (NSString *)queryDefinition { return @".value"; } -- (NSString *) description { +- (NSString *)description { return @"FValueIndex"; } @@ -85,21 +92,20 @@ - (id)copyWithZone:(NSZone *)zone { return self; } -- (BOOL) isEqual:(id)other { +- (BOOL)isEqual:(id)other { // since we're a singleton. return (other == self); } -- (NSUInteger) hash { +- (NSUInteger)hash { return [@".value" hash]; } - -+ (id) valueIndex { ++ (id)valueIndex { static id valueIndex; static dispatch_once_t once; dispatch_once(&once, ^{ - valueIndex = [[FValueIndex alloc] init]; + valueIndex = [[FValueIndex alloc] init]; }); return valueIndex; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessor.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessor.h index 59bfd2d..ea6676e 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessor.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessor.h @@ -25,17 +25,18 @@ @protocol FOperation; @protocol FNodeFilter; - @interface FViewProcessor : NSObject - (id)initWithFilter:(id)nodeFilter; -- (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache operation:(id)operation writesCache:(FWriteTreeRef *)writesCache completeCache:(id )optCompleteCache; -- (FViewCache *) revertUserWriteOn:(FViewCache *)viewCache - path:(FPath *)path - writesCache:(FWriteTreeRef *)writesCache - completeCache:(id)optCompleteCache - accumulator:(FChildChangeAccumulator *)accumulator; - +- (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache + operation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache; +- (FViewCache *)revertUserWriteOn:(FViewCache *)viewCache + path:(FPath *)path + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + accumulator:(FChildChangeAccumulator *)accumulator; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessor.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessor.m index 50a3594..5524996 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessor.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessor.m @@ -15,65 +15,71 @@ */ #import "FViewProcessor.h" -#import "FCompleteChildSource.h" -#import "FWriteTreeRef.h" -#import "FViewCache.h" +#import "FAckUserWrite.h" #import "FCacheNode.h" +#import "FChange.h" +#import "FChildChangeAccumulator.h" +#import "FChildrenNode.h" +#import "FCompleteChildSource.h" +#import "FCompoundWrite.h" +#import "FEmptyNode.h" +#import "FIRDataEventType.h" +#import "FImmutableTree.h" +#import "FKeyIndex.h" +#import "FMerge.h" #import "FNode.h" +#import "FNodeFilter.h" #import "FOperation.h" #import "FOperationSource.h" -#import "FChildChangeAccumulator.h" -#import "FNodeFilter.h" #import "FOverwrite.h" -#import "FMerge.h" -#import "FAckUserWrite.h" -#import "FViewProcessorResult.h" -#import "FIRDataEventType.h" -#import "FChange.h" -#import "FEmptyNode.h" -#import "FChildrenNode.h" #import "FPath.h" -#import "FKeyIndex.h" -#import "FCompoundWrite.h" -#import "FImmutableTree.h" +#import "FViewCache.h" +#import "FViewProcessorResult.h" +#import "FWriteTreeRef.h" /** -* An implementation of FCompleteChildSource that never returns any additional children -*/ -@interface FNoCompleteChildSource: NSObject + * An implementation of FCompleteChildSource that never returns any additional + * children + */ +@interface FNoCompleteChildSource : NSObject @end @implementation FNoCompleteChildSource -+ (FNoCompleteChildSource *) instance { ++ (FNoCompleteChildSource *)instance { static FNoCompleteChildSource *source = nil; static dispatch_once_t once; dispatch_once(&once, ^{ - source = [[FNoCompleteChildSource alloc] init]; + source = [[FNoCompleteChildSource alloc] init]; }); return source; } -- (id) completeChild:(NSString *)childKey { +- (id)completeChild:(NSString *)childKey { return nil; } -- (FNamedNode *) childByIndex:(id)index afterChild:(FNamedNode *)child isReverse:(BOOL)reverse { +- (FNamedNode *)childByIndex:(id)index + afterChild:(FNamedNode *)child + isReverse:(BOOL)reverse { return nil; } @end /** -* An implementation of FCompleteChildSource that uses a FWriteTree in addition to any other server data or -* old event caches available to calculate complete children. -*/ -@interface FWriteTreeCompleteChildSource: NSObject -@property (nonatomic, strong) FWriteTreeRef *writes; -@property (nonatomic, strong) FViewCache *viewCache; -@property (nonatomic, strong) id optCompleteServerCache; + * An implementation of FCompleteChildSource that uses a FWriteTree in addition + * to any other server data or old event caches available to calculate complete + * children. + */ +@interface FWriteTreeCompleteChildSource : NSObject +@property(nonatomic, strong) FWriteTreeRef *writes; +@property(nonatomic, strong) FViewCache *viewCache; +@property(nonatomic, strong) id optCompleteServerCache; @end @implementation FWriteTreeCompleteChildSource -- (id) initWithWrites:(FWriteTreeRef *)writes viewCache:(FViewCache *)viewCache serverCache:(id)optCompleteServerCache { +- (id)initWithWrites:(FWriteTreeRef *)writes + viewCache:(FViewCache *)viewCache + serverCache:(id)optCompleteServerCache { self = [super init]; if (self) { self.writes = writes; @@ -83,16 +89,21 @@ - (id) initWithWrites:(FWriteTreeRef *)writes viewCache:(FViewCache *)viewCache return self; } -- (id) completeChild:(NSString *)childKey { +- (id)completeChild:(NSString *)childKey { FCacheNode *node = self.viewCache.cachedEventSnap; if ([node isCompleteForChild:childKey]) { return [node.node getImmediateChild:childKey]; } else { FCacheNode *serverNode; if (self.optCompleteServerCache) { - // Since we're only ever getting child nodes, we can use the key index here - FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:self.optCompleteServerCache index:[FKeyIndex keyIndex]]; - serverNode = [[FCacheNode alloc] initWithIndexedNode:indexed isFullyInitialized:YES isFiltered:NO]; + // Since we're only ever getting child nodes, we can use the key + // index here + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:self.optCompleteServerCache + index:[FKeyIndex keyIndex]]; + serverNode = [[FCacheNode alloc] initWithIndexedNode:indexed + isFullyInitialized:YES + isFiltered:NO]; } else { serverNode = self.viewCache.cachedServerSnap; } @@ -100,10 +111,12 @@ - (id) initWithWrites:(FWriteTreeRef *)writes viewCache:(FViewCache *)viewCache } } -- (FNamedNode *) childByIndex:(id)index afterChild:(FNamedNode *)child isReverse:(BOOL)reverse { +- (FNamedNode *)childByIndex:(id)index + afterChild:(FNamedNode *)child + isReverse:(BOOL)reverse { id completeServerData = self.optCompleteServerCache != nil - ? self.optCompleteServerCache - : self.viewCache.completeServerSnap; + ? self.optCompleteServerCache + : self.viewCache.completeServerSnap; return [self.writes calculateNextNodeAfterPost:child completeServerData:completeServerData reverse:reverse @@ -113,7 +126,7 @@ - (FNamedNode *) childByIndex:(id)index afterChild:(FNamedNode *)child i @end @interface FViewProcessor () -@property (nonatomic, strong) id filter; +@property(nonatomic, strong) id filter; @end @implementation FViewProcessor @@ -126,12 +139,16 @@ - (id)initWithFilter:(id)nodeFilter { return self; } -- (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache operation:(id)operation writesCache:(FWriteTreeRef *)writesCache completeCache:(id )optCompleteCache { - FChildChangeAccumulator *accumulator = [[FChildChangeAccumulator alloc] init]; +- (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache + operation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache { + FChildChangeAccumulator *accumulator = + [[FChildChangeAccumulator alloc] init]; FViewCache *newViewCache; if (operation.type == FOperationTypeOverwrite) { - FOverwrite *overwrite = (FOverwrite *) operation; + FOverwrite *overwrite = (FOverwrite *)operation; if (operation.source.fromUser) { newViewCache = [self applyUserOverwriteTo:oldViewCache changePath:overwrite.path @@ -140,11 +157,14 @@ - (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache operation: completeCache:optCompleteCache accumulator:accumulator]; } else { - NSAssert(operation.source.fromServer, @"Unknown source for overwrite."); - // We filter the node if it's a tagged update or the node has been previously filtered and the update is - // not at the root in which case it is ok (and necessary) to mark the node unfiltered again - BOOL filterServerNode = overwrite.source.isTagged || (oldViewCache.cachedServerSnap.isFiltered && - !overwrite.path.isEmpty); + NSAssert(operation.source.fromServer, + @"Unknown source for overwrite."); + // We filter the node if it's a tagged update or the node has been + // previously filtered and the update is not at the root in which + // case it is ok (and necessary) to mark the node unfiltered again + BOOL filterServerNode = overwrite.source.isTagged || + (oldViewCache.cachedServerSnap.isFiltered && + !overwrite.path.isEmpty); newViewCache = [self applyServerOverwriteTo:oldViewCache changePath:overwrite.path snap:overwrite.snap @@ -154,7 +174,7 @@ - (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache operation: accumulator:accumulator]; } } else if (operation.type == FOperationTypeMerge) { - FMerge *merge = (FMerge*)operation; + FMerge *merge = (FMerge *)operation; if (operation.source.fromUser) { newViewCache = [self applyUserMergeTo:oldViewCache path:merge.path @@ -164,8 +184,10 @@ - (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache operation: accumulator:accumulator]; } else { NSAssert(operation.source.fromServer, @"Unknown source for merge."); - // We filter the node if it's a tagged update or the node has been previously filtered - BOOL filterServerNode = merge.source.isTagged || oldViewCache.cachedServerSnap.isFiltered; + // We filter the node if it's a tagged update or the node has been + // previously filtered + BOOL filterServerNode = merge.source.isTagged || + oldViewCache.cachedServerSnap.isFiltered; newViewCache = [self applyServerMergeTo:oldViewCache path:merge.path changedChildren:merge.children @@ -175,7 +197,7 @@ - (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache operation: accumulator:accumulator]; } } else if (operation.type == FOperationTypeAckUserWrite) { - FAckUserWrite *ackWrite = (FAckUserWrite *) operation; + FAckUserWrite *ackWrite = (FAckUserWrite *)operation; if (!ackWrite.revert) { newViewCache = [self ackUserWriteOn:oldViewCache ackPath:ackWrite.path @@ -185,10 +207,10 @@ - (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache operation: accumulator:accumulator]; } else { newViewCache = [self revertUserWriteOn:oldViewCache - path:ackWrite.path - writesCache:writesCache - completeCache:optCompleteCache - accumulator:accumulator]; + path:ackWrite.path + writesCache:writesCache + completeCache:optCompleteCache + accumulator:accumulator]; } } else if (operation.type == FOperationTypeListenComplete) { newViewCache = [self listenCompleteOldCache:oldViewCache @@ -197,26 +219,38 @@ - (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache operation: serverCache:optCompleteCache accumulator:accumulator]; } else { - [NSException raise:NSInternalInconsistencyException - format:@"Unknown operation encountered %ld.", (long)operation.type]; + [NSException + raise:NSInternalInconsistencyException + format:@"Unknown operation encountered %ld.", (long)operation.type]; return nil; } - NSArray *changes = [self maybeAddValueFromOldViewCache:oldViewCache newViewCache:newViewCache changes:accumulator.changes]; - FViewProcessorResult *results = [[FViewProcessorResult alloc] initWithViewCache:newViewCache changes:changes]; + NSArray *changes = [self maybeAddValueFromOldViewCache:oldViewCache + newViewCache:newViewCache + changes:accumulator.changes]; + FViewProcessorResult *results = + [[FViewProcessorResult alloc] initWithViewCache:newViewCache + changes:changes]; return results; } -- (NSArray *) maybeAddValueFromOldViewCache:(FViewCache *)oldViewCache newViewCache:(FViewCache *)newViewCache changes:(NSArray *)changes { +- (NSArray *)maybeAddValueFromOldViewCache:(FViewCache *)oldViewCache + newViewCache:(FViewCache *)newViewCache + changes:(NSArray *)changes { NSArray *newChanges = changes; FCacheNode *eventSnap = newViewCache.cachedEventSnap; if (eventSnap.isFullyInitialized) { - BOOL isLeafOrEmpty = eventSnap.node.isLeafNode || eventSnap.node.isEmpty; + BOOL isLeafOrEmpty = + eventSnap.node.isLeafNode || eventSnap.node.isEmpty; if ([changes count] > 0 || - !oldViewCache.cachedEventSnap.isFullyInitialized || - (isLeafOrEmpty && ![eventSnap.node isEqual:oldViewCache.completeEventSnap]) || - ![eventSnap.node.getPriority isEqual:oldViewCache.completeEventSnap.getPriority]) { - FChange *valueChange = [[FChange alloc] initWithType:FIRDataEventTypeValue indexedNode:eventSnap.indexedNode]; + !oldViewCache.cachedEventSnap.isFullyInitialized || + (isLeafOrEmpty && + ![eventSnap.node isEqual:oldViewCache.completeEventSnap]) || + ![eventSnap.node.getPriority + isEqual:oldViewCache.completeEventSnap.getPriority]) { + FChange *valueChange = + [[FChange alloc] initWithType:FIRDataEventTypeValue + indexedNode:eventSnap.indexedNode]; NSMutableArray *mutableChanges = [changes mutableCopy]; [mutableChanges addObject:valueChange]; newChanges = mutableChanges; @@ -225,11 +259,12 @@ - (NSArray *) maybeAddValueFromOldViewCache:(FViewCache *)oldViewCache newViewCa return newChanges; } -- (FViewCache *) generateEventCacheAfterServerEvent:(FViewCache *)viewCache - path:(FPath *)changePath - writesCache:(FWriteTreeRef *)writesCache - source:(id)source - accumulator:(FChildChangeAccumulator *)accumulator { +- (FViewCache *) + generateEventCacheAfterServerEvent:(FViewCache *)viewCache + path:(FPath *)changePath + writesCache:(FWriteTreeRef *)writesCache + source:(id)source + accumulator:(FChildChangeAccumulator *)accumulator { FCacheNode *oldEventSnap = viewCache.cachedEventSnap; if ([writesCache shadowingWriteAtPath:changePath] != nil) { // we have a shadowing write, ignore changes. @@ -238,34 +273,55 @@ - (FViewCache *) generateEventCacheAfterServerEvent:(FViewCache *)viewCache FIndexedNode *newEventCache; if (changePath.isEmpty) { // TODO: figure out how this plays with "sliding ack windows" - NSAssert(viewCache.cachedServerSnap.isFullyInitialized, @"If change path is empty, we must have complete server data"); + NSAssert( + viewCache.cachedServerSnap.isFullyInitialized, + @"If change path is empty, we must have complete server data"); id nodeWithLocalWrites; if (viewCache.cachedServerSnap.isFiltered) { - // We need to special case this, because we need to only apply writes to complete children, or - // we might end up raising events for incomplete children. If the server data is filtered deep - // writes cannot be guaranteed to be complete + // We need to special case this, because we need to only apply + // writes to complete children, or we might end up raising + // events for incomplete children. If the server data is + // filtered deep writes cannot be guaranteed to be complete id serverCache = viewCache.completeServerSnap; - FChildrenNode *completeChildren = ([serverCache isKindOfClass:[FChildrenNode class]]) ? serverCache : [FEmptyNode emptyNode]; - nodeWithLocalWrites = [writesCache calculateCompleteEventChildrenWithCompleteServerChildren:completeChildren]; + FChildrenNode *completeChildren = + ([serverCache isKindOfClass:[FChildrenNode class]]) + ? serverCache + : [FEmptyNode emptyNode]; + nodeWithLocalWrites = [writesCache + calculateCompleteEventChildrenWithCompleteServerChildren: + completeChildren]; } else { - nodeWithLocalWrites = [writesCache calculateCompleteEventCacheWithCompleteServerCache:viewCache.completeServerSnap]; + nodeWithLocalWrites = [writesCache + calculateCompleteEventCacheWithCompleteServerCache: + viewCache.completeServerSnap]; } - FIndexedNode *indexedNode = [FIndexedNode indexedNodeWithNode:nodeWithLocalWrites index:self.filter.index]; - newEventCache = [self.filter updateFullNode:viewCache.cachedEventSnap.indexedNode - withNewNode:indexedNode - accumulator:accumulator]; + FIndexedNode *indexedNode = + [FIndexedNode indexedNodeWithNode:nodeWithLocalWrites + index:self.filter.index]; + newEventCache = [self.filter + updateFullNode:viewCache.cachedEventSnap.indexedNode + withNewNode:indexedNode + accumulator:accumulator]; } else { NSString *childKey = [changePath getFront]; if ([childKey isEqualToString:@".priority"]) { - NSAssert(changePath.length == 1, @"Can't have a priority with additional path components"); + NSAssert( + changePath.length == 1, + @"Can't have a priority with additional path components"); id oldEventNode = oldEventSnap.node; id serverNode = viewCache.cachedServerSnap.node; // we might have overwrites for this priority - id updatedPriority = [writesCache calculateEventCacheAfterServerOverwriteWithChildPath:changePath - existingEventSnap:oldEventNode - existingServerSnap:serverNode]; + id updatedPriority = [writesCache + calculateEventCacheAfterServerOverwriteWithChildPath: + changePath + existingEventSnap: + oldEventNode + existingServerSnap: + serverNode]; if (updatedPriority != nil) { - newEventCache = [self.filter updatePriority:updatedPriority forNode:oldEventSnap.indexedNode]; + newEventCache = + [self.filter updatePriority:updatedPriority + forNode:oldEventSnap.indexedNode]; } else { // priority didn't change, keep old node newEventCache = oldEventSnap.indexedNode; @@ -275,23 +331,36 @@ - (FViewCache *) generateEventCacheAfterServerEvent:(FViewCache *)viewCache id newEventChild; if ([oldEventSnap isCompleteForChild:childKey]) { id serverNode = viewCache.cachedServerSnap.node; - id eventChildUpdate = [writesCache calculateEventCacheAfterServerOverwriteWithChildPath:changePath existingEventSnap:oldEventSnap.node existingServerSnap:serverNode]; + id eventChildUpdate = [writesCache + calculateEventCacheAfterServerOverwriteWithChildPath: + changePath + existingEventSnap: + oldEventSnap.node + existingServerSnap: + serverNode]; if (eventChildUpdate != nil) { - newEventChild = [[oldEventSnap.node getImmediateChild:childKey] updateChild:childChangePath withNewChild:eventChildUpdate]; + newEventChild = + [[oldEventSnap.node getImmediateChild:childKey] + updateChild:childChangePath + withNewChild:eventChildUpdate]; } else { // Nothing changed, just keep the old child - newEventChild = [oldEventSnap.node getImmediateChild:childKey]; + newEventChild = + [oldEventSnap.node getImmediateChild:childKey]; } } else { - newEventChild = [writesCache calculateCompleteChild:childKey cache:viewCache.cachedServerSnap]; + newEventChild = [writesCache + calculateCompleteChild:childKey + cache:viewCache.cachedServerSnap]; } if (newEventChild != nil) { - newEventCache = [self.filter updateChildIn:oldEventSnap.indexedNode - forChildKey:childKey - newChild:newEventChild - affectedPath:childChangePath - fromSource:source - accumulator:accumulator]; + newEventCache = + [self.filter updateChildIn:oldEventSnap.indexedNode + forChildKey:childKey + newChild:newEventChild + affectedPath:childChangePath + fromSource:source + accumulator:accumulator]; } else { // No complete children available or no change newEventCache = oldEventSnap.indexedNode; @@ -299,56 +368,82 @@ - (FViewCache *) generateEventCacheAfterServerEvent:(FViewCache *)viewCache } } return [viewCache updateEventSnap:newEventCache - isComplete:(oldEventSnap.isFullyInitialized || changePath.isEmpty) + isComplete:(oldEventSnap.isFullyInitialized || + changePath.isEmpty) isFiltered:self.filter.filtersNodes]; } } -- (FViewCache *) applyServerOverwriteTo:(FViewCache *)oldViewCache changePath:(FPath *)changePath snap:(id)changedSnap - writesCache:(FWriteTreeRef *)writesCache completeCache:(id)optCompleteCache - filterServerNode:(BOOL)filterServerNode accumulator:(FChildChangeAccumulator *)accumulator { +- (FViewCache *)applyServerOverwriteTo:(FViewCache *)oldViewCache + changePath:(FPath *)changePath + snap:(id)changedSnap + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + filterServerNode:(BOOL)filterServerNode + accumulator:(FChildChangeAccumulator *)accumulator { FCacheNode *oldServerSnap = oldViewCache.cachedServerSnap; FIndexedNode *newServerCache; - id serverFilter = filterServerNode ? self.filter : self.filter.indexedFilter; + id serverFilter = + filterServerNode ? self.filter : self.filter.indexedFilter; if (changePath.isEmpty) { - FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:changedSnap index:serverFilter.index]; - newServerCache = [serverFilter updateFullNode:oldServerSnap.indexedNode withNewNode:indexed accumulator:nil]; + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:changedSnap + index:serverFilter.index]; + newServerCache = [serverFilter updateFullNode:oldServerSnap.indexedNode + withNewNode:indexed + accumulator:nil]; } else if (serverFilter.filtersNodes && !oldServerSnap.isFiltered) { - // We want to filter the server node, but we didn't filter the server node yet, so simulate a full update - NSAssert(![changePath isEmpty], @"An empty path should been caught in the other branch"); + // We want to filter the server node, but we didn't filter the server + // node yet, so simulate a full update + NSAssert(![changePath isEmpty], + @"An empty path should been caught in the other branch"); NSString *childKey = [changePath getFront]; FPath *updatePath = [changePath popFront]; - id newChild = [[oldServerSnap.node getImmediateChild:childKey] updateChild:updatePath - withNewChild:changedSnap]; - FIndexedNode *indexed = [oldServerSnap.indexedNode updateChild:childKey withNewChild:newChild]; - newServerCache = [serverFilter updateFullNode:oldServerSnap.indexedNode withNewNode:indexed accumulator:nil]; + id newChild = [[oldServerSnap.node getImmediateChild:childKey] + updateChild:updatePath + withNewChild:changedSnap]; + FIndexedNode *indexed = + [oldServerSnap.indexedNode updateChild:childKey + withNewChild:newChild]; + newServerCache = [serverFilter updateFullNode:oldServerSnap.indexedNode + withNewNode:indexed + accumulator:nil]; } else { NSString *childKey = [changePath getFront]; - if (![oldServerSnap isCompleteForPath:changePath] && changePath.length > 1) { - // We don't update incomplete nodes with updates intended for other listeners. + if (![oldServerSnap isCompleteForPath:changePath] && + changePath.length > 1) { + // We don't update incomplete nodes with updates intended for other + // listeners. return oldViewCache; } FPath *childChangePath = [changePath popFront]; id childNode = [oldServerSnap.node getImmediateChild:childKey]; - id newChildNode = [childNode updateChild:childChangePath withNewChild:changedSnap]; + id newChildNode = [childNode updateChild:childChangePath + withNewChild:changedSnap]; if ([childKey isEqualToString:@".priority"]) { - newServerCache = [serverFilter updatePriority:newChildNode forNode:oldServerSnap.indexedNode]; + newServerCache = + [serverFilter updatePriority:newChildNode + forNode:oldServerSnap.indexedNode]; } else { - newServerCache = [serverFilter updateChildIn:oldServerSnap.indexedNode - forChildKey:childKey - newChild:newChildNode - affectedPath:childChangePath - fromSource:[FNoCompleteChildSource instance] - accumulator:nil]; + newServerCache = + [serverFilter updateChildIn:oldServerSnap.indexedNode + forChildKey:childKey + newChild:newChildNode + affectedPath:childChangePath + fromSource:[FNoCompleteChildSource instance] + accumulator:nil]; } } - FViewCache *newViewCache = [oldViewCache updateServerSnap:newServerCache - isComplete:(oldServerSnap.isFullyInitialized || changePath.isEmpty) - isFiltered:serverFilter.filtersNodes]; - id source = [[FWriteTreeCompleteChildSource alloc] initWithWrites:writesCache - viewCache:newViewCache - serverCache:optCompleteCache]; + FViewCache *newViewCache = + [oldViewCache updateServerSnap:newServerCache + isComplete:(oldServerSnap.isFullyInitialized || + changePath.isEmpty) + isFiltered:serverFilter.filtersNodes]; + id source = + [[FWriteTreeCompleteChildSource alloc] initWithWrites:writesCache + viewCache:newViewCache + serverCache:optCompleteCache]; return [self generateEventCacheAfterServerEvent:newViewCache path:changePath writesCache:writesCache @@ -356,31 +451,39 @@ - (FViewCache *) applyServerOverwriteTo:(FViewCache *)oldViewCache changePath:(F accumulator:accumulator]; } -- (FViewCache *) applyUserOverwriteTo:(FViewCache *)oldViewCache - changePath:(FPath *)changePath - changedSnap:(id)changedSnap - writesCache:(FWriteTreeRef *)writesCache - completeCache:(id)optCompleteCache - accumulator:(FChildChangeAccumulator *)accumulator { +- (FViewCache *)applyUserOverwriteTo:(FViewCache *)oldViewCache + changePath:(FPath *)changePath + changedSnap:(id)changedSnap + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + accumulator:(FChildChangeAccumulator *)accumulator { FCacheNode *oldEventSnap = oldViewCache.cachedEventSnap; FViewCache *newViewCache; - id source = [[FWriteTreeCompleteChildSource alloc] initWithWrites:writesCache - viewCache:oldViewCache - serverCache:optCompleteCache]; + id source = + [[FWriteTreeCompleteChildSource alloc] initWithWrites:writesCache + viewCache:oldViewCache + serverCache:optCompleteCache]; if (changePath.isEmpty) { - FIndexedNode *newIndexed = [FIndexedNode indexedNodeWithNode:changedSnap index:self.filter.index]; - FIndexedNode *newEventCache = [self.filter updateFullNode:oldEventSnap.indexedNode - withNewNode:newIndexed - accumulator:accumulator]; - newViewCache = [oldViewCache updateEventSnap:newEventCache isComplete:YES isFiltered:self.filter.filtersNodes]; + FIndexedNode *newIndexed = + [FIndexedNode indexedNodeWithNode:changedSnap + index:self.filter.index]; + FIndexedNode *newEventCache = + [self.filter updateFullNode:oldEventSnap.indexedNode + withNewNode:newIndexed + accumulator:accumulator]; + newViewCache = [oldViewCache updateEventSnap:newEventCache + isComplete:YES + isFiltered:self.filter.filtersNodes]; } else { NSString *childKey = [changePath getFront]; if ([childKey isEqualToString:@".priority"]) { - FIndexedNode *newEventCache = [self.filter updatePriority:changedSnap - forNode:oldViewCache.cachedEventSnap.indexedNode]; - newViewCache = [oldViewCache updateEventSnap:newEventCache - isComplete:oldEventSnap.isFullyInitialized - isFiltered:oldEventSnap.isFiltered]; + FIndexedNode *newEventCache = [self.filter + updatePriority:changedSnap + forNode:oldViewCache.cachedEventSnap.indexedNode]; + newViewCache = + [oldViewCache updateEventSnap:newEventCache + isComplete:oldEventSnap.isFullyInitialized + isFiltered:oldEventSnap.isFiltered]; } else { FPath *childChangePath = [changePath popFront]; id oldChild = [oldEventSnap.node getImmediateChild:childKey]; @@ -391,25 +494,33 @@ - (FViewCache *) applyUserOverwriteTo:(FViewCache *)oldViewCache } else { id childNode = [source completeChild:childKey]; if (childNode != nil) { - if ([[childChangePath getBack] isEqualToString:@".priority"] && [childNode getChild:[childChangePath parent]].isEmpty) { - // This is a priority update on an empty node. If this node exists on the server, the server - // will send down the priority in the update, so ignore for now + if ([[childChangePath getBack] + isEqualToString:@".priority"] && + [childNode getChild:[childChangePath parent]].isEmpty) { + // This is a priority update on an empty node. If this + // node exists on the server, the server will send down + // the priority in the update, so ignore for now newChild = childNode; } else { - newChild = [childNode updateChild:childChangePath withNewChild:changedSnap]; + newChild = [childNode updateChild:childChangePath + withNewChild:changedSnap]; } } else { newChild = [FEmptyNode emptyNode]; } } if (![oldChild isEqual:newChild]) { - FIndexedNode *newEventSnap = [self.filter updateChildIn:oldEventSnap.indexedNode - forChildKey:childKey - newChild:newChild - affectedPath:childChangePath - fromSource:source - accumulator:accumulator]; - newViewCache = [oldViewCache updateEventSnap:newEventSnap isComplete:oldEventSnap.isFullyInitialized isFiltered:self.filter.filtersNodes]; + FIndexedNode *newEventSnap = + [self.filter updateChildIn:oldEventSnap.indexedNode + forChildKey:childKey + newChild:newChild + affectedPath:childChangePath + fromSource:source + accumulator:accumulator]; + newViewCache = [oldViewCache + updateEventSnap:newEventSnap + isComplete:oldEventSnap.isFullyInitialized + isFiltered:self.filter.filtersNodes]; } else { newViewCache = oldViewCache; } @@ -418,121 +529,140 @@ - (FViewCache *) applyUserOverwriteTo:(FViewCache *)oldViewCache return newViewCache; } -+ (BOOL) cache:(FViewCache *)viewCache hasChild:(NSString *)childKey { ++ (BOOL)cache:(FViewCache *)viewCache hasChild:(NSString *)childKey { return [viewCache.cachedEventSnap isCompleteForChild:childKey]; } /** -* @param changedChildren NSDictionary of child name (NSString*) to child value (id) -*/ -- (FViewCache *) applyUserMergeTo:(FViewCache *)viewCache - path:(FPath *)path - changedChildren:(FCompoundWrite *)changedChildren - writesCache:(FWriteTreeRef *)writesCache - completeCache:(id)serverCache - accumulator:(FChildChangeAccumulator *)accumulator { - // HACK: In the case of a limit query, there may be some changes that bump things out of the - // window leaving room for new items. It's important we process these changes first, so we - // iterate the changes twice, first processing any that affect items currently in view. - // TODO: I consider an item "in view" if cacheHasChild is true, which checks both the server - // and event snap. I'm not sure if this will result in edge cases when a child is in one but - // not the other. + * @param changedChildren NSDictionary of child name (NSString*) to child value + * (id) + */ +- (FViewCache *)applyUserMergeTo:(FViewCache *)viewCache + path:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)serverCache + accumulator:(FChildChangeAccumulator *)accumulator { + // HACK: In the case of a limit query, there may be some changes that bump + // things out of the window leaving room for new items. It's important we + // process these changes first, so we iterate the changes twice, first + // processing any that affect items currently in view. + // TODO: I consider an item "in view" if cacheHasChild is true, which checks + // both the server and event snap. I'm not sure if this will result in edge + // cases when a child is in one but not the other. __block FViewCache *curViewCache = viewCache; - [changedChildren enumerateWrites:^(FPath *relativePath, id childNode, BOOL *stop) { - FPath *writePath = [path child:relativePath]; - if ([FViewProcessor cache:viewCache hasChild:[writePath getFront]]) { - curViewCache = [self applyUserOverwriteTo:curViewCache - changePath:writePath - changedSnap:childNode - writesCache:writesCache - completeCache:serverCache - accumulator:accumulator]; - } + [changedChildren enumerateWrites:^(FPath *relativePath, id childNode, + BOOL *stop) { + FPath *writePath = [path child:relativePath]; + if ([FViewProcessor cache:viewCache hasChild:[writePath getFront]]) { + curViewCache = [self applyUserOverwriteTo:curViewCache + changePath:writePath + changedSnap:childNode + writesCache:writesCache + completeCache:serverCache + accumulator:accumulator]; + } }]; - [changedChildren enumerateWrites:^(FPath *relativePath, id childNode, BOOL *stop) { - FPath *writePath = [path child:relativePath]; - if (![FViewProcessor cache:viewCache hasChild:[writePath getFront]]) { - curViewCache = [self applyUserOverwriteTo:curViewCache - changePath:writePath - changedSnap:childNode - writesCache:writesCache - completeCache:serverCache - accumulator:accumulator]; - } + [changedChildren enumerateWrites:^(FPath *relativePath, id childNode, + BOOL *stop) { + FPath *writePath = [path child:relativePath]; + if (![FViewProcessor cache:viewCache hasChild:[writePath getFront]]) { + curViewCache = [self applyUserOverwriteTo:curViewCache + changePath:writePath + changedSnap:childNode + writesCache:writesCache + completeCache:serverCache + accumulator:accumulator]; + } }]; return curViewCache; } -- (FViewCache *) applyServerMergeTo:(FViewCache *)viewCache - path:(FPath *)path - changedChildren:(FCompoundWrite *)changedChildren - writesCache:(FWriteTreeRef *)writesCache - completeCache:(id)serverCache - filterServerNode:(BOOL)filterServerNode - accumulator:(FChildChangeAccumulator *)accumulator { - // If we don't have a cache yet, this merge was intended for a previously listen in the same location. Ignore it and - // wait for the complete data update coming soon. - if (viewCache.cachedServerSnap.node.isEmpty && !viewCache.cachedServerSnap.isFullyInitialized) { +- (FViewCache *)applyServerMergeTo:(FViewCache *)viewCache + path:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)serverCache + filterServerNode:(BOOL)filterServerNode + accumulator:(FChildChangeAccumulator *)accumulator { + // If we don't have a cache yet, this merge was intended for a previously + // listen in the same location. Ignore it and wait for the complete data + // update coming soon. + if (viewCache.cachedServerSnap.node.isEmpty && + !viewCache.cachedServerSnap.isFullyInitialized) { return viewCache; } - // HACK: In the case of a limit query, there may be some changes that bump things out of the - // window leaving room for new items. It's important we process these changes first, so we - // iterate the changes twice, first processing any that affect items currently in view. - // TODO: I consider an item "in view" if cacheHasChild is true, which checks both the server - // and event snap. I'm not sure if this will result in edge cases when a child is in one but - // not the other. + // HACK: In the case of a limit query, there may be some changes that bump + // things out of the window leaving room for new items. It's important we + // process these changes first, so we iterate the changes twice, first + // processing any that affect items currently in view. + // TODO: I consider an item "in view" if cacheHasChild is true, which checks + // both the server and event snap. I'm not sure if this will result in edge + // cases when a child is in one but not the other. __block FViewCache *curViewCache = viewCache; FCompoundWrite *actualMerge; if (path.isEmpty) { actualMerge = changedChildren; } else { - actualMerge = [[FCompoundWrite emptyWrite] addCompoundWrite:changedChildren atPath:path]; + actualMerge = + [[FCompoundWrite emptyWrite] addCompoundWrite:changedChildren + atPath:path]; } id serverNode = viewCache.cachedServerSnap.node; NSDictionary *childCompoundWrites = actualMerge.childCompoundWrites; - [childCompoundWrites enumerateKeysAndObjectsUsingBlock:^(NSString *childKey, FCompoundWrite *childMerge, BOOL *stop) { - if ([serverNode hasChild:childKey]) { - id serverChild = [viewCache.cachedServerSnap.node getImmediateChild:childKey]; - id newChild = [childMerge applyToNode:serverChild]; - curViewCache = [self applyServerOverwriteTo:curViewCache - changePath:[[FPath alloc] initWith:childKey] - snap:newChild - writesCache:writesCache - completeCache:serverCache - filterServerNode:filterServerNode - accumulator:accumulator]; - } - }]; + [childCompoundWrites + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FCompoundWrite *childMerge, BOOL *stop) { + if ([serverNode hasChild:childKey]) { + id serverChild = + [viewCache.cachedServerSnap.node getImmediateChild:childKey]; + id newChild = [childMerge applyToNode:serverChild]; + curViewCache = + [self applyServerOverwriteTo:curViewCache + changePath:[[FPath alloc] initWith:childKey] + snap:newChild + writesCache:writesCache + completeCache:serverCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } + }]; - [childCompoundWrites enumerateKeysAndObjectsUsingBlock:^(NSString *childKey, FCompoundWrite *childMerge, BOOL *stop) { - bool isUnknownDeepMerge = ![viewCache.cachedServerSnap isCompleteForChild:childKey] && childMerge.rootWrite == nil; - if (![serverNode hasChild:childKey] && !isUnknownDeepMerge) { - id serverChild = [viewCache.cachedServerSnap.node getImmediateChild:childKey]; - id newChild = [childMerge applyToNode:serverChild]; - curViewCache = [self applyServerOverwriteTo:curViewCache - changePath:[[FPath alloc] initWith:childKey] - snap:newChild - writesCache:writesCache - completeCache:serverCache - filterServerNode:filterServerNode - accumulator:accumulator]; - } - }]; + [childCompoundWrites + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FCompoundWrite *childMerge, BOOL *stop) { + bool isUnknownDeepMerge = + ![viewCache.cachedServerSnap isCompleteForChild:childKey] && + childMerge.rootWrite == nil; + if (![serverNode hasChild:childKey] && !isUnknownDeepMerge) { + id serverChild = + [viewCache.cachedServerSnap.node getImmediateChild:childKey]; + id newChild = [childMerge applyToNode:serverChild]; + curViewCache = + [self applyServerOverwriteTo:curViewCache + changePath:[[FPath alloc] initWith:childKey] + snap:newChild + writesCache:writesCache + completeCache:serverCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } + }]; return curViewCache; } -- (FViewCache *) ackUserWriteOn:(FViewCache *)viewCache - ackPath:(FPath *)ackPath - affectedTree:(FImmutableTree *)affectedTree - writesCache:(FWriteTreeRef *)writesCache - completeCache:(id )optCompleteCache - accumulator:(FChildChangeAccumulator *)accumulator { +- (FViewCache *)ackUserWriteOn:(FViewCache *)viewCache + ackPath:(FPath *)ackPath + affectedTree:(FImmutableTree *)affectedTree + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + accumulator:(FChildChangeAccumulator *)accumulator { if ([writesCache shadowingWriteAtPath:ackPath] != nil) { return viewCache; @@ -541,25 +671,37 @@ - (FViewCache *) ackUserWriteOn:(FViewCache *)viewCache // Only filter server node if it is currently filtered BOOL filterServerNode = viewCache.cachedServerSnap.isFiltered; - // Essentially we'll just get our existing server cache for the affected paths and re-apply it as a server update - // now that it won't be shadowed. + // Essentially we'll just get our existing server cache for the affected + // paths and re-apply it as a server update now that it won't be shadowed. FCacheNode *serverCache = viewCache.cachedServerSnap; if (affectedTree.value != nil) { // This is an overwrite. - if ((ackPath.isEmpty && serverCache.isFullyInitialized) || [serverCache isCompleteForPath:ackPath]) { - return [self applyServerOverwriteTo:viewCache changePath:ackPath snap:[serverCache.node getChild:ackPath] - writesCache:writesCache completeCache:optCompleteCache - filterServerNode:filterServerNode accumulator:accumulator]; + if ((ackPath.isEmpty && serverCache.isFullyInitialized) || + [serverCache isCompleteForPath:ackPath]) { + return + [self applyServerOverwriteTo:viewCache + changePath:ackPath + snap:[serverCache.node getChild:ackPath] + writesCache:writesCache + completeCache:optCompleteCache + filterServerNode:filterServerNode + accumulator:accumulator]; } else if (ackPath.isEmpty) { - // This is a goofy edge case where we are acking data at this location but don't have full data. We - // should just re-apply whatever we have in our cache as a merge. + // This is a goofy edge case where we are acking data at this + // location but don't have full data. We should just re-apply + // whatever we have in our cache as a merge. FCompoundWrite *changedChildren = [FCompoundWrite emptyWrite]; - for(FNamedNode *child in serverCache.node.childEnumerator) { - changedChildren = [changedChildren addWrite:child.node atKey:child.name]; + for (FNamedNode *child in serverCache.node.childEnumerator) { + changedChildren = [changedChildren addWrite:child.node + atKey:child.name]; } - return [self applyServerMergeTo:viewCache path:ackPath changedChildren:changedChildren - writesCache:writesCache completeCache:optCompleteCache - filterServerNode:filterServerNode accumulator:accumulator]; + return [self applyServerMergeTo:viewCache + path:ackPath + changedChildren:changedChildren + writesCache:writesCache + completeCache:optCompleteCache + filterServerNode:filterServerNode + accumulator:accumulator]; } else { return viewCache; } @@ -567,43 +709,61 @@ - (FViewCache *) ackUserWriteOn:(FViewCache *)viewCache // This is a merge. __block FCompoundWrite *changedChildren = [FCompoundWrite emptyWrite]; [affectedTree forEach:^(FPath *mergePath, id value) { - FPath *serverCachePath = [ackPath child:mergePath]; - if ([serverCache isCompleteForPath:serverCachePath]) { - changedChildren = [changedChildren addWrite:[serverCache.node getChild:serverCachePath] atPath:mergePath]; - } + FPath *serverCachePath = [ackPath child:mergePath]; + if ([serverCache isCompleteForPath:serverCachePath]) { + changedChildren = [changedChildren + addWrite:[serverCache.node getChild:serverCachePath] + atPath:mergePath]; + } }]; - return [self applyServerMergeTo:viewCache path:ackPath changedChildren:changedChildren - writesCache:writesCache completeCache:optCompleteCache - filterServerNode:filterServerNode accumulator:accumulator]; + return [self applyServerMergeTo:viewCache + path:ackPath + changedChildren:changedChildren + writesCache:writesCache + completeCache:optCompleteCache + filterServerNode:filterServerNode + accumulator:accumulator]; } } -- (FViewCache *) revertUserWriteOn:(FViewCache *)viewCache - path:(FPath *)path - writesCache:(FWriteTreeRef *)writesCache - completeCache:(id)optCompleteCache - accumulator:(FChildChangeAccumulator *)accumulator { +- (FViewCache *)revertUserWriteOn:(FViewCache *)viewCache + path:(FPath *)path + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + accumulator:(FChildChangeAccumulator *)accumulator { if ([writesCache shadowingWriteAtPath:path] != nil) { return viewCache; } else { - id source = [[FWriteTreeCompleteChildSource alloc] initWithWrites:writesCache - viewCache:viewCache - serverCache:optCompleteCache]; + id source = [[FWriteTreeCompleteChildSource alloc] + initWithWrites:writesCache + viewCache:viewCache + serverCache:optCompleteCache]; FIndexedNode *oldEventCache = viewCache.cachedEventSnap.indexedNode; FIndexedNode *newEventCache; if (path.isEmpty || [[path getFront] isEqualToString:@".priority"]) { id newNode; if (viewCache.cachedServerSnap.isFullyInitialized) { - newNode = [writesCache calculateCompleteEventCacheWithCompleteServerCache:viewCache.completeServerSnap]; + newNode = [writesCache + calculateCompleteEventCacheWithCompleteServerCache: + viewCache.completeServerSnap]; } else { - newNode = [writesCache calculateCompleteEventChildrenWithCompleteServerChildren:viewCache.cachedServerSnap.node]; + newNode = [writesCache + calculateCompleteEventChildrenWithCompleteServerChildren: + viewCache.cachedServerSnap.node]; } - FIndexedNode *indexedNode = [FIndexedNode indexedNodeWithNode:newNode index:self.filter.index]; - newEventCache = [self.filter updateFullNode:oldEventCache withNewNode:indexedNode accumulator:accumulator]; + FIndexedNode *indexedNode = + [FIndexedNode indexedNodeWithNode:newNode + index:self.filter.index]; + newEventCache = [self.filter updateFullNode:oldEventCache + withNewNode:indexedNode + accumulator:accumulator]; } else { NSString *childKey = [path getFront]; - id newChild = [writesCache calculateCompleteChild:childKey cache:viewCache.cachedServerSnap]; - if (newChild == nil && [viewCache.cachedServerSnap isCompleteForChild:childKey]) { + id newChild = + [writesCache calculateCompleteChild:childKey + cache:viewCache.cachedServerSnap]; + if (newChild == nil && + [viewCache.cachedServerSnap isCompleteForChild:childKey]) { newChild = [oldEventCache.node getImmediateChild:childKey]; } if (newChild != nil) { @@ -613,43 +773,59 @@ - (FViewCache *) revertUserWriteOn:(FViewCache *)viewCache affectedPath:[path popFront] fromSource:source accumulator:accumulator]; - } else if (newChild == nil && [viewCache.cachedEventSnap.node hasChild:childKey]) { + } else if (newChild == nil && + [viewCache.cachedEventSnap.node hasChild:childKey]) { // No complete child available, delete the existing one, if any - newEventCache = [self.filter updateChildIn:oldEventCache - forChildKey:childKey - newChild:[FEmptyNode emptyNode] - affectedPath:[path popFront] - fromSource:source - accumulator:accumulator]; + newEventCache = + [self.filter updateChildIn:oldEventCache + forChildKey:childKey + newChild:[FEmptyNode emptyNode] + affectedPath:[path popFront] + fromSource:source + accumulator:accumulator]; } else { newEventCache = oldEventCache; } - if (newEventCache.node.isEmpty && viewCache.cachedServerSnap.isFullyInitialized) { - // We might have reverted all child writes. Maybe the old event was a leaf node. - id complete = [writesCache calculateCompleteEventCacheWithCompleteServerCache:viewCache.completeServerSnap]; + if (newEventCache.node.isEmpty && + viewCache.cachedServerSnap.isFullyInitialized) { + // We might have reverted all child writes. Maybe the old event + // was a leaf node. + id complete = [writesCache + calculateCompleteEventCacheWithCompleteServerCache: + viewCache.completeServerSnap]; if (complete.isLeafNode) { - FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:complete]; + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:complete]; newEventCache = [self.filter updateFullNode:newEventCache withNewNode:indexed accumulator:accumulator]; } } } - BOOL complete = viewCache.cachedServerSnap.isFullyInitialized || [writesCache shadowingWriteAtPath:[FPath empty]] != nil; - return [viewCache updateEventSnap:newEventCache isComplete:complete isFiltered:self.filter.filtersNodes]; + BOOL complete = viewCache.cachedServerSnap.isFullyInitialized || + [writesCache shadowingWriteAtPath:[FPath empty]] != nil; + return [viewCache updateEventSnap:newEventCache + isComplete:complete + isFiltered:self.filter.filtersNodes]; } } -- (FViewCache *) listenCompleteOldCache:(FViewCache *)viewCache - path:(FPath *)path - writesCache:(FWriteTreeRef *)writesCache - serverCache:(id)servercache - accumulator:(FChildChangeAccumulator *)accumulator { +- (FViewCache *)listenCompleteOldCache:(FViewCache *)viewCache + path:(FPath *)path + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)servercache + accumulator:(FChildChangeAccumulator *)accumulator { FCacheNode *oldServerNode = viewCache.cachedServerSnap; - FViewCache *newViewCache = [viewCache updateServerSnap:oldServerNode.indexedNode - isComplete:(oldServerNode.isFullyInitialized || path.isEmpty) - isFiltered:oldServerNode.isFiltered]; - return [self generateEventCacheAfterServerEvent:newViewCache path:path writesCache:writesCache source:[FNoCompleteChildSource instance] accumulator:accumulator]; + FViewCache *newViewCache = [viewCache + updateServerSnap:oldServerNode.indexedNode + isComplete:(oldServerNode.isFullyInitialized || path.isEmpty) + isFiltered:oldServerNode.isFiltered]; + return [self + generateEventCacheAfterServerEvent:newViewCache + path:path + writesCache:writesCache + source:[FNoCompleteChildSource instance] + accumulator:accumulator]; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessorResult.h b/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessorResult.h index e211d19..8d3e2ef 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessorResult.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessorResult.h @@ -18,13 +18,12 @@ @class FViewCache; - @interface FViewProcessorResult : NSObject -@property (nonatomic, strong, readonly) FViewCache *viewCache; +@property(nonatomic, strong, readonly) FViewCache *viewCache; /** -* List of FChanges. -*/ -@property (nonatomic, strong, readonly) NSArray *changes; + * List of FChanges. + */ +@property(nonatomic, strong, readonly) NSArray *changes; -- (id) initWithViewCache:(FViewCache *)viewCache changes:(NSArray *)changes; +- (id)initWithViewCache:(FViewCache *)viewCache changes:(NSArray *)changes; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessorResult.m b/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessorResult.m index 3327888..0d38947 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessorResult.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/FViewProcessorResult.m @@ -18,12 +18,12 @@ #import "FViewCache.h" @interface FViewProcessorResult () -@property (nonatomic, strong, readwrite) FViewCache *viewCache; -@property (nonatomic, strong, readwrite) NSArray *changes; +@property(nonatomic, strong, readwrite) FViewCache *viewCache; +@property(nonatomic, strong, readwrite) NSArray *changes; @end @implementation FViewProcessorResult -- (id) initWithViewCache:(FViewCache *)viewCache changes:(NSArray *)changes { +- (id)initWithViewCache:(FViewCache *)viewCache changes:(NSArray *)changes { self = [super init]; if (self) { self.viewCache = viewCache; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Login/FAuthTokenProvider.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Login/FAuthTokenProvider.m index 5010360..cd7fbe7 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Login/FAuthTokenProvider.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Login/FAuthTokenProvider.m @@ -21,28 +21,30 @@ #import #import -#import "FUtilities.h" #import "FIRDatabaseQuery_Private.h" #import "FIRNoopAuthTokenProvider.h" +#import "FUtilities.h" @interface FAuthStateListenerWrapper : NSObject -@property (nonatomic, copy) fbt_void_nsstring listener; -@property (nonatomic, weak) id auth; +@property(nonatomic, copy) fbt_void_nsstring listener; +@property(nonatomic, weak) id auth; @end @implementation FAuthStateListenerWrapper -- (instancetype)initWithListener:(fbt_void_nsstring)listener auth:(id)auth { +- (instancetype)initWithListener:(fbt_void_nsstring)listener + auth:(id)auth { self = [super init]; if (self != nil) { self->_listener = listener; self->_auth = auth; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(authStateDidChangeNotification:) - name:FIRAuthStateDidChangeInternalNotification - object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(authStateDidChangeNotification:) + name:FIRAuthStateDidChangeInternalNotification + object:nil]; } return self; } @@ -50,9 +52,10 @@ - (instancetype)initWithListener:(fbt_void_nsstring)listener auth:(id -@property (nonatomic, strong) id auth; -/** Strong references to the auth listeners as they are only weak in FIRFirebaseApp */ -@property (nonatomic, strong) NSMutableArray *authListeners; +@property(nonatomic, strong) id auth; +/** Strong references to the auth listeners as they are only weak in + * FIRFirebaseApp */ +@property(nonatomic, strong) NSMutableArray *authListeners; -- (instancetype) initWithAuth:(id)auth; +- (instancetype)initWithAuth:(id)auth; @end @@ -86,23 +89,25 @@ - (instancetype)initWithAuth:(id)auth { } - (void)fetchTokenForcingRefresh:(BOOL)forceRefresh - withCallback:(fbt_void_nsstring_nserror)callback { - if (self.auth == nil) { - // Signal that Auth is not available by returning nil. - callback(nil, nil); - } else { - [self.auth getTokenForcingRefresh:forceRefresh - withCallback:^(NSString * _Nullable token, NSError * _Nullable error) { - dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - callback(token, error); - }); - }]; - } + withCallback:(fbt_void_nsstring_nserror)callback { + if (self.auth == nil) { + // Signal that Auth is not available by returning nil. + callback(nil, nil); + } else { + [self.auth getTokenForcingRefresh:forceRefresh + withCallback:^(NSString *_Nullable token, + NSError *_Nullable error) { + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + callback(token, error); + }); + }]; + } } - (void)listenForTokenChanges:(_Nonnull fbt_void_nsstring)listener { FAuthStateListenerWrapper *wrapper = - [[FAuthStateListenerWrapper alloc] initWithListener:listener auth:self.auth]; + [[FAuthStateListenerWrapper alloc] initWithListener:listener + auth:self.auth]; [self.authListeners addObject:wrapper]; } @@ -110,7 +115,8 @@ - (void)listenForTokenChanges:(_Nonnull fbt_void_nsstring)listener { @implementation FAuthTokenProvider -+ (id)authTokenProviderWithAuth:(id)authInterop { ++ (id)authTokenProviderWithAuth: + (id)authInterop { return [[FIRFirebaseAuthTokenProvider alloc] initWithAuth:authInterop]; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Login/FIRNoopAuthTokenProvider.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Login/FIRNoopAuthTokenProvider.h index e27ddb4..137c0ce 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Login/FIRNoopAuthTokenProvider.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Login/FIRNoopAuthTokenProvider.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#import #import "FAuthTokenProvider.h" +#import @interface FIRNoopAuthTokenProvider : NSObject diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Login/FIRNoopAuthTokenProvider.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Login/FIRNoopAuthTokenProvider.m index 8bf467b..c50d308 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Login/FIRNoopAuthTokenProvider.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Login/FIRNoopAuthTokenProvider.m @@ -20,13 +20,14 @@ @implementation FIRNoopAuthTokenProvider -- (void) fetchTokenForcingRefresh:(BOOL)forceRefresh withCallback:(fbt_void_nsstring_nserror)callback { +- (void)fetchTokenForcingRefresh:(BOOL)forceRefresh + withCallback:(fbt_void_nsstring_nserror)callback { dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - callback(nil, nil); + callback(nil, nil); }); } -- (void) listenForTokenChanges:(fbt_void_nsstring)listener { +- (void)listenForTokenChanges:(fbt_void_nsstring)listener { // no-op, because token never changes } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FCachePolicy.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FCachePolicy.h index 16b49fb..6305d34 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FCachePolicy.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FCachePolicy.h @@ -18,23 +18,23 @@ @protocol FCachePolicy -- (BOOL)shouldPruneCacheWithSize:(NSUInteger)cacheSize numberOfTrackedQueries:(NSUInteger)numTrackedQueries; +- (BOOL)shouldPruneCacheWithSize:(NSUInteger)cacheSize + numberOfTrackedQueries:(NSUInteger)numTrackedQueries; - (BOOL)shouldCheckCacheSize:(NSUInteger)serverUpdatesSinceLastCheck; - (float)percentOfQueriesToPruneAtOnce; - (NSUInteger)maxNumberOfQueriesToKeep; @end +@interface FLRUCachePolicy : NSObject -@interface FLRUCachePolicy : NSObject - -@property (nonatomic, readonly) NSUInteger maxSize; +@property(nonatomic, readonly) NSUInteger maxSize; - (id)initWithMaxSize:(NSUInteger)maxSize; @end -@interface FNoCachePolicy : NSObject +@interface FNoCachePolicy : NSObject + (FNoCachePolicy *)noCachePolicy; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FCachePolicy.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FCachePolicy.m index 7da76ef..c1ecd98 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FCachePolicy.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FCachePolicy.m @@ -18,7 +18,7 @@ @interface FLRUCachePolicy () -@property (nonatomic, readwrite) NSUInteger maxSize; +@property(nonatomic, readwrite) NSUInteger maxSize; @end @@ -36,8 +36,10 @@ - (id)initWithMaxSize:(NSUInteger)maxSize { return self; } -- (BOOL)shouldPruneCacheWithSize:(NSUInteger)cacheSize numberOfTrackedQueries:(NSUInteger)numTrackedQueries { - return cacheSize > self.maxSize || numTrackedQueries > kFMaxNumberOfPrunableQueriesToKeep; +- (BOOL)shouldPruneCacheWithSize:(NSUInteger)cacheSize + numberOfTrackedQueries:(NSUInteger)numTrackedQueries { + return cacheSize > self.maxSize || + numTrackedQueries > kFMaxNumberOfPrunableQueriesToKeep; } - (BOOL)shouldCheckCacheSize:(NSUInteger)serverUpdatesSinceLastCheck { @@ -60,7 +62,8 @@ + (FNoCachePolicy *)noCachePolicy { return [[FNoCachePolicy alloc] init]; } -- (BOOL)shouldPruneCacheWithSize:(NSUInteger)cacheSize numberOfTrackedQueries:(NSUInteger)numTrackedQueries { +- (BOOL)shouldPruneCacheWithSize:(NSUInteger)cacheSize + numberOfTrackedQueries:(NSUInteger)numTrackedQueries { return NO; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FLevelDBStorageEngine.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FLevelDBStorageEngine.h index 84f3864..6d32b98 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FLevelDBStorageEngine.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FLevelDBStorageEngine.h @@ -16,20 +16,20 @@ #import -#import "FStorageEngine.h" +#import "FCompoundWrite.h" #import "FNode.h" #import "FPath.h" -#import "FCompoundWrite.h" #import "FQuerySpec.h" +#import "FStorageEngine.h" @class FCacheNode; @class FTrackedQuery; @class FPruneForest; @class FRepoInfo; -@interface FLevelDBStorageEngine : NSObject +@interface FLevelDBStorageEngine : NSObject -+ (NSString *) firebaseDir; ++ (NSString *)firebaseDir; - (id)initWithPath:(NSString *)path; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FLevelDBStorageEngine.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FLevelDBStorageEngine.m index 68254ad..77a8303 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FLevelDBStorageEngine.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FLevelDBStorageEngine.m @@ -18,84 +18,90 @@ #import "FLevelDBStorageEngine.h" -#import #import "APLevelDB.h" -#import "FSnapshotUtilities.h" -#import "FWriteRecord.h" -#import "FTrackedQuery.h" -#import "FQueryParams.h" #import "FEmptyNode.h" +#import "FPendingPut.h" // For legacy migration #import "FPruneForest.h" +#import "FQueryParams.h" +#import "FSnapshotUtilities.h" +#import "FTrackedQuery.h" #import "FUtilities.h" -#import "FPendingPut.h" // For legacy migration +#import "FWriteRecord.h" +#import @interface FLevelDBStorageEngine () -@property (nonatomic, strong) NSString *basePath; -@property (nonatomic, strong) APLevelDB *writesDB; -@property (nonatomic, strong) APLevelDB *serverCacheDB; +@property(nonatomic, strong) NSString *basePath; +@property(nonatomic, strong) APLevelDB *writesDB; +@property(nonatomic, strong) APLevelDB *serverCacheDB; @end // WARNING: If you change this, you need to write a migration script -static NSString * const kFPersistenceVersion = @"1"; +static NSString *const kFPersistenceVersion = @"1"; -static NSString * const kFServerDBPath = @"server_data"; -static NSString * const kFWritesDBPath = @"writes"; +static NSString *const kFServerDBPath = @"server_data"; +static NSString *const kFWritesDBPath = @"writes"; -static NSString * const kFUserWriteId = @"id"; -static NSString * const kFUserWritePath = @"path"; -static NSString * const kFUserWriteOverwrite = @"o"; -static NSString * const kFUserWriteMerge = @"m"; +static NSString *const kFUserWriteId = @"id"; +static NSString *const kFUserWritePath = @"path"; +static NSString *const kFUserWriteOverwrite = @"o"; +static NSString *const kFUserWriteMerge = @"m"; -static NSString * const kFTrackedQueryId = @"id"; -static NSString * const kFTrackedQueryPath = @"path"; -static NSString * const kFTrackedQueryParams = @"p"; -static NSString * const kFTrackedQueryLastUse = @"lu"; -static NSString * const kFTrackedQueryIsComplete = @"c"; -static NSString * const kFTrackedQueryIsActive = @"a"; +static NSString *const kFTrackedQueryId = @"id"; +static NSString *const kFTrackedQueryPath = @"path"; +static NSString *const kFTrackedQueryParams = @"p"; +static NSString *const kFTrackedQueryLastUse = @"lu"; +static NSString *const kFTrackedQueryIsComplete = @"c"; +static NSString *const kFTrackedQueryIsActive = @"a"; -static NSString * const kFServerCachePrefix = @"/server_cache/"; +static NSString *const kFServerCachePrefix = @"/server_cache/"; // '~' is the last non-control character in the ASCII table until 127 // We wan't the entire range of thing stored in the DB -static NSString * const kFServerCacheRangeEnd = @"/server_cache~"; -static NSString * const kFTrackedQueriesPrefix = @"/tracked_queries/"; -static NSString * const kFTrackedQueryKeysPrefix = @"/tracked_query_keys/"; +static NSString *const kFServerCacheRangeEnd = @"/server_cache~"; +static NSString *const kFTrackedQueriesPrefix = @"/tracked_queries/"; +static NSString *const kFTrackedQueryKeysPrefix = @"/tracked_query_keys/"; -// Failed to load JSON because a valid JSON turns out to be NaN while deserializing +// Failed to load JSON because a valid JSON turns out to be NaN while +// deserializing static const NSInteger kFNanFailureCode = 3840; -static NSString* writeRecordKey(NSUInteger writeId) { +static NSString *writeRecordKey(NSUInteger writeId) { return [NSString stringWithFormat:@"%lu", (unsigned long)(writeId)]; } -static NSString* serverCacheKey(FPath *path) { - return [NSString stringWithFormat:@"%@%@", kFServerCachePrefix, ([path toStringWithTrailingSlash])]; +static NSString *serverCacheKey(FPath *path) { + return [NSString stringWithFormat:@"%@%@", kFServerCachePrefix, + ([path toStringWithTrailingSlash])]; } -static NSString* trackedQueryKey(NSUInteger trackedQueryId) { - return [NSString stringWithFormat:@"%@%lu", kFTrackedQueriesPrefix, (unsigned long)trackedQueryId]; +static NSString *trackedQueryKey(NSUInteger trackedQueryId) { + return [NSString stringWithFormat:@"%@%lu", kFTrackedQueriesPrefix, + (unsigned long)trackedQueryId]; } -static NSString* trackedQueryKeysKeyPrefix(NSUInteger trackedQueryId) { - return [NSString stringWithFormat:@"%@%lu/", kFTrackedQueryKeysPrefix, (unsigned long)trackedQueryId]; +static NSString *trackedQueryKeysKeyPrefix(NSUInteger trackedQueryId) { + return [NSString stringWithFormat:@"%@%lu/", kFTrackedQueryKeysPrefix, + (unsigned long)trackedQueryId]; } -static NSString* trackedQueryKeysKey(NSUInteger trackedQueryId, NSString *key) { - return [NSString stringWithFormat:@"%@%lu/%@", kFTrackedQueryKeysPrefix, (unsigned long)trackedQueryId, key]; +static NSString *trackedQueryKeysKey(NSUInteger trackedQueryId, NSString *key) { + return [NSString stringWithFormat:@"%@%lu/%@", kFTrackedQueryKeysPrefix, + (unsigned long)trackedQueryId, key]; } @implementation FLevelDBStorageEngine #pragma mark - Constructors -- (id)initWithPath:(NSString*)dbPath -{ +- (id)initWithPath:(NSString *)dbPath { self = [super init]; if (self) { - self.basePath = [[FLevelDBStorageEngine firebaseDir] stringByAppendingPathComponent:dbPath]; + self.basePath = [[FLevelDBStorageEngine firebaseDir] + stringByAppendingPathComponent:dbPath]; /* For reference: serverDataDB = [aPersistence createDbByName:@"server_data"]; - FPangolinDB *completenessDb = [aPersistence createDbByName:@"server_complete"]; + FPangolinDB *completenessDb = [aPersistence + createDbByName:@"server_complete"]; */ [FLevelDBStorageEngine ensureDir:self.basePath markAsDoNotBackup:YES]; [self runMigration]; @@ -105,72 +111,112 @@ - (id)initWithPath:(NSString*)dbPath } - (void)runMigration { - // Currently we're at version 1, so all we need to do is write that to a file - NSString *versionFile = [self.basePath stringByAppendingPathComponent:@"version"]; + // Currently we're at version 1, so all we need to do is write that to a + // file + NSString *versionFile = + [self.basePath stringByAppendingPathComponent:@"version"]; NSError *error; - NSString *oldVersion = [NSString stringWithContentsOfFile:versionFile encoding:NSUTF8StringEncoding error:&error]; + NSString *oldVersion = + [NSString stringWithContentsOfFile:versionFile + encoding:NSUTF8StringEncoding + error:&error]; if (!oldVersion) { // This is probably fine, we don't have a version file yet - BOOL success = [kFPersistenceVersion writeToFile:versionFile atomically:NO encoding:NSUTF8StringEncoding error:&error]; + BOOL success = [kFPersistenceVersion writeToFile:versionFile + atomically:NO + encoding:NSUTF8StringEncoding + error:&error]; if (!success) { - FFWarn(@"I-RDB076001", @"Failed to write version for database: %@", error); + FFWarn(@"I-RDB076001", @"Failed to write version for database: %@", + error); } } else if ([oldVersion isEqualToString:kFPersistenceVersion]) { // Everythings fine no need for migration } else { // If we add more versions in the future, we need to run migration here - [NSException raise:NSInternalInconsistencyException format:@"Unrecognized database version: %@", oldVersion]; + [NSException raise:NSInternalInconsistencyException + format:@"Unrecognized database version: %@", oldVersion]; } } - (void)runLegacyMigration:(FRepoInfo *)info { - NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSArray *dirPaths = NSSearchPathForDirectoriesInDomains( + NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDir = [dirPaths objectAtIndex:0]; - NSString *firebaseDir = [documentsDir stringByAppendingPathComponent:@"firebase"]; - NSString* repoHashString = [NSString stringWithFormat:@"%@_%@", info.host, info.namespace]; - NSString *legacyBaseDir = [NSString stringWithFormat:@"%@/1/%@/v1", firebaseDir, repoHashString]; + NSString *firebaseDir = + [documentsDir stringByAppendingPathComponent:@"firebase"]; + NSString *repoHashString = + [NSString stringWithFormat:@"%@_%@", info.host, info.namespace]; + NSString *legacyBaseDir = + [NSString stringWithFormat:@"%@/1/%@/v1", firebaseDir, repoHashString]; if ([[NSFileManager defaultManager] fileExistsAtPath:legacyBaseDir]) { FFWarn(@"I-RDB076002", @"Legacy database found, migrating..."); // We only need to migrate writes NSError *error = nil; - APLevelDB *writes = [APLevelDB levelDBWithPath:[legacyBaseDir stringByAppendingPathComponent:@"outstanding_puts"] error:&error]; + APLevelDB *writes = [APLevelDB + levelDBWithPath:[legacyBaseDir stringByAppendingPathComponent: + @"outstanding_puts"] + error:&error]; if (writes != nil) { __block NSUInteger numberOfWritesRestored = 0; - // Maybe we could use write batches, but what the heck, I'm sure it'll go fine :P - [writes enumerateKeysAndValuesAsData:^(NSString *key, NSData *data, BOOL *stop) { - id pendingPut = [NSKeyedUnarchiver unarchiveObjectWithData:data]; - if ([pendingPut isKindOfClass:[FPendingPut class]]) { - FPendingPut *put = pendingPut; - id newNode = [FSnapshotUtilities nodeFrom:put.data priority:put.priority]; - [self saveUserOverwrite:newNode atPath:put.path writeId:[key integerValue]]; - numberOfWritesRestored++; - } else if ([pendingPut isKindOfClass:[FPendingPutPriority class]]) { - // This is for backwards compatibility. Older clients will save FPendingPutPriority. New ones will need to read it and translate. - FPendingPutPriority *putPriority = pendingPut; - FPath *priorityPath = [putPriority.path childFromString:@".priority"]; - id newNode = [FSnapshotUtilities nodeFrom:putPriority.priority priority:nil]; - [self saveUserOverwrite:newNode atPath:priorityPath writeId:[key integerValue]]; - numberOfWritesRestored++; - } else if ([pendingPut isKindOfClass:[FPendingUpdate class]]) { - FPendingUpdate *update = pendingPut; - FCompoundWrite *merge = [FCompoundWrite compoundWriteWithValueDictionary:update.data]; - [self saveUserMerge:merge atPath:update.path writeId:[key integerValue]]; - numberOfWritesRestored++; - } else { - FFWarn(@"I-RDB076003", @"Failed to migrate legacy write, meh!"); - } + // Maybe we could use write batches, but what the heck, I'm sure + // it'll go fine :P + [writes enumerateKeysAndValuesAsData:^(NSString *key, NSData *data, + BOOL *stop) { + id pendingPut = [NSKeyedUnarchiver unarchiveObjectWithData:data]; + if ([pendingPut isKindOfClass:[FPendingPut class]]) { + FPendingPut *put = pendingPut; + id newNode = + [FSnapshotUtilities nodeFrom:put.data + priority:put.priority]; + [self saveUserOverwrite:newNode + atPath:put.path + writeId:[key integerValue]]; + numberOfWritesRestored++; + } else if ([pendingPut + isKindOfClass:[FPendingPutPriority class]]) { + // This is for backwards compatibility. Older clients will + // save FPendingPutPriority. New ones will need to read it and + // translate. + FPendingPutPriority *putPriority = pendingPut; + FPath *priorityPath = + [putPriority.path childFromString:@".priority"]; + id newNode = + [FSnapshotUtilities nodeFrom:putPriority.priority + priority:nil]; + [self saveUserOverwrite:newNode + atPath:priorityPath + writeId:[key integerValue]]; + numberOfWritesRestored++; + } else if ([pendingPut isKindOfClass:[FPendingUpdate class]]) { + FPendingUpdate *update = pendingPut; + FCompoundWrite *merge = [FCompoundWrite + compoundWriteWithValueDictionary:update.data]; + [self saveUserMerge:merge + atPath:update.path + writeId:[key integerValue]]; + numberOfWritesRestored++; + } else { + FFWarn(@"I-RDB076003", + @"Failed to migrate legacy write, meh!"); + } }]; - FFWarn(@"I-RDB076004", @"Migrated %lu writes", (unsigned long)numberOfWritesRestored); + FFWarn(@"I-RDB076004", @"Migrated %lu writes", + (unsigned long)numberOfWritesRestored); [writes close]; FFWarn(@"I-RDB076005", @"Deleting legacy database..."); - BOOL success = [[NSFileManager defaultManager] removeItemAtPath:legacyBaseDir error:&error]; + BOOL success = + [[NSFileManager defaultManager] removeItemAtPath:legacyBaseDir + error:&error]; if (!success) { - FFWarn(@"I-RDB076006", @"Failed to delete legacy database: %@", error); + FFWarn(@"I-RDB076006", @"Failed to delete legacy database: %@", + error); } else { FFWarn(@"I-RDB076007", @"Finished migrating legacy database."); } } else { - FFWarn(@"I-RDB076008", @"Failed to migrate old database: %@", error); + FFWarn(@"I-RDB076008", @"Failed to migrate old database: %@", + error); } } } @@ -180,22 +226,25 @@ - (void)openDatabases { self.writesDB = [self createDB:kFWritesDBPath]; } -- (void)purgeDatabase:(NSString*) dbPath { +- (void)purgeDatabase:(NSString *)dbPath { NSString *path = [self.basePath stringByAppendingPathComponent:dbPath]; NSError *error; FFWarn(@"I-RDB076009", @"Deleting database at path %@", path); - BOOL success = [[NSFileManager defaultManager] removeItemAtPath:path error:&error]; + BOOL success = [[NSFileManager defaultManager] removeItemAtPath:path + error:&error]; if (!success) { - [NSException raise:NSInternalInconsistencyException format:@"Failed to delete database files: %@", error]; + [NSException raise:NSInternalInconsistencyException + format:@"Failed to delete database files: %@", error]; } } - (void)purgeEverything { [self close]; - [@[kFServerDBPath, kFWritesDBPath] - enumerateObjectsUsingBlock:^(NSString *dbPath, NSUInteger idx, BOOL *stop) { - [self purgeDatabase:dbPath]; - }]; + [@[ kFServerDBPath, kFWritesDBPath ] + enumerateObjectsUsingBlock:^(NSString *dbPath, NSUInteger idx, + BOOL *stop) { + [self purgeDatabase:dbPath]; + }]; [self openDatabases]; } @@ -210,14 +259,15 @@ - (void)close { } } -+ (NSString *) firebaseDir { - #if TARGET_OS_IOS || TARGET_OS_TV - NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); ++ (NSString *)firebaseDir { +#if TARGET_OS_IOS || TARGET_OS_TV + NSArray *dirPaths = NSSearchPathForDirectoriesInDomains( + NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDir = [dirPaths objectAtIndex:0]; return [documentsDir stringByAppendingPathComponent:@"firebase"]; - #elif TARGET_OS_OSX +#elif TARGET_OS_OSX return [NSHomeDirectory() stringByAppendingPathComponent:@".firebase"]; - #endif +#endif } - (APLevelDB *)createDB:(NSString *)dbName { @@ -226,8 +276,9 @@ - (APLevelDB *)createDB:(NSString *)dbName { APLevelDB *db = [APLevelDB levelDBWithPath:path error:&err]; if (err) { - FFWarn(@"I-RDB076036", @"Failed to read database persistence file '%@': %@", - dbName, [err localizedDescription]); + FFWarn(@"I-RDB076036", + @"Failed to read database persistence file '%@': %@", dbName, + [err localizedDescription]); err = nil; // Delete the database and try again. @@ -235,33 +286,50 @@ - (APLevelDB *)createDB:(NSString *)dbName { db = [APLevelDB levelDBWithPath:path error:&err]; if (err) { - NSString *reason = [NSString stringWithFormat:@"Error initializing persistence: %@", [err description]]; - @throw [NSException exceptionWithName:@"FirebaseDatabasePersistenceFailure" reason:reason userInfo:nil]; + NSString *reason = [NSString + stringWithFormat:@"Error initializing persistence: %@", + [err description]]; + @throw [NSException + exceptionWithName:@"FirebaseDatabasePersistenceFailure" + reason:reason + userInfo:nil]; } } return db; } -- (void)saveUserOverwrite:(id)node atPath:(FPath *)path writeId:(NSUInteger)writeId { - NSDictionary *write = - @{ kFUserWriteId: @(writeId), - kFUserWritePath: [path toStringWithTrailingSlash], - kFUserWriteOverwrite: [node valForExport:YES] }; +- (void)saveUserOverwrite:(id)node + atPath:(FPath *)path + writeId:(NSUInteger)writeId { + NSDictionary *write = @{ + kFUserWriteId : @(writeId), + kFUserWritePath : [path toStringWithTrailingSlash], + kFUserWriteOverwrite : [node valForExport:YES] + }; NSError *error = nil; - NSData *data = [NSJSONSerialization dataWithJSONObject:write options:0 error:&error]; - NSAssert(data, @"Failed to serialize user overwrite: %@, (Error: %@)", write, error); + NSData *data = [NSJSONSerialization dataWithJSONObject:write + options:0 + error:&error]; + NSAssert(data, @"Failed to serialize user overwrite: %@, (Error: %@)", + write, error); [self.writesDB setData:data forKey:writeRecordKey(writeId)]; } -- (void)saveUserMerge:(FCompoundWrite *)merge atPath:(FPath *)path writeId:(NSUInteger)writeId { - NSDictionary *write = - @{ kFUserWriteId: @(writeId), - kFUserWritePath: [path toStringWithTrailingSlash], - kFUserWriteMerge: [merge valForExport:YES] }; +- (void)saveUserMerge:(FCompoundWrite *)merge + atPath:(FPath *)path + writeId:(NSUInteger)writeId { + NSDictionary *write = @{ + kFUserWriteId : @(writeId), + kFUserWritePath : [path toStringWithTrailingSlash], + kFUserWriteMerge : [merge valForExport:YES] + }; NSError *error = nil; - NSData *data = [NSJSONSerialization dataWithJSONObject:write options:0 error:&error]; - NSAssert(data, @"Failed to serialize user merge: %@ (Error: %@)", write, error); + NSData *data = [NSJSONSerialization dataWithJSONObject:write + options:0 + error:&error]; + NSAssert(data, @"Failed to serialize user merge: %@ (Error: %@)", write, + error); [self.writesDB setData:data forKey:writeRecordKey(writeId)]; } @@ -274,61 +342,80 @@ - (void)removeAllUserWrites { NSDate *start = [NSDate date]; id batch = [self.writesDB beginWriteBatch]; [self.writesDB enumerateKeys:^(NSString *key, BOOL *stop) { - [batch removeKey:key]; - count++; + [batch removeKey:key]; + count++; }]; BOOL success = [batch commit]; if (!success) { FFWarn(@"I-RDB076010", @"Failed to remove all users writes on disk!"); } else { - FFDebug(@"I-RDB076011", @"Removed %lu writes in %fms", (unsigned long)count, [start timeIntervalSinceNow]*-1000); + FFDebug(@"I-RDB076011", @"Removed %lu writes in %fms", + (unsigned long)count, [start timeIntervalSinceNow] * -1000); } } - (NSArray *)userWrites { NSDate *date = [NSDate date]; NSMutableArray *writes = [NSMutableArray array]; - [self.writesDB enumerateKeysAndValuesAsData:^(NSString *key, NSData *data, BOOL *stop) { - NSError *error = nil; - NSDictionary *writeJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; - if (writeJSON == nil) { - if (error.code == kFNanFailureCode) { - FFWarn(@"I-RDB076012", @"Failed to deserialize write (%@), likely because of out of range doubles (Error: %@)", - [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding], - error); - FFWarn(@"I-RDB076013", @"Removing failed write with key %@", key); - [self.writesDB removeKey:key]; - } else { - [NSException raise:NSInternalInconsistencyException format:@"Failed to deserialize write: %@", error]; - } - } else { - NSInteger writeId = ((NSNumber *)writeJSON[kFUserWriteId]).integerValue; - FPath *path = [FPath pathWithString:writeJSON[kFUserWritePath]]; - FWriteRecord *writeRecord; - if (writeJSON[kFUserWriteMerge] != nil) { - // It's a merge - FCompoundWrite *merge = [FCompoundWrite compoundWriteWithValueDictionary:writeJSON[kFUserWriteMerge]]; - writeRecord = [[FWriteRecord alloc] initWithPath:path merge:merge writeId:writeId]; - } else { - // It's an overwrite - NSAssert(writeJSON[kFUserWriteOverwrite] != nil, @"Persisted write did not contain merge or overwrite!"); - id node = [FSnapshotUtilities nodeFrom:writeJSON[kFUserWriteOverwrite]]; - writeRecord = [[FWriteRecord alloc] initWithPath:path overwrite:node writeId:writeId visible:YES]; - } - [writes addObject:writeRecord]; - } + [self.writesDB enumerateKeysAndValuesAsData:^(NSString *key, NSData *data, + BOOL *stop) { + NSError *error = nil; + NSDictionary *writeJSON = [NSJSONSerialization JSONObjectWithData:data + options:0 + error:&error]; + if (writeJSON == nil) { + if (error.code == kFNanFailureCode) { + FFWarn(@"I-RDB076012", + @"Failed to deserialize write (%@), likely because of out " + @"of range doubles (Error: %@)", + [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding], + error); + FFWarn(@"I-RDB076013", @"Removing failed write with key %@", key); + [self.writesDB removeKey:key]; + } else { + [NSException raise:NSInternalInconsistencyException + format:@"Failed to deserialize write: %@", error]; + } + } else { + NSInteger writeId = + ((NSNumber *)writeJSON[kFUserWriteId]).integerValue; + FPath *path = [FPath pathWithString:writeJSON[kFUserWritePath]]; + FWriteRecord *writeRecord; + if (writeJSON[kFUserWriteMerge] != nil) { + // It's a merge + FCompoundWrite *merge = [FCompoundWrite + compoundWriteWithValueDictionary:writeJSON[kFUserWriteMerge]]; + writeRecord = [[FWriteRecord alloc] initWithPath:path + merge:merge + writeId:writeId]; + } else { + // It's an overwrite + NSAssert(writeJSON[kFUserWriteOverwrite] != nil, + @"Persisted write did not contain merge or overwrite!"); + id node = + [FSnapshotUtilities nodeFrom:writeJSON[kFUserWriteOverwrite]]; + writeRecord = [[FWriteRecord alloc] initWithPath:path + overwrite:node + writeId:writeId + visible:YES]; + } + [writes addObject:writeRecord]; + } }]; // Make sure writes are sorted - [writes sortUsingComparator:^NSComparisonResult(FWriteRecord *one, FWriteRecord *two) { - if (one.writeId < two.writeId) { - return NSOrderedAscending; - } else if (one.writeId > two.writeId) { - return NSOrderedDescending; - } else { - return NSOrderedSame; - } + [writes sortUsingComparator:^NSComparisonResult(FWriteRecord *one, + FWriteRecord *two) { + if (one.writeId < two.writeId) { + return NSOrderedAscending; + } else if (one.writeId > two.writeId) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } }]; - FFDebug(@"I-RDB076014", @"Loaded %lu writes in %fms", (unsigned long)writes.count, [date timeIntervalSinceNow]*-1000); + FFDebug(@"I-RDB076014", @"Loaded %lu writes in %fms", + (unsigned long)writes.count, [date timeIntervalSinceNow] * -1000); return writes; } @@ -336,7 +423,8 @@ - (NSArray *)userWrites { NSDate *start = [NSDate date]; id data = [self internalNestedDataForPath:path]; id node = [FSnapshotUtilities nodeFrom:data]; - FFDebug(@"I-RDB076015", @"Loaded node with %d children at %@ in %fms", [node numChildren], path, [start timeIntervalSinceNow]*-1000); + FFDebug(@"I-RDB076015", @"Loaded node with %d children at %@ in %fms", + [node numChildren], path, [start timeIntervalSinceNow] * -1000); return node; } @@ -344,14 +432,20 @@ - (NSArray *)userWrites { NSDate *start = [NSDate date]; __block id node = [FEmptyNode emptyNode]; [keys enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) { - id data = [self internalNestedDataForPath:[path childFromString:key]]; - node = [node updateImmediateChild:key withNewChild:[FSnapshotUtilities nodeFrom:data]]; + id data = [self internalNestedDataForPath:[path childFromString:key]]; + node = [node updateImmediateChild:key + withNewChild:[FSnapshotUtilities nodeFrom:data]]; }]; - FFDebug(@"I-RDB076016", @"Loaded node with %d children for %lu keys at %@ in %fms", [node numChildren], (unsigned long)keys.count, path, [start timeIntervalSinceNow]*-1000); + FFDebug(@"I-RDB076016", + @"Loaded node with %d children for %lu keys at %@ in %fms", + [node numChildren], (unsigned long)keys.count, path, + [start timeIntervalSinceNow] * -1000); return node; } -- (void)updateServerCache:(id)node atPath:(FPath *)path merge:(BOOL)merge { +- (void)updateServerCache:(id)node + atPath:(FPath *)path + merge:(BOOL)merge { NSDate *start = [NSDate date]; id batch = [self.serverCacheDB beginWriteBatch]; // Remove any leaf nodes that might be higher up @@ -359,54 +453,78 @@ - (void)updateServerCache:(id)node atPath:(FPath *)path merge:(BOOL)merge __block NSUInteger counter = 0; if (merge) { // remove any children that exist - [node enumerateChildrenUsingBlock:^(NSString *childKey, id childNode, BOOL *stop) { - FPath *childPath = [path childFromString:childKey]; - [self removeAllWithPrefix:serverCacheKey(childPath) batch:batch database:self.serverCacheDB]; - [self saveNodeInternal:childNode atPath:childPath batch:batch counter:&counter]; + [node enumerateChildrenUsingBlock:^(NSString *childKey, + id childNode, BOOL *stop) { + FPath *childPath = [path childFromString:childKey]; + [self removeAllWithPrefix:serverCacheKey(childPath) + batch:batch + database:self.serverCacheDB]; + [self saveNodeInternal:childNode + atPath:childPath + batch:batch + counter:&counter]; }]; } else { // remove everything - [self removeAllWithPrefix:serverCacheKey(path) batch:batch database:self.serverCacheDB]; + [self removeAllWithPrefix:serverCacheKey(path) + batch:batch + database:self.serverCacheDB]; [self saveNodeInternal:node atPath:path batch:batch counter:&counter]; } BOOL success = [batch commit]; if (!success) { FFWarn(@"I-RDB076017", @"Failed to update server cache on disk!"); } else { - FFDebug(@"I-RDB076018", @"Saved %lu leaf nodes for overwrite in %fms", (unsigned long)counter, [start timeIntervalSinceNow]*-1000); + FFDebug(@"I-RDB076018", @"Saved %lu leaf nodes for overwrite in %fms", + (unsigned long)counter, [start timeIntervalSinceNow] * -1000); } } -- (void)updateServerCacheWithMerge:(FCompoundWrite *)merge atPath:(FPath *)path { +- (void)updateServerCacheWithMerge:(FCompoundWrite *)merge + atPath:(FPath *)path { NSDate *start = [NSDate date]; __block NSUInteger counter = 0; id batch = [self.serverCacheDB beginWriteBatch]; // Remove any leaf nodes that might be higher up [self removeAllLeafNodesOnPath:path batch:batch]; [merge enumerateWrites:^(FPath *relativePath, id node, BOOL *stop) { - FPath *childPath = [path child:relativePath]; - [self removeAllWithPrefix:serverCacheKey(childPath) batch:batch database:self.serverCacheDB]; - [self saveNodeInternal:node atPath:childPath batch:batch counter:&counter]; + FPath *childPath = [path child:relativePath]; + [self removeAllWithPrefix:serverCacheKey(childPath) + batch:batch + database:self.serverCacheDB]; + [self saveNodeInternal:node + atPath:childPath + batch:batch + counter:&counter]; }]; BOOL success = [batch commit]; if (!success) { FFWarn(@"I-RDB076019", @"Failed to update server cache on disk!"); } else { - FFDebug(@"I-RDB076020", @"Saved %lu leaf nodes for merge in %fms", (unsigned long)counter, [start timeIntervalSinceNow]*-1000); + FFDebug(@"I-RDB076020", @"Saved %lu leaf nodes for merge in %fms", + (unsigned long)counter, [start timeIntervalSinceNow] * -1000); } } -- (void)saveNodeInternal:(id)node atPath:(FPath *)path batch:(id)batch counter:(NSUInteger *)counter { +- (void)saveNodeInternal:(id)node + atPath:(FPath *)path + batch:(id)batch + counter:(NSUInteger *)counter { id data = [node valForExport:YES]; - if(data != nil && ![data isKindOfClass:[NSNull class]]) { - [self internalSetNestedData:data forKey:serverCacheKey(path) withBatch:batch counter:counter]; + if (data != nil && ![data isKindOfClass:[NSNull class]]) { + [self internalSetNestedData:data + forKey:serverCacheKey(path) + withBatch:batch + counter:counter]; } } - (NSUInteger)serverCacheEstimatedSizeInBytes { - // Use the exact size, because for pruning the approximate size can lead to weird situations where we prune everything - // because no compaction is ever run - return [self.serverCacheDB exactSizeFrom:kFServerCachePrefix to:kFServerCacheRangeEnd]; + // Use the exact size, because for pruning the approximate size can lead to + // weird situations where we prune everything because no compaction is ever + // run + return [self.serverCacheDB exactSizeFrom:kFServerCachePrefix + to:kFServerCacheRangeEnd]; } - (void)pruneCache:(FPruneForest *)pruneForest atPath:(FPath *)path { @@ -419,21 +537,27 @@ - (void)pruneCache:(FPruneForest *)pruneForest atPath:(FPath *)path { NSString *prefix = serverCacheKey(path); id batch = [self.serverCacheDB beginWriteBatch]; - [self.serverCacheDB enumerateKeysWithPrefix:prefix usingBlock:^(NSString *dbKey, BOOL *stop) { - NSString *pathStr = [dbKey substringFromIndex:prefix.length]; - FPath *relativePath = [[FPath alloc] initWith:pathStr]; - if ([pruneForest shouldPruneUnkeptDescendantsAtPath:relativePath]) { - pruned++; - [batch removeKey:dbKey]; - } else { - kept++; - } - }]; + [self.serverCacheDB + enumerateKeysWithPrefix:prefix + usingBlock:^(NSString *dbKey, BOOL *stop) { + NSString *pathStr = + [dbKey substringFromIndex:prefix.length]; + FPath *relativePath = [[FPath alloc] initWith:pathStr]; + if ([pruneForest shouldPruneUnkeptDescendantsAtPath: + relativePath]) { + pruned++; + [batch removeKey:dbKey]; + } else { + kept++; + } + }]; BOOL success = [batch commit]; if (!success) { FFWarn(@"I-RDB076021", @"Failed to prune cache on disk!"); } else { - FFDebug(@"I-RDB076022", @"Pruned %lu paths, kept %lu paths in %fms", (unsigned long)pruned, (unsigned long)kept, [start timeIntervalSinceNow]*-1000); + FFDebug(@"I-RDB076022", @"Pruned %lu paths, kept %lu paths in %fms", + (unsigned long)pruned, (unsigned long)kept, + [start timeIntervalSinceNow] * -1000); } } @@ -442,38 +566,74 @@ - (void)pruneCache:(FPruneForest *)pruneForest atPath:(FPath *)path { - (NSArray *)loadTrackedQueries { NSDate *date = [NSDate date]; NSMutableArray *trackedQueries = [NSMutableArray array]; - [self.serverCacheDB enumerateKeysWithPrefix:kFTrackedQueriesPrefix asData:^(NSString *key, NSData *data, BOOL *stop) { - NSError *error = nil; - NSDictionary *queryJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; - if (queryJSON == nil) { - if (error.code == kFNanFailureCode) { - FFWarn(@"I-RDB076023", @"Failed to deserialize tracked query (%@), likely because of out of range doubles (Error: %@)", - [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding], - error); - FFWarn(@"I-RDB076024", @"Removing failed tracked query with key %@", key); - [self.serverCacheDB removeKey:key]; - } else { - [NSException raise:NSInternalInconsistencyException format:@"Failed to deserialize tracked query: %@", error]; - } - } else { - NSUInteger queryId = ((NSNumber *)queryJSON[kFTrackedQueryId]).unsignedIntegerValue; - FPath *path = [FPath pathWithString:queryJSON[kFTrackedQueryPath]]; - FQueryParams *params = [FQueryParams fromQueryObject:queryJSON[kFTrackedQueryParams]]; - FQuerySpec *query = [[FQuerySpec alloc] initWithPath:path params:params]; - BOOL isComplete = [queryJSON[kFTrackedQueryIsComplete] boolValue]; - BOOL isActive = [queryJSON[kFTrackedQueryIsActive] boolValue]; - NSTimeInterval lastUse = [queryJSON[kFTrackedQueryLastUse] doubleValue]; - - FTrackedQuery *trackedQuery = [[FTrackedQuery alloc] initWithId:queryId - query:query - lastUse:lastUse - isActive:isActive - isComplete:isComplete]; - - [trackedQueries addObject:trackedQuery]; - } - }]; - FFDebug(@"I-RDB076025", @"Loaded %lu tracked queries in %fms", (unsigned long)trackedQueries.count, [date timeIntervalSinceNow]*-1000); + [self.serverCacheDB + enumerateKeysWithPrefix:kFTrackedQueriesPrefix + asData:^(NSString *key, NSData *data, BOOL *stop) { + NSError *error = nil; + NSDictionary *queryJSON = + [NSJSONSerialization JSONObjectWithData:data + options:0 + error:&error]; + if (queryJSON == nil) { + if (error.code == kFNanFailureCode) { + FFWarn( + @"I-RDB076023", + @"Failed to deserialize tracked query " + @"(%@), likely because of out of range " + @"doubles (Error: %@)", + [[NSString alloc] + initWithData:data + encoding:NSUTF8StringEncoding], + error); + FFWarn(@"I-RDB076024", + @"Removing failed tracked query with " + @"key %@", + key); + [self.serverCacheDB removeKey:key]; + } else { + [NSException + raise:NSInternalInconsistencyException + format:@"Failed to deserialize tracked " + @"query: %@", + error]; + } + } else { + NSUInteger queryId = + ((NSNumber *)queryJSON[kFTrackedQueryId]) + .unsignedIntegerValue; + FPath *path = + [FPath pathWithString: + queryJSON[kFTrackedQueryPath]]; + FQueryParams *params = [FQueryParams + fromQueryObject:queryJSON + [kFTrackedQueryParams]]; + FQuerySpec *query = + [[FQuerySpec alloc] initWithPath:path + params:params]; + BOOL isComplete = + [queryJSON[kFTrackedQueryIsComplete] + boolValue]; + BOOL isActive = + [queryJSON[kFTrackedQueryIsActive] + boolValue]; + NSTimeInterval lastUse = + [queryJSON[kFTrackedQueryLastUse] + doubleValue]; + + FTrackedQuery *trackedQuery = + [[FTrackedQuery alloc] + initWithId:queryId + query:query + lastUse:lastUse + isActive:isActive + isComplete:isComplete]; + + [trackedQueries addObject:trackedQuery]; + } + }]; + FFDebug(@"I-RDB076025", @"Loaded %lu tracked queries in %fms", + (unsigned long)trackedQueries.count, + [date timeIntervalSinceNow] * -1000); return trackedQueries; } @@ -482,38 +642,42 @@ - (void)removeTrackedQuery:(NSUInteger)queryId { id batch = [self.serverCacheDB beginWriteBatch]; [batch removeKey:trackedQueryKey(queryId)]; __block NSUInteger keyCount = 0; - [self.serverCacheDB enumerateKeysWithPrefix:trackedQueryKeysKeyPrefix(queryId) usingBlock:^(NSString *key, BOOL *stop) { - [batch removeKey:key]; - keyCount++; - }]; + [self.serverCacheDB + enumerateKeysWithPrefix:trackedQueryKeysKeyPrefix(queryId) + usingBlock:^(NSString *key, BOOL *stop) { + [batch removeKey:key]; + keyCount++; + }]; BOOL success = [batch commit]; if (!success) { FFWarn(@"I-RDB076026", @"Failed to remove tracked query on disk!"); } else { - FFDebug(@"I-RDB076027", @"Removed query with id %lu (and removed %lu keys) in %fms", - (unsigned long)queryId, - (unsigned long)keyCount, - [start timeIntervalSinceNow]*-1000); + FFDebug(@"I-RDB076027", + @"Removed query with id %lu (and removed %lu keys) in %fms", + (unsigned long)queryId, (unsigned long)keyCount, + [start timeIntervalSinceNow] * -1000); } } - (void)saveTrackedQuery:(FTrackedQuery *)query { NSDate *start = [NSDate date]; - NSDictionary *trackedQuery = - @{ - kFTrackedQueryId: @(query.queryId), - kFTrackedQueryPath: [query.query.path toStringWithTrailingSlash], - kFTrackedQueryParams: [query.query.params wireProtocolParams], - kFTrackedQueryLastUse: @(query.lastUse), - kFTrackedQueryIsComplete: @(query.isComplete), - kFTrackedQueryIsActive: @(query.isActive) + NSDictionary *trackedQuery = @{ + kFTrackedQueryId : @(query.queryId), + kFTrackedQueryPath : [query.query.path toStringWithTrailingSlash], + kFTrackedQueryParams : [query.query.params wireProtocolParams], + kFTrackedQueryLastUse : @(query.lastUse), + kFTrackedQueryIsComplete : @(query.isComplete), + kFTrackedQueryIsActive : @(query.isActive) }; NSError *error = nil; - NSData *data = [NSJSONSerialization dataWithJSONObject:trackedQuery options:0 error:&error]; + NSData *data = [NSJSONSerialization dataWithJSONObject:trackedQuery + options:0 + error:&error]; NSAssert(data, @"Failed to serialize tracked query (Error: %@)", error); [self.serverCacheDB setData:data forKey:trackedQueryKey(query.queryId)]; - FFDebug(@"I-RDB076028", @"Saved tracked query %lu in %fms", (unsigned long)query.queryId, [start timeIntervalSinceNow]*-1000); + FFDebug(@"I-RDB076028", @"Saved tracked query %lu in %fms", + (unsigned long)query.queryId, [start timeIntervalSinceNow] * -1000); } - (void)setTrackedQueryKeys:(NSSet *)keys forQueryId:(NSUInteger)queryId { @@ -522,68 +686,84 @@ - (void)setTrackedQueryKeys:(NSSet *)keys forQueryId:(NSUInteger)queryId { __block NSUInteger added = 0; id batch = [self.serverCacheDB beginWriteBatch]; NSMutableSet *seenKeys = [NSMutableSet set]; - // First, delete any keys that might be stored and are not part of the current keys - [self.serverCacheDB enumerateKeysWithPrefix:trackedQueryKeysKeyPrefix(queryId) asStrings:^(NSString *dbKey, NSString *actualKey, BOOL *stop) { - if ([keys containsObject:actualKey]) { - // Already in DB - [seenKeys addObject:actualKey]; - } else { - // Not part of set, delete key - [batch removeKey:dbKey]; - removed++; - } - }]; + // First, delete any keys that might be stored and are not part of the + // current keys + [self.serverCacheDB + enumerateKeysWithPrefix:trackedQueryKeysKeyPrefix(queryId) + asStrings:^(NSString *dbKey, NSString *actualKey, + BOOL *stop) { + if ([keys containsObject:actualKey]) { + // Already in DB + [seenKeys addObject:actualKey]; + } else { + // Not part of set, delete key + [batch removeKey:dbKey]; + removed++; + } + }]; // Next add any keys that are missing in the database [keys enumerateObjectsUsingBlock:^(NSString *childKey, BOOL *stop) { - if (![seenKeys containsObject:childKey]) { - [batch setString:childKey forKey:trackedQueryKeysKey(queryId, childKey)]; - added++; - } + if (![seenKeys containsObject:childKey]) { + [batch setString:childKey + forKey:trackedQueryKeysKey(queryId, childKey)]; + added++; + } }]; BOOL success = [batch commit]; if (!success) { FFWarn(@"I-RDB076029", @"Failed to set tracked queries on disk!"); } else { - FFDebug(@"I-RDB076030", @"Set %lu tracked keys (%lu added, %lu removed) for query %lu in %fms", - (unsigned long)keys.count, - (unsigned long)added, - (unsigned long)removed, - (unsigned long)queryId, - [start timeIntervalSinceNow]*-1000); + FFDebug(@"I-RDB076030", + @"Set %lu tracked keys (%lu added, %lu removed) for query %lu " + @"in %fms", + (unsigned long)keys.count, (unsigned long)added, + (unsigned long)removed, (unsigned long)queryId, + [start timeIntervalSinceNow] * -1000); } } -- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added removedKeys:(NSSet *)removed forQueryId:(NSUInteger)queryId { +- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added + removedKeys:(NSSet *)removed + forQueryId:(NSUInteger)queryId { NSDate *start = [NSDate date]; id batch = [self.serverCacheDB beginWriteBatch]; [removed enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) { - [batch removeKey:trackedQueryKeysKey(queryId, key)]; + [batch removeKey:trackedQueryKeysKey(queryId, key)]; }]; [added enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) { - [batch setString:key forKey:trackedQueryKeysKey(queryId, key)]; + [batch setString:key forKey:trackedQueryKeysKey(queryId, key)]; }]; BOOL success = [batch commit]; if (!success) { FFWarn(@"I-RDB076031", @"Failed to update tracked queries on disk!"); } else { - FFDebug(@"I-RDB076032", @"Added %lu tracked keys, removed %lu for query %lu in %fms", (unsigned long)added.count, (unsigned long)removed.count, (unsigned long)queryId, [start timeIntervalSinceNow]*-1000); + FFDebug(@"I-RDB076032", + @"Added %lu tracked keys, removed %lu for query %lu in %fms", + (unsigned long)added.count, (unsigned long)removed.count, + (unsigned long)queryId, [start timeIntervalSinceNow] * -1000); } } - (NSSet *)trackedQueryKeysForQuery:(NSUInteger)queryId { NSDate *start = [NSDate date]; NSMutableSet *set = [NSMutableSet set]; - [self.serverCacheDB enumerateKeysWithPrefix:trackedQueryKeysKeyPrefix(queryId) asStrings:^(NSString *dbKey, NSString *actualKey, BOOL *stop) { - [set addObject:actualKey]; - }]; - FFDebug(@"I-RDB076033", @"Loaded %lu tracked keys for query %lu in %fms", (unsigned long)set.count, (unsigned long)queryId, [start timeIntervalSinceNow]*-1000); + [self.serverCacheDB + enumerateKeysWithPrefix:trackedQueryKeysKeyPrefix(queryId) + asStrings:^(NSString *dbKey, NSString *actualKey, + BOOL *stop) { + [set addObject:actualKey]; + }]; + FFDebug(@"I-RDB076033", @"Loaded %lu tracked keys for query %lu in %fms", + (unsigned long)set.count, (unsigned long)queryId, + [start timeIntervalSinceNow] * -1000); return set; } #pragma mark - Internal methods -- (void)removeAllLeafNodesOnPath:(FPath *)path batch:(id)batch { +- (void)removeAllLeafNodesOnPath:(FPath *)path + batch:(id)batch { while (!path.isEmpty) { [batch removeKey:serverCacheKey(path)]; path = [path parent]; @@ -592,26 +772,36 @@ - (void)removeAllLeafNodesOnPath:(FPath *)path batch:(id)ba [batch removeKey:serverCacheKey([FPath empty])]; } -- (void)removeAllWithPrefix:(NSString *)prefix batch:(id)batch database:(APLevelDB *)database { +- (void)removeAllWithPrefix:(NSString *)prefix + batch:(id)batch + database:(APLevelDB *)database { assert(prefix != nil); - [database enumerateKeysWithPrefix:prefix usingBlock:^(NSString *key, BOOL *stop) { - [batch removeKey:key]; - }]; + [database enumerateKeysWithPrefix:prefix + usingBlock:^(NSString *key, BOOL *stop) { + [batch removeKey:key]; + }]; } #pragma mark - Internal helper methods -- (void)internalSetNestedData:(id)value forKey:(NSString *)key withBatch:(id)batch counter:(NSUInteger *)counter { - if([value isKindOfClass:[NSDictionary class]]) { - NSDictionary* dictionary = value; - [dictionary enumerateKeysAndObjectsUsingBlock:^(id childKey, id obj, BOOL *stop) { - assert(obj != nil); - NSString* childPath = [NSString stringWithFormat:@"%@%@/", key, childKey]; - [self internalSetNestedData:obj forKey:childPath withBatch:batch counter:counter]; +- (void)internalSetNestedData:(id)value + forKey:(NSString *)key + withBatch:(id)batch + counter:(NSUInteger *)counter { + if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictionary = value; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id childKey, id obj, + BOOL *stop) { + assert(obj != nil); + NSString *childPath = + [NSString stringWithFormat:@"%@%@/", key, childKey]; + [self internalSetNestedData:obj + forKey:childPath + withBatch:batch + counter:counter]; }]; - } - else { + } else { NSData *data = [self serializePrimitive:value]; [batch setData:data forKey:key]; (*counter)++; @@ -623,22 +813,26 @@ - (id)internalNestedDataForPath:(FPath *)path { NSString *baseKey = serverCacheKey(path); - // HACK to make sure iter is freed now to avoid race conditions (if self.db is deleted before iter, you get an access violation). + // HACK to make sure iter is freed now to avoid race conditions (if self.db + // is deleted before iter, you get an access violation). @autoreleasepool { - APLevelDBIterator* iter = [APLevelDBIterator iteratorWithLevelDB:self.serverCacheDB]; + APLevelDBIterator *iter = + [APLevelDBIterator iteratorWithLevelDB:self.serverCacheDB]; [iter seekToKey:baseKey]; if (iter.key == nil || ![iter.key hasPrefix:baseKey]) { // No data. return nil; } else { - return [self internalNestedDataFromIterator:iter andKeyPrefix:baseKey]; + return [self internalNestedDataFromIterator:iter + andKeyPrefix:baseKey]; } } } -- (id) internalNestedDataFromIterator:(APLevelDBIterator*)iterator andKeyPrefix:(NSString*)prefix { - NSString* key = iterator.key; +- (id)internalNestedDataFromIterator:(APLevelDBIterator *)iterator + andKeyPrefix:(NSString *)prefix { + NSString *key = iterator.key; if ([key isEqualToString:prefix]) { id result = [self deserializePrimitive:iterator.valueAsData]; @@ -648,11 +842,14 @@ - (id) internalNestedDataFromIterator:(APLevelDBIterator*)iterator andKeyPrefix: NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; while (key != nil && [key hasPrefix:prefix]) { NSString *relativePath = [key substringFromIndex:prefix.length]; - NSArray* pathPieces = [relativePath componentsSeparatedByString:@"/"]; + NSArray *pathPieces = + [relativePath componentsSeparatedByString:@"/"]; assert(pathPieces.count > 0); NSString *childName = pathPieces[0]; - NSString *childPath = [NSString stringWithFormat:@"%@%@/", prefix, childName]; - id childValue = [self internalNestedDataFromIterator:iterator andKeyPrefix:childPath]; + NSString *childPath = + [NSString stringWithFormat:@"%@%@/", prefix, childName]; + id childValue = [self internalNestedDataFromIterator:iterator + andKeyPrefix:childPath]; [dict setValue:childValue forKey:childName]; key = iterator.key; @@ -661,28 +858,68 @@ - (id) internalNestedDataFromIterator:(APLevelDBIterator*)iterator andKeyPrefix: } } - -- (NSData*) serializePrimitive:(id)value { - // HACK: The built-in serialization only works on dicts and arrays. So we create an array and then strip off - // the leading / trailing byte (the [ and ]). +- (NSData *)serializePrimitive:(id)value { + // HACK: The built-in serialization only works on dicts and arrays. So we + // create an array and then strip off the leading / trailing byte (the [ and + // ]). NSError *error = nil; - NSData *data = [NSJSONSerialization dataWithJSONObject:@[value] options:0 error:&error]; + NSData *data = [NSJSONSerialization dataWithJSONObject:@[ value ] + options:0 + error:&error]; NSAssert(data, @"Failed to serialize primitive: %@", error); return [data subdataWithRange:NSMakeRange(1, data.length - 2)]; } -- (id)fixDoubleParsing:(id)value __attribute__((no_sanitize("float-cast-overflow"))) { - // The parser for double values in JSONSerialization at the root takes some short-cuts and delivers wrong results - // (wrong rounding) for some double values, including 2.47. Because we use the exact bytes for hashing on the server - // this will lead to hash mismatches. The parser of NSNumber seems to be more in line with what the server expects, - // so we use that here - if ([value isKindOfClass:[NSNumber class]]) { +- (id)fixDoubleParsing:(id)value + __attribute__((no_sanitize("float-cast-overflow"))) { + if ([value isKindOfClass:[NSDecimalNumber class]]) { + // In case the value is an NSDecimalNumber, we may be dealing with + // precisions that are higher than what can be represented in a double. + // In this case it does not suffice to check for integral numbers by + // casting the [value doubleValue] to an int64_t, because this will + // cause the compared values to be rounded to double precision. + // Coupled with a bug in [NSDecimalNumber longLongValue] that triggers + // when converting values with high precision, this would cause + // values of high precision, but with an integral 'doubleValue' + // representation to be converted to bogus values. + // A radar for the NSDecimalNumber issue can be found here: + // http://www.openradar.me/radar?id=5007005597040640 + // Consider the NSDecimalNumber value: 999.9999999999999487 + // This number has a 'doubleValue' of 1000. Using the previous version + // of this method would cause the value to be interpreted to be integral + // and then the resulting value would be based on the longLongValue + // which due to the NSDecimalNumber issue would turn out as -844. + // By using NSDecimal logic to test for integral values, + // 999.9999999999999487 will not be considered integral, and instead + // of triggering the 'longLongValue' issue, it will be returned as + // the 'doubleValue' representation (1000). + // Please note, that even without the NSDecimalNumber issue, the + // 'correct' longLongValue of 999.9999999999999487 is 999 and not 1000, + // so the previous code would cause issues even without the bug + // referenced in the radar. + NSDecimal original = [(NSDecimalNumber *)value decimalValue]; + NSDecimal rounded; + NSDecimalRound(&rounded, &original, 0, NSRoundPlain); + if (NSDecimalCompare(&original, &rounded) != NSOrderedSame) { + NSString *doubleString = [value stringValue]; + return [NSNumber numberWithDouble:[doubleString doubleValue]]; + } else { + return [NSNumber numberWithLongLong:[value longLongValue]]; + } + } else if ([value isKindOfClass:[NSNumber class]]) { + // The parser for double values in JSONSerialization at the root takes + // some short-cuts and delivers wrong results (wrong rounding) for some + // double values, including 2.47. Because we use the exact bytes for + // hashing on the server this will lead to hash mismatches. The parser + // of NSNumber seems to be more in line with what the server expects, so + // we use that here CFNumberType type = CFNumberGetType((CFNumberRef)value); if (type == kCFNumberDoubleType || type == kCFNumberFloatType) { - // The NSJSON parser returns all numbers as double values, even those that contain no exponent. To - // make sure that the String conversion below doesn't unexpectedly reduce precision, we make sure that - // our number is indeed not an integer. + // The NSJSON parser returns all numbers as double values, even + // those that contain no exponent. To make sure that the String + // conversion below doesn't unexpectedly reduce precision, we make + // sure that our number is indeed not an integer. if ((double)(int64_t)[value doubleValue] != [value doubleValue]) { NSString *doubleString = [value stringValue]; return [NSNumber numberWithDouble:[doubleString doubleValue]]; @@ -694,32 +931,43 @@ - (id)fixDoubleParsing:(id)value __attribute__((no_sanitize("float-cast-overflow return value; } -- (id) deserializePrimitive:(NSData*)data { +- (id)deserializePrimitive:(NSData *)data { NSError *error = nil; - id result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error]; + id result = + [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingAllowFragments + error:&error]; if (result != nil) { return [self fixDoubleParsing:result]; } else { if (error.code == kFNanFailureCode) { - FFWarn(@"I-RDB076034", @"Failed to load primitive %@, likely because doubles where out of range (Error: %@)", - [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding], error); + FFWarn(@"I-RDB076034", + @"Failed to load primitive %@, likely because doubles where " + @"out of range (Error: %@)", + [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding], + error); return [NSNull null]; } else { - [NSException raise:NSInternalInconsistencyException format:@"Failed to deserialiaze primitive: %@", error]; + [NSException raise:NSInternalInconsistencyException + format:@"Failed to deserialiaze primitive: %@", error]; return nil; } } - } -+ (void)ensureDir:(NSString*)path markAsDoNotBackup:(BOOL)markAsDoNotBackup { - NSError* error; - BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:path - withIntermediateDirectories:YES - attributes:nil - error:&error]; ++ (void)ensureDir:(NSString *)path markAsDoNotBackup:(BOOL)markAsDoNotBackup { + NSError *error; + BOOL success = + [[NSFileManager defaultManager] createDirectoryAtPath:path + withIntermediateDirectories:YES + attributes:nil + error:&error]; if (!success) { - @throw [NSException exceptionWithName:@"FailedToCreatePersistenceDir" reason:@"Failed to create persistence directory." userInfo:@{ @"path": path }]; + @throw [NSException + exceptionWithName:@"FailedToCreatePersistenceDir" + reason:@"Failed to create persistence directory." + userInfo:@{@"path" : path}]; } if (markAsDoNotBackup) { @@ -728,11 +976,15 @@ + (void)ensureDir:(NSString*)path markAsDoNotBackup:(BOOL)markAsDoNotBackup { forKey:NSURLIsExcludedFromBackupKey error:&error]; if (!success) { - FFWarn(@"I-RDB076035", @"Failed to mark firebase database folder as do not backup: %@", error); - [NSException raise:@"Error marking as do not backup" format:@"Failed to mark folder %@ as do not backup", firebaseDirURL]; + FFWarn( + @"I-RDB076035", + @"Failed to mark firebase database folder as do not backup: %@", + error); + [NSException raise:@"Error marking as do not backup" + format:@"Failed to mark folder %@ as do not backup", + firebaseDirURL]; } } } - @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPendingPut.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPendingPut.h index 0d8de55..602bf8c 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPendingPut.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPendingPut.h @@ -14,42 +14,40 @@ * limitations under the License. */ -#import #import "FPath.h" +#import -// These are all legacy classes and are used to migrate older persistence data base to newer ones -// These classes should not be used in newer code +// These are all legacy classes and are used to migrate older persistence data +// base to newer ones These classes should not be used in newer code -@interface FPendingPut : NSObject +@interface FPendingPut : NSObject -@property (nonatomic, strong) FPath* path; -@property (nonatomic, strong) id data; -@property (nonatomic, strong) id priority; +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) id data; +@property(nonatomic, strong) id priority; -- (id) initWithPath:(FPath*)aPath andData:(id)aData andPriority:aPriority; +- (id)initWithPath:(FPath *)aPath andData:(id)aData andPriority:aPriority; - (void)encodeWithCoder:(NSCoder *)aCoder; - (id)initWithCoder:(NSCoder *)aDecoder; @end +@interface FPendingPutPriority : NSObject -@interface FPendingPutPriority : NSObject +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) id priority; -@property (nonatomic, strong) FPath* path; -@property (nonatomic, strong) id priority; - -- (id) initWithPath:(FPath*)aPath andPriority:(id)aPriority; +- (id)initWithPath:(FPath *)aPath andPriority:(id)aPriority; - (void)encodeWithCoder:(NSCoder *)aCoder; - (id)initWithCoder:(NSCoder *)aDecoder; @end +@interface FPendingUpdate : NSObject -@interface FPendingUpdate : NSObject - -@property (nonatomic, strong) FPath* path; -@property (nonatomic, strong) NSDictionary* data; +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) NSDictionary *data; -- (id) initWithPath:(FPath*)aPath andData:(NSDictionary*)aData; +- (id)initWithPath:(FPath *)aPath andData:(NSDictionary *)aData; - (void)encodeWithCoder:(NSCoder *)aCoder; - (id)initWithCoder:(NSCoder *)aDecoder; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPendingPut.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPendingPut.m index 12be825..c519599 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPendingPut.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPendingPut.m @@ -21,7 +21,7 @@ @implementation FPendingPut @synthesize path; @synthesize data; -- (id) initWithPath:(FPath *)aPath andData:(id)aData andPriority:(id)aPriority { +- (id)initWithPath:(FPath *)aPath andData:(id)aData andPriority:(id)aPriority { self = [super init]; if (self) { self.path = aPath; @@ -39,8 +39,9 @@ - (void)encodeWithCoder:(NSCoder *)aCoder { - (id)initWithCoder:(NSCoder *)aDecoder { self = [super init]; - if(self) { - self.path = [[FPath alloc] initWith:[aDecoder decodeObjectForKey:@"path"]]; + if (self) { + self.path = + [[FPath alloc] initWith:[aDecoder decodeObjectForKey:@"path"]]; self.data = [aDecoder decodeObjectForKey:@"data"]; self.priority = [aDecoder decodeObjectForKey:@"priority"]; } @@ -49,13 +50,12 @@ - (id)initWithCoder:(NSCoder *)aDecoder { @end - @implementation FPendingPutPriority @synthesize path; @synthesize priority; -- (id) initWithPath:(FPath *)aPath andPriority:(id)aPriority { +- (id)initWithPath:(FPath *)aPath andPriority:(id)aPriority { self = [super init]; if (self) { self.path = aPath; @@ -71,8 +71,9 @@ - (void)encodeWithCoder:(NSCoder *)aCoder { - (id)initWithCoder:(NSCoder *)aDecoder { self = [super init]; - if(self) { - self.path = [[FPath alloc] initWith:[aDecoder decodeObjectForKey:@"path"]]; + if (self) { + self.path = + [[FPath alloc] initWith:[aDecoder decodeObjectForKey:@"path"]]; self.priority = [aDecoder decodeObjectForKey:@"priority"]; } return self; @@ -80,13 +81,12 @@ - (id)initWithCoder:(NSCoder *)aDecoder { @end - @implementation FPendingUpdate @synthesize path; @synthesize data; -- (id) initWithPath:(FPath *)aPath andData:(id)aData { +- (id)initWithPath:(FPath *)aPath andData:(id)aData { self = [super init]; if (self) { self.path = aPath; @@ -102,8 +102,9 @@ - (void)encodeWithCoder:(NSCoder *)aCoder { - (id)initWithCoder:(NSCoder *)aDecoder { self = [super init]; - if(self) { - self.path = [[FPath alloc] initWith:[aDecoder decodeObjectForKey:@"path"]]; + if (self) { + self.path = + [[FPath alloc] initWith:[aDecoder decodeObjectForKey:@"path"]]; self.data = [aDecoder decodeObjectForKey:@"data"]; } return self; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPersistenceManager.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPersistenceManager.h index a3688b3..681c56d 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPersistenceManager.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPersistenceManager.h @@ -16,21 +16,26 @@ #import -#import "FNode.h" +#import "FCacheNode.h" +#import "FCachePolicy.h" #import "FCompoundWrite.h" +#import "FNode.h" #import "FQuerySpec.h" #import "FRepoInfo.h" #import "FStorageEngine.h" -#import "FCachePolicy.h" -#import "FCacheNode.h" @interface FPersistenceManager : NSObject -- (id)initWithStorageEngine:(id)storageEngine cachePolicy:(id)cachePolicy; +- (id)initWithStorageEngine:(id)storageEngine + cachePolicy:(id)cachePolicy; - (void)close; -- (void)saveUserOverwrite:(id)node atPath:(FPath *)path writeId:(NSUInteger)writeId; -- (void)saveUserMerge:(FCompoundWrite *)merge atPath:(FPath *)path writeId:(NSUInteger)writeId; +- (void)saveUserOverwrite:(id)node + atPath:(FPath *)path + writeId:(NSUInteger)writeId; +- (void)saveUserMerge:(FCompoundWrite *)merge + atPath:(FPath *)path + writeId:(NSUInteger)writeId; - (void)removeUserWrite:(NSUInteger)writeId; - (void)removeAllUserWrites; - (NSArray *)userWrites; @@ -40,13 +45,16 @@ - (void)updateServerCacheWithMerge:(FCompoundWrite *)merge atPath:(FPath *)path; - (void)applyUserWrite:(id)write toServerCacheAtPath:(FPath *)path; -- (void)applyUserMerge:(FCompoundWrite *)merge toServerCacheAtPath:(FPath *)path; +- (void)applyUserMerge:(FCompoundWrite *)merge + toServerCacheAtPath:(FPath *)path; - (void)setQueryComplete:(FQuerySpec *)spec; - (void)setQueryActive:(FQuerySpec *)spec; - (void)setQueryInactive:(FQuerySpec *)spec; - (void)setTrackedQueryKeys:(NSSet *)keys forQuery:(FQuerySpec *)query; -- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added removedKeys:(NSSet *)removed forQuery:(FQuerySpec *)query; +- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added + removedKeys:(NSSet *)removed + forQuery:(FQuerySpec *)query; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPersistenceManager.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPersistenceManager.m index b488f3e..8924802 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPersistenceManager.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPersistenceManager.m @@ -14,35 +14,37 @@ * limitations under the License. */ -#import #import "FPersistenceManager.h" -#import "FLevelDBStorageEngine.h" #import "FCacheNode.h" +#import "FClock.h" #import "FIndexedNode.h" -#import "FTrackedQueryManager.h" +#import "FLevelDBStorageEngine.h" +#import "FPruneForest.h" #import "FTrackedQuery.h" +#import "FTrackedQueryManager.h" #import "FUtilities.h" -#import "FPruneForest.h" -#import "FClock.h" +#import @interface FPersistenceManager () -@property (nonatomic, strong) id storageEngine; -@property (nonatomic, strong) id cachePolicy; -@property (nonatomic, strong) FTrackedQueryManager *trackedQueryManager; -@property (nonatomic) NSUInteger serverCacheUpdatesSinceLastPruneCheck; +@property(nonatomic, strong) id storageEngine; +@property(nonatomic, strong) id cachePolicy; +@property(nonatomic, strong) FTrackedQueryManager *trackedQueryManager; +@property(nonatomic) NSUInteger serverCacheUpdatesSinceLastPruneCheck; @end @implementation FPersistenceManager -- (id)initWithStorageEngine:(id)storageEngine cachePolicy:(id)cachePolicy { +- (id)initWithStorageEngine:(id)storageEngine + cachePolicy:(id)cachePolicy { self = [super init]; if (self != nil) { self->_storageEngine = storageEngine; self->_cachePolicy = cachePolicy; - self->_trackedQueryManager = [[FTrackedQueryManager alloc] initWithStorageEngine:self.storageEngine - clock:[FSystemClock clock]]; + self->_trackedQueryManager = [[FTrackedQueryManager alloc] + initWithStorageEngine:self.storageEngine + clock:[FSystemClock clock]]; } return self; } @@ -53,11 +55,15 @@ - (void)close { self.trackedQueryManager = nil; } -- (void)saveUserOverwrite:(id)node atPath:(FPath *)path writeId:(NSUInteger)writeId { +- (void)saveUserOverwrite:(id)node + atPath:(FPath *)path + writeId:(NSUInteger)writeId { [self.storageEngine saveUserOverwrite:node atPath:path writeId:writeId]; } -- (void)saveUserMerge:(FCompoundWrite *)merge atPath:(FPath *)path writeId:(NSUInteger)writeId { +- (void)saveUserMerge:(FCompoundWrite *)merge + atPath:(FPath *)path + writeId:(NSUInteger)writeId { [self.storageEngine saveUserMerge:merge atPath:path writeId:writeId]; } @@ -76,29 +82,37 @@ - (NSArray *)userWrites { - (FCacheNode *)serverCacheForQuery:(FQuerySpec *)query { NSSet *trackedKeys; BOOL complete; - // TODO[offline]: Should we use trackedKeys to find out if this location is a child of a complete query? + // TODO[offline]: Should we use trackedKeys to find out if this location is + // a child of a complete query? if ([self.trackedQueryManager isQueryComplete:query]) { complete = YES; - FTrackedQuery *trackedQuery = [self.trackedQueryManager findTrackedQuery:query]; + FTrackedQuery *trackedQuery = + [self.trackedQueryManager findTrackedQuery:query]; if (!query.loadsAllData && trackedQuery.isComplete) { - trackedKeys = [self.storageEngine trackedQueryKeysForQuery:trackedQuery.queryId]; + trackedKeys = [self.storageEngine + trackedQueryKeysForQuery:trackedQuery.queryId]; } else { trackedKeys = nil; } } else { complete = NO; - trackedKeys = [self.trackedQueryManager knownCompleteChildrenAtPath:query.path]; + trackedKeys = + [self.trackedQueryManager knownCompleteChildrenAtPath:query.path]; } id node; if (trackedKeys != nil) { - node = [self.storageEngine serverCacheForKeys:trackedKeys atPath:query.path]; + node = [self.storageEngine serverCacheForKeys:trackedKeys + atPath:query.path]; } else { node = [self.storageEngine serverCacheAtPath:query.path]; } - FIndexedNode *indexedNode = [FIndexedNode indexedNodeWithNode:node index:query.index]; - return [[FCacheNode alloc] initWithIndexedNode:indexedNode isFullyInitialized:complete isFiltered:(trackedKeys != nil)]; + FIndexedNode *indexedNode = [FIndexedNode indexedNodeWithNode:node + index:query.index]; + return [[FCacheNode alloc] initWithIndexedNode:indexedNode + isFullyInitialized:complete + isFiltered:(trackedKeys != nil)]; } - (void)updateServerCacheWithNode:(id)node forQuery:(FQuerySpec *)query { @@ -108,25 +122,29 @@ - (void)updateServerCacheWithNode:(id)node forQuery:(FQuerySpec *)query { [self doPruneCheckAfterServerUpdate]; } -- (void)updateServerCacheWithMerge:(FCompoundWrite *)merge atPath:(FPath *)path { +- (void)updateServerCacheWithMerge:(FCompoundWrite *)merge + atPath:(FPath *)path { [self.storageEngine updateServerCacheWithMerge:merge atPath:path]; [self doPruneCheckAfterServerUpdate]; } -- (void)applyUserMerge:(FCompoundWrite *)merge toServerCacheAtPath:(FPath *)path { +- (void)applyUserMerge:(FCompoundWrite *)merge + toServerCacheAtPath:(FPath *)path { // TODO[offline]: rework this to be more efficient [merge enumerateWrites:^(FPath *relativePath, id node, BOOL *stop) { - [self applyUserWrite:node toServerCacheAtPath:[path child:relativePath]]; + [self applyUserWrite:node toServerCacheAtPath:[path child:relativePath]]; }]; } - (void)applyUserWrite:(id)write toServerCacheAtPath:(FPath *)path { - // This is a hack to guess whether we already cached this because we got a server data update for this - // write via an existing active default query. If we didn't, then we'll manually cache this and add a - // tracked query to mark it complete and keep it cached. - // Unfortunately this is just a guess and it's possible that we *did* get an update (e.g. via a filtered - // query) and by overwriting the cache here, we'll actually store an incorrect value (e.g. in the case - // that we wrote a ServerValue.TIMESTAMP and the server resolved it to a different value). + // This is a hack to guess whether we already cached this because we got a + // server data update for this write via an existing active default query. + // If we didn't, then we'll manually cache this and add a tracked query to + // mark it complete and keep it cached. Unfortunately this is just a guess + // and it's possible that we *did* get an update (e.g. via a filtered query) + // and by overwriting the cache here, we'll actually store an incorrect + // value (e.g. in the case that we wrote a ServerValue.TIMESTAMP and the + // server resolved it to a different value). // TODO[offline]: Consider reworking. if (![self.trackedQueryManager hasActiveDefaultQueryAtPath:path]) { [self.storageEngine updateServerCache:write atPath:path merge:NO]; @@ -152,40 +170,62 @@ - (void)setQueryInactive:(FQuerySpec *)spec { - (void)doPruneCheckAfterServerUpdate { self.serverCacheUpdatesSinceLastPruneCheck++; - if ([self.cachePolicy shouldCheckCacheSize:self.serverCacheUpdatesSinceLastPruneCheck]) { + if ([self.cachePolicy + shouldCheckCacheSize:self.serverCacheUpdatesSinceLastPruneCheck]) { FFDebug(@"I-RDB078001", @"Reached prune check threshold. Checking..."); NSDate *date = [NSDate date]; self.serverCacheUpdatesSinceLastPruneCheck = 0; BOOL canPrune = YES; - NSUInteger cacheSize = [self.storageEngine serverCacheEstimatedSizeInBytes]; - FFDebug(@"I-RDB078002", @"Server cache size: %lu", (unsigned long)cacheSize); - while (canPrune && [self.cachePolicy shouldPruneCacheWithSize:cacheSize - numberOfTrackedQueries:self.trackedQueryManager.numberOfPrunableQueries]) { - FPruneForest *pruneForest = [self.trackedQueryManager pruneOldQueries:self.cachePolicy]; + NSUInteger cacheSize = + [self.storageEngine serverCacheEstimatedSizeInBytes]; + FFDebug(@"I-RDB078002", @"Server cache size: %lu", + (unsigned long)cacheSize); + while (canPrune && + [self.cachePolicy + shouldPruneCacheWithSize:cacheSize + numberOfTrackedQueries:self.trackedQueryManager + .numberOfPrunableQueries]) { + FPruneForest *pruneForest = + [self.trackedQueryManager pruneOldQueries:self.cachePolicy]; if (pruneForest.prunesAnything) { - [self.storageEngine pruneCache:pruneForest atPath:[FPath empty]]; + [self.storageEngine pruneCache:pruneForest + atPath:[FPath empty]]; } else { canPrune = NO; } cacheSize = [self.storageEngine serverCacheEstimatedSizeInBytes]; - FFDebug(@"I-RDB078003", @"Cache size after pruning: %lu", (unsigned long)cacheSize); + FFDebug(@"I-RDB078003", @"Cache size after pruning: %lu", + (unsigned long)cacheSize); } - FFDebug(@"I-RDB078004", @"Pruning round took %fms", [date timeIntervalSinceNow]*-1000); + FFDebug(@"I-RDB078004", @"Pruning round took %fms", + [date timeIntervalSinceNow] * -1000); } } - (void)setTrackedQueryKeys:(NSSet *)keys forQuery:(FQuerySpec *)query { - NSAssert(!query.loadsAllData, @"We should only track keys for filtered queries"); - FTrackedQuery *trackedQuery = [self.trackedQueryManager findTrackedQuery:query]; - NSAssert(trackedQuery.isActive, @"We only expect tracked keys for currently-active queries."); - [self.storageEngine setTrackedQueryKeys:keys forQueryId:trackedQuery.queryId]; -} - -- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added removedKeys:(NSSet *)removed forQuery:(FQuerySpec *)query { - NSAssert(!query.loadsAllData, @"We should only track keys for filtered queries"); - FTrackedQuery *trackedQuery = [self.trackedQueryManager findTrackedQuery:query]; - NSAssert(trackedQuery.isActive, @"We only expect tracked keys for currently-active queries."); - [self.storageEngine updateTrackedQueryKeysWithAddedKeys:added removedKeys:removed forQueryId:trackedQuery.queryId]; + NSAssert(!query.loadsAllData, + @"We should only track keys for filtered queries"); + FTrackedQuery *trackedQuery = + [self.trackedQueryManager findTrackedQuery:query]; + NSAssert(trackedQuery.isActive, + @"We only expect tracked keys for currently-active queries."); + [self.storageEngine setTrackedQueryKeys:keys + forQueryId:trackedQuery.queryId]; +} + +- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added + removedKeys:(NSSet *)removed + forQuery:(FQuerySpec *)query { + NSAssert(!query.loadsAllData, + @"We should only track keys for filtered queries"); + FTrackedQuery *trackedQuery = + [self.trackedQueryManager findTrackedQuery:query]; + NSAssert(trackedQuery.isActive, + @"We only expect tracked keys for currently-active queries."); + [self.storageEngine + updateTrackedQueryKeysWithAddedKeys:added + removedKeys:removed + forQueryId:trackedQuery.queryId]; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPruneForest.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPruneForest.m index ae5ce91..e795c69 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPruneForest.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FPruneForest.m @@ -20,26 +20,25 @@ @interface FPruneForest () -@property (nonatomic, strong) FImmutableTree *pruneForest; +@property(nonatomic, strong) FImmutableTree *pruneForest; @end @implementation FPruneForest static BOOL (^kFPrunePredicate)(id) = ^BOOL(NSNumber *pruneValue) { - return [pruneValue boolValue]; + return [pruneValue boolValue]; }; static BOOL (^kFKeepPredicate)(id) = ^BOOL(NSNumber *pruneValue) { - return ![pruneValue boolValue]; + return ![pruneValue boolValue]; }; - + (FImmutableTree *)pruneTree { static dispatch_once_t onceToken; static FImmutableTree *pruneTree; dispatch_once(&onceToken, ^{ - pruneTree = [[FImmutableTree alloc] initWithValue:@YES]; + pruneTree = [[FImmutableTree alloc] initWithValue:@YES]; }); return pruneTree; } @@ -48,12 +47,12 @@ + (FImmutableTree *)keepTree { static dispatch_once_t onceToken; static FImmutableTree *keepTree; dispatch_once(&onceToken, ^{ - keepTree = [[FImmutableTree alloc] initWithValue:@NO]; + keepTree = [[FImmutableTree alloc] initWithValue:@NO]; }); return keepTree; } -- (id) initWithForest:(FImmutableTree *)tree { +- (id)initWithForest:(FImmutableTree *)tree { self = [super init]; if (self != nil) { self->_pruneForest = tree; @@ -65,7 +64,7 @@ + (FPruneForest *)empty { static dispatch_once_t onceToken; static FPruneForest *forest; dispatch_once(&onceToken, ^{ - forest = [[FPruneForest alloc] initWithForest:[FImmutableTree empty]]; + forest = [[FPruneForest alloc] initWithForest:[FImmutableTree empty]]; }); return forest; } @@ -85,20 +84,24 @@ - (BOOL)shouldKeepPath:(FPath *)path { } - (BOOL)affectsPath:(FPath *)path { - return [self.pruneForest rootMostValueOnPath:path] != nil || ![[self.pruneForest subtreeAtPath:path] isEmpty]; + return [self.pruneForest rootMostValueOnPath:path] != nil || + ![[self.pruneForest subtreeAtPath:path] isEmpty]; } - (FPruneForest *)child:(NSString *)childKey { FImmutableTree *childPruneForest = [self.pruneForest.children get:childKey]; if (childPruneForest == nil) { if (self.pruneForest.value != nil) { - childPruneForest = [self.pruneForest.value boolValue] ? [FPruneForest pruneTree] : [FPruneForest keepTree]; + childPruneForest = [self.pruneForest.value boolValue] + ? [FPruneForest pruneTree] + : [FPruneForest keepTree]; } else { childPruneForest = [FImmutableTree empty]; } } else { if (childPruneForest.value == nil && self.pruneForest.value != nil) { - childPruneForest = [childPruneForest setValue:self.pruneForest.value atPath:[FPath empty]]; + childPruneForest = [childPruneForest setValue:self.pruneForest.value + atPath:[FPath empty]]; } } return [[FPruneForest alloc] initWithForest:childPruneForest]; @@ -114,13 +117,15 @@ - (FPruneForest *)childAtPath:(FPath *)path { - (FPruneForest *)prunePath:(FPath *)path { if ([self.pruneForest rootMostValueOnPath:path matching:kFKeepPredicate]) { - [NSException raise:NSInvalidArgumentException format:@"Can't prune path that was kept previously!"]; + [NSException raise:NSInvalidArgumentException + format:@"Can't prune path that was kept previously!"]; } if ([self.pruneForest rootMostValueOnPath:path matching:kFPrunePredicate]) { // This path will already be pruned return self; } else { - FImmutableTree *newPruneForest = [self.pruneForest setTree:[FPruneForest pruneTree] atPath:path]; + FImmutableTree *newPruneForest = + [self.pruneForest setTree:[FPruneForest pruneTree] atPath:path]; return [[FPruneForest alloc] initWithForest:newPruneForest]; } } @@ -130,7 +135,8 @@ - (FPruneForest *)keepPath:(FPath *)path { // This path will already be kept return self; } else { - FImmutableTree *newPruneForest = [self.pruneForest setTree:[FPruneForest keepTree] atPath:path]; + FImmutableTree *newPruneForest = + [self.pruneForest setTree:[FPruneForest keepTree] atPath:path]; return [[FPruneForest alloc] initWithForest:newPruneForest]; } } @@ -140,37 +146,48 @@ - (FPruneForest *)keepAll:(NSSet *)children atPath:(FPath *)path { // This path will already be kept return self; } else { - return [self setPruneValue:[FPruneForest keepTree] forAll:children atPath:path]; + return [self setPruneValue:[FPruneForest keepTree] + forAll:children + atPath:path]; } } - (FPruneForest *)pruneAll:(NSSet *)children atPath:(FPath *)path { if ([self.pruneForest rootMostValueOnPath:path matching:kFKeepPredicate]) { - [NSException raise:NSInvalidArgumentException format:@"Can't prune path that was kept previously!"]; + [NSException raise:NSInvalidArgumentException + format:@"Can't prune path that was kept previously!"]; } if ([self.pruneForest rootMostValueOnPath:path matching:kFPrunePredicate]) { // This path will already be pruned return self; } else { - return [self setPruneValue:[FPruneForest pruneTree] forAll:children atPath:path]; + return [self setPruneValue:[FPruneForest pruneTree] + forAll:children + atPath:path]; } } -- (FPruneForest *)setPruneValue:(FImmutableTree *)pruneValue forAll:(NSSet *)children atPath:(FPath *)path { +- (FPruneForest *)setPruneValue:(FImmutableTree *)pruneValue + forAll:(NSSet *)children + atPath:(FPath *)path { FImmutableTree *subtree = [self.pruneForest subtreeAtPath:path]; __block FImmutableSortedDictionary *childrenDictionary = subtree.children; [children enumerateObjectsUsingBlock:^(NSString *childKey, BOOL *stop) { - childrenDictionary = [childrenDictionary insertKey:childKey withValue:pruneValue]; + childrenDictionary = [childrenDictionary insertKey:childKey + withValue:pruneValue]; }]; - FImmutableTree *newSubtree = [[FImmutableTree alloc] initWithValue:subtree.value children:childrenDictionary]; - return [[FPruneForest alloc] initWithForest:[self.pruneForest setTree:newSubtree atPath:path]]; + FImmutableTree *newSubtree = + [[FImmutableTree alloc] initWithValue:subtree.value + children:childrenDictionary]; + return [[FPruneForest alloc] + initWithForest:[self.pruneForest setTree:newSubtree atPath:path]]; } - (void)enumarateKeptNodesUsingBlock:(void (^)(FPath *))block { [self.pruneForest forEach:^(FPath *path, id value) { - if (value != nil && ![value boolValue]) { - block(path); - } + if (value != nil && ![value boolValue]) { + block(path); + } }]; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FStorageEngine.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FStorageEngine.h index 4f168e7..5f418b8 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FStorageEngine.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FStorageEngine.h @@ -27,15 +27,21 @@ - (void)close; -- (void)saveUserOverwrite:(id)node atPath:(FPath *)path writeId:(NSUInteger)writeId; -- (void)saveUserMerge:(FCompoundWrite *)merge atPath:(FPath *)path writeId:(NSUInteger)writeId; +- (void)saveUserOverwrite:(id)node + atPath:(FPath *)path + writeId:(NSUInteger)writeId; +- (void)saveUserMerge:(FCompoundWrite *)merge + atPath:(FPath *)path + writeId:(NSUInteger)writeId; - (void)removeUserWrite:(NSUInteger)writeId; - (void)removeAllUserWrites; - (NSArray *)userWrites; - (id)serverCacheAtPath:(FPath *)path; - (id)serverCacheForKeys:(NSSet *)keys atPath:(FPath *)path; -- (void)updateServerCache:(id)node atPath:(FPath *)path merge:(BOOL)merge; +- (void)updateServerCache:(id)node + atPath:(FPath *)path + merge:(BOOL)merge; - (void)updateServerCacheWithMerge:(FCompoundWrite *)merge atPath:(FPath *)path; - (NSUInteger)serverCacheEstimatedSizeInBytes; @@ -46,8 +52,9 @@ - (void)saveTrackedQuery:(FTrackedQuery *)query; - (void)setTrackedQueryKeys:(NSSet *)keys forQueryId:(NSUInteger)queryId; -- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added removedKeys:(NSSet *)removed forQueryId:(NSUInteger)queryId; +- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added + removedKeys:(NSSet *)removed + forQueryId:(NSUInteger)queryId; - (NSSet *)trackedQueryKeysForQuery:(NSUInteger)queryId; - @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQuery.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQuery.h index 7bc8ef1..7413816 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQuery.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQuery.h @@ -20,13 +20,16 @@ @interface FTrackedQuery : NSObject -@property (nonatomic, readonly) NSUInteger queryId; -@property (nonatomic, strong, readonly) FQuerySpec *query; -@property (nonatomic, readonly) NSTimeInterval lastUse; -@property (nonatomic, readonly) BOOL isComplete; -@property (nonatomic, readonly) BOOL isActive; +@property(nonatomic, readonly) NSUInteger queryId; +@property(nonatomic, strong, readonly) FQuerySpec *query; +@property(nonatomic, readonly) NSTimeInterval lastUse; +@property(nonatomic, readonly) BOOL isComplete; +@property(nonatomic, readonly) BOOL isActive; -- (id)initWithId:(NSUInteger)queryId query:(FQuerySpec *)query lastUse:(NSTimeInterval)lastUse isActive:(BOOL)isActive; +- (id)initWithId:(NSUInteger)queryId + query:(FQuerySpec *)query + lastUse:(NSTimeInterval)lastUse + isActive:(BOOL)isActive; - (id)initWithId:(NSUInteger)queryId query:(FQuerySpec *)query lastUse:(NSTimeInterval)lastUse diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQuery.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQuery.m index 1720805..6ca7ec0 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQuery.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQuery.m @@ -20,15 +20,14 @@ @interface FTrackedQuery () -@property (nonatomic, readwrite) NSUInteger queryId; -@property (nonatomic, strong, readwrite) FQuerySpec *query; -@property (nonatomic, readwrite) NSTimeInterval lastUse; -@property (nonatomic, readwrite) BOOL isComplete; -@property (nonatomic, readwrite) BOOL isActive; +@property(nonatomic, readwrite) NSUInteger queryId; +@property(nonatomic, strong, readwrite) FQuerySpec *query; +@property(nonatomic, readwrite) NSTimeInterval lastUse; +@property(nonatomic, readwrite) BOOL isComplete; +@property(nonatomic, readwrite) BOOL isActive; @end - @implementation FTrackedQuery - (id)initWithId:(NSUInteger)queryId @@ -47,8 +46,15 @@ - (id)initWithId:(NSUInteger)queryId return self; } -- (id)initWithId:(NSUInteger)queryId query:(FQuerySpec *)query lastUse:(NSTimeInterval)lastUse isActive:(BOOL)isActive { - return [self initWithId:queryId query:query lastUse:lastUse isActive:isActive isComplete:NO]; +- (id)initWithId:(NSUInteger)queryId + query:(FQuerySpec *)query + lastUse:(NSTimeInterval)lastUse + isActive:(BOOL)isActive { + return [self initWithId:queryId + query:query + lastUse:lastUse + isActive:isActive + isComplete:NO]; } - (FTrackedQuery *)updateLastUse:(NSTimeInterval)lastUse { @@ -80,11 +86,16 @@ - (BOOL)isEqual:(id)object { return NO; } FTrackedQuery *other = (FTrackedQuery *)object; - if (self.queryId != other.queryId) return NO; - if (self.query != other.query && ![self.query isEqual:other.query]) return NO; - if (self.lastUse != other.lastUse) return NO; - if (self.isComplete != other.isComplete) return NO; - if (self.isActive != other.isActive) return NO; + if (self.queryId != other.queryId) + return NO; + if (self.query != other.query && ![self.query isEqual:other.query]) + return NO; + if (self.lastUse != other.lastUse) + return NO; + if (self.isComplete != other.isComplete) + return NO; + if (self.isActive != other.isActive) + return NO; return YES; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQueryManager.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQueryManager.h index ba2631b..cd7d5a1 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQueryManager.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQueryManager.h @@ -26,7 +26,8 @@ @interface FTrackedQueryManager : NSObject -- (id)initWithStorageEngine:(id)storageEngine clock:(id)clock; +- (id)initWithStorageEngine:(id)storageEngine + clock:(id)clock; - (FTrackedQuery *)findTrackedQuery:(FQuerySpec *)query; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQueryManager.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQueryManager.m index 9176f25..26accaf 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQueryManager.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Persistence/FTrackedQueryManager.m @@ -14,29 +14,29 @@ * limitations under the License. */ -#import #import "FTrackedQueryManager.h" +#import "FCachePolicy.h" +#import "FClock.h" #import "FImmutableTree.h" #import "FLevelDBStorageEngine.h" -#import "FUtilities.h" -#import "FTrackedQuery.h" #import "FPruneForest.h" -#import "FClock.h" +#import "FTrackedQuery.h" #import "FUtilities.h" -#import "FCachePolicy.h" +#import @interface FTrackedQueryManager () -@property (nonatomic, strong) FImmutableTree *trackedQueryTree; -@property (nonatomic, strong) id storageEngine; -@property (nonatomic, strong) id clock; -@property (nonatomic) NSUInteger currentQueryId; +@property(nonatomic, strong) FImmutableTree *trackedQueryTree; +@property(nonatomic, strong) id storageEngine; +@property(nonatomic, strong) id clock; +@property(nonatomic) NSUInteger currentQueryId; @end @implementation FTrackedQueryManager -- (id)initWithStorageEngine:(id)storageEngine clock:(id)clock { +- (id)initWithStorageEngine:(id)storageEngine + clock:(id)clock { self = [super init]; if (self != nil) { self->_storageEngine = storageEngine; @@ -46,25 +46,34 @@ - (id)initWithStorageEngine:(id)storageEngine clock:(id) NSTimeInterval lastUse = [clock currentTime]; NSArray *trackedQueries = [self.storageEngine loadTrackedQueries]; - [trackedQueries enumerateObjectsUsingBlock:^(FTrackedQuery *trackedQuery, NSUInteger idx, BOOL *stop) { - self.currentQueryId = MAX(trackedQuery.queryId + 1, self.currentQueryId); - if (trackedQuery.isActive) { - trackedQuery = [[trackedQuery setActiveState:NO] updateLastUse:lastUse]; - FFDebug(@"I-RDB081001", @"Setting active query %lu from previous app start inactive", (unsigned long)trackedQuery.queryId); - [self.storageEngine saveTrackedQuery:trackedQuery]; - } - [self cacheTrackedQuery:trackedQuery]; + [trackedQueries enumerateObjectsUsingBlock:^( + FTrackedQuery *trackedQuery, NSUInteger idx, + BOOL *stop) { + self.currentQueryId = + MAX(trackedQuery.queryId + 1, self.currentQueryId); + if (trackedQuery.isActive) { + trackedQuery = + [[trackedQuery setActiveState:NO] updateLastUse:lastUse]; + FFDebug( + @"I-RDB081001", + @"Setting active query %lu from previous app start inactive", + (unsigned long)trackedQuery.queryId); + [self.storageEngine saveTrackedQuery:trackedQuery]; + } + [self cacheTrackedQuery:trackedQuery]; }]; } return self; } + (void)assertValidTrackedQuery:(FQuerySpec *)query { - NSAssert(!query.loadsAllData || query.isDefault, @"Can't have tracked non-default query that loads all data"); + NSAssert(!query.loadsAllData || query.isDefault, + @"Can't have tracked non-default query that loads all data"); } + (FQuerySpec *)normalizeQuery:(FQuerySpec *)query { - return query.loadsAllData ? [FQuerySpec defaultQueryAtPath:query.path] : query; + return query.loadsAllData ? [FQuerySpec defaultQueryAtPath:query.path] + : query; } - (FTrackedQuery *)findTrackedQuery:(FQuerySpec *)query { @@ -79,7 +88,8 @@ - (void)removeTrackedQuery:(FQuerySpec *)query { NSAssert(trackedQuery, @"Tracked query must exist to be removed!"); [self.storageEngine removeTrackedQuery:trackedQuery.queryId]; - NSMutableDictionary *trackedQueries = [self.trackedQueryTree valueAtPath:query.path]; + NSMutableDictionary *trackedQueries = + [self.trackedQueryTree valueAtPath:query.path]; [trackedQueries removeObjectForKey:query.params]; } @@ -95,13 +105,16 @@ - (void)setQueryActive:(BOOL)isActive forQuery:(FQuerySpec *)query { query = [FTrackedQueryManager normalizeQuery:query]; FTrackedQuery *trackedQuery = [self findTrackedQuery:query]; - // Regardless of whether it's now active or no langer active, we update the lastUse time + // Regardless of whether it's now active or no langer active, we update the + // lastUse time NSTimeInterval lastUse = [self.clock currentTime]; if (trackedQuery != nil) { - trackedQuery = [[trackedQuery updateLastUse:lastUse] setActiveState:isActive]; + trackedQuery = + [[trackedQuery updateLastUse:lastUse] setActiveState:isActive]; [self.storageEngine saveTrackedQuery:trackedQuery]; } else { - NSAssert(isActive, @"If we're setting the query to inactive, we should already be tracking it!"); + NSAssert(isActive, @"If we're setting the query to inactive, we should " + @"already be tracking it!"); trackedQuery = [[FTrackedQuery alloc] initWithId:self.currentQueryId++ query:query lastUse:lastUse @@ -116,8 +129,10 @@ - (void)setQueryComplete:(FQuerySpec *)query { query = [FTrackedQueryManager normalizeQuery:query]; FTrackedQuery *trackedQuery = [self findTrackedQuery:query]; if (!trackedQuery) { - // We might have removed a query and pruned it before we got the complete message from the server... - FFWarn(@"I-RDB081002", @"Trying to set a query complete that is not tracked!"); + // We might have removed a query and pruned it before we got the + // complete message from the server... + FFWarn(@"I-RDB081002", + @"Trying to set a query complete that is not tracked!"); } else if (!trackedQuery.isComplete) { trackedQuery = [trackedQuery setComplete]; [self.storageEngine saveTrackedQuery:trackedQuery]; @@ -128,15 +143,18 @@ - (void)setQueryComplete:(FQuerySpec *)query { } - (void)setQueriesCompleteAtPath:(FPath *)path { - [[self.trackedQueryTree subtreeAtPath:path] forEach:^(FPath *childPath, NSDictionary *trackedQueries) { - [trackedQueries enumerateKeysAndObjectsUsingBlock:^(FQueryParams *parms, FTrackedQuery *trackedQuery, BOOL *stop) { + [[self.trackedQueryTree subtreeAtPath:path] + forEach:^(FPath *childPath, NSDictionary *trackedQueries) { + [trackedQueries enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *parms, FTrackedQuery *trackedQuery, + BOOL *stop) { if (!trackedQuery.isComplete) { FTrackedQuery *newTrackedQuery = [trackedQuery setComplete]; [self.storageEngine saveTrackedQuery:newTrackedQuery]; [self cacheTrackedQuery:newTrackedQuery]; } + }]; }]; - }]; } - (BOOL)isQueryComplete:(FQuerySpec *)query { @@ -146,15 +164,20 @@ - (BOOL)isQueryComplete:(FQuerySpec *)query { // We didn't find a default complete query, so must not be complete. return NO; } else { - NSDictionary *trackedQueries = [self.trackedQueryTree valueAtPath:query.path]; + NSDictionary *trackedQueries = + [self.trackedQueryTree valueAtPath:query.path]; return [trackedQueries[query.params] isComplete]; } } - (BOOL)hasActiveDefaultQueryAtPath:(FPath *)path { - return [self.trackedQueryTree rootMostValueOnPath:path matching:^BOOL(NSDictionary *trackedQueries) { - return [trackedQueries[[FQueryParams defaultInstance]] isActive]; - }] != nil; + return [self.trackedQueryTree + rootMostValueOnPath:path + matching:^BOOL(NSDictionary *trackedQueries) { + return + [trackedQueries[[FQueryParams defaultInstance]] + isActive]; + }] != nil; } - (void)ensureCompleteTrackedQueryAtPath:(FPath *)path { @@ -162,13 +185,15 @@ - (void)ensureCompleteTrackedQueryAtPath:(FPath *)path { if (![self isIncludedInDefaultCompleteQuery:query]) { FTrackedQuery *trackedQuery = [self findTrackedQuery:query]; if (trackedQuery == nil) { - trackedQuery = [[FTrackedQuery alloc] initWithId:self.currentQueryId++ - query:query - lastUse:[self.clock currentTime] - isActive:NO - isComplete:YES]; + trackedQuery = + [[FTrackedQuery alloc] initWithId:self.currentQueryId++ + query:query + lastUse:[self.clock currentTime] + isActive:NO + isComplete:YES]; } else { - NSAssert(!trackedQuery.isComplete, @"This should have been handled above!"); + NSAssert(!trackedQuery.isComplete, + @"This should have been handled above!"); trackedQuery = [trackedQuery setComplete]; } [self.storageEngine saveTrackedQuery:trackedQuery]; @@ -177,23 +202,33 @@ - (void)ensureCompleteTrackedQueryAtPath:(FPath *)path { } - (BOOL)isIncludedInDefaultCompleteQuery:(FQuerySpec *)query { - return [self.trackedQueryTree findRootMostMatchingPath:query.path predicate:^BOOL(NSDictionary *trackedQueries) { - return [trackedQueries[[FQueryParams defaultInstance]] isComplete]; - }] != nil; + return + [self.trackedQueryTree + findRootMostMatchingPath:query.path + predicate:^BOOL(NSDictionary *trackedQueries) { + return + [trackedQueries[[FQueryParams defaultInstance]] + isComplete]; + }] != nil; } - (void)cacheTrackedQuery:(FTrackedQuery *)query { [FTrackedQueryManager assertValidTrackedQuery:query.query]; - NSMutableDictionary *trackedDict = [self.trackedQueryTree valueAtPath:query.query.path]; + NSMutableDictionary *trackedDict = + [self.trackedQueryTree valueAtPath:query.query.path]; if (trackedDict == nil) { trackedDict = [NSMutableDictionary dictionary]; - self.trackedQueryTree = [self.trackedQueryTree setValue:trackedDict atPath:query.query.path]; + self.trackedQueryTree = + [self.trackedQueryTree setValue:trackedDict + atPath:query.query.path]; } trackedDict[query.query.params] = query; } -- (NSUInteger) numberOfQueriesToPrune:(id)cachePolicy prunableCount:(NSUInteger)numPrunable { - NSUInteger numPercent = (NSUInteger)ceilf(numPrunable * [cachePolicy percentOfQueriesToPruneAtOnce]); +- (NSUInteger)numberOfQueriesToPrune:(id)cachePolicy + prunableCount:(NSUInteger)numPrunable { + NSUInteger numPercent = (NSUInteger)ceilf( + numPrunable * [cachePolicy percentOfQueriesToPruneAtOnce]); NSUInteger maxToKeep = [cachePolicy maxNumberOfQueriesToKeep]; NSUInteger numMax = (numPrunable > maxToKeep) ? numPrunable - maxToKeep : 0; // Make sure we get below number of max queries to prune @@ -203,28 +238,33 @@ - (NSUInteger) numberOfQueriesToPrune:(id)cachePolicy prunableCoun - (FPruneForest *)pruneOldQueries:(id)cachePolicy { NSMutableArray *pruneableQueries = [NSMutableArray array]; NSMutableArray *unpruneableQueries = [NSMutableArray array]; - [self.trackedQueryTree forEach:^(FPath *path, NSDictionary *trackedQueries) { - [trackedQueries enumerateKeysAndObjectsUsingBlock:^(FQueryParams *params, FTrackedQuery *trackedQuery, BOOL *stop) { + [self.trackedQueryTree + forEach:^(FPath *path, NSDictionary *trackedQueries) { + [trackedQueries enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *params, FTrackedQuery *trackedQuery, + BOOL *stop) { if (!trackedQuery.isActive) { [pruneableQueries addObject:trackedQuery]; } else { [unpruneableQueries addObject:trackedQuery]; } + }]; }]; + [pruneableQueries sortUsingComparator:^NSComparisonResult( + FTrackedQuery *q1, FTrackedQuery *q2) { + if (q1.lastUse < q2.lastUse) { + return NSOrderedAscending; + } else if (q1.lastUse > q2.lastUse) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } }]; - [pruneableQueries sortUsingComparator:^NSComparisonResult(FTrackedQuery *q1, FTrackedQuery *q2) { - if (q1.lastUse < q2.lastUse) { - return NSOrderedAscending; - } else if (q1.lastUse > q2.lastUse) { - return NSOrderedDescending; - } else { - return NSOrderedSame; - } - }]; - __block FPruneForest *pruneForest = [FPruneForest empty]; - NSUInteger numToPrune = [self numberOfQueriesToPrune:cachePolicy prunableCount:pruneableQueries.count]; + NSUInteger numToPrune = + [self numberOfQueriesToPrune:cachePolicy + prunableCount:pruneableQueries.count]; // TODO: do in transaction for (NSUInteger i = 0; i < numToPrune; i++) { @@ -240,8 +280,9 @@ - (FPruneForest *)pruneOldQueries:(id)cachePolicy { } // Also keep unprunable queries - [unpruneableQueries enumerateObjectsUsingBlock:^(FTrackedQuery *toKeep, NSUInteger idx, BOOL *stop) { - pruneForest = [pruneForest keepPath:toKeep.query.path]; + [unpruneableQueries enumerateObjectsUsingBlock:^( + FTrackedQuery *toKeep, NSUInteger idx, BOOL *stop) { + pruneForest = [pruneForest keepPath:toKeep.query.path]; }]; return pruneForest; @@ -249,13 +290,16 @@ - (FPruneForest *)pruneOldQueries:(id)cachePolicy { - (NSUInteger)numberOfPrunableQueries { __block NSUInteger count = 0; - [self.trackedQueryTree forEach:^(FPath *path, NSDictionary *trackedQueries) { - [trackedQueries enumerateKeysAndObjectsUsingBlock:^(FQueryParams *params, FTrackedQuery *trackedQuery, BOOL *stop) { + [self.trackedQueryTree + forEach:^(FPath *path, NSDictionary *trackedQueries) { + [trackedQueries enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *params, FTrackedQuery *trackedQuery, + BOOL *stop) { if (!trackedQuery.isActive) { count++; } + }]; }]; - }]; return count; } @@ -263,10 +307,11 @@ - (NSSet *)filteredQueryIdsAtPath:(FPath *)path { NSDictionary *queries = [self.trackedQueryTree valueAtPath:path]; if (queries) { NSMutableSet *ids = [NSMutableSet set]; - [queries enumerateKeysAndObjectsUsingBlock:^(FQueryParams *params, FTrackedQuery *query, BOOL *stop) { - if (!query.query.loadsAllData) { - [ids addObject:@(query.queryId)]; - } + [queries enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *params, FTrackedQuery *query, BOOL *stop) { + if (!query.query.loadsAllData) { + [ids addObject:@(query.queryId)]; + } }]; return ids; } else { @@ -275,22 +320,26 @@ - (NSSet *)filteredQueryIdsAtPath:(FPath *)path { } - (NSSet *)knownCompleteChildrenAtPath:(FPath *)path { - NSAssert(![self isQueryComplete:[FQuerySpec defaultQueryAtPath:path]], @"Path is fully complete"); + NSAssert(![self isQueryComplete:[FQuerySpec defaultQueryAtPath:path]], + @"Path is fully complete"); NSMutableSet *completeChildren = [NSMutableSet set]; // First, get complete children from any queries at this location. NSSet *queryIds = [self filteredQueryIdsAtPath:path]; [queryIds enumerateObjectsUsingBlock:^(NSNumber *queryId, BOOL *stop) { - NSSet *keys = [self.storageEngine trackedQueryKeysForQuery:[queryId unsignedIntegerValue]]; - [completeChildren unionSet:keys]; + NSSet *keys = [self.storageEngine + trackedQueryKeysForQuery:[queryId unsignedIntegerValue]]; + [completeChildren unionSet:keys]; }]; // Second, get any complete default queries immediately below us. - [[[self.trackedQueryTree subtreeAtPath:path] children] enumerateKeysAndObjectsUsingBlock:^(NSString *childKey, FImmutableTree *childTree, BOOL *stop) { - if ([childTree.value[[FQueryParams defaultInstance]] isComplete]) { - [completeChildren addObject:childKey]; - } - }]; + [[[self.trackedQueryTree subtreeAtPath:path] children] + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + if ([childTree.value[[FQueryParams defaultInstance]] isComplete]) { + [completeChildren addObject:childKey]; + } + }]; return completeChildren; } @@ -300,22 +349,26 @@ - (void)verifyCache { NSMutableArray *trackedQueries = [NSMutableArray array]; [self.trackedQueryTree forEach:^(FPath *path, NSDictionary *queryDict) { - [trackedQueries addObjectsFromArray:queryDict.allValues]; + [trackedQueries addObjectsFromArray:queryDict.allValues]; }]; - NSComparator comparator = ^NSComparisonResult(FTrackedQuery *q1, FTrackedQuery *q2) { - if (q1.queryId < q2.queryId) { - return NSOrderedAscending; - } else if (q1.queryId > q2.queryId) { - return NSOrderedDescending; - } else { - return NSOrderedSame; - } - }; + NSComparator comparator = + ^NSComparisonResult(FTrackedQuery *q1, FTrackedQuery *q2) { + if (q1.queryId < q2.queryId) { + return NSOrderedAscending; + } else if (q1.queryId > q2.queryId) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } + }; [trackedQueries sortUsingComparator:comparator]; - storedTrackedQueries = [storedTrackedQueries sortedArrayUsingComparator:comparator]; + storedTrackedQueries = + [storedTrackedQueries sortedArrayUsingComparator:comparator]; if (![trackedQueries isEqualToArray:storedTrackedQueries]) { - [NSException raise:NSInternalInconsistencyException format:@"Tracked queries and queries stored on disk don't match"]; + [NSException + raise:NSInternalInconsistencyException + format:@"Tracked queries and queries stored on disk don't match"]; } } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDataEventType.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDataEventType.h index 916ce32..3aecd81 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDataEventType.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDataEventType.h @@ -20,7 +20,8 @@ #import /** - * This enum is the set of events that you can observe at a Firebase Database location. + * This enum is the set of events that you can observe at a Firebase Database + * location. */ typedef NS_ENUM(NSInteger, FIRDataEventType) { /// A new child node is added to a location. diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDataSnapshot.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDataSnapshot.h index 02a1e6a..e88febb 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDataSnapshot.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDataSnapshot.h @@ -21,18 +21,18 @@ NS_ASSUME_NONNULL_BEGIN @class FIRDatabaseReference; /** - * A FIRDataSnapshot contains data from a Firebase Database location. Any time you read - * Firebase data, you receive the data as a FIRDataSnapshot. - * - * FIRDataSnapshots are passed to the blocks you attach with observeEventType:withBlock: or observeSingleEvent:withBlock:. - * They are efficiently-generated immutable copies of the data at a Firebase Database location. - * They can't be modified and will never change. To modify data at a location, - * use a FIRDatabaseReference (e.g. with setValue:). + * A FIRDataSnapshot contains data from a Firebase Database location. Any time + * you read Firebase data, you receive the data as a FIRDataSnapshot. + * + * FIRDataSnapshots are passed to the blocks you attach with + * observeEventType:withBlock: or observeSingleEvent:withBlock:. They are + * efficiently-generated immutable copies of the data at a Firebase Database + * location. They can't be modified and will never change. To modify data at a + * location, use a FIRDatabaseReference (e.g. with setValue:). */ NS_SWIFT_NAME(DataSnapshot) @interface FIRDataSnapshot : NSObject - #pragma mark - Navigating and inspecting a snapshot /** @@ -46,42 +46,39 @@ NS_SWIFT_NAME(DataSnapshot) */ - (FIRDataSnapshot *)childSnapshotForPath:(NSString *)childPathString; - /** * Return YES if the specified child exists. * * @param childPathString A relative path to the location of a potential child. * @return YES if data exists at the specified childPathString, else NO. */ -- (BOOL) hasChild:(NSString *)childPathString; - +- (BOOL)hasChild:(NSString *)childPathString; /** * Return YES if the DataSnapshot has any children. * * @return YES if this snapshot has any children, else NO. */ -- (BOOL) hasChildren; - +- (BOOL)hasChildren; /** * Return YES if the DataSnapshot contains a non-null value. * * @return YES if this snapshot contains a non-null value, else NO. */ -- (BOOL) exists; - +- (BOOL)exists; #pragma mark - Data export /** - * Returns the raw value at this location, coupled with any metadata, such as priority. + * Returns the raw value at this location, coupled with any metadata, such as + * priority. * - * Priorities, where they exist, are accessible under the ".priority" key in instances of NSDictionary. - * For leaf locations with priorities, the value will be under the ".value" key. + * Priorities, where they exist, are accessible under the ".priority" key in + * instances of NSDictionary. For leaf locations with priorities, the value will + * be under the ".value" key. */ -- (id __nullable) valueInExportFormat; - +- (id __nullable)valueInExportFormat; #pragma mark - Properties @@ -96,32 +93,29 @@ NS_SWIFT_NAME(DataSnapshot) * * @return The data as a native object. */ -@property (strong, readonly, nonatomic, nullable) id value; - +@property(strong, readonly, nonatomic, nullable) id value; /** * Gets the number of children for this DataSnapshot. * * @return An integer indicating the number of children. */ -@property (readonly, nonatomic) NSUInteger childrenCount; - +@property(readonly, nonatomic) NSUInteger childrenCount; /** * Gets a FIRDatabaseReference for the location that this data came from. * * @return A FIRDatabaseReference instance for the location of this data. */ -@property (nonatomic, readonly, strong) FIRDatabaseReference * ref; - +@property(nonatomic, readonly, strong) FIRDatabaseReference *ref; /** * The key of the location that generated this FIRDataSnapshot. * - * @return An NSString containing the key for the location of this FIRDataSnapshot. + * @return An NSString containing the key for the location of this + * FIRDataSnapshot. */ -@property (strong, readonly, nonatomic) NSString* key; - +@property(strong, readonly, nonatomic) NSString *key; /** * An iterator for snapshots of the child nodes in this snapshot. @@ -133,14 +127,15 @@ NS_SWIFT_NAME(DataSnapshot) * * @return An NSEnumerator of the children. */ -@property (strong, readonly, nonatomic) NSEnumerator* children; +@property(strong, readonly, nonatomic) + NSEnumerator *children; /** * The priority of the data in this FIRDataSnapshot. * * @return The priority as a string, or nil if no priority was set. */ -@property (strong, readonly, nonatomic, nullable) id priority; +@property(strong, readonly, nonatomic, nullable) id priority; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDatabase.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDatabase.h index 15c8700..02af8c7 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDatabase.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDatabase.h @@ -14,35 +14,36 @@ * limitations under the License. */ -#import #import "FIRDatabaseReference.h" +#import @class FIRApp; NS_ASSUME_NONNULL_BEGIN /** - * The entry point for accessing a Firebase Database. You can get an instance by calling - * [FIRDatabase database]. To access a location in the database and read or write data, - * use [FIRDatabase reference]. + * The entry point for accessing a Firebase Database. You can get an instance + * by calling [FIRDatabase database]. To access a location in the database and + * read or write data, use [FIRDatabase reference]. */ NS_SWIFT_NAME(Database) @interface FIRDatabase : NSObject /** - * The NSObject initializer that has been marked as unavailable. Use the `database` - * method instead + * The NSObject initializer that has been marked as unavailable. Use the + * `database` method instead * * @return An instancetype instance -*/ -- (instancetype) init __attribute__((unavailable("use the database method instead"))); + */ +- (instancetype)init + __attribute__((unavailable("use the database method instead"))); /** * Gets the instance of FIRDatabase for the default FIRApp. * * @return A FIRDatabase instance. */ -+ (FIRDatabase *) database NS_SWIFT_NAME(database()); ++ (FIRDatabase *)database NS_SWIFT_NAME(database()); /** * Gets a FirebaseDatabase instance for the specified URL. @@ -71,15 +72,15 @@ NS_SWIFT_NAME(Database) * @param app The FIRApp to get a FIRDatabase for. * @return A FIRDatabase instance. */ -+ (FIRDatabase *) databaseForApp:(FIRApp *)app NS_SWIFT_NAME(database(app:)); ++ (FIRDatabase *)databaseForApp:(FIRApp *)app NS_SWIFT_NAME(database(app:)); /** The FIRApp instance to which this FIRDatabase belongs. */ -@property (weak, readonly, nonatomic) FIRApp *app; +@property(weak, readonly, nonatomic) FIRApp *app; /** * Gets a FIRDatabaseReference for the root of your Firebase Database. */ -- (FIRDatabaseReference *) reference; +- (FIRDatabaseReference *)reference; /** * Gets a FIRDatabaseReference for the provided path. @@ -87,81 +88,94 @@ NS_SWIFT_NAME(Database) * @param path Path to a location in your Firebase Database. * @return A FIRDatabaseReference pointing to the specified path. */ -- (FIRDatabaseReference *) referenceWithPath:(NSString *)path; +- (FIRDatabaseReference *)referenceWithPath:(NSString *)path; /** - * Gets a FIRDatabaseReference for the provided URL. The URL must be a URL to a path - * within this Firebase Database. To create a FIRDatabaseReference to a different database, - * create a FIRApp} with a FIROptions object configured with the appropriate database URL. + * Gets a FIRDatabaseReference for the provided URL. The URL must be a URL to a + * path within this Firebase Database. To create a FIRDatabaseReference to a + * different database, create a FIRApp} with a FIROptions object configured with + * the appropriate database URL. * * @param databaseUrl A URL to a path within your database. * @return A FIRDatabaseReference for the provided URL. -*/ -- (FIRDatabaseReference *) referenceFromURL:(NSString *)databaseUrl; + */ +- (FIRDatabaseReference *)referenceFromURL:(NSString *)databaseUrl; /** - * The Firebase Database client automatically queues writes and sends them to the server at the earliest opportunity, - * depending on network connectivity. In some cases (e.g. offline usage) there may be a large number of writes - * waiting to be sent. Calling this method will purge all outstanding writes so they are abandoned. + * The Firebase Database client automatically queues writes and sends them to + * the server at the earliest opportunity, depending on network connectivity. In + * some cases (e.g. offline usage) there may be a large number of writes waiting + * to be sent. Calling this method will purge all outstanding writes so they are + * abandoned. * - * All writes will be purged, including transactions and onDisconnect writes. The writes will - * be rolled back locally, perhaps triggering events for affected event listeners, and the client will not - * (re-)send them to the Firebase Database backend. + * All writes will be purged, including transactions and onDisconnect writes. + * The writes will be rolled back locally, perhaps triggering events for + * affected event listeners, and the client will not (re-)send them to the + * Firebase Database backend. */ - (void)purgeOutstandingWrites; /** - * Shuts down our connection to the Firebase Database backend until goOnline is called. + * Shuts down our connection to the Firebase Database backend until goOnline is + * called. */ - (void)goOffline; /** - * Resumes our connection to the Firebase Database backend after a previous goOffline call. + * Resumes our connection to the Firebase Database backend after a previous + * goOffline call. */ - (void)goOnline; /** - * The Firebase Database client will cache synchronized data and keep track of all writes you've - * initiated while your application is running. It seamlessly handles intermittent network - * connections and re-sends write operations when the network connection is restored. + * The Firebase Database client will cache synchronized data and keep track of + * all writes you've initiated while your application is running. It seamlessly + * handles intermittent network connections and re-sends write operations when + * the network connection is restored. * - * However by default your write operations and cached data are only stored in-memory and will - * be lost when your app restarts. By setting this value to `YES`, the data will be persisted - * to on-device (disk) storage and will thus be available again when the app is restarted - * (even when there is no network connectivity at that time). Note that this property must be - * set before creating your first Database reference and only needs to be called once per + * However by default your write operations and cached data are only stored + * in-memory and will be lost when your app restarts. By setting this value to + * `YES`, the data will be persisted to on-device (disk) storage and will thus + * be available again when the app is restarted (even when there is no network + * connectivity at that time). Note that this property must be set before + * creating your first Database reference and only needs to be called once per * application. * */ -@property (nonatomic) BOOL persistenceEnabled NS_SWIFT_NAME(isPersistenceEnabled); +@property(nonatomic) BOOL persistenceEnabled NS_SWIFT_NAME(isPersistenceEnabled) + ; /** - * By default the Firebase Database client will use up to 10MB of disk space to cache data. If the cache grows beyond - * this size, the client will start removing data that hasn't been recently used. If you find that your application - * caches too little or too much data, call this method to change the cache size. This property must be set before - * creating your first FIRDatabaseReference and only needs to be called once per application. + * By default the Firebase Database client will use up to 10MB of disk space to + * cache data. If the cache grows beyond this size, the client will start + * removing data that hasn't been recently used. If you find that your + * application caches too little or too much data, call this method to change + * the cache size. This property must be set before creating your first + * FIRDatabaseReference and only needs to be called once per application. * - * Note that the specified cache size is only an approximation and the size on disk may temporarily exceed it - * at times. Cache sizes smaller than 1 MB or greater than 100 MB are not supported. + * Note that the specified cache size is only an approximation and the size on + * disk may temporarily exceed it at times. Cache sizes smaller than 1 MB or + * greater than 100 MB are not supported. */ -@property (nonatomic) NSUInteger persistenceCacheSizeBytes; +@property(nonatomic) NSUInteger persistenceCacheSizeBytes; /** - * Sets the dispatch queue on which all events are raised. The default queue is the main queue. + * Sets the dispatch queue on which all events are raised. The default queue is + * the main queue. * * Note that this must be set before creating your first Database reference. */ -@property (nonatomic, strong) dispatch_queue_t callbackQueue; +@property(nonatomic, strong) dispatch_queue_t callbackQueue; /** * Enables verbose diagnostic logging. * * @param enabled YES to enable logging, NO to disable. */ -+ (void) setLoggingEnabled:(BOOL)enabled; ++ (void)setLoggingEnabled:(BOOL)enabled; /** Retrieve the Firebase Database SDK version. */ -+ (NSString *) sdkVersion; ++ (NSString *)sdkVersion; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDatabaseQuery.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDatabaseQuery.h index fc6d27e..82057aa 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDatabaseQuery.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDatabaseQuery.h @@ -14,300 +14,381 @@ * limitations under the License. */ -#import #import "FIRDataEventType.h" #import "FIRDataSnapshot.h" +#import NS_ASSUME_NONNULL_BEGIN /** - * A FIRDatabaseHandle is used to identify listeners of Firebase Database events. These handles - * are returned by observeEventType: and can later be passed to removeObserverWithHandle: to stop - * receiving updates. + * A FIRDatabaseHandle is used to identify listeners of Firebase Database + * events. These handles are returned by observeEventType: and can later be + * passed to removeObserverWithHandle: to stop receiving updates. */ typedef NSUInteger FIRDatabaseHandle NS_SWIFT_NAME(DatabaseHandle); /** - * A FIRDatabaseQuery instance represents a query over the data at a particular location. + * A FIRDatabaseQuery instance represents a query over the data at a particular + * location. * - * You create one by calling one of the query methods (queryOrderedByChild:, queryStartingAtValue:, etc.) - * on a FIRDatabaseReference. The query methods can be chained to further specify the data you are interested in - * observing + * You create one by calling one of the query methods (queryOrderedByChild:, + * queryStartingAtValue:, etc.) on a FIRDatabaseReference. The query methods can + * be chained to further specify the data you are interested in observing */ NS_SWIFT_NAME(DatabaseQuery) @interface FIRDatabaseQuery : NSObject - #pragma mark - Attach observers to read data /** - * observeEventType:withBlock: is used to listen for data changes at a particular location. - * This is the primary way to read data from the Firebase Database. Your block will be triggered - * for the initial data and again whenever the data changes. + * observeEventType:withBlock: is used to listen for data changes at a + * particular location. This is the primary way to read data from the Firebase + * Database. Your block will be triggered for the initial data and again + * whenever the data changes. * * Use removeObserverWithHandle: to stop receiving updates. * * @param eventType The type of event to listen for. - * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot. - * @return A handle used to unregister this block later using removeObserverWithHandle: + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot. + * @return A handle used to unregister this block later using + * removeObserverWithHandle: */ -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block; - +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock: + (void (^)(FIRDataSnapshot *snapshot))block; /** - * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data changes at a particular location. - * This is the primary way to read data from the Firebase Database. Your block will be triggered - * for the initial data and again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and - * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data + * changes at a particular location. This is the primary way to read data from + * the Firebase Database. Your block will be triggered for the initial data and + * again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, + * FIRDataEventTypeChildMoved, and FIRDataEventTypeChildChanged events, your + * block will be passed the key of the previous node by priority order. * * Use removeObserverWithHandle: to stop receiving updates. * * @param eventType The type of event to listen for. - * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot - * and the previous child's key. - * @return A handle used to unregister this block later using removeObserverWithHandle: + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot and the previous child's key. + * @return A handle used to unregister this block later using + * removeObserverWithHandle: */ -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block; - +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block; /** - * observeEventType:withBlock: is used to listen for data changes at a particular location. - * This is the primary way to read data from the Firebase Database. Your block will be triggered - * for the initial data and again whenever the data changes. + * observeEventType:withBlock: is used to listen for data changes at a + * particular location. This is the primary way to read data from the Firebase + * Database. Your block will be triggered for the initial data and again + * whenever the data changes. * - * The cancelBlock will be called if you will no longer receive new events due to no longer having permission. + * The cancelBlock will be called if you will no longer receive new events due + * to no longer having permission. * * Use removeObserverWithHandle: to stop receiving updates. * * @param eventType The type of event to listen for. - * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot. - * @param cancelBlock The block that should be called if this client no longer has permission to receive these events - * @return A handle used to unregister this block later using removeObserverWithHandle: + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot. + * @param cancelBlock The block that should be called if this client no longer + * has permission to receive these events + * @return A handle used to unregister this block later using + * removeObserverWithHandle: */ -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; - +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; /** - * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data changes at a particular location. - * This is the primary way to read data from the Firebase Database. Your block will be triggered - * for the initial data and again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and - * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data + * changes at a particular location. This is the primary way to read data from + * the Firebase Database. Your block will be triggered for the initial data and + * again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, + * FIRDataEventTypeChildMoved, and FIRDataEventTypeChildChanged events, your + * block will be passed the key of the previous node by priority order. * - * The cancelBlock will be called if you will no longer receive new events due to no longer having permission. + * The cancelBlock will be called if you will no longer receive new events due + * to no longer having permission. * * Use removeObserverWithHandle: to stop receiving updates. * * @param eventType The type of event to listen for. - * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot - * and the previous child's key. - * @param cancelBlock The block that should be called if this client no longer has permission to receive these events - * @return A handle used to unregister this block later using removeObserverWithHandle: + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot and the previous child's key. + * @param cancelBlock The block that should be called if this client no longer + * has permission to receive these events + * @return A handle used to unregister this block later using + * removeObserverWithHandle: */ -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; - +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; /** - * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. * * @param eventType The type of event to listen for. - * @param block The block that should be called. It is passed the data as a FIRDataSnapshot. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot. */ -- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block; - +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block; /** - * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and - * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. In addition, for + * FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the + * previous node by priority order. * * @param eventType The type of event to listen for. - * @param block The block that should be called. It is passed the data as a FIRDataSnapshot and the previous child's key. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot and the previous child's key. */ -- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block; - +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block; /** - * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. * - * The cancelBlock will be called if you do not have permission to read data at this location. + * The cancelBlock will be called if you do not have permission to read data at + * this location. * * @param eventType The type of event to listen for. - * @param block The block that should be called. It is passed the data as a FIRDataSnapshot. - * @param cancelBlock The block that will be called if you don't have permission to access this data + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot. + * @param cancelBlock The block that will be called if you don't have permission + * to access this data */ -- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; - +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block + withCancelBlock:(nullable void (^)(NSError *error))cancelBlock; /** - * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and - * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. In addition, for + * FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the + * previous node by priority order. * - * The cancelBlock will be called if you do not have permission to read data at this location. + * The cancelBlock will be called if you do not have permission to read data at + * this location. * * @param eventType The type of event to listen for. - * @param block The block that should be called. It is passed the data as a FIRDataSnapshot and the previous child's key. - * @param cancelBlock The block that will be called if you don't have permission to access this data + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot and the previous child's key. + * @param cancelBlock The block that will be called if you don't have permission + * to access this data */ -- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; - +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; #pragma mark - Detaching observers /** * Detach a block previously attached with observeEventType:withBlock:. * - * @param handle The handle returned by the call to observeEventType:withBlock: which we are trying to remove. + * @param handle The handle returned by the call to observeEventType:withBlock: + * which we are trying to remove. */ -- (void) removeObserverWithHandle:(FIRDatabaseHandle)handle; - +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle; /** - * Detach all blocks previously attached to this Firebase Database location with observeEventType:withBlock: + * Detach all blocks previously attached to this Firebase Database location with + * observeEventType:withBlock: */ -- (void) removeAllObservers; +- (void)removeAllObservers; /** - * By calling `keepSynced:YES` on a location, the data for that location will automatically be downloaded and - * kept in sync, even when no listeners are attached for that location. Additionally, while a location is kept - * synced, it will not be evicted from the persistent disk cache. + * By calling `keepSynced:YES` on a location, the data for that location will + * automatically be downloaded and kept in sync, even when no listeners are + * attached for that location. Additionally, while a location is kept synced, it + * will not be evicted from the persistent disk cache. * - * @param keepSynced Pass YES to keep this location synchronized, pass NO to stop synchronization. -*/ - - (void) keepSynced:(BOOL)keepSynced; - + * @param keepSynced Pass YES to keep this location synchronized, pass NO to + * stop synchronization. + */ +- (void)keepSynced:(BOOL)keepSynced; #pragma mark - Querying and limiting /** -* queryLimitedToFirst: is used to generate a reference to a limited view of the data at this location. -* The FIRDatabaseQuery instance returned by queryLimitedToFirst: will respond to at most the first limit child nodes. -* -* @param limit The upper bound, inclusive, for the number of child nodes to receive events for -* @return A FIRDatabaseQuery instance, limited to at most limit child nodes. -*/ + * queryLimitedToFirst: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryLimitedToFirst: will respond to at most the first limit child nodes. + * + * @param limit The upper bound, inclusive, for the number of child nodes to + * receive events for + * @return A FIRDatabaseQuery instance, limited to at most limit child nodes. + */ - (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit; - /** -* queryLimitedToLast: is used to generate a reference to a limited view of the data at this location. -* The FIRDatabaseQuery instance returned by queryLimitedToLast: will respond to at most the last limit child nodes. -* -* @param limit The upper bound, inclusive, for the number of child nodes to receive events for -* @return A FIRDatabaseQuery instance, limited to at most limit child nodes. -*/ + * queryLimitedToLast: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryLimitedToLast: will respond to at most the last limit child nodes. + * + * @param limit The upper bound, inclusive, for the number of child nodes to + * receive events for + * @return A FIRDatabaseQuery instance, limited to at most limit child nodes. + */ - (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit; /** - * queryOrderBy: is used to generate a reference to a view of the data that's been sorted by the values of - * a particular child key. This method is intended to be used in combination with queryStartingAtValue:, - * queryEndingAtValue:, or queryEqualToValue:. - * - * @param key The child key to use in ordering data visible to the returned FIRDatabaseQuery - * @return A FIRDatabaseQuery instance, ordered by the values of the specified child key. -*/ + * queryOrderBy: is used to generate a reference to a view of the data that's + * been sorted by the values of a particular child key. This method is intended + * to be used in combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. + * + * @param key The child key to use in ordering data visible to the returned + * FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, ordered by the values of the specified + * child key. + */ - (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)key; /** - * queryOrderedByKey: is used to generate a reference to a view of the data that's been sorted by child key. - * This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, - * or queryEqualToValue:. + * queryOrderedByKey: is used to generate a reference to a view of the data + * that's been sorted by child key. This method is intended to be used in + * combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. * * @return A FIRDatabaseQuery instance, ordered by child keys. */ -- (FIRDatabaseQuery *) queryOrderedByKey; +- (FIRDatabaseQuery *)queryOrderedByKey; /** - * queryOrderedByValue: is used to generate a reference to a view of the data that's been sorted by child value. - * This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, - * or queryEqualToValue:. + * queryOrderedByValue: is used to generate a reference to a view of the data + * that's been sorted by child value. This method is intended to be used in + * combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. * * @return A FIRDatabaseQuery instance, ordered by child value. */ -- (FIRDatabaseQuery *) queryOrderedByValue; +- (FIRDatabaseQuery *)queryOrderedByValue; /** - * queryOrderedByPriority: is used to generate a reference to a view of the data that's been sorted by child - * priority. This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, - * or queryEqualToValue:. + * queryOrderedByPriority: is used to generate a reference to a view of the data + * that's been sorted by child priority. This method is intended to be used in + * combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. * * @return A FIRDatabaseQuery instance, ordered by child priorities. */ -- (FIRDatabaseQuery *) queryOrderedByPriority; +- (FIRDatabaseQuery *)queryOrderedByPriority; /** - * queryStartingAtValue: is used to generate a reference to a limited view of the data at this location. - * The FIRDatabaseQuery instance returned by queryStartingAtValue: will respond to events at nodes with a value - * greater than or equal to startValue. - * - * @param startValue The lower bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery - * @return A FIRDatabaseQuery instance, limited to data with value greater than or equal to startValue + * queryStartingAtValue: is used to generate a reference to a limited view of + * the data at this location. The FIRDatabaseQuery instance returned by + * queryStartingAtValue: will respond to events at nodes with a value greater + * than or equal to startValue. + * + * @param startValue The lower bound, inclusive, for the value of data visible + * to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * or equal to startValue */ - (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue; /** - * queryStartingAtValue:childKey: is used to generate a reference to a limited view of the data at this location. - * The FIRDatabaseQuery instance returned by queryStartingAtValue:childKey will respond to events at nodes with a value - * greater than startValue, or equal to startValue and with a key greater than or equal to childKey. This is most - * useful when implementing pagination in a case where multiple nodes can match the startValue. - * - * @param startValue The lower bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery - * @param childKey The lower bound, inclusive, for the key of nodes with value equal to startValue - * @return A FIRDatabaseQuery instance, limited to data with value greater than or equal to startValue + * queryStartingAtValue:childKey: is used to generate a reference to a limited + * view of the data at this location. The FIRDatabaseQuery instance returned by + * queryStartingAtValue:childKey will respond to events at nodes with a value + * greater than startValue, or equal to startValue and with a key greater than + * or equal to childKey. This is most useful when implementing pagination in a + * case where multiple nodes can match the startValue. + * + * @param startValue The lower bound, inclusive, for the value of data visible + * to the returned FIRDatabaseQuery + * @param childKey The lower bound, inclusive, for the key of nodes with value + * equal to startValue + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * or equal to startValue */ -- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue childKey:(nullable NSString *)childKey; +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue + childKey:(nullable NSString *)childKey; /** - * queryEndingAtValue: is used to generate a reference to a limited view of the data at this location. - * The FIRDatabaseQuery instance returned by queryEndingAtValue: will respond to events at nodes with a value - * less than or equal to endValue. - * - * @param endValue The upper bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery - * @return A FIRDatabaseQuery instance, limited to data with value less than or equal to endValue + * queryEndingAtValue: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryEndingAtValue: will respond to events at nodes with a value less than or + * equal to endValue. + * + * @param endValue The upper bound, inclusive, for the value of data visible to + * the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value less than or + * equal to endValue */ - (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue; /** - * queryEndingAtValue:childKey: is used to generate a reference to a limited view of the data at this location. - * The FIRDatabaseQuery instance returned by queryEndingAtValue:childKey will respond to events at nodes with a value - * less than endValue, or equal to endValue and with a key less than or equal to childKey. This is most useful when - * implementing pagination in a case where multiple nodes can match the endValue. - * - * @param endValue The upper bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery - * @param childKey The upper bound, inclusive, for the key of nodes with value equal to endValue - * @return A FIRDatabaseQuery instance, limited to data with value less than or equal to endValue + * queryEndingAtValue:childKey: is used to generate a reference to a limited + * view of the data at this location. The FIRDatabaseQuery instance returned by + * queryEndingAtValue:childKey will respond to events at nodes with a value less + * than endValue, or equal to endValue and with a key less than or equal to + * childKey. This is most useful when implementing pagination in a case where + * multiple nodes can match the endValue. + * + * @param endValue The upper bound, inclusive, for the value of data visible to + * the returned FIRDatabaseQuery + * @param childKey The upper bound, inclusive, for the key of nodes with value + * equal to endValue + * @return A FIRDatabaseQuery instance, limited to data with value less than or + * equal to endValue */ -- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue childKey:(nullable NSString *)childKey; +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue + childKey:(nullable NSString *)childKey; /** - * queryEqualToValue: is used to generate a reference to a limited view of the data at this location. - * The FIRDatabaseQuery instance returned by queryEqualToValue: will respond to events at nodes with a value equal - * to the supplied argument. + * queryEqualToValue: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryEqualToValue: will respond to events at nodes with a value equal to the + * supplied argument. * - * @param value The value that the data returned by this FIRDatabaseQuery will have + * @param value The value that the data returned by this FIRDatabaseQuery will + * have * @return A FIRDatabaseQuery instance, limited to data with the supplied value. */ - (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value; /** - * queryEqualToValue:childKey: is used to generate a reference to a limited view of the data at this location. - * The FIRDatabaseQuery instance returned by queryEqualToValue:childKey will respond to events at nodes with a value - * equal to the supplied argument and with their key equal to childKey. There will be at most one node that matches - * because child keys are unique. - * - * @param value The value that the data returned by this FIRDatabaseQuery will have + * queryEqualToValue:childKey: is used to generate a reference to a limited view + * of the data at this location. The FIRDatabaseQuery instance returned by + * queryEqualToValue:childKey will respond to events at nodes with a value equal + * to the supplied argument and with their key equal to childKey. There will be + * at most one node that matches because child keys are unique. + * + * @param value The value that the data returned by this FIRDatabaseQuery will + * have * @param childKey The name of nodes with the right value - * @return A FIRDatabaseQuery instance, limited to data with the supplied value and the key. + * @return A FIRDatabaseQuery instance, limited to data with the supplied value + * and the key. */ -- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value childKey:(nullable NSString *)childKey; - +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value + childKey:(nullable NSString *)childKey; #pragma mark - Properties /** -* Gets a FIRDatabaseReference for the location of this query. -* -* @return A FIRDatabaseReference for the location of this query. -*/ -@property (nonatomic, readonly, strong) FIRDatabaseReference * ref; + * Gets a FIRDatabaseReference for the location of this query. + * + * @return A FIRDatabaseReference for the location of this query. + */ +@property(nonatomic, readonly, strong) FIRDatabaseReference *ref; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDatabaseReference.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDatabaseReference.h index b96585e..c80b2f8 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDatabaseReference.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDatabaseReference.h @@ -14,31 +14,31 @@ * limitations under the License. */ -#import -#import "FIRDatabaseQuery.h" -#import "FIRDatabase.h" #import "FIRDataSnapshot.h" +#import "FIRDatabase.h" +#import "FIRDatabaseQuery.h" #import "FIRMutableData.h" -#import "FIRTransactionResult.h" #import "FIRServerValue.h" +#import "FIRTransactionResult.h" +#import NS_ASSUME_NONNULL_BEGIN @class FIRDatabase; /** - * A FIRDatabaseReference represents a particular location in your Firebase Database - * and can be used for reading or writing data to that Firebase Database location. + * A FIRDatabaseReference represents a particular location in your Firebase + * Database and can be used for reading or writing data to that Firebase + * Database location. * - * This class is the starting point for all Firebase Database operations. After you've - * obtained your first FIRDatabaseReference via [FIRDatabase reference], you can use it - * to read data (ie. observeEventType:withBlock:), write data (ie. setValue:), and to - * create new FIRDatabaseReferences (ie. child:). + * This class is the starting point for all Firebase Database operations. After + * you've obtained your first FIRDatabaseReference via [FIRDatabase reference], + * you can use it to read data (ie. observeEventType:withBlock:), write data + * (ie. setValue:), and to create new FIRDatabaseReferences (ie. child:). */ NS_SWIFT_NAME(DatabaseReference) @interface FIRDatabaseReference : FIRDatabaseQuery - #pragma mark - Getting references to children locations /** @@ -46,28 +46,24 @@ NS_SWIFT_NAME(DatabaseReference) * The relative path can either be a simple child key (e.g. 'fred') or a * deeper slash-separated path (e.g. 'fred/name/first'). * - * @param pathString A relative path from this location to the desired child location. + * @param pathString A relative path from this location to the desired child + * location. * @return A FIRDatabaseReference for the specified relative path. */ - (FIRDatabaseReference *)child:(NSString *)pathString; -/** - * childByAppendingPath: is deprecated, use child: instead. - */ -- (FIRDatabaseReference *)childByAppendingPath:(NSString *)pathString __deprecated_msg("use child: instead"); - /** * childByAutoId generates a new child location using a unique key and returns a - * FIRDatabaseReference to it. This is useful when the children of a Firebase Database - * location represent a list of items. + * FIRDatabaseReference to it. This is useful when the children of a Firebase + * Database location represent a list of items. * - * The unique key generated by childByAutoId: is prefixed with a client-generated - * timestamp so that the resulting list will be chronologically-sorted. + * The unique key generated by childByAutoId: is prefixed with a + * client-generated timestamp so that the resulting list will be + * chronologically-sorted. * * @return A FIRDatabaseReference for the generated location. */ -- (FIRDatabaseReference *) childByAutoId; - +- (FIRDatabaseReference *)childByAutoId; #pragma mark - Writing data @@ -89,366 +85,461 @@ servers will also be started. Passing null for the new value is equivalent to calling remove:; all data at this location or any child location will be deleted. -Note that setValue: will remove any priority stored at this location, so if priority -is meant to be preserved, you should use setValue:andPriority: instead. +Note that setValue: will remove any priority stored at this location, so if +priority is meant to be preserved, you should use setValue:andPriority: instead. @param value The value to be written. */ -- (void) setValue:(nullable id)value; - +- (void)setValue:(nullable id)value; /** - * The same as setValue: with a block that gets triggered after the write operation has - * been committed to the Firebase Database servers. + * The same as setValue: with a block that gets triggered after the write + * operation has been committed to the Firebase Database servers. * * @param value The value to be written. - * @param block The block to be called after the write has been committed to the Firebase Database servers. + * @param block The block to be called after the write has been committed to the + * Firebase Database servers. */ -- (void) setValue:(nullable id)value withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; - +- (void)setValue:(nullable id)value + withCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; /** - * The same as setValue: with an additional priority to be attached to the data being written. - * Priorities are used to order items. + * The same as setValue: with an additional priority to be attached to the data + * being written. Priorities are used to order items. * * @param value The value to be written. * @param priority The priority to be attached to that data. */ -- (void) setValue:(nullable id)value andPriority:(nullable id)priority; - +- (void)setValue:(nullable id)value andPriority:(nullable id)priority; /** - * The same as setValue:andPriority: with a block that gets triggered after the write operation has - * been committed to the Firebase Database servers. + * The same as setValue:andPriority: with a block that gets triggered after the + * write operation has been committed to the Firebase Database servers. * * @param value The value to be written. * @param priority The priority to be attached to that data. - * @param block The block to be called after the write has been committed to the Firebase Database servers. + * @param block The block to be called after the write has been committed to the + * Firebase Database servers. */ -- (void) setValue:(nullable id)value andPriority:(nullable id)priority withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; - +- (void)setValue:(nullable id)value + andPriority:(nullable id)priority + withCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; /** - * Remove the data at this Firebase Database location. Any data at child locations will also be deleted. + * Remove the data at this Firebase Database location. Any data at child + * locations will also be deleted. * - * The effect of the delete will be visible immediately and the corresponding events - * will be triggered. Synchronization of the delete to the Firebase Database servers will - * also be started. + * The effect of the delete will be visible immediately and the corresponding + * events will be triggered. Synchronization of the delete to the Firebase + * Database servers will also be started. * * remove: is equivalent to calling setValue:nil */ -- (void) removeValue; - +- (void)removeValue; /** - * The same as remove: with a block that gets triggered after the remove operation has - * been committed to the Firebase Database servers. + * The same as remove: with a block that gets triggered after the remove + * operation has been committed to the Firebase Database servers. * - * @param block The block to be called after the remove has been committed to the Firebase Database servers. + * @param block The block to be called after the remove has been committed to + * the Firebase Database servers. */ -- (void) removeValueWithCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; +- (void)removeValueWithCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; /** * Sets a priority for the data at this Firebase Database location. - * Priorities can be used to provide a custom ordering for the children at a location - * (if no priorities are specified, the children are ordered by key). + * Priorities can be used to provide a custom ordering for the children at a + * location (if no priorities are specified, the children are ordered by key). * * You cannot set a priority on an empty location. For this reason - * setValue:andPriority: should be used when setting initial data with a specific priority - * and setPriority: should be used when updating the priority of existing data. + * setValue:andPriority: should be used when setting initial data with a + * specific priority and setPriority: should be used when updating the priority + * of existing data. * * Children are sorted based on this priority using the following rules: * * Children with no priority come first. - * Children with a number as their priority come next. They are sorted numerically by priority (small to large). - * Children with a string as their priority come last. They are sorted lexicographically by priority. - * Whenever two children have the same priority (including no priority), they are sorted by key. Numeric - * keys come first (sorted numerically), followed by the remaining keys (sorted lexicographically). + * Children with a number as their priority come next. They are sorted + * numerically by priority (small to large). Children with a string as their + * priority come last. They are sorted lexicographically by priority. Whenever + * two children have the same priority (including no priority), they are sorted + * by key. Numeric keys come first (sorted numerically), followed by the + * remaining keys (sorted lexicographically). * - * Note that priorities are parsed and ordered as IEEE 754 double-precision floating-point numbers. - * Keys are always stored as strings and are treated as numbers only when they can be parsed as a - * 32-bit integer + * Note that priorities are parsed and ordered as IEEE 754 double-precision + * floating-point numbers. Keys are always stored as strings and are treated as + * numbers only when they can be parsed as a 32-bit integer * * @param priority The priority to set at the specified location. */ -- (void) setPriority:(nullable id)priority; - +- (void)setPriority:(nullable id)priority; /** * The same as setPriority: with a block that is called once the priority has * been committed to the Firebase Database servers. * * @param priority The priority to set at the specified location. - * @param block The block that is triggered after the priority has been written on the servers. + * @param block The block that is triggered after the priority has been written + * on the servers. */ -- (void) setPriority:(nullable id)priority withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; +- (void)setPriority:(nullable id)priority + withCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; /** - * Updates the values at the specified paths in the dictionary without overwriting other - * keys at this location. + * Updates the values at the specified paths in the dictionary without + * overwriting other keys at this location. * * @param values A dictionary of the keys to change and their new values */ -- (void) updateChildValues:(NSDictionary *)values; +- (void)updateChildValues:(NSDictionary *)values; /** - * The same as update: with a block that is called once the update has been committed to the - * Firebase Database servers + * The same as update: with a block that is called once the update has been + * committed to the Firebase Database servers * * @param values A dictionary of the keys to change and their new values - * @param block The block that is triggered after the update has been written on the Firebase Database servers + * @param block The block that is triggered after the update has been written on + * the Firebase Database servers */ -- (void) updateChildValues:(NSDictionary *)values withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; - +- (void)updateChildValues:(NSDictionary *)values + withCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; #pragma mark - Attaching observers to read data /** - * observeEventType:withBlock: is used to listen for data changes at a particular location. - * This is the primary way to read data from the Firebase Database. Your block will be triggered - * for the initial data and again whenever the data changes. + * observeEventType:withBlock: is used to listen for data changes at a + * particular location. This is the primary way to read data from the Firebase + * Database. Your block will be triggered for the initial data and again + * whenever the data changes. * * Use removeObserverWithHandle: to stop receiving updates. * @param eventType The type of event to listen for. - * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot. - * @return A handle used to unregister this block later using removeObserverWithHandle: + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot. + * @return A handle used to unregister this block later using + * removeObserverWithHandle: */ -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block; - +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock: + (void (^)(FIRDataSnapshot *snapshot))block; /** - * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data changes at a particular location. - * This is the primary way to read data from the Firebase Database. Your block will be triggered - * for the initial data and again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and - * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data + * changes at a particular location. This is the primary way to read data from + * the Firebase Database. Your block will be triggered for the initial data and + * again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, + * FIRDataEventTypeChildMoved, and FIRDataEventTypeChildChanged events, your + * block will be passed the key of the previous node by priority order. * * Use removeObserverWithHandle: to stop receiving updates. * * @param eventType The type of event to listen for. - * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot - * and the previous child's key. - * @return A handle used to unregister this block later using removeObserverWithHandle: + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot and the previous child's key. + * @return A handle used to unregister this block later using + * removeObserverWithHandle: */ -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block; - +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block; /** - * observeEventType:withBlock: is used to listen for data changes at a particular location. - * This is the primary way to read data from the Firebase Database. Your block will be triggered - * for the initial data and again whenever the data changes. + * observeEventType:withBlock: is used to listen for data changes at a + * particular location. This is the primary way to read data from the Firebase + * Database. Your block will be triggered for the initial data and again + * whenever the data changes. * - * The cancelBlock will be called if you will no longer receive new events due to no longer having permission. + * The cancelBlock will be called if you will no longer receive new events due + * to no longer having permission. * * Use removeObserverWithHandle: to stop receiving updates. * * @param eventType The type of event to listen for. - * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot. - * @param cancelBlock The block that should be called if this client no longer has permission to receive these events - * @return A handle used to unregister this block later using removeObserverWithHandle: + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot. + * @param cancelBlock The block that should be called if this client no longer + * has permission to receive these events + * @return A handle used to unregister this block later using + * removeObserverWithHandle: */ -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; - +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; /** - * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data changes at a particular location. - * This is the primary way to read data from the Firebase Database. Your block will be triggered - * for the initial data and again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and - * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data + * changes at a particular location. This is the primary way to read data from + * the Firebase Database. Your block will be triggered for the initial data and + * again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, + * FIRDataEventTypeChildMoved, and FIRDataEventTypeChildChanged events, your + * block will be passed the key of the previous node by priority order. * - * The cancelBlock will be called if you will no longer receive new events due to no longer having permission. + * The cancelBlock will be called if you will no longer receive new events due + * to no longer having permission. * * Use removeObserverWithHandle: to stop receiving updates. * * @param eventType The type of event to listen for. - * @param block The block that should be called with initial data and updates. It is passed the data as a FIRDataSnapshot - * and the previous child's key. - * @param cancelBlock The block that should be called if this client no longer has permission to receive these events - * @return A handle used to unregister this block later using removeObserverWithHandle: + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot and the previous child's key. + * @param cancelBlock The block that should be called if this client no longer + * has permission to receive these events + * @return A handle used to unregister this block later using + * removeObserverWithHandle: */ -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; - +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; /** - * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. * * @param eventType The type of event to listen for. - * @param block The block that should be called. It is passed the data as a FIRDataSnapshot. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot. */ -- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block; - +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block; /** - * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and - * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. In addition, for + * FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the + * previous node by priority order. * * @param eventType The type of event to listen for. - * @param block The block that should be called. It is passed the data as a FIRDataSnapshot and the previous child's key. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot and the previous child's key. */ -- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block; - +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block; /** - * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. * - * The cancelBlock will be called if you do not have permission to read data at this location. + * The cancelBlock will be called if you do not have permission to read data at + * this location. * * @param eventType The type of event to listen for. - * @param block The block that should be called. It is passed the data as a FIRDataSnapshot. - * @param cancelBlock The block that will be called if you don't have permission to access this data + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot. + * @param cancelBlock The block that will be called if you don't have permission + * to access this data */ -- (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(void (^)(FIRDataSnapshot *snapshot))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; - +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block + withCancelBlock:(nullable void (^)(NSError *error))cancelBlock; /** - * This is equivalent to observeEventType:withBlock:, except the block is immediately canceled after the initial data is returned. In addition, for FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and - * FIRDataEventTypeChildChanged events, your block will be passed the key of the previous node by priority order. + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. In addition, for + * FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the + * previous node by priority order. * - * The cancelBlock will be called if you do not have permission to read data at this location. + * The cancelBlock will be called if you do not have permission to read data at + * this location. * * @param eventType The type of event to listen for. - * @param block The block that should be called. It is passed the data as a FIRDataSnapshot and the previous child's key. - * @param cancelBlock The block that will be called if you don't have permission to access this data + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot and the previous child's key. + * @param cancelBlock The block that will be called if you don't have permission + * to access this data */ -- (void)observeSingleEventOfType:(FIRDataEventType)eventType andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; #pragma mark - Detaching observers /** * Detach a block previously attached with observeEventType:withBlock:. * - * @param handle The handle returned by the call to observeEventType:withBlock: which we are trying to remove. + * @param handle The handle returned by the call to observeEventType:withBlock: + * which we are trying to remove. */ -- (void) removeObserverWithHandle:(FIRDatabaseHandle)handle; +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle; /** - * By calling `keepSynced:YES` on a location, the data for that location will automatically be downloaded and - * kept in sync, even when no listeners are attached for that location. Additionally, while a location is kept - * synced, it will not be evicted from the persistent disk cache. + * By calling `keepSynced:YES` on a location, the data for that location will + * automatically be downloaded and kept in sync, even when no listeners are + * attached for that location. Additionally, while a location is kept synced, it + * will not be evicted from the persistent disk cache. * - * @param keepSynced Pass YES to keep this location synchronized, pass NO to stop synchronization. + * @param keepSynced Pass YES to keep this location synchronized, pass NO to + * stop synchronization. */ -- (void) keepSynced:(BOOL)keepSynced; - +- (void)keepSynced:(BOOL)keepSynced; /** - * Removes all observers at the current reference, but does not remove any observers at child references. - * removeAllObservers must be called again for each child reference where a listener was established to remove the observers. + * Removes all observers at the current reference, but does not remove any + * observers at child references. removeAllObservers must be called again for + * each child reference where a listener was established to remove the + * observers. */ -- (void) removeAllObservers; +- (void)removeAllObservers; #pragma mark - Querying and limiting - /** - * queryLimitedToFirst: is used to generate a reference to a limited view of the data at this location. - * The FIRDatabaseQuery instance returned by queryLimitedToFirst: will respond to at most the first limit child nodes. + * queryLimitedToFirst: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryLimitedToFirst: will respond to at most the first limit child nodes. * - * @param limit The upper bound, inclusive, for the number of child nodes to receive events for + * @param limit The upper bound, inclusive, for the number of child nodes to + * receive events for * @return A FIRDatabaseQuery instance, limited to at most limit child nodes. */ - (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit; - /** - * queryLimitedToLast: is used to generate a reference to a limited view of the data at this location. - * The FIRDatabaseQuery instance returned by queryLimitedToLast: will respond to at most the last limit child nodes. + * queryLimitedToLast: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryLimitedToLast: will respond to at most the last limit child nodes. * - * @param limit The upper bound, inclusive, for the number of child nodes to receive events for + * @param limit The upper bound, inclusive, for the number of child nodes to + * receive events for * @return A FIRDatabaseQuery instance, limited to at most limit child nodes. */ - (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit; /** - * queryOrderBy: is used to generate a reference to a view of the data that's been sorted by the values of - * a particular child key. This method is intended to be used in combination with queryStartingAtValue:, - * queryEndingAtValue:, or queryEqualToValue:. + * queryOrderBy: is used to generate a reference to a view of the data that's + * been sorted by the values of a particular child key. This method is intended + * to be used in combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. * - * @param key The child key to use in ordering data visible to the returned FIRDatabaseQuery - * @return A FIRDatabaseQuery instance, ordered by the values of the specified child key. + * @param key The child key to use in ordering data visible to the returned + * FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, ordered by the values of the specified + * child key. */ - (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)key; /** - * queryOrderedByKey: is used to generate a reference to a view of the data that's been sorted by child key. - * This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, - * or queryEqualToValue:. + * queryOrderedByKey: is used to generate a reference to a view of the data + * that's been sorted by child key. This method is intended to be used in + * combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. * * @return A FIRDatabaseQuery instance, ordered by child keys. */ -- (FIRDatabaseQuery *) queryOrderedByKey; +- (FIRDatabaseQuery *)queryOrderedByKey; /** - * queryOrderedByPriority: is used to generate a reference to a view of the data that's been sorted by child - * priority. This method is intended to be used in combination with queryStartingAtValue:, queryEndingAtValue:, - * or queryEqualToValue:. + * queryOrderedByPriority: is used to generate a reference to a view of the data + * that's been sorted by child priority. This method is intended to be used in + * combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. * * @return A FIRDatabaseQuery instance, ordered by child priorities. */ -- (FIRDatabaseQuery *) queryOrderedByPriority; +- (FIRDatabaseQuery *)queryOrderedByPriority; /** - * queryStartingAtValue: is used to generate a reference to a limited view of the data at this location. - * The FIRDatabaseQuery instance returned by queryStartingAtValue: will respond to events at nodes with a value - * greater than or equal to startValue. + * queryStartingAtValue: is used to generate a reference to a limited view of + * the data at this location. The FIRDatabaseQuery instance returned by + * queryStartingAtValue: will respond to events at nodes with a value greater + * than or equal to startValue. * - * @param startValue The lower bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery - * @return A FIRDatabaseQuery instance, limited to data with value greater than or equal to startValue + * @param startValue The lower bound, inclusive, for the value of data visible + * to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * or equal to startValue */ - (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue; /** - * queryStartingAtValue:childKey: is used to generate a reference to a limited view of the data at this location. - * The FIRDatabaseQuery instance returned by queryStartingAtValue:childKey will respond to events at nodes with a value - * greater than startValue, or equal to startValue and with a key greater than or equal to childKey. + * queryStartingAtValue:childKey: is used to generate a reference to a limited + * view of the data at this location. The FIRDatabaseQuery instance returned by + * queryStartingAtValue:childKey will respond to events at nodes with a value + * greater than startValue, or equal to startValue and with a key greater than + * or equal to childKey. * - * @param startValue The lower bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery - * @param childKey The lower bound, inclusive, for the key of nodes with value equal to startValue - * @return A FIRDatabaseQuery instance, limited to data with value greater than or equal to startValue + * @param startValue The lower bound, inclusive, for the value of data visible + * to the returned FIRDatabaseQuery + * @param childKey The lower bound, inclusive, for the key of nodes with value + * equal to startValue + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * or equal to startValue */ -- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue childKey:(nullable NSString *)childKey; +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue + childKey:(nullable NSString *)childKey; /** - * queryEndingAtValue: is used to generate a reference to a limited view of the data at this location. - * The FIRDatabaseQuery instance returned by queryEndingAtValue: will respond to events at nodes with a value - * less than or equal to endValue. + * queryEndingAtValue: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryEndingAtValue: will respond to events at nodes with a value less than or + * equal to endValue. * - * @param endValue The upper bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery - * @return A FIRDatabaseQuery instance, limited to data with value less than or equal to endValue + * @param endValue The upper bound, inclusive, for the value of data visible to + * the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value less than or + * equal to endValue */ - (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue; /** - * queryEndingAtValue:childKey: is used to generate a reference to a limited view of the data at this location. - * The FIRDatabaseQuery instance returned by queryEndingAtValue:childKey will respond to events at nodes with a value - * less than endValue, or equal to endValue and with a key less than or equal to childKey. + * queryEndingAtValue:childKey: is used to generate a reference to a limited + * view of the data at this location. The FIRDatabaseQuery instance returned by + * queryEndingAtValue:childKey will respond to events at nodes with a value less + * than endValue, or equal to endValue and with a key less than or equal to + * childKey. * - * @param endValue The upper bound, inclusive, for the value of data visible to the returned FIRDatabaseQuery - * @param childKey The upper bound, inclusive, for the key of nodes with value equal to endValue - * @return A FIRDatabaseQuery instance, limited to data with value less than or equal to endValue + * @param endValue The upper bound, inclusive, for the value of data visible to + * the returned FIRDatabaseQuery + * @param childKey The upper bound, inclusive, for the key of nodes with value + * equal to endValue + * @return A FIRDatabaseQuery instance, limited to data with value less than or + * equal to endValue */ -- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue childKey:(nullable NSString *)childKey; +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue + childKey:(nullable NSString *)childKey; /** - * queryEqualToValue: is used to generate a reference to a limited view of the data at this location. - * The FIRDatabaseQuery instance returned by queryEqualToValue: will respond to events at nodes with a value equal - * to the supplied argument. + * queryEqualToValue: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryEqualToValue: will respond to events at nodes with a value equal to the + * supplied argument. * - * @param value The value that the data returned by this FIRDatabaseQuery will have + * @param value The value that the data returned by this FIRDatabaseQuery will + * have * @return A FIRDatabaseQuery instance, limited to data with the supplied value. */ - (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value; /** - * queryEqualToValue:childKey: is used to generate a reference to a limited view of the data at this location. - * The FIRDatabaseQuery instance returned by queryEqualToValue:childKey will respond to events at nodes with a value - * equal to the supplied argument with a key equal to childKey. There will be at most one node that matches because - * child keys are unique. + * queryEqualToValue:childKey: is used to generate a reference to a limited view + * of the data at this location. The FIRDatabaseQuery instance returned by + * queryEqualToValue:childKey will respond to events at nodes with a value equal + * to the supplied argument with a key equal to childKey. There will be at most + * one node that matches because child keys are unique. * - * @param value The value that the data returned by this FIRDatabaseQuery will have + * @param value The value that the data returned by this FIRDatabaseQuery will + * have * @param childKey The key of nodes with the right value - * @return A FIRDatabaseQuery instance, limited to data with the supplied value and the key. + * @return A FIRDatabaseQuery instance, limited to data with the supplied value + * and the key. */ -- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value childKey:(nullable NSString *)childKey; +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value + childKey:(nullable NSString *)childKey; #pragma mark - Managing presence @@ -457,75 +548,81 @@ is meant to be preserved, you should use setValue:andPriority: instead. * the client is disconnected (due to closing the browser, navigating * to a new page, or network issues). * - * onDisconnectSetValue: is especially useful for implementing "presence" systems, - * where a value should be changed or cleared when a user disconnects + * onDisconnectSetValue: is especially useful for implementing "presence" + * systems, where a value should be changed or cleared when a user disconnects * so that he appears "offline" to other users. * * @param value The value to be set after the connection is lost. */ -- (void) onDisconnectSetValue:(nullable id)value; - +- (void)onDisconnectSetValue:(nullable id)value; /** * Ensure the data at this location is set to the specified value when * the client is disconnected (due to closing the browser, navigating * to a new page, or network issues). * - * The completion block will be triggered when the operation has been successfully queued up on the Firebase Database servers + * The completion block will be triggered when the operation has been + * successfully queued up on the Firebase Database servers * * @param value The value to be set after the connection is lost. - * @param block Block to be triggered when the operation has been queued up on the Firebase Database servers + * @param block Block to be triggered when the operation has been queued up on + * the Firebase Database servers */ -- (void) onDisconnectSetValue:(nullable id)value withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; - +- (void)onDisconnectSetValue:(nullable id)value + withCompletionBlock:(void (^)(NSError *__nullable error, + FIRDatabaseReference *ref))block; /** - * Ensure the data at this location is set to the specified value and priority when - * the client is disconnected (due to closing the browser, navigating - * to a new page, or network issues). + * Ensure the data at this location is set to the specified value and priority + * when the client is disconnected (due to closing the browser, navigating to a + * new page, or network issues). * * @param value The value to be set after the connection is lost. * @param priority The priority to be set after the connection is lost. */ -- (void) onDisconnectSetValue:(nullable id)value andPriority:(id)priority; - +- (void)onDisconnectSetValue:(nullable id)value andPriority:(id)priority; /** - * Ensure the data at this location is set to the specified value and priority when - * the client is disconnected (due to closing the browser, navigating - * to a new page, or network issues). + * Ensure the data at this location is set to the specified value and priority + * when the client is disconnected (due to closing the browser, navigating to a + * new page, or network issues). * - * The completion block will be triggered when the operation has been successfully queued up on the Firebase Database servers + * The completion block will be triggered when the operation has been + * successfully queued up on the Firebase Database servers * * @param value The value to be set after the connection is lost. * @param priority The priority to be set after the connection is lost. - * @param block Block to be triggered when the operation has been queued up on the Firebase Database servers + * @param block Block to be triggered when the operation has been queued up on + * the Firebase Database servers */ -- (void) onDisconnectSetValue:(nullable id)value andPriority:(nullable id)priority withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; - +- (void)onDisconnectSetValue:(nullable id)value + andPriority:(nullable id)priority + withCompletionBlock:(void (^)(NSError *__nullable error, + FIRDatabaseReference *ref))block; /** * Ensure the data at this location is removed when * the client is disconnected (due to closing the app, navigating * to a new page, or network issues). * - * onDisconnectRemoveValue is especially useful for implementing "presence" systems. + * onDisconnectRemoveValue is especially useful for implementing "presence" + * systems. */ -- (void) onDisconnectRemoveValue; - +- (void)onDisconnectRemoveValue; /** * Ensure the data at this location is removed when * the client is disconnected (due to closing the app, navigating * to a new page, or network issues). * - * onDisconnectRemoveValueWithCompletionBlock: is especially useful for implementing "presence" systems. + * onDisconnectRemoveValueWithCompletionBlock: is especially useful for + * implementing "presence" systems. * - * @param block Block to be triggered when the operation has been queued up on the Firebase Database servers + * @param block Block to be triggered when the operation has been queued up on + * the Firebase Database servers */ -- (void) onDisconnectRemoveValueWithCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; - - +- (void)onDisconnectRemoveValueWithCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; /** * Ensure the data has the specified child values updated when @@ -533,10 +630,10 @@ is meant to be preserved, you should use setValue:andPriority: instead. * to a new page, or network issues). * * - * @param values A dictionary of child node keys and the values to set them to after the connection is lost. + * @param values A dictionary of child node keys and the values to set them to + * after the connection is lost. */ -- (void) onDisconnectUpdateChildValues:(NSDictionary *)values; - +- (void)onDisconnectUpdateChildValues:(NSDictionary *)values; /** * Ensure the data has the specified child values updated when @@ -544,124 +641,170 @@ is meant to be preserved, you should use setValue:andPriority: instead. * to a new page, or network issues). * * - * @param values A dictionary of child node keys and the values to set them to after the connection is lost. - * @param block A block that will be called once the operation has been queued up on the Firebase Database servers + * @param values A dictionary of child node keys and the values to set them to + * after the connection is lost. + * @param block A block that will be called once the operation has been queued + * up on the Firebase Database servers */ -- (void) onDisconnectUpdateChildValues:(NSDictionary *)values withCompletionBlock:(void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; - +- (void)onDisconnectUpdateChildValues:(NSDictionary *)values + withCompletionBlock: + (void (^)(NSError *__nullable error, + FIRDatabaseReference *ref))block; /** - * Cancel any operations that are set to run on disconnect. If you previously called onDisconnectSetValue:, - * onDisconnectRemoveValue:, or onDisconnectUpdateChildValues:, and no longer want the values updated when the - * connection is lost, call cancelDisconnectOperations: + * Cancel any operations that are set to run on disconnect. If you previously + * called onDisconnectSetValue:, onDisconnectRemoveValue:, or + * onDisconnectUpdateChildValues:, and no longer want the values updated when + * the connection is lost, call cancelDisconnectOperations: */ -- (void) cancelDisconnectOperations; - +- (void)cancelDisconnectOperations; /** - * Cancel any operations that are set to run on disconnect. If you previously called onDisconnectSetValue:, - * onDisconnectRemoveValue:, or onDisconnectUpdateChildValues:, and no longer want the values updated when the - * connection is lost, call cancelDisconnectOperations: + * Cancel any operations that are set to run on disconnect. If you previously + * called onDisconnectSetValue:, onDisconnectRemoveValue:, or + * onDisconnectUpdateChildValues:, and no longer want the values updated when + * the connection is lost, call cancelDisconnectOperations: * - * @param block A block that will be triggered once the Firebase Database servers have acknowledged the cancel request. + * @param block A block that will be triggered once the Firebase Database + * servers have acknowledged the cancel request. */ -- (void) cancelDisconnectOperationsWithCompletionBlock:(nullable void (^)(NSError *__nullable error, FIRDatabaseReference * ref))block; - +- (void)cancelDisconnectOperationsWithCompletionBlock: + (nullable void (^)(NSError *__nullable error, + FIRDatabaseReference *ref))block; #pragma mark - Manual Connection Management /** - * Manually disconnect the Firebase Database client from the server and disable automatic reconnection. + * Manually disconnect the Firebase Database client from the server and disable + * automatic reconnection. * - * The Firebase Database client automatically maintains a persistent connection to the Firebase Database server, - * which will remain active indefinitely and reconnect when disconnected. However, the goOffline( ) - * and goOnline( ) methods may be used to manually control the client connection in cases where + * The Firebase Database client automatically maintains a persistent connection + * to the Firebase Database server, which will remain active indefinitely and + * reconnect when disconnected. However, the goOffline( ) and goOnline( ) + * methods may be used to manually control the client connection in cases where * a persistent connection is undesirable. * - * While offline, the Firebase Database client will no longer receive data updates from the server. However, - * all database operations performed locally will continue to immediately fire events, allowing - * your application to continue behaving normally. Additionally, each operation performed locally - * will automatically be queued and retried upon reconnection to the Firebase Database server. + * While offline, the Firebase Database client will no longer receive data + * updates from the server. However, all database operations performed locally + * will continue to immediately fire events, allowing your application to + * continue behaving normally. Additionally, each operation performed locally + * will automatically be queued and retried upon reconnection to the Firebase + * Database server. * - * To reconnect to the Firebase Database server and begin receiving remote events, see goOnline( ). - * Once the connection is reestablished, the Firebase Database client will transmit the appropriate data - * and fire the appropriate events so that your client "catches up" automatically. + * To reconnect to the Firebase Database server and begin receiving remote + * events, see goOnline( ). Once the connection is reestablished, the Firebase + * Database client will transmit the appropriate data and fire the appropriate + * events so that your client "catches up" automatically. * * Note: Invoking this method will impact all Firebase Database connections. */ -+ (void) goOffline; ++ (void)goOffline; /** - * Manually reestablish a connection to the Firebase Database server and enable automatic reconnection. + * Manually reestablish a connection to the Firebase Database server and enable + * automatic reconnection. * - * The Firebase Database client automatically maintains a persistent connection to the Firebase Database server, - * which will remain active indefinitely and reconnect when disconnected. However, the goOffline( ) - * and goOnline( ) methods may be used to manually control the client connection in cases where + * The Firebase Database client automatically maintains a persistent connection + * to the Firebase Database server, which will remain active indefinitely and + * reconnect when disconnected. However, the goOffline( ) and goOnline( ) + * methods may be used to manually control the client connection in cases where * a persistent connection is undesirable. * - * This method should be used after invoking goOffline( ) to disable the active connection. - * Once reconnected, the Firebase Database client will automatically transmit the proper data and fire - * the appropriate events so that your client "catches up" automatically. + * This method should be used after invoking goOffline( ) to disable the active + * connection. Once reconnected, the Firebase Database client will automatically + * transmit the proper data and fire the appropriate events so that your client + * "catches up" automatically. * * To disconnect from the Firebase Database server, see goOffline( ). * * Note: Invoking this method will impact all Firebase Database connections. */ -+ (void) goOnline; - ++ (void)goOnline; #pragma mark - Transactions /** - * Performs an optimistic-concurrency transactional update to the data at this location. Your block will be called with a FIRMutableData - * instance that contains the current data at this location. Your block should update this data to the value you - * wish to write to this location, and then return an instance of FIRTransactionResult with the new data. - * - * If, when the operation reaches the server, it turns out that this client had stale data, your block will be run - * again with the latest data from the server. - * - * When your block is run, you may decide to abort the transaction by returning [FIRTransactionResult abort]. - * - * @param block This block receives the current data at this location and must return an instance of FIRTransactionResult - */ -- (void) runTransactionBlock:(FIRTransactionResult * (^) (FIRMutableData* currentData))block; - - -/** - * Performs an optimistic-concurrency transactional update to the data at this location. Your block will be called with a FIRMutableData - * instance that contains the current data at this location. Your block should update this data to the value you - * wish to write to this location, and then return an instance of FIRTransactionResult with the new data. - * - * If, when the operation reaches the server, it turns out that this client had stale data, your block will be run - * again with the latest data from the server. - * - * When your block is run, you may decide to abort the transaction by returning [FIRTransactionResult abort]. - * - * @param block This block receives the current data at this location and must return an instance of FIRTransactionResult - * @param completionBlock This block will be triggered once the transaction is complete, whether it was successful or not. It will indicate if there was an error, whether or not the data was committed, and what the current value of the data at this location is. - */ -- (void)runTransactionBlock:(FIRTransactionResult * (^) (FIRMutableData* currentData))block andCompletionBlock:(void (^) (NSError *__nullable error, BOOL committed, FIRDataSnapshot *__nullable snapshot))completionBlock; - - - -/** - * Performs an optimistic-concurrency transactional update to the data at this location. Your block will be called with a FIRMutableData - * instance that contains the current data at this location. Your block should update this data to the value you - * wish to write to this location, and then return an instance of FIRTransactionResult with the new data. - * - * If, when the operation reaches the server, it turns out that this client had stale data, your block will be run - * again with the latest data from the server. - * - * When your block is run, you may decide to abort the transaction by return [FIRTransactionResult abort]. - * - * Since your block may be run multiple times, this client could see several immediate states that don't exist on the server. You can suppress those immediate states until the server confirms the final state of the transaction. - * - * @param block This block receives the current data at this location and must return an instance of FIRTransactionResult - * @param completionBlock This block will be triggered once the transaction is complete, whether it was successful or not. It will indicate if there was an error, whether or not the data was committed, and what the current value of the data at this location is. - * @param localEvents Set this to NO to suppress events raised for intermediate states, and only get events based on the final state of the transaction. - */ -- (void)runTransactionBlock:(FIRTransactionResult * (^) (FIRMutableData* currentData))block andCompletionBlock:(nullable void (^) (NSError *__nullable error, BOOL committed, FIRDataSnapshot *__nullable snapshot))completionBlock withLocalEvents:(BOOL)localEvents; - + * Performs an optimistic-concurrency transactional update to the data at this + * location. Your block will be called with a FIRMutableData instance that + * contains the current data at this location. Your block should update this + * data to the value you wish to write to this location, and then return an + * instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had + * stale data, your block will be run again with the latest data from the + * server. + * + * When your block is run, you may decide to abort the transaction by returning + * [FIRTransactionResult abort]. + * + * @param block This block receives the current data at this location and must + * return an instance of FIRTransactionResult + */ +- (void)runTransactionBlock: + (FIRTransactionResult * (^)(FIRMutableData *currentData))block; + +/** + * Performs an optimistic-concurrency transactional update to the data at this + * location. Your block will be called with a FIRMutableData instance that + * contains the current data at this location. Your block should update this + * data to the value you wish to write to this location, and then return an + * instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had + * stale data, your block will be run again with the latest data from the + * server. + * + * When your block is run, you may decide to abort the transaction by returning + * [FIRTransactionResult abort]. + * + * @param block This block receives the current data at this location and must + * return an instance of FIRTransactionResult + * @param completionBlock This block will be triggered once the transaction is + * complete, whether it was successful or not. It will indicate if there was an + * error, whether or not the data was committed, and what the current value of + * the data at this location is. + */ +- (void)runTransactionBlock: + (FIRTransactionResult * (^)(FIRMutableData *currentData))block + andCompletionBlock: + (void (^)(NSError *__nullable error, BOOL committed, + FIRDataSnapshot *__nullable snapshot))completionBlock; + +/** + * Performs an optimistic-concurrency transactional update to the data at this + * location. Your block will be called with a FIRMutableData instance that + * contains the current data at this location. Your block should update this + * data to the value you wish to write to this location, and then return an + * instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had + * stale data, your block will be run again with the latest data from the + * server. + * + * When your block is run, you may decide to abort the transaction by return + * [FIRTransactionResult abort]. + * + * Since your block may be run multiple times, this client could see several + * immediate states that don't exist on the server. You can suppress those + * immediate states until the server confirms the final state of the + * transaction. + * + * @param block This block receives the current data at this location and must + * return an instance of FIRTransactionResult + * @param completionBlock This block will be triggered once the transaction is + * complete, whether it was successful or not. It will indicate if there was an + * error, whether or not the data was committed, and what the current value of + * the data at this location is. + * @param localEvents Set this to NO to suppress events raised for intermediate + * states, and only get events based on the final state of the transaction. + */ +- (void)runTransactionBlock: + (FIRTransactionResult * (^)(FIRMutableData *currentData))block + andCompletionBlock: + (nullable void (^)(NSError *__nullable error, BOOL committed, + FIRDataSnapshot *__nullable snapshot)) + completionBlock + withLocalEvents:(BOOL)localEvents; #pragma mark - Retrieving String Representation @@ -670,48 +813,48 @@ is meant to be preserved, you should use setValue:andPriority: instead. * * @return The absolute URL of the referenced Firebase Database location. */ -- (NSString *) description; +- (NSString *)description; #pragma mark - Properties /** * Gets a FIRDatabaseReference for the parent location. - * If this instance refers to the root of your Firebase Database, it has no parent, - * and therefore parent( ) will return null. + * If this instance refers to the root of your Firebase Database, it has no + * parent, and therefore parent( ) will return null. * * @return A FIRDatabaseReference for the parent location. */ -@property (strong, readonly, nonatomic, nullable) FIRDatabaseReference * parent; - +@property(strong, readonly, nonatomic, nullable) FIRDatabaseReference *parent; /** * Gets a FIRDatabaseReference for the root location * * @return A new FIRDatabaseReference to root location. */ -@property (strong, readonly, nonatomic) FIRDatabaseReference * root; - +@property(strong, readonly, nonatomic) FIRDatabaseReference *root; /** - * Gets the last token in a Firebase Database location (e.g. 'fred' in https://SampleChat.firebaseIO-demo.com/users/fred) + * Gets the last token in a Firebase Database location (e.g. 'fred' in + * https://SampleChat.firebaseIO-demo.com/users/fred) * * @return The key of the location this reference points to. */ -@property (strong, readonly, nonatomic, nullable) NSString* key; +@property(strong, readonly, nonatomic, nullable) NSString *key; /** - * Gets the URL for the Firebase Database location referenced by this FIRDatabaseReference. + * Gets the URL for the Firebase Database location referenced by this + * FIRDatabaseReference. * * @return The url of the location this reference points to. */ -@property (strong, readonly, nonatomic) NSString* URL; +@property(strong, readonly, nonatomic) NSString *URL; /** * Gets the FIRDatabase instance associated with this reference. * * @return The FIRDatabase object for this reference. */ -@property (strong, readonly, nonatomic) FIRDatabase *database; +@property(strong, readonly, nonatomic) FIRDatabase *database; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRMutableData.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRMutableData.h index 7445d71..9797a67 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRMutableData.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRMutableData.h @@ -19,12 +19,14 @@ NS_ASSUME_NONNULL_BEGIN /** - * A FIRMutableData instance is populated with data from a Firebase Database location. - * When you are using runTransactionBlock:, you will be given an instance containing the current - * data at that location. Your block will be responsible for updating that instance to the data - * you wish to save at that location, and then returning using [FIRTransactionResult successWithValue:]. + * A FIRMutableData instance is populated with data from a Firebase Database + * location. When you are using runTransactionBlock:, you will be given an + * instance containing the current data at that location. Your block will be + * responsible for updating that instance to the data you wish to save at that + * location, and then returning using [FIRTransactionResult successWithValue:]. * - * To modify the data, set its value property to any of the native types support by Firebase Database: + * To modify the data, set its value property to any of the native types support + * by Firebase Database: * * + NSNumber (includes BOOL) * + NSDictionary @@ -32,47 +34,46 @@ NS_ASSUME_NONNULL_BEGIN * + NSString * + nil / NSNull to remove the data * - * Note that changes made to a child FIRMutableData instance will be visible to the parent. + * Note that changes made to a child FIRMutableData instance will be visible to + * the parent. */ NS_SWIFT_NAME(MutableData) @interface FIRMutableData : NSObject - #pragma mark - Inspecting and navigating the data - /** * Returns boolean indicating whether this mutable data has children. * * @return YES if this data contains child nodes. */ -- (BOOL) hasChildren; - +- (BOOL)hasChildren; /** * Indicates whether this mutable data has a child at the given path. * - * @param path A path string, consisting either of a single segment, like 'child', or multiple segments, 'a/deeper/child' + * @param path A path string, consisting either of a single segment, like + * 'child', or multiple segments, 'a/deeper/child' * @return YES if this data contains a child at the specified relative path */ -- (BOOL) hasChildAtPath:(NSString *)path; - +- (BOOL)hasChildAtPath:(NSString *)path; /** - * Used to obtain a FIRMutableData instance that encapsulates the data at the given relative path. - * Note that changes made to the child will be visible to the parent. + * Used to obtain a FIRMutableData instance that encapsulates the data at the + * given relative path. Note that changes made to the child will be visible to + * the parent. * - * @param path A path string, consisting either of a single segment, like 'child', or multiple segments, 'a/deeper/child' + * @param path A path string, consisting either of a single segment, like + * 'child', or multiple segments, 'a/deeper/child' * @return A FIRMutableData instance containing the data at the given path */ - (FIRMutableData *)childDataByAppendingPath:(NSString *)path; - #pragma mark - Properties - /** - * To modify the data contained by this instance of FIRMutableData, set this to any of the native types supported by Firebase Database: + * To modify the data contained by this instance of FIRMutableData, set this to + * any of the native types supported by Firebase Database: * * + NSNumber (includes BOOL) * + NSDictionary @@ -84,11 +85,11 @@ NS_SWIFT_NAME(MutableData) * * @return The current data at this location as a native object */ -@property (strong, nonatomic, nullable) id value; - +@property(strong, nonatomic, nullable) id value; /** - * Set this property to update the priority of the data at this location. Can be set to the following types: + * Set this property to update the priority of the data at this location. Can be + * set to the following types: * * + NSNumber * + NSString @@ -96,33 +97,31 @@ NS_SWIFT_NAME(MutableData) * * @return The priority of the data at this location */ -@property (strong, nonatomic, nullable) id priority; - +@property(strong, nonatomic, nullable) id priority; /** * @return The number of child nodes at this location */ -@property (readonly, nonatomic) NSUInteger childrenCount; - +@property(readonly, nonatomic) NSUInteger childrenCount; /** - * Used to iterate over the children at this location. You can use the native for .. in syntax: + * Used to iterate over the children at this location. You can use the native + * for .. in syntax: * * for (FIRMutableData* child in data.children) { * ... * } * - * Note that this enumerator operates on an immutable copy of the child list. So, you can modify the instance - * during iteration, but the new additions will not be visible until you get a new enumerator. + * Note that this enumerator operates on an immutable copy of the child list. + * So, you can modify the instance during iteration, but the new additions will + * not be visible until you get a new enumerator. */ -@property (readonly, nonatomic, strong) NSEnumerator* children; - +@property(readonly, nonatomic, strong) NSEnumerator *children; /** * @return The key name of this node, or nil if it is the top-most location */ -@property (readonly, nonatomic, strong, nullable) NSString* key; - +@property(readonly, nonatomic, strong, nullable) NSString *key; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRServerValue.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRServerValue.h index 365590c..8fca5e0 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRServerValue.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRServerValue.h @@ -14,11 +14,14 @@ * limitations under the License. */ +#import + NS_ASSUME_NONNULL_BEGIN /** - * Placeholder values you may write into Firebase Database as a value or priority - * that will automatically be populated by the Firebase Database server. + * Placeholder values you may write into Firebase Database as a value or + * priority that will automatically be populated by the Firebase Database + * server. */ NS_SWIFT_NAME(ServerValue) @interface FIRServerValue : NSObject @@ -26,7 +29,7 @@ NS_SWIFT_NAME(ServerValue) /** * Placeholder value for the number of milliseconds since the Unix epoch */ -+ (NSDictionary *) timestamp; ++ (NSDictionary *)timestamp; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRTransactionResult.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRTransactionResult.h index d356c5c..7f5ccc1 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRTransactionResult.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FIRTransactionResult.h @@ -14,32 +14,36 @@ * limitations under the License. */ -#import #import "FIRMutableData.h" +#import NS_ASSUME_NONNULL_BEGIN /** - * Used for runTransactionBlock:. An FIRTransactionResult instance is a container for the results of the transaction. + * Used for runTransactionBlock:. An FIRTransactionResult instance is a + * container for the results of the transaction. */ NS_SWIFT_NAME(TransactionResult) @interface FIRTransactionResult : NSObject /** - * Used for runTransactionBlock:. Indicates that the new value should be saved at this location + * Used for runTransactionBlock:. Indicates that the new value should be saved + * at this location * * @param value A FIRMutableData instance containing the new value to be set - * @return An FIRTransactionResult instance that can be used as a return value from the block given to runTransactionBlock: + * @return An FIRTransactionResult instance that can be used as a return value + * from the block given to runTransactionBlock: */ + (FIRTransactionResult *)successWithValue:(FIRMutableData *)value; - /** - * Used for runTransactionBlock:. Indicates that the current transaction should no longer proceed. + * Used for runTransactionBlock:. Indicates that the current transaction should + * no longer proceed. * - * @return An FIRTransactionResult instance that can be used as a return value from the block given to runTransactionBlock: + * @return An FIRTransactionResult instance that can be used as a return value + * from the block given to runTransactionBlock: */ -+ (FIRTransactionResult *) abort; ++ (FIRTransactionResult *)abort; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FirebaseDatabase.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FirebaseDatabase.h index e52f5d6..ae6b933 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FirebaseDatabase.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Public/FirebaseDatabase.h @@ -17,11 +17,11 @@ #ifndef FirebaseDatabase_h #define FirebaseDatabase_h +#import "FIRDataEventType.h" +#import "FIRDataSnapshot.h" #import "FIRDatabase.h" #import "FIRDatabaseQuery.h" #import "FIRDatabaseReference.h" -#import "FIRDataEventType.h" -#import "FIRDataSnapshot.h" #import "FIRMutableData.h" #import "FIRServerValue.h" #import "FIRTransactionResult.h" diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FConnection.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FConnection.h index ed4879a..7198615 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FConnection.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FConnection.h @@ -14,25 +14,29 @@ * limitations under the License. */ -#import -#import "FWebSocketConnection.h" #import "FTypedefs.h" +#import "FWebSocketConnection.h" +#import @protocol FConnectionDelegate; @interface FConnection : NSObject -@property (nonatomic, weak) id delegate; +@property(nonatomic, weak) id delegate; -- (id)initWith:(FRepoInfo *)aRepoInfo andDispatchQueue:(dispatch_queue_t)queue lastSessionID:(NSString *)lastSessionID; +- (id)initWith:(FRepoInfo *)aRepoInfo + andDispatchQueue:(dispatch_queue_t)queue + lastSessionID:(NSString *)lastSessionID; - (void)open; - (void)close; - (void)sendRequest:(NSDictionary *)dataMsg sensitive:(BOOL)sensitive; // FWebSocketDelegate delegate methods -- (void)onMessage:(FWebSocketConnection *)fwebSocket withMessage:(NSDictionary *)message; -- (void)onDisconnect:(FWebSocketConnection *)fwebSocket wasEverConnected:(BOOL)everConnected; +- (void)onMessage:(FWebSocketConnection *)fwebSocket + withMessage:(NSDictionary *)message; +- (void)onDisconnect:(FWebSocketConnection *)fwebSocket + wasEverConnected:(BOOL)everConnected; @end @@ -43,10 +47,13 @@ typedef enum { @protocol FConnectionDelegate -- (void)onReady:(FConnection *)fconnection atTime:(NSNumber *)timestamp sessionID:(NSString *)sessionID; -- (void)onDataMessage:(FConnection *)fconnection withMessage:(NSDictionary *)message; -- (void)onDisconnect:(FConnection *)fconnection withReason:(FDisconnectReason)reason; +- (void)onReady:(FConnection *)fconnection + atTime:(NSNumber *)timestamp + sessionID:(NSString *)sessionID; +- (void)onDataMessage:(FConnection *)fconnection + withMessage:(NSDictionary *)message; +- (void)onDisconnect:(FConnection *)fconnection + withReason:(FDisconnectReason)reason; - (void)onKill:(FConnection *)fconnection withReason:(NSString *)reason; @end - diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FConnection.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FConnection.m index 08014f6..a33ebd7 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FConnection.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FConnection.m @@ -14,9 +14,9 @@ * limitations under the License. */ -#import #import "FConnection.h" #import "FConstants.h" +#import typedef enum { REALTIME_STATE_CONNECTING = 0, @@ -28,8 +28,8 @@ @interface FConnection () { FConnectionState state; } -@property (nonatomic, strong) FWebSocketConnection* conn; -@property (nonatomic, strong) FRepoInfo* repoInfo; +@property(nonatomic, strong) FWebSocketConnection *conn; +@property(nonatomic, strong) FRepoInfo *repoInfo; @end @@ -45,12 +45,16 @@ @implementation FConnection #pragma mark - #pragma mark Initializers -- (id)initWith:(FRepoInfo *)aRepoInfo andDispatchQueue:(dispatch_queue_t)queue lastSessionID:(NSString *)lastSessionID{ +- (id)initWith:(FRepoInfo *)aRepoInfo + andDispatchQueue:(dispatch_queue_t)queue + lastSessionID:(NSString *)lastSessionID { self = [super init]; if (self) { state = REALTIME_STATE_CONNECTING; self.repoInfo = aRepoInfo; - self.conn = [[FWebSocketConnection alloc] initWith:self.repoInfo andQueue:queue lastSessionID:lastSessionID]; + self.conn = [[FWebSocketConnection alloc] initWith:self.repoInfo + andQueue:queue + lastSessionID:lastSessionID]; self.conn.delegate = self; } return self; @@ -64,7 +68,7 @@ - (void)open { [self.conn open]; } -- (void) closeWithReason:(FDisconnectReason)reason { +- (void)closeWithReason:(FDisconnectReason)reason { if (state != REALTIME_STATE_DISCONNECTED) { FFLog(@"I-RDB082002", @"Closing realtime connection."); state = REALTIME_STATE_DISCONNECTED; @@ -79,15 +83,16 @@ - (void) closeWithReason:(FDisconnectReason)reason { } } -- (void) close { +- (void)close { [self closeWithReason:DISCONNECT_REASON_OTHER]; } -- (void) sendRequest:(NSDictionary *)dataMsg sensitive:(BOOL)sensitive { - // since this came from the persistent connection, wrap it in a data message envelope - NSDictionary* msg = @{ - kFWPRequestType: kFWPRequestTypeData, - kFWPRequestDataPayload: dataMsg +- (void)sendRequest:(NSDictionary *)dataMsg sensitive:(BOOL)sensitive { + // since this came from the persistent connection, wrap it in a data message + // envelope + NSDictionary *msg = @{ + kFWPRequestType : kFWPRequestTypeData, + kFWPRequestDataPayload : dataMsg }; [self sendData:msg sensitive:sensitive]; } @@ -95,10 +100,12 @@ - (void) sendRequest:(NSDictionary *)dataMsg sensitive:(BOOL)sensitive { #pragma mark - #pragma mark Helpers - -- (void) sendData:(NSDictionary *)data sensitive:(BOOL)sensitive { +- (void)sendData:(NSDictionary *)data sensitive:(BOOL)sensitive { if (state != REALTIME_STATE_CONNECTED) { - @throw [[NSException alloc] initWithName:@"InvalidConnectionState" reason:@"Tried to send data on an unconnected FConnection" userInfo:nil]; + @throw [[NSException alloc] + initWithName:@"InvalidConnectionState" + reason:@"Tried to send data on an unconnected FConnection" + userInfo:nil]; } else { if (sensitive) { FFLog(@"I-RDB082004", @"Sending data (contents hidden)"); @@ -113,13 +120,15 @@ - (void) sendData:(NSDictionary *)data sensitive:(BOOL)sensitive { #pragma mark FWebSocketConnectinDelegate implementation // Corresponds to onConnectionLost in JS -- (void)onDisconnect:(FWebSocketConnection *)fwebSocket wasEverConnected:(BOOL)everConnected { +- (void)onDisconnect:(FWebSocketConnection *)fwebSocket + wasEverConnected:(BOOL)everConnected { self.conn = nil; if (!everConnected && state == REALTIME_STATE_CONNECTING) { FFLog(@"I-RDB082006", @"Realtime connection failed."); - // Since we failed to connect at all, clear any cached entry for this namespace in case the machine went away + // Since we failed to connect at all, clear any cached entry for this + // namespace in case the machine went away [self.repoInfo clearInternalHostCache]; } else if (state == REALTIME_STATE_CONNECTED) { FFLog(@"I-RDB082007", @"Realtime connection lost."); @@ -129,62 +138,69 @@ - (void)onDisconnect:(FWebSocketConnection *)fwebSocket wasEverConnected:(BOOL)e } // Corresponds to onMessageReceived in JS -- (void)onMessage:(FWebSocketConnection *)fwebSocket withMessage:(NSDictionary *)message { - NSString* rawMessageType = [message objectForKey:kFWPAsyncServerEnvelopeType]; - if(rawMessageType != nil) { - if([rawMessageType isEqualToString:kFWPAsyncServerDataMessage]) { - [self onDataMessage:[message objectForKey:kFWPAsyncServerEnvelopeData]]; - } - else if ([rawMessageType isEqualToString:kFWPAsyncServerControlMessage]) { +- (void)onMessage:(FWebSocketConnection *)fwebSocket + withMessage:(NSDictionary *)message { + NSString *rawMessageType = + [message objectForKey:kFWPAsyncServerEnvelopeType]; + if (rawMessageType != nil) { + if ([rawMessageType isEqualToString:kFWPAsyncServerDataMessage]) { + [self onDataMessage:[message + objectForKey:kFWPAsyncServerEnvelopeData]]; + } else if ([rawMessageType + isEqualToString:kFWPAsyncServerControlMessage]) { [self onControl:[message objectForKey:kFWPAsyncServerEnvelopeData]]; + } else { + FFLog(@"I-RDB082008", @"Unrecognized server packet type: %@", + rawMessageType); } - else { - FFLog(@"I-RDB082008", @"Unrecognized server packet type: %@", rawMessageType); - } - } - else { - FFLog(@"I-RDB082009", @"Unrecognized raw server packet received: %@", message); + } else { + FFLog(@"I-RDB082009", @"Unrecognized raw server packet received: %@", + message); } } -- (void) onDataMessage:(NSDictionary *)message { +- (void)onDataMessage:(NSDictionary *)message { // we don't do anything with data messages, just kick them up a level FFLog(@"I-RDB082010", @"Got data message: %@", message); [self.delegate onDataMessage:self withMessage:message]; } -- (void) onControl:(NSDictionary *)message { +- (void)onControl:(NSDictionary *)message { FFLog(@"I-RDB082011", @"Got control message: %@", message); - NSString* type = [message objectForKey:kFWPAsyncServerControlMessageType]; - if([type isEqualToString:kFWPAsyncServerControlMessageShutdown]) { - NSString* reason = [message objectForKey:kFWPAsyncServerControlMessageData]; + NSString *type = [message objectForKey:kFWPAsyncServerControlMessageType]; + if ([type isEqualToString:kFWPAsyncServerControlMessageShutdown]) { + NSString *reason = + [message objectForKey:kFWPAsyncServerControlMessageData]; [self onConnectionShutdownWithReason:reason]; - } - else if ([type isEqualToString:kFWPAsyncServerControlMessageReset]) { - NSString* host = [message objectForKey:kFWPAsyncServerControlMessageData]; + } else if ([type isEqualToString:kFWPAsyncServerControlMessageReset]) { + NSString *host = + [message objectForKey:kFWPAsyncServerControlMessageData]; [self onReset:host]; - } - else if ([type isEqualToString:kFWPAsyncServerHello]) { - NSDictionary* handshakeData = [message objectForKey:kFWPAsyncServerControlMessageData]; + } else if ([type isEqualToString:kFWPAsyncServerHello]) { + NSDictionary *handshakeData = + [message objectForKey:kFWPAsyncServerControlMessageData]; [self onHandshake:handshakeData]; - } - else { - FFLog(@"I-RDB082012", @"Unknown control message returned from server: %@", message); + } else { + FFLog(@"I-RDB082012", + @"Unknown control message returned from server: %@", message); } } -- (void) onConnectionShutdownWithReason:(NSString *)reason { - FFLog(@"I-RDB082013", @"Connection shutdown command received. Shutting down..."); +- (void)onConnectionShutdownWithReason:(NSString *)reason { + FFLog(@"I-RDB082013", + @"Connection shutdown command received. Shutting down..."); [self.delegate onKill:self withReason:reason]; [self close]; } -- (void) onHandshake:(NSDictionary *)handshake { - NSNumber* timestamp = [handshake objectForKey:kFWPAsyncServerHelloTimestamp]; -// NSString* version = [handshake objectForKey:kFWPAsyncServerHelloVersion]; - NSString* host = [handshake objectForKey:kFWPAsyncServerHelloConnectedHost]; - NSString* sessionID = [handshake objectForKey:kFWPAsyncServerHelloSession]; +- (void)onHandshake:(NSDictionary *)handshake { + NSNumber *timestamp = + [handshake objectForKey:kFWPAsyncServerHelloTimestamp]; + // NSString* version = [handshake + // objectForKey:kFWPAsyncServerHelloVersion]; + NSString *host = [handshake objectForKey:kFWPAsyncServerHelloConnectedHost]; + NSString *sessionID = [handshake objectForKey:kFWPAsyncServerHelloSession]; self.repoInfo.internalHost = host; @@ -194,18 +210,24 @@ - (void) onHandshake:(NSDictionary *)handshake { } } -- (void) onConnection:(FWebSocketConnection *)conn readyAtTime:(NSNumber *)timestamp sessionID:(NSString *)sessionID { +- (void)onConnection:(FWebSocketConnection *)conn + readyAtTime:(NSNumber *)timestamp + sessionID:(NSString *)sessionID { FFLog(@"I-RDB082014", @"Realtime connection established"); state = REALTIME_STATE_CONNECTED; [self.delegate onReady:self atTime:timestamp sessionID:sessionID]; } -- (void) onReset:(NSString *)host { - FFLog(@"I-RDB082015", @"Got a reset; killing connection to: %@; Updating internalHost to: %@", repoInfo.internalHost, host); +- (void)onReset:(NSString *)host { + FFLog( + @"I-RDB082015", + @"Got a reset; killing connection to: %@; Updating internalHost to: %@", + repoInfo.internalHost, host); self.repoInfo.internalHost = host; - // Explicitly close the connection with SERVER_RESET so calling code knows to reconnect immediately. + // Explicitly close the connection with SERVER_RESET so calling code knows + // to reconnect immediately. [self closeWithReason:DISCONNECT_REASON_SERVER_RESET]; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FWebSocketConnection.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FWebSocketConnection.h index 6a14d47..abb7474 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FWebSocketConnection.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FWebSocketConnection.h @@ -14,33 +14,40 @@ * limitations under the License. */ -#import #import "FSRWebSocket.h" #import "FUtilities.h" +#import @protocol FWebSocketDelegate; @interface FWebSocketConnection : NSObject -@property (nonatomic, weak) id delegate; +@property(nonatomic, weak) id delegate; -- (id)initWith:(FRepoInfo *)repoInfo andQueue:(dispatch_queue_t)queue lastSessionID:(NSString *)lastSessionID; +- (id)initWith:(FRepoInfo *)repoInfo + andQueue:(dispatch_queue_t)queue + lastSessionID:(NSString *)lastSessionID; -- (void) open; -- (void) close; -- (void) start; -- (void) send:(NSDictionary *)dictionary; +- (void)open; +- (void)close; +- (void)start; +- (void)send:(NSDictionary *)dictionary; - (void)webSocket:(FSRWebSocket *)webSocket didReceiveMessage:(id)message; - (void)webSocketDidOpen:(FSRWebSocket *)webSocket; - (void)webSocket:(FSRWebSocket *)webSocket didFailWithError:(NSError *)error; -- (void)webSocket:(FSRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean; +- (void)webSocket:(FSRWebSocket *)webSocket + didCloseWithCode:(NSInteger)code + reason:(NSString *)reason + wasClean:(BOOL)wasClean; @end @protocol FWebSocketDelegate -- (void)onMessage:(FWebSocketConnection *)fwebSocket withMessage:(NSDictionary *)message; -- (void)onDisconnect:(FWebSocketConnection *)fwebSocket wasEverConnected:(BOOL)everConnected; +- (void)onMessage:(FWebSocketConnection *)fwebSocket + withMessage:(NSDictionary *)message; +- (void)onDisconnect:(FWebSocketConnection *)fwebSocket + wasEverConnected:(BOOL)everConnected; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FWebSocketConnection.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FWebSocketConnection.m index 49d6bd8..edcae09 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FWebSocketConnection.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Realtime/FWebSocketConnection.m @@ -14,38 +14,39 @@ * limitations under the License. */ -// Targetted compilation is ONLY for testing. UIKit is weak-linked in actual release build. +// Targetted compilation is ONLY for testing. UIKit is weak-linked in actual +// release build. #import -#import -#import "FWebSocketConnection.h" #import "FConstants.h" #import "FIRDatabaseReference.h" -#import "FStringUtilities.h" #import "FIRDatabase_Private.h" +#import "FStringUtilities.h" +#import "FWebSocketConnection.h" +#import #if TARGET_OS_IOS || TARGET_OS_TV #import #endif @interface FWebSocketConnection () { - NSMutableString* frame; + NSMutableString *frame; BOOL everConnected; BOOL isClosed; - NSTimer* keepAlive; + NSTimer *keepAlive; } -- (void) shutdown; -- (void) onClosed; -- (void) closeIfNeverConnected; +- (void)shutdown; +- (void)onClosed; +- (void)closeIfNeverConnected; -@property (nonatomic, strong) FSRWebSocket* webSocket; -@property (nonatomic, strong) NSNumber* connectionId; -@property (nonatomic, readwrite) int totalFrames; -@property (nonatomic, readonly) BOOL buffering; -@property (nonatomic, readonly) NSString* userAgent; -@property (nonatomic) dispatch_queue_t dispatchQueue; +@property(nonatomic, strong) FSRWebSocket *webSocket; +@property(nonatomic, strong) NSNumber *connectionId; +@property(nonatomic, readwrite) int totalFrames; +@property(nonatomic, readonly) BOOL buffering; +@property(nonatomic, readonly) NSString *userAgent; +@property(nonatomic) dispatch_queue_t dispatchQueue; - (void)nop:(NSTimer *)timer; @@ -57,7 +58,9 @@ @implementation FWebSocketConnection @synthesize webSocket; @synthesize connectionId; -- (id)initWith:(FRepoInfo *)repoInfo andQueue:(dispatch_queue_t)queue lastSessionID:(NSString *)lastSessionID { +- (id)initWith:(FRepoInfo *)repoInfo + andQueue:(dispatch_queue_t)queue + lastSessionID:(NSString *)lastSessionID { self = [super init]; if (self) { everConnected = NO; @@ -67,120 +70,144 @@ - (id)initWith:(FRepoInfo *)repoInfo andQueue:(dispatch_queue_t)queue lastSessio self.dispatchQueue = queue; frame = nil; - NSString* connectionUrl = [repoInfo connectionURLWithLastSessionID:lastSessionID]; - NSString* ua = [self userAgent]; - FFLog(@"I-RDB083001", @"(wsc:%@) Connecting to: %@ as %@", self.connectionId, connectionUrl, ua); - - NSURLRequest* req = [[NSURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:connectionUrl]]; - self.webSocket = [[FSRWebSocket alloc] initWithURLRequest:req queue:queue andUserAgent:ua]; + NSString *connectionUrl = + [repoInfo connectionURLWithLastSessionID:lastSessionID]; + NSString *ua = [self userAgent]; + FFLog(@"I-RDB083001", @"(wsc:%@) Connecting to: %@ as %@", + self.connectionId, connectionUrl, ua); + + NSURLRequest *req = [[NSURLRequest alloc] + initWithURL:[[NSURL alloc] initWithString:connectionUrl]]; + self.webSocket = [[FSRWebSocket alloc] initWithURLRequest:req + queue:queue + andUserAgent:ua]; [self.webSocket setDelegateDispatchQueue:queue]; self.webSocket.delegate = self; } return self; } -- (NSString *) userAgent { - NSString* systemVersion; - NSString* deviceName; +- (NSString *)userAgent { + NSString *systemVersion; + NSString *deviceName; BOOL hasUiDeviceClass = NO; - // Targetted compilation is ONLY for testing. UIKit is weak-linked in actual release build. - #if TARGET_OS_IOS || TARGET_OS_TV +// Targetted compilation is ONLY for testing. UIKit is weak-linked in actual +// release build. +#if TARGET_OS_IOS || TARGET_OS_TV Class uiDeviceClass = NSClassFromString(@"UIDevice"); if (uiDeviceClass) { systemVersion = [uiDeviceClass currentDevice].systemVersion; deviceName = [uiDeviceClass currentDevice].model; hasUiDeviceClass = YES; } - #endif +#endif if (!hasUiDeviceClass) { - NSDictionary *systemVersionDictionary = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]; - systemVersion = [systemVersionDictionary objectForKey:@"ProductVersion"]; + NSDictionary *systemVersionDictionary = [NSDictionary + dictionaryWithContentsOfFile: + @"/System/Library/CoreServices/SystemVersion.plist"]; + systemVersion = + [systemVersionDictionary objectForKey:@"ProductVersion"]; deviceName = [systemVersionDictionary objectForKey:@"ProductName"]; } - NSString* bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; // Sanitize '/'s in deviceName and bundleIdentifier for stats deviceName = [FStringUtilities sanitizedForUserAgent:deviceName]; - bundleIdentifier = [FStringUtilities sanitizedForUserAgent:bundleIdentifier]; - - // Firebase/5/__//{device model / os (Mac OS X, iPhone, etc.}_ - NSString* ua = [NSString stringWithFormat:@"Firebase/%@/%@/%@/%@_%@", kWebsocketProtocolVersion, [FIRDatabase buildVersion], systemVersion, deviceName, bundleIdentifier]; + bundleIdentifier = + [FStringUtilities sanitizedForUserAgent:bundleIdentifier]; + + // Firebase/5/__//{device model / + // os (Mac OS X, iPhone, etc.}_ + NSString *ua = [NSString + stringWithFormat:@"Firebase/%@/%@/%@/%@_%@", kWebsocketProtocolVersion, + [FIRDatabase buildVersion], systemVersion, deviceName, + bundleIdentifier]; return ua; } -- (BOOL) buffering { +- (BOOL)buffering { return frame != nil; } #pragma mark - #pragma mark Public FWebSocketConnection methods -- (void) open { - FFLog(@"I-RDB083002", @"(wsc:%@) FWebSocketConnection open.", self.connectionId); +- (void)open { + FFLog(@"I-RDB083002", @"(wsc:%@) FWebSocketConnection open.", + self.connectionId); assert(delegate); everConnected = NO; // TODO Assert url [self.webSocket open]; - dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, kWebsocketConnectTimeout * NSEC_PER_SEC); + dispatch_time_t when = dispatch_time( + DISPATCH_TIME_NOW, kWebsocketConnectTimeout * NSEC_PER_SEC); dispatch_after(when, self.dispatchQueue, ^{ - [self closeIfNeverConnected]; + [self closeIfNeverConnected]; }); } -- (void) close { - FFLog(@"I-RDB083003", @"(wsc:%@) FWebSocketConnection is being closed.", self.connectionId); +- (void)close { + FFLog(@"I-RDB083003", @"(wsc:%@) FWebSocketConnection is being closed.", + self.connectionId); isClosed = YES; [self.webSocket close]; } -- (void) start { +- (void)start { // Start is a no-op for websockets. } -- (void) send:(NSDictionary *)dictionary { +- (void)send:(NSDictionary *)dictionary { [self resetKeepAlive]; - NSData* jsonData = [NSJSONSerialization dataWithJSONObject:dictionary - options:kNilOptions error:nil]; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary + options:kNilOptions + error:nil]; - NSString* data = [[NSString alloc] initWithData:jsonData + NSString *data = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; - NSArray* dataSegs = [FUtilities splitString:data intoMaxSize:kWebsocketMaxFrameSize]; + NSArray *dataSegs = [FUtilities splitString:data + intoMaxSize:kWebsocketMaxFrameSize]; - // First send the header so the server knows how many segments are forthcoming + // First send the header so the server knows how many segments are + // forthcoming if (dataSegs.count > 1) { - [self.webSocket send:[NSString stringWithFormat:@"%u", (unsigned int)dataSegs.count]]; + [self.webSocket + send:[NSString + stringWithFormat:@"%u", (unsigned int)dataSegs.count]]; } // Then, actually send the segments. - for(NSString * segment in dataSegs) { + for (NSString *segment in dataSegs) { [self.webSocket send:segment]; } } -- (void) nop:(NSTimer *)timer { +- (void)nop:(NSTimer *)timer { if (!isClosed) { FFLog(@"I-RDB083004", @"(wsc:%@) nop", self.connectionId); [self.webSocket send:@"0"]; - } - else { - FFLog(@"I-RDB083005", @"(wsc:%@) No more websocket; invalidating nop timer.", self.connectionId); + } else { + FFLog(@"I-RDB083005", + @"(wsc:%@) No more websocket; invalidating nop timer.", + self.connectionId); [timer invalidate]; } } -- (void) handleNewFrameCount:(int) numFrames { +- (void)handleNewFrameCount:(int)numFrames { self.totalFrames = numFrames; frame = [[NSMutableString alloc] initWithString:@""]; - FFLog(@"I-RDB083006", @"(wsc:%@) handleNewFrameCount: %d", self.connectionId, self.totalFrames); + FFLog(@"I-RDB083006", @"(wsc:%@) handleNewFrameCount: %d", + self.connectionId, self.totalFrames); } -- (NSString *) extractFrameCount:(NSString *) message { +- (NSString *)extractFrameCount:(NSString *)message { if ([message length] <= 4) { int frameCount = [message intValue]; if (frameCount > 0) { @@ -192,17 +219,20 @@ - (NSString *) extractFrameCount:(NSString *) message { return message; } -- (void) appendFrame:(NSString *) message { +- (void)appendFrame:(NSString *)message { [frame appendString:message]; self.totalFrames = self.totalFrames - 1; if (self.totalFrames == 0) { // Call delegate and pass an immutable version of the frame - NSDictionary* json = [NSJSONSerialization JSONObjectWithData:[frame dataUsingEncoding:NSUTF8StringEncoding] - options:kNilOptions - error:nil]; + NSDictionary *json = [NSJSONSerialization + JSONObjectWithData:[frame dataUsingEncoding:NSUTF8StringEncoding] + options:kNilOptions + error:nil]; frame = nil; - FFLog(@"I-RDB083007", @"(wsc:%@) handleIncomingFrame sending complete frame: %d", self.connectionId, self.totalFrames); + FFLog(@"I-RDB083007", + @"(wsc:%@) handleIncomingFrame sending complete frame: %d", + self.connectionId, self.totalFrames); @autoreleasepool { [self.delegate onMessage:self withMessage:json]; @@ -210,7 +240,7 @@ - (void) appendFrame:(NSString *) message { } } -- (void) handleIncomingFrame:(NSString *) message { +- (void)handleIncomingFrame:(NSString *)message { [self resetKeepAlive]; if (self.buffering) { [self appendFrame:message]; @@ -224,36 +254,39 @@ - (void) handleIncomingFrame:(NSString *) message { #pragma mark - #pragma mark SRWebSocketDelegate implementation -- (void)webSocket:(FSRWebSocket *)webSocket didReceiveMessage:(id)message -{ +- (void)webSocket:(FSRWebSocket *)webSocket didReceiveMessage:(id)message { [self handleIncomingFrame:message]; } -- (void)webSocketDidOpen:(FSRWebSocket *)webSocket -{ +- (void)webSocketDidOpen:(FSRWebSocket *)webSocket { FFLog(@"I-RDB083008", @"(wsc:%@) webSocketDidOpen", self.connectionId); everConnected = YES; dispatch_async(dispatch_get_main_queue(), ^{ - self->keepAlive = [NSTimer scheduledTimerWithTimeInterval:kWebsocketKeepaliveInterval - target:self - selector:@selector(nop:) - userInfo:nil - repeats:YES]; - FFLog(@"I-RDB083009", @"(wsc:%@) nop timer kicked off", self.connectionId); + self->keepAlive = + [NSTimer scheduledTimerWithTimeInterval:kWebsocketKeepaliveInterval + target:self + selector:@selector(nop:) + userInfo:nil + repeats:YES]; + FFLog(@"I-RDB083009", @"(wsc:%@) nop timer kicked off", + self.connectionId); }); } -- (void)webSocket:(FSRWebSocket *)webSocket didFailWithError:(NSError *)error -{ - FFLog(@"I-RDB083010", @"(wsc:%@) didFailWithError didFailWithError: %@", self.connectionId, [error description]); +- (void)webSocket:(FSRWebSocket *)webSocket didFailWithError:(NSError *)error { + FFLog(@"I-RDB083010", @"(wsc:%@) didFailWithError didFailWithError: %@", + self.connectionId, [error description]); [self onClosed]; } -- (void)webSocket:(FSRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean -{ - FFLog(@"I-RDB083011", @"(wsc:%@) didCloseWithCode: %ld %@", self.connectionId, (long)code, reason); +- (void)webSocket:(FSRWebSocket *)webSocket + didCloseWithCode:(NSInteger)code + reason:(NSString *)reason + wasClean:(BOOL)wasClean { + FFLog(@"I-RDB083011", @"(wsc:%@) didCloseWithCode: %ld %@", + self.connectionId, (long)code, reason); [self onClosed]; } @@ -261,31 +294,33 @@ - (void)webSocket:(FSRWebSocket *)webSocket didCloseWithCode:(NSInteger)code rea #pragma mark Private methods /** - * Note that the close / onClosed / shutdown cycle here is a little different from the javascript client. - * In order to properly handle deallocation, no close-related action is taken at a higher level until we - * have received notification from the websocket itself that it is closed. Otherwise, we end up deallocating - * this class and the FConnection class before the websocket has a change to call some of its delegate methods. - * So, since close is the external close handler, we just set a flag saying not to call our own delegate method - * and close the websocket. That will trigger a callback into this class that can then do things like clean up - * the keepalive timer. + * Note that the close / onClosed / shutdown cycle here is a little different + * from the javascript client. In order to properly handle deallocation, no + * close-related action is taken at a higher level until we have received + * notification from the websocket itself that it is closed. Otherwise, we end + * up deallocating this class and the FConnection class before the websocket has + * a change to call some of its delegate methods. So, since close is the + * external close handler, we just set a flag saying not to call our own + * delegate method and close the websocket. That will trigger a callback into + * this class that can then do things like clean up the keepalive timer. */ -- (void) closeIfNeverConnected { +- (void)closeIfNeverConnected { if (!everConnected) { - FFLog(@"I-RDB083012", @"(wsc:%@) Websocket timed out on connect", self.connectionId); + FFLog(@"I-RDB083012", @"(wsc:%@) Websocket timed out on connect", + self.connectionId); [self.webSocket close]; } } -- (void) shutdown { +- (void)shutdown { isClosed = YES; // Call delegate methods [self.delegate onDisconnect:self wasEverConnected:everConnected]; - } -- (void) onClosed { +- (void)onClosed { if (!isClosed) { FFLog(@"I-RDB083013", @"Websocket is closing itself"); [self shutdown]; @@ -296,11 +331,14 @@ - (void) onClosed { } } -- (void) resetKeepAlive { - NSDate* newTime = [NSDate dateWithTimeIntervalSinceNow:kWebsocketKeepaliveInterval]; - // Calling setFireDate is actually kinda' expensive, so wait at least 5 seconds before updating it. +- (void)resetKeepAlive { + NSDate *newTime = + [NSDate dateWithTimeIntervalSinceNow:kWebsocketKeepaliveInterval]; + // Calling setFireDate is actually kinda' expensive, so wait at least 5 + // seconds before updating it. if ([newTime timeIntervalSinceDate:keepAlive.fireDate] > 5) { - FFLog(@"I-RDB083014", @"(wsc:%@) resetting keepalive, to %@ ; old: %@", self.connectionId, newTime, [keepAlive fireDate]); + FFLog(@"I-RDB083014", @"(wsc:%@) resetting keepalive, to %@ ; old: %@", + self.connectionId, newTime, [keepAlive fireDate]); [keepAlive setFireDate:newTime]; } } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FChildrenNode.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FChildrenNode.h index 9eebdae..cc3239e 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FChildrenNode.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FChildrenNode.h @@ -14,27 +14,29 @@ * limitations under the License. */ -#import +#import "FImmutableSortedDictionary.h" #import "FNode.h" #import "FTypedefs.h" #import "FTypedefs_Private.h" -#import "FImmutableSortedDictionary.h" +#import @class FNamedNode; @interface FChildrenNode : NSObject - (id)initWithChildren:(FImmutableSortedDictionary *)someChildren; -- (id)initWithPriority:(id)aPriority children:(FImmutableSortedDictionary *)someChildren; +- (id)initWithPriority:(id)aPriority + children:(FImmutableSortedDictionary *)someChildren; // FChildrenNode specific methods -- (void) enumerateChildrenAndPriorityUsingBlock:(void (^)(NSString *, id, BOOL *))block; +- (void)enumerateChildrenAndPriorityUsingBlock:(void (^)(NSString *, id, + BOOL *))block; -- (FNamedNode *) firstChild; -- (FNamedNode *) lastChild; +- (FNamedNode *)firstChild; +- (FNamedNode *)lastChild; -@property (nonatomic, strong) FImmutableSortedDictionary* children; -@property (nonatomic, strong) id priorityNode; +@property(nonatomic, strong) FImmutableSortedDictionary *children; +@property(nonatomic, strong) id priorityNode; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FChildrenNode.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FChildrenNode.m index d53ae80..bd02bf8 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FChildrenNode.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FChildrenNode.m @@ -15,92 +15,94 @@ */ #import "FChildrenNode.h" -#import "FEmptyNode.h" #import "FConstants.h" -#import "FStringUtilities.h" -#import "FUtilities.h" -#import "FNamedNode.h" +#import "FEmptyNode.h" #import "FMaxNode.h" -#import "FTransformedEnumerator.h" +#import "FNamedNode.h" +#import "FPriorityIndex.h" #import "FSnapshotUtilities.h" +#import "FStringUtilities.h" #import "FTransformedEnumerator.h" -#import "FPriorityIndex.h" #import "FUtilities.h" @interface FChildrenNode () -@property (nonatomic, strong) NSString *lazyHash; +@property(nonatomic, strong) NSString *lazyHash; @end @implementation FChildrenNode -// Note: The only reason we allow nil priority is to for EmptyNode, since we can't use -// EmptyNode as the priority of EmptyNode. We might want to consider making EmptyNode its own -// class instead of an empty ChildrenNode. +// Note: The only reason we allow nil priority is to for EmptyNode, since we +// can't use EmptyNode as the priority of EmptyNode. We might want to consider +// making EmptyNode its own class instead of an empty ChildrenNode. - (id)init { - return [self initWithPriority:nil children:[FImmutableSortedDictionary dictionaryWithComparator:[FUtilities keyComparator]]]; + return [self + initWithPriority:nil + children:[FImmutableSortedDictionary + dictionaryWithComparator:[FUtilities + keyComparator]]]; } - (id)initWithChildren:(FImmutableSortedDictionary *)someChildren { return [self initWithPriority:nil children:someChildren]; } -- (id)initWithPriority:(id)aPriority children:(FImmutableSortedDictionary *)someChildren { +- (id)initWithPriority:(id)aPriority + children:(FImmutableSortedDictionary *)someChildren { if (someChildren.isEmpty && aPriority != nil && ![aPriority isEmpty]) { - [NSException raise:NSInvalidArgumentException format:@"Can't create empty node with priority!"]; + [NSException raise:NSInvalidArgumentException + format:@"Can't create empty node with priority!"]; } self = [super init]; - if(self) { + if (self) { self.children = someChildren; self.priorityNode = aPriority; } return self; } -- (NSString *) description { +- (NSString *)description { return [[self valForExport:YES] description]; } #pragma mark - #pragma mark FNode methods - -- (BOOL) isLeafNode { +- (BOOL)isLeafNode { return NO; } -- (id) getPriority { +- (id)getPriority { if (self.priorityNode) { return self.priorityNode; } else { return [FEmptyNode emptyNode]; } - } -- (id) updatePriority:(id)aPriority { +- (id)updatePriority:(id)aPriority { if ([self.children isEmpty]) { return [FEmptyNode emptyNode]; } else { - return [[FChildrenNode alloc] initWithPriority:aPriority children:self.children]; + return [[FChildrenNode alloc] initWithPriority:aPriority + children:self.children]; } } -- (id) getImmediateChild:(NSString *) childName { +- (id)getImmediateChild:(NSString *)childName { if ([childName isEqualToString:@".priority"]) { return [self getPriority]; } else { - id child = [self.children objectForKey:childName]; + id child = [self.children objectForKey:childName]; return (child == nil) ? [FEmptyNode emptyNode] : child; } } -- (id) getChild:(FPath *)path { - NSString* front = [path getFront]; - if(front == nil) { +- (id)getChild:(FPath *)path { + NSString *front = [path getFront]; + if (front == nil) { return self; - } - else { + } else { return [[self getImmediateChild:front] getChild:[path popFront]]; } } @@ -109,8 +111,8 @@ - (BOOL)hasChild:(NSString *)childName { return ![self getImmediateChild:childName].isEmpty; } - -- (id) updateImmediateChild:(NSString *)childName withNewChild:(id)newChildNode { +- (id)updateImmediateChild:(NSString *)childName + withNewChild:(id)newChildNode { NSAssert(newChildNode != nil, @"Should always be passing nodes."); if ([childName isEqualToString:@".priority"]) { @@ -120,41 +122,46 @@ - (BOOL)hasChild:(NSString *)childName { if (newChildNode.isEmpty) { newChildren = [self.children removeObjectForKey:childName]; } else { - newChildren = [self.children setObject:newChildNode forKey:childName]; + newChildren = [self.children setObject:newChildNode + forKey:childName]; } if (newChildren.isEmpty) { return [FEmptyNode emptyNode]; } else { - return [[FChildrenNode alloc] initWithPriority:self.getPriority children:newChildren]; + return [[FChildrenNode alloc] initWithPriority:self.getPriority + children:newChildren]; } } } -- (id) updateChild:(FPath *)path withNewChild:(id)newChildNode { - NSString* front = [path getFront]; - if(front == nil) { +- (id)updateChild:(FPath *)path withNewChild:(id)newChildNode { + NSString *front = [path getFront]; + if (front == nil) { return newChildNode; } else { - NSAssert(![front isEqualToString:@".priority"] || path.length == 1, @".priority must be the last token in a path."); - id newImmediateChild = [[self getImmediateChild:front] updateChild:[path popFront] withNewChild:newChildNode]; + NSAssert(![front isEqualToString:@".priority"] || path.length == 1, + @".priority must be the last token in a path."); + id newImmediateChild = + [[self getImmediateChild:front] updateChild:[path popFront] + withNewChild:newChildNode]; return [self updateImmediateChild:front withNewChild:newImmediateChild]; } } -- (BOOL) isEmpty { +- (BOOL)isEmpty { return [self.children isEmpty]; } -- (int) numChildren { +- (int)numChildren { return [self.children count]; } -- (id) val { +- (id)val { return [self valForExport:NO]; } -- (id) valForExport:(BOOL)exp { - if([self isEmpty]) { +- (id)valForExport:(BOOL)exp { + if ([self isEmpty]) { return [NSNull null]; } @@ -162,39 +169,42 @@ - (id) valForExport:(BOOL)exp { __block NSInteger maxKey = 0; __block BOOL allIntegerKeys = YES; - NSMutableDictionary* obj = [[NSMutableDictionary alloc] initWithCapacity:[self.children count]]; - [self enumerateChildrenUsingBlock:^(NSString *key, id childNode, BOOL *stop) { - [obj setObject:[childNode valForExport:exp] forKey:key]; - - numKeys++; - - // If we already found a string key, don't bother with any of this - if (!allIntegerKeys) { - return; - } - - // Treat leading zeroes that are not exactly "0" as strings - NSString* firstChar = [key substringWithRange:NSMakeRange(0, 1)]; - if ([firstChar isEqualToString:@"0"] && [key length] > 1) { - allIntegerKeys = NO; - } else { - NSNumber *keyAsNum = [FUtilities intForString:key]; - if (keyAsNum != nil) { - NSInteger keyAsInt = [keyAsNum integerValue]; - if (keyAsInt > maxKey) { - maxKey = keyAsInt; - } - } else { - allIntegerKeys = NO; - } - } + NSMutableDictionary *obj = + [[NSMutableDictionary alloc] initWithCapacity:[self.children count]]; + [self enumerateChildrenUsingBlock:^(NSString *key, id childNode, + BOOL *stop) { + [obj setObject:[childNode valForExport:exp] forKey:key]; + + numKeys++; + + // If we already found a string key, don't bother with any of this + if (!allIntegerKeys) { + return; + } + + // Treat leading zeroes that are not exactly "0" as strings + NSString *firstChar = [key substringWithRange:NSMakeRange(0, 1)]; + if ([firstChar isEqualToString:@"0"] && [key length] > 1) { + allIntegerKeys = NO; + } else { + NSNumber *keyAsNum = [FUtilities intForString:key]; + if (keyAsNum != nil) { + NSInteger keyAsInt = [keyAsNum integerValue]; + if (keyAsInt > maxKey) { + maxKey = keyAsInt; + } + } else { + allIntegerKeys = NO; + } + } }]; if (!exp && allIntegerKeys && maxKey < 2 * numKeys) { // convert to an array - NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity:maxKey + 1]; + NSMutableArray *array = + [[NSMutableArray alloc] initWithCapacity:maxKey + 1]; for (int i = 0; i <= maxKey; ++i) { - NSString* keyString = [NSString stringWithFormat:@"%i", i]; + NSString *keyString = [NSString stringWithFormat:@"%i", i]; id child = obj[keyString]; if (child != nil) { [array addObject:child]; @@ -205,7 +215,7 @@ - (id) valForExport:(BOOL)exp { return array; } else { - if(exp && [self getPriority] != nil && !self.getPriority.isEmpty) { + if (exp && [self getPriority] != nil && !self.getPriority.isEmpty) { obj[kPayloadPriority] = [self.getPriority val]; } @@ -213,53 +223,66 @@ - (id) valForExport:(BOOL)exp { } } -- (NSString *) dataHash { +- (NSString *)dataHash { if (self.lazyHash == nil) { NSMutableString *toHash = [[NSMutableString alloc] init]; if (!self.getPriority.isEmpty) { [toHash appendString:@"priority:"]; - [FSnapshotUtilities appendHashRepresentationForLeafNode:(FLeafNode *)self.getPriority - toString:toHash - hashVersion:FDataHashVersionV1]; + [FSnapshotUtilities + appendHashRepresentationForLeafNode:(FLeafNode *) + self.getPriority + toString:toHash + hashVersion:FDataHashVersionV1]; [toHash appendString:@":"]; } __block BOOL sawPriority = NO; - [self enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - sawPriority = sawPriority || [[node getPriority] isEmpty]; - *stop = sawPriority; + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + sawPriority = sawPriority || [[node getPriority] isEmpty]; + *stop = sawPriority; }]; if (sawPriority) { NSMutableArray *array = [NSMutableArray array]; - [self enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - FNamedNode *namedNode = [[FNamedNode alloc] initWithName:key andNode:node]; - [array addObject:namedNode]; + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + FNamedNode *namedNode = [[FNamedNode alloc] initWithName:key + andNode:node]; + [array addObject:namedNode]; }]; - [array sortUsingComparator:^NSComparisonResult(FNamedNode *namedNode1, FNamedNode *namedNode2) { - return [[FPriorityIndex priorityIndex] compareNamedNode:namedNode1 toNamedNode:namedNode2]; + [array sortUsingComparator:^NSComparisonResult( + FNamedNode *namedNode1, FNamedNode *namedNode2) { + return + [[FPriorityIndex priorityIndex] compareNamedNode:namedNode1 + toNamedNode:namedNode2]; }]; - [array enumerateObjectsUsingBlock:^(FNamedNode *namedNode, NSUInteger idx, BOOL *stop) { - NSString *childHash = [namedNode.node dataHash]; - if (![childHash isEqualToString:@""]) { - [toHash appendFormat:@":%@:%@", namedNode.name, childHash]; - } + [array enumerateObjectsUsingBlock:^(FNamedNode *namedNode, + NSUInteger idx, BOOL *stop) { + NSString *childHash = [namedNode.node dataHash]; + if (![childHash isEqualToString:@""]) { + [toHash appendFormat:@":%@:%@", namedNode.name, childHash]; + } }]; } else { - [self enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - NSString *childHash = [node dataHash]; - if (![childHash isEqualToString:@""]) { - [toHash appendFormat:@":%@:%@", key, childHash]; - } + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + NSString *childHash = [node dataHash]; + if (![childHash isEqualToString:@""]) { + [toHash appendFormat:@":%@:%@", key, childHash]; + } }]; } - self.lazyHash = [toHash isEqualToString:@""] ? @"" : [FStringUtilities base64EncodedSha1:toHash]; + self.lazyHash = [toHash isEqualToString:@""] + ? @"" + : [FStringUtilities base64EncodedSha1:toHash]; } return self.lazyHash; } -- (NSComparisonResult)compare:(id )other { - // children nodes come last, unless this is actually an empty node, then we come first. +- (NSComparisonResult)compare:(id)other { + // children nodes come last, unless this is actually an empty node, then we + // come first. if (self.isEmpty) { if (other.isEmpty) { return NSOrderedSame; @@ -276,7 +299,7 @@ - (NSComparisonResult)compare:(id )other { } } -- (BOOL)isEqual:(id )other { +- (BOOL)isEqual:(id)other { if (other == self) { return YES; } else if (other == nil) { @@ -292,12 +315,13 @@ - (BOOL)isEqual:(id )other { return NO; } else if (self.children.count == otherChildrenNode.children.count) { __block BOOL equal = YES; - [self enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - id child = [otherChildrenNode getImmediateChild:key]; - if (![child isEqual:node]) { - equal = NO; - *stop = YES; - } + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + id child = [otherChildrenNode getImmediateChild:key]; + if (![child isEqual:node]) { + equal = NO; + *stop = YES; + } }]; return equal; } else { @@ -308,75 +332,84 @@ - (BOOL)isEqual:(id )other { - (NSUInteger)hash { __block NSUInteger hashCode = 0; - [self enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - hashCode = 31 * hashCode + key.hash; - hashCode = 17 * hashCode + node.hash; + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + hashCode = 31 * hashCode + key.hash; + hashCode = 17 * hashCode + node.hash; }]; return 17 * hashCode + self.priorityNode.hash; } -- (void) enumerateChildrenAndPriorityUsingBlock:(void (^)(NSString *, id, BOOL *))block -{ +- (void)enumerateChildrenAndPriorityUsingBlock:(void (^)(NSString *, id, + BOOL *))block { if ([self.getPriority isEmpty]) { [self enumerateChildrenUsingBlock:block]; } else { __block BOOL passedPriorityKey = NO; - [self enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - if (!passedPriorityKey && [FUtilities compareKey:key toKey:@".priority"] == NSOrderedDescending) { - passedPriorityKey = YES; - BOOL stopAfterPriority = NO; - block(@".priority", [self getPriority], &stopAfterPriority); - if (stopAfterPriority) return; - } - block(key, node, stop); + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + if (!passedPriorityKey && + [FUtilities compareKey:key + toKey:@".priority"] == NSOrderedDescending) { + passedPriorityKey = YES; + BOOL stopAfterPriority = NO; + block(@".priority", [self getPriority], &stopAfterPriority); + if (stopAfterPriority) + return; + } + block(key, node, stop); }]; } } -- (void) enumerateChildrenUsingBlock:(void (^)(NSString *, id, BOOL *))block -{ +- (void)enumerateChildrenUsingBlock:(void (^)(NSString *, id, + BOOL *))block { [self.children enumerateKeysAndObjectsUsingBlock:block]; } -- (void) enumerateChildrenReverse:(BOOL)reverse usingBlock:(void (^)(NSString *, id, BOOL *))block -{ +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock: + (void (^)(NSString *, id, BOOL *))block { [self.children enumerateKeysAndObjectsReverse:reverse usingBlock:block]; } -- (NSEnumerator *)childEnumerator -{ - return [[FTransformedEnumerator alloc] initWithEnumerator:self.children.keyEnumerator andTransform:^id(NSString *key) { - return [FNamedNode nodeWithName:key node:[self getImmediateChild:key]]; - }]; +- (NSEnumerator *)childEnumerator { + return [[FTransformedEnumerator alloc] + initWithEnumerator:self.children.keyEnumerator + andTransform:^id(NSString *key) { + return [FNamedNode nodeWithName:key + node:[self getImmediateChild:key]]; + }]; } -- (NSString *) predecessorChildKey:(NSString *)childKey -{ +- (NSString *)predecessorChildKey:(NSString *)childKey { return [self.children getPredecessorKey:childKey]; } #pragma mark - #pragma mark FChildrenNode specific methods -- (id) childrenGetter:(id)key { +- (id)childrenGetter:(id)key { return [self.children objectForKey:key]; } -- (FNamedNode *)firstChild -{ +- (FNamedNode *)firstChild { NSString *childKey = self.children.minKey; if (childKey) { - return [[FNamedNode alloc] initWithName:childKey andNode:[self getImmediateChild:childKey]]; + return + [[FNamedNode alloc] initWithName:childKey + andNode:[self getImmediateChild:childKey]]; } else { return nil; } } -- (FNamedNode *)lastChild -{ +- (FNamedNode *)lastChild { NSString *childKey = self.children.maxKey; if (childKey) { - return [[FNamedNode alloc] initWithName:childKey andNode:[self getImmediateChild:childKey]]; + return + [[FNamedNode alloc] initWithName:childKey + andNode:[self getImmediateChild:childKey]]; } else { return nil; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FCompoundWrite.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FCompoundWrite.h index c67cfc7..47de66f 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FCompoundWrite.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FCompoundWrite.h @@ -21,41 +21,44 @@ @class FPath; /** -* This class holds a collection of writes that can be applied to nodes in unison. It abstracts away the logic with -* dealing with priority writes and multiple nested writes. At any given path, there is only allowed to be one write -* modifying that path. Any write to an existing path or shadowing an existing path will modify that existing write to -* reflect the write added. -*/ + * This class holds a collection of writes that can be applied to nodes in + * unison. It abstracts away the logic with dealing with priority writes and + * multiple nested writes. At any given path, there is only allowed to be one + * write modifying that path. Any write to an existing path or shadowing an + * existing path will modify that existing write to reflect the write added. + */ @interface FCompoundWrite : NSObject -- (id) initWithWriteTree:(FImmutableTree *)tree; +- (id)initWithWriteTree:(FImmutableTree *)tree; /** * Creates a compound write with NSDictionary from path string to object */ -+ (FCompoundWrite *) compoundWriteWithValueDictionary:(NSDictionary *)dictionary; ++ (FCompoundWrite *)compoundWriteWithValueDictionary:(NSDictionary *)dictionary; /** * Creates a compound write with NSDictionary from path string to node */ -+ (FCompoundWrite *) compoundWriteWithNodeDictionary:(NSDictionary *)dictionary; ++ (FCompoundWrite *)compoundWriteWithNodeDictionary:(NSDictionary *)dictionary; -+ (FCompoundWrite *) emptyWrite; ++ (FCompoundWrite *)emptyWrite; -- (FCompoundWrite *) addWrite:(id)node atPath:(FPath *)path; -- (FCompoundWrite *) addWrite:(id)node atKey:(NSString *)key; -- (FCompoundWrite *) addCompoundWrite:(FCompoundWrite *)node atPath:(FPath *)path; -- (FCompoundWrite *) removeWriteAtPath:(FPath *)path; +- (FCompoundWrite *)addWrite:(id)node atPath:(FPath *)path; +- (FCompoundWrite *)addWrite:(id)node atKey:(NSString *)key; +- (FCompoundWrite *)addCompoundWrite:(FCompoundWrite *)node + atPath:(FPath *)path; +- (FCompoundWrite *)removeWriteAtPath:(FPath *)path; - (id)rootWrite; -- (BOOL) hasCompleteWriteAtPath:(FPath *)path; -- (id) completeNodeAtPath:(FPath *)path; -- (NSArray *) completeChildren; +- (BOOL)hasCompleteWriteAtPath:(FPath *)path; +- (id)completeNodeAtPath:(FPath *)path; +- (NSArray *)completeChildren; - (NSDictionary *)childCompoundWrites; -- (FCompoundWrite *) childCompoundWriteAtPath:(FPath *)path; -- (id) applyToNode:(id)node; -- (void)enumerateWrites:(void (^)(FPath *path, idnode, BOOL *stop))block; +- (FCompoundWrite *)childCompoundWriteAtPath:(FPath *)path; +- (id)applyToNode:(id)node; +- (void)enumerateWrites:(void (^)(FPath *path, id node, + BOOL *stop))block; - (NSDictionary *)valForExport:(BOOL)exportFormat; -- (BOOL) isEmpty; +- (BOOL)isEmpty; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FCompoundWrite.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FCompoundWrite.m index 8887095..bc40b2b 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FCompoundWrite.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FCompoundWrite.m @@ -16,18 +16,18 @@ #import "FCompoundWrite.h" #import "FImmutableTree.h" +#import "FNamedNode.h" #import "FNode.h" #import "FPath.h" -#import "FNamedNode.h" #import "FSnapshotUtilities.h" @interface FCompoundWrite () -@property (nonatomic, strong) FImmutableTree *writeTree; +@property(nonatomic, strong) FImmutableTree *writeTree; @end @implementation FCompoundWrite -- (id) initWithWriteTree:(FImmutableTree *)tree { +- (id)initWithWriteTree:(FImmutableTree *)tree { self = [super init]; if (self) { self.writeTree = tree; @@ -35,95 +35,114 @@ - (id) initWithWriteTree:(FImmutableTree *)tree { return self; } -+ (FCompoundWrite *)compoundWriteWithValueDictionary:(NSDictionary *)dictionary { ++ (FCompoundWrite *)compoundWriteWithValueDictionary: + (NSDictionary *)dictionary { __block FImmutableTree *writeTree = [FImmutableTree empty]; - [dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *pathString, id value, BOOL *stop) { - id node = [FSnapshotUtilities nodeFrom:value]; - FImmutableTree *tree = [[FImmutableTree alloc] initWithValue:node]; - writeTree = [writeTree setTree:tree atPath:[[FPath alloc] initWith:pathString]]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *pathString, + id value, BOOL *stop) { + id node = [FSnapshotUtilities nodeFrom:value]; + FImmutableTree *tree = [[FImmutableTree alloc] initWithValue:node]; + writeTree = [writeTree setTree:tree + atPath:[[FPath alloc] initWith:pathString]]; }]; return [[FCompoundWrite alloc] initWithWriteTree:writeTree]; } + (FCompoundWrite *)compoundWriteWithNodeDictionary:(NSDictionary *)dictionary { __block FImmutableTree *writeTree = [FImmutableTree empty]; - [dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *pathString, id node, BOOL *stop) { - FImmutableTree *tree = [[FImmutableTree alloc] initWithValue:node]; - writeTree = [writeTree setTree:tree atPath:[[FPath alloc] initWith:pathString]]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *pathString, + id node, BOOL *stop) { + FImmutableTree *tree = [[FImmutableTree alloc] initWithValue:node]; + writeTree = [writeTree setTree:tree + atPath:[[FPath alloc] initWith:pathString]]; }]; return [[FCompoundWrite alloc] initWithWriteTree:writeTree]; } -+ (FCompoundWrite *) emptyWrite { ++ (FCompoundWrite *)emptyWrite { static dispatch_once_t pred = 0; static FCompoundWrite *empty = nil; dispatch_once(&pred, ^{ - empty = [[FCompoundWrite alloc] initWithWriteTree:[[FImmutableTree alloc] initWithValue:nil]]; + empty = [[FCompoundWrite alloc] + initWithWriteTree:[[FImmutableTree alloc] initWithValue:nil]]; }); return empty; } -- (FCompoundWrite *) addWrite:(id)node atPath:(FPath *)path { +- (FCompoundWrite *)addWrite:(id)node atPath:(FPath *)path { if (path.isEmpty) { - return [[FCompoundWrite alloc] initWithWriteTree:[[FImmutableTree alloc] initWithValue:node]]; + return [[FCompoundWrite alloc] + initWithWriteTree:[[FImmutableTree alloc] initWithValue:node]]; } else { - FTuplePathValue *rootMost = [self.writeTree findRootMostValueAndPath:path]; + FTuplePathValue *rootMost = + [self.writeTree findRootMostValueAndPath:path]; if (rootMost != nil) { - FPath *relativePath = [FPath relativePathFrom:rootMost.path to:path]; - id value = [rootMost.value updateChild:relativePath withNewChild:node]; - return [[FCompoundWrite alloc] initWithWriteTree:[self.writeTree setValue:value atPath:rootMost.path]]; + FPath *relativePath = [FPath relativePathFrom:rootMost.path + to:path]; + id value = [rootMost.value updateChild:relativePath + withNewChild:node]; + return [[FCompoundWrite alloc] + initWithWriteTree:[self.writeTree setValue:value + atPath:rootMost.path]]; } else { - FImmutableTree *subtree = [[FImmutableTree alloc] initWithValue:node]; - FImmutableTree *newWriteTree = [self.writeTree setTree:subtree atPath:path]; + FImmutableTree *subtree = + [[FImmutableTree alloc] initWithValue:node]; + FImmutableTree *newWriteTree = [self.writeTree setTree:subtree + atPath:path]; return [[FCompoundWrite alloc] initWithWriteTree:newWriteTree]; } } } -- (FCompoundWrite *) addWrite:(id)node atKey:(NSString *)key { +- (FCompoundWrite *)addWrite:(id)node atKey:(NSString *)key { return [self addWrite:node atPath:[[FPath alloc] initWith:key]]; } -- (FCompoundWrite *) addCompoundWrite:(FCompoundWrite *)compoundWrite atPath:(FPath *)path { +- (FCompoundWrite *)addCompoundWrite:(FCompoundWrite *)compoundWrite + atPath:(FPath *)path { __block FCompoundWrite *newWrite = self; [compoundWrite.writeTree forEach:^(FPath *childPath, id value) { - newWrite = [newWrite addWrite:value atPath:[path child:childPath]]; + newWrite = [newWrite addWrite:value atPath:[path child:childPath]]; }]; return newWrite; } /** -* Will remove a write at the given path and deeper paths. This will not modify a write at a higher location, -* which must be removed by calling this method with that path. -* @param path The path at which a write and all deeper writes should be removed. -* @return The new FWriteCompound with the removed path. -*/ -- (FCompoundWrite *) removeWriteAtPath:(FPath *)path { + * Will remove a write at the given path and deeper paths. This will + * not modify a write at a higher location, which must be removed by + * calling this method with that path. + * @param path The path at which a write and all deeper writes should be + * removed. + * @return The new FWriteCompound with the removed path. + */ +- (FCompoundWrite *)removeWriteAtPath:(FPath *)path { if (path.isEmpty) { return [FCompoundWrite emptyWrite]; } else { - FImmutableTree *newWriteTree = [self.writeTree setTree:[FImmutableTree empty] atPath:path]; + FImmutableTree *newWriteTree = + [self.writeTree setTree:[FImmutableTree empty] atPath:path]; return [[FCompoundWrite alloc] initWithWriteTree:newWriteTree]; } } /** -* Returns whether this FCompoundWrite will fully overwrite a node at a given location and can therefore be considered -* "complete". -* @param path The path to check for -* @return Whether there is a complete write at that path. -*/ -- (BOOL) hasCompleteWriteAtPath:(FPath *)path { + * Returns whether this FCompoundWrite will fully overwrite a node at a given + * location and can therefore be considered "complete". + * @param path The path to check for + * @return Whether there is a complete write at that path. + */ +- (BOOL)hasCompleteWriteAtPath:(FPath *)path { return [self completeNodeAtPath:path] != nil; } /** -* Returns a node for a path if and only if the node is a "complete" overwrite at that path. This will not aggregate -* writes from depeer paths, but will return child nodes from a more shallow path. -* @param path The path to get a complete write -* @return The node if complete at that path, or nil otherwise. -*/ -- (id) completeNodeAtPath:(FPath *)path { + * Returns a node for a path if and only if the node is a "complete" overwrite + * at that path. This will not aggregate writes from depeer paths, but will + * return child nodes from a more shallow path. + * @param path The path to get a complete write + * @return The node if complete at that path, or nil otherwise. + */ +- (id)completeNodeAtPath:(FPath *)path { FTuplePathValue *rootMost = [self.writeTree findRootMostValueAndPath:path]; if (rootMost != nil) { FPath *relativePath = [FPath relativePathFrom:rootMost.path to:path]; @@ -134,66 +153,89 @@ - (BOOL) hasCompleteWriteAtPath:(FPath *)path { } // TODO: change into traversal method... -- (NSArray *) completeChildren { +- (NSArray *)completeChildren { NSMutableArray *children = [[NSMutableArray alloc] init]; if (self.writeTree.value != nil) { id node = self.writeTree.value; - [node enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - [children addObject:[[FNamedNode alloc] initWithName:key andNode:node]]; + [node enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + [children addObject:[[FNamedNode alloc] initWithName:key + andNode:node]]; }]; } else { - [self.writeTree.children enumerateKeysAndObjectsUsingBlock:^(NSString *childKey, FImmutableTree *childTree, BOOL *stop) { - if (childTree.value != nil) { - [children addObject:[[FNamedNode alloc] initWithName:childKey andNode:childTree.value]]; - } - }]; + [self.writeTree.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + if (childTree.value != nil) { + [children addObject:[[FNamedNode alloc] + initWithName:childKey + andNode:childTree.value]]; + } + }]; } return children; } - // TODO: change into enumarate method - (NSDictionary *)childCompoundWrites { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; - [self.writeTree.children enumerateKeysAndObjectsUsingBlock:^(NSString *key, FImmutableTree *childWrite, BOOL *stop) { - dict[key] = [[FCompoundWrite alloc] initWithWriteTree:childWrite]; - }]; + [self.writeTree.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *key, FImmutableTree *childWrite, BOOL *stop) { + dict[key] = [[FCompoundWrite alloc] initWithWriteTree:childWrite]; + }]; return dict; } -- (FCompoundWrite *) childCompoundWriteAtPath:(FPath *)path { +- (FCompoundWrite *)childCompoundWriteAtPath:(FPath *)path { if (path.isEmpty) { return self; } else { id shadowingNode = [self completeNodeAtPath:path]; if (shadowingNode != nil) { - return [[FCompoundWrite alloc] initWithWriteTree:[[FImmutableTree alloc] initWithValue:shadowingNode]]; + return [[FCompoundWrite alloc] + initWithWriteTree:[[FImmutableTree alloc] + initWithValue:shadowingNode]]; } else { - return [[FCompoundWrite alloc] initWithWriteTree:[self.writeTree subtreeAtPath:path]]; + return [[FCompoundWrite alloc] + initWithWriteTree:[self.writeTree subtreeAtPath:path]]; } } } -- (id) applySubtreeWrite:(FImmutableTree *)subtreeWrite atPath:(FPath *)relativePath toNode:(id)node { +- (id)applySubtreeWrite:(FImmutableTree *)subtreeWrite + atPath:(FPath *)relativePath + toNode:(id)node { if (subtreeWrite.value != nil) { // Since a write there is always a leaf, we're done here. return [node updateChild:relativePath withNewChild:subtreeWrite.value]; } else { __block id priorityWrite = nil; __block id blockNode = node; - [subtreeWrite.children enumerateKeysAndObjectsUsingBlock:^(NSString *childKey, FImmutableTree *childTree, BOOL *stop) { - if ([childKey isEqualToString:@".priority"]) { - // Apply priorities at the end so we don't update priorities for either empty nodes or forget to apply - // priorities to empty nodes that are later filled. - NSAssert(childTree.value != nil, @"Priority writes must always be leaf nodes"); - priorityWrite = childTree.value; - } else { - blockNode = [self applySubtreeWrite:childTree atPath:[relativePath childFromString:childKey] toNode:blockNode]; - } - }]; - // If there was a priority write, we only apply it if the node is not empty - if (![blockNode getChild:relativePath].isEmpty && priorityWrite != nil) { - blockNode = [blockNode updateChild:[relativePath childFromString:@".priority"] withNewChild:priorityWrite]; + [subtreeWrite.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + if ([childKey isEqualToString:@".priority"]) { + // Apply priorities at the end so we don't update priorities + // for either empty nodes or forget to apply priorities to + // empty nodes that are later filled. + NSAssert(childTree.value != nil, + @"Priority writes must always be leaf nodes"); + priorityWrite = childTree.value; + } else { + blockNode = [self + applySubtreeWrite:childTree + atPath:[relativePath childFromString:childKey] + toNode:blockNode]; + } + }]; + // If there was a priority write, we only apply it if the node is not + // empty + if (![blockNode getChild:relativePath].isEmpty && + priorityWrite != nil) { + blockNode = [blockNode + updateChild:[relativePath childFromString:@".priority"] + withNewChild:priorityWrite]; } return blockNode; } @@ -203,30 +245,34 @@ - (void)enumerateWrites:(void (^)(FPath *, id, BOOL *))block { __block BOOL stop = NO; // TODO: add stop to tree iterator... [self.writeTree forEach:^(FPath *path, id value) { - if (!stop) { - block(path, value, &stop); - } + if (!stop) { + block(path, value, &stop); + } }]; } /** -* Applies this FCompoundWrite to a node. The node is returned with all writes from this FCompoundWrite applied to the node. -* @param node The node to apply this FCompoundWrite to -* @return The node with all writes applied -*/ -- (id) applyToNode:(id)node { - return [self applySubtreeWrite:self.writeTree atPath:[FPath empty] toNode:node]; + * Applies this FCompoundWrite to a node. The node is returned with all writes + * from this FCompoundWrite applied to the node. + * @param node The node to apply this FCompoundWrite to + * @return The node with all writes applied + */ +- (id)applyToNode:(id)node { + return [self applySubtreeWrite:self.writeTree + atPath:[FPath empty] + toNode:node]; } /** -* Return true if this CompoundWrite is empty and therefore does not modify any nodes. -* @return Whether this CompoundWrite is empty -*/ -- (BOOL) isEmpty { + * Return true if this CompoundWrite is empty and therefore does not modify any + * nodes. + * @return Whether this CompoundWrite is empty + */ +- (BOOL)isEmpty { return self.writeTree.isEmpty; } -- (id) rootWrite { +- (id)rootWrite { return self.writeTree.value; } @@ -235,7 +281,8 @@ - (BOOL)isEqual:(id)object { return NO; } FCompoundWrite *other = (FCompoundWrite *)object; - return [[self valForExport:YES] isEqualToDictionary:[other valForExport:YES]]; + return + [[self valForExport:YES] isEqualToDictionary:[other valForExport:YES]]; } - (NSUInteger)hash { @@ -245,7 +292,7 @@ - (NSUInteger)hash { - (NSDictionary *)valForExport:(BOOL)exportFormat { NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; [self.writeTree forEach:^(FPath *path, id value) { - dictionary[path.wireFormat] = [value valForExport:exportFormat]; + dictionary[path.wireFormat] = [value valForExport:exportFormat]; }]; return dictionary; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FEmptyNode.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FEmptyNode.h index ab404c2..d002df0 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FEmptyNode.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FEmptyNode.h @@ -14,11 +14,11 @@ * limitations under the License. */ -#import #import "FNode.h" +#import @interface FEmptyNode : NSObject -+ (id) emptyNode; ++ (id)emptyNode; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FEmptyNode.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FEmptyNode.m index f41e118..bde3a8a 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FEmptyNode.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FEmptyNode.m @@ -19,11 +19,11 @@ @implementation FEmptyNode -+ (id) emptyNode { - static FChildrenNode* empty = nil; ++ (id)emptyNode { + static FChildrenNode *empty = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - empty = [[FChildrenNode alloc] init]; + empty = [[FChildrenNode alloc] init]; }); return empty; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FIndexedNode.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FIndexedNode.h index fd2db37..b161dea 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FIndexedNode.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FIndexedNode.h @@ -14,35 +14,41 @@ * limitations under the License. */ - #import -#import "FNode.h" #import "FIndex.h" #import "FNamedNode.h" +#import "FNode.h" /** - * Represents a node together with an index. The index and node are updated in unison. In the case where the index - * does not affect the ordering (i.e. the ordering is identical to the key ordering) this class uses a fallback index - * to save memory. Everything operating on the index must special case the fallback index. + * Represents a node together with an index. The index and node are updated in + * unison. In the case where the index does not affect the ordering (i.e. the + * ordering is identical to the key ordering) this class uses a fallback index + * to save memory. Everything operating on the index must special case the + * fallback index. */ @interface FIndexedNode : NSObject -@property (nonatomic, strong, readonly) id node; +@property(nonatomic, strong, readonly) id node; + (FIndexedNode *)indexedNodeWithNode:(id)node; + (FIndexedNode *)indexedNodeWithNode:(id)node index:(id)index; - (BOOL)hasIndex:(id)index; -- (FIndexedNode *)updateChild:(NSString *)key withNewChild:(id)newChildNode; +- (FIndexedNode *)updateChild:(NSString *)key + withNewChild:(id)newChildNode; - (FIndexedNode *)updatePriority:(id)priority; - (FNamedNode *)firstChild; - (FNamedNode *)lastChild; -- (NSString *)predecessorForChildKey:(NSString *)childKey childNode:(id)childNode index:(id)index; +- (NSString *)predecessorForChildKey:(NSString *)childKey + childNode:(id)childNode + index:(id)index; -- (void)enumerateChildrenReverse:(BOOL)reverse usingBlock:(void (^)(NSString *key, id node, BOOL *stop))block; +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock:(void (^)(NSString *key, id node, + BOOL *stop))block; - (NSEnumerator *)childEnumerator; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FIndexedNode.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FIndexedNode.m index 9dc60e1..dafe9c3 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FIndexedNode.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FIndexedNode.m @@ -16,22 +16,23 @@ #import "FIndexedNode.h" +#import "FChildrenNode.h" #import "FImmutableSortedSet.h" #import "FIndex.h" -#import "FPriorityIndex.h" #import "FKeyIndex.h" -#import "FChildrenNode.h" +#import "FPriorityIndex.h" static FImmutableSortedSet *FALLBACK_INDEX; @interface FIndexedNode () -@property (nonatomic, strong) id node; +@property(nonatomic, strong) id node; /** - * The indexed set is initialized lazily to prevent creation when it is not needed + * The indexed set is initialized lazily to prevent creation when it is not + * needed */ -@property (nonatomic, strong) FImmutableSortedSet *indexed; -@property (nonatomic, strong) id index; +@property(nonatomic, strong) FImmutableSortedSet *indexed; +@property(nonatomic, strong) id index; @end @@ -41,29 +42,28 @@ + (FImmutableSortedSet *)fallbackIndex { static FImmutableSortedSet *fallbackIndex; static dispatch_once_t once; dispatch_once(&once, ^{ - fallbackIndex = [[FImmutableSortedSet alloc] init]; + fallbackIndex = [[FImmutableSortedSet alloc] init]; }); return fallbackIndex; } -+ (FIndexedNode *)indexedNodeWithNode:(id)node -{ - return [[FIndexedNode alloc] initWithNode:node index:[FPriorityIndex priorityIndex]]; ++ (FIndexedNode *)indexedNodeWithNode:(id)node { + return [[FIndexedNode alloc] initWithNode:node + index:[FPriorityIndex priorityIndex]]; } -+ (FIndexedNode *)indexedNodeWithNode:(id)node index:(id)index -{ ++ (FIndexedNode *)indexedNodeWithNode:(id)node index:(id)index { return [[FIndexedNode alloc] initWithNode:node index:index]; } -- (id)initWithNode:(id)node index:(id)index -{ +- (id)initWithNode:(id)node index:(id)index { // Initialize indexed lazily return [self initWithNode:node index:index indexed:nil]; } -- (id)initWithNode:(id)node index:(id)index indexed:(FImmutableSortedSet *)indexed -{ +- (id)initWithNode:(id)node + index:(id)index + indexed:(FImmutableSortedSet *)indexed { self = [super init]; if (self != nil) { self->_node = node; @@ -73,30 +73,36 @@ - (id)initWithNode:(id)node index:(id)index indexed:(FImmutableSo return self; } -- (void)ensureIndexed -{ +- (void)ensureIndexed { if (!self.indexed) { if ([self.index isEqual:[FKeyIndex keyIndex]]) { self.indexed = [FIndexedNode fallbackIndex]; } else { __block BOOL sawChild = NO; - [self.node enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - sawChild = sawChild || [self.index isDefinedOn:node]; - *stop = sawChild; + [self.node enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + sawChild = sawChild || [self.index isDefinedOn:node]; + *stop = sawChild; }]; if (sawChild) { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; - [self.node enumerateChildrenUsingBlock:^(NSString *key, id node, BOOL *stop) { - FNamedNode *namedNode = [[FNamedNode alloc] initWithName:key andNode:node]; - dict[namedNode] = [NSNull null]; + [self.node enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + FNamedNode *namedNode = + [[FNamedNode alloc] initWithName:key andNode:node]; + dict[namedNode] = [NSNull null]; }]; - // Make sure to assign index here, because the comparator will be retained and using self will cause a - // cycle + // Make sure to assign index here, because the comparator will + // be retained and using self will cause a cycle id index = self.index; - self.indexed = [FImmutableSortedSet setWithKeysFromDictionary:dict - comparator:^NSComparisonResult(FNamedNode *namedNode1, FNamedNode *namedNode2) { - return [index compareNamedNode:namedNode1 toNamedNode:namedNode2]; - }]; + self.indexed = [FImmutableSortedSet + setWithKeysFromDictionary:dict + comparator:^NSComparisonResult( + FNamedNode *namedNode1, + FNamedNode *namedNode2) { + return [index compareNamedNode:namedNode1 + toNamedNode:namedNode2]; + }]; } else { self.indexed = [FIndexedNode fallbackIndex]; } @@ -104,39 +110,45 @@ - (void)ensureIndexed } } -- (BOOL)hasIndex:(id)index -{ +- (BOOL)hasIndex:(id)index { return [self.index isEqual:index]; } -- (FIndexedNode *)updateChild:(NSString *)key withNewChild:(id)newChildNode -{ - id newNode = [self.node updateImmediateChild:key withNewChild:newChildNode]; - if (self.indexed == [FIndexedNode fallbackIndex] && ![self.index isDefinedOn:newChildNode]) { +- (FIndexedNode *)updateChild:(NSString *)key + withNewChild:(id)newChildNode { + id newNode = [self.node updateImmediateChild:key + withNewChild:newChildNode]; + if (self.indexed == [FIndexedNode fallbackIndex] && + ![self.index isDefinedOn:newChildNode]) { // doesn't affect the index, no need to create an index - return [[FIndexedNode alloc] initWithNode:newNode index:self.index indexed:[FIndexedNode fallbackIndex]]; + return [[FIndexedNode alloc] initWithNode:newNode + index:self.index + indexed:[FIndexedNode fallbackIndex]]; } else if (!self.indexed || self.indexed == [FIndexedNode fallbackIndex]) { // No need to index yet, index lazily return [[FIndexedNode alloc] initWithNode:newNode index:self.index]; } else { id oldChild = [self.node getImmediateChild:key]; - FImmutableSortedSet *newIndexed = [self.indexed removeObject:[FNamedNode nodeWithName:key node:oldChild]]; + FImmutableSortedSet *newIndexed = [self.indexed + removeObject:[FNamedNode nodeWithName:key node:oldChild]]; if (![newChildNode isEmpty]) { - newIndexed = [newIndexed addObject:[FNamedNode nodeWithName:key node:newChildNode]]; + newIndexed = [newIndexed + addObject:[FNamedNode nodeWithName:key node:newChildNode]]; } - return [[FIndexedNode alloc] initWithNode:newNode index:self.index indexed:newIndexed]; + return [[FIndexedNode alloc] initWithNode:newNode + index:self.index + indexed:newIndexed]; } } -- (FIndexedNode *)updatePriority:(id)priority -{ - return [[FIndexedNode alloc] initWithNode:[self.node updatePriority:priority] - index:self.index - indexed:self.indexed]; +- (FIndexedNode *)updatePriority:(id)priority { + return + [[FIndexedNode alloc] initWithNode:[self.node updatePriority:priority] + index:self.index + indexed:self.indexed]; } -- (FNamedNode *)firstChild -{ +- (FNamedNode *)firstChild { if (![self.node isKindOfClass:[FChildrenNode class]]) { return nil; } else { @@ -149,8 +161,7 @@ - (FNamedNode *)firstChild } } -- (FNamedNode *)lastChild -{ +- (FNamedNode *)lastChild { if (![self.node isKindOfClass:[FChildrenNode class]]) { return nil; } else { @@ -163,34 +174,39 @@ - (FNamedNode *)lastChild } } -- (NSString *)predecessorForChildKey:(NSString *)childKey childNode:(id)childNode index:(id)index -{ +- (NSString *)predecessorForChildKey:(NSString *)childKey + childNode:(id)childNode + index:(id)index { if (![self.index isEqual:index]) { - [NSException raise:NSInvalidArgumentException format:@"Index not available in IndexedNode!"]; + [NSException raise:NSInvalidArgumentException + format:@"Index not available in IndexedNode!"]; } [self ensureIndexed]; if (self.indexed == [FIndexedNode fallbackIndex]) { return [self.node predecessorChildKey:childKey]; } else { - FNamedNode *node = [self.indexed predecessorEntry:[FNamedNode nodeWithName:childKey node:childNode]]; + FNamedNode *node = [self.indexed + predecessorEntry:[FNamedNode nodeWithName:childKey node:childNode]]; return node.name; } } -- (void)enumerateChildrenReverse:(BOOL)reverse usingBlock:(void (^)(NSString *, id, BOOL *))block -{ +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock: + (void (^)(NSString *, id, BOOL *))block { [self ensureIndexed]; if (self.indexed == [FIndexedNode fallbackIndex]) { [self.node enumerateChildrenReverse:reverse usingBlock:block]; } else { - [self.indexed enumerateObjectsReverse:reverse usingBlock:^(FNamedNode *namedNode, BOOL *stop) { - block(namedNode.name, namedNode.node, stop); - }]; + [self.indexed + enumerateObjectsReverse:reverse + usingBlock:^(FNamedNode *namedNode, BOOL *stop) { + block(namedNode.name, namedNode.node, stop); + }]; } } -- (NSEnumerator *)childEnumerator -{ +- (NSEnumerator *)childEnumerator { [self ensureIndexed]; if (self.indexed == [FIndexedNode fallbackIndex]) { return [self.node childEnumerator]; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FLeafNode.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FLeafNode.h index 15e0132..6bd2862 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FLeafNode.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FLeafNode.h @@ -14,15 +14,14 @@ * limitations under the License. */ -#import #import "FNode.h" - +#import @interface FLeafNode : NSObject - (id)initWithValue:(id)aValue; - (id)initWithValue:(id)aValue withPriority:(id)aPriority; -@property (nonatomic, strong) id value; +@property(nonatomic, strong) id value; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FLeafNode.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FLeafNode.m index a26e057..e741fd9 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FLeafNode.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FLeafNode.m @@ -15,17 +15,17 @@ */ #import "FLeafNode.h" -#import "FEmptyNode.h" #import "FChildrenNode.h" #import "FConstants.h" +#import "FEmptyNode.h" #import "FImmutableSortedDictionary.h" -#import "FUtilities.h" -#import "FStringUtilities.h" #import "FSnapshotUtilities.h" +#import "FStringUtilities.h" +#import "FUtilities.h" @interface FLeafNode () -@property (nonatomic, strong) id priorityNode; -@property (nonatomic, strong) NSString *lazyHash; +@property(nonatomic, strong) id priorityNode; +@property(nonatomic, strong) NSString *lazyHash; @end @@ -56,19 +56,19 @@ - (id)initWithValue:(id)aValue withPriority:(id)aPriority { #pragma mark - #pragma mark FNode methods -- (BOOL) isLeafNode { +- (BOOL)isLeafNode { return YES; } -- (id) getPriority { +- (id)getPriority { return self.priorityNode; } -- (id) updatePriority:(id)aPriority { +- (id)updatePriority:(id)aPriority { return [[FLeafNode alloc] initWithValue:self.value withPriority:aPriority]; } -- (id) getImmediateChild:(NSString *) childName { +- (id)getImmediateChild:(NSString *)childName { if ([childName isEqualToString:@".priority"]) { return self.priorityNode; } else { @@ -76,7 +76,7 @@ - (BOOL) isLeafNode { } } -- (id) getChild:(FPath *)path { +- (id)getChild:(FPath *)path { if (path.getFront == nil) { return self; } else if ([[path getFront] isEqualToString:@".priority"]) { @@ -87,64 +87,71 @@ - (BOOL) isLeafNode { } - (BOOL)hasChild:(NSString *)childName { - return [childName isEqualToString:@".priority"] && ![self getPriority].isEmpty; + return + [childName isEqualToString:@".priority"] && ![self getPriority].isEmpty; } - -- (NSString *)predecessorChildKey:(NSString *)childKey -{ +- (NSString *)predecessorChildKey:(NSString *)childKey { return nil; } -- (id) updateImmediateChild:(NSString *)childName withNewChild:(id)newChildNode { +- (id)updateImmediateChild:(NSString *)childName + withNewChild:(id)newChildNode { if ([childName isEqualToString:@".priority"]) { return [self updatePriority:newChildNode]; } else if (newChildNode.isEmpty) { return self; } else { - FChildrenNode* childrenNode = [[FChildrenNode alloc] init]; - childrenNode = [childrenNode updateImmediateChild:childName withNewChild:newChildNode]; + FChildrenNode *childrenNode = [[FChildrenNode alloc] init]; + childrenNode = [childrenNode updateImmediateChild:childName + withNewChild:newChildNode]; childrenNode = [childrenNode updatePriority:self.priorityNode]; return childrenNode; } } -- (id) updateChild:(FPath *)path withNewChild:(id)newChildNode { - NSString* front = [path getFront]; - if(front == nil) { +- (id)updateChild:(FPath *)path withNewChild:(id)newChildNode { + NSString *front = [path getFront]; + if (front == nil) { return newChildNode; } else if (newChildNode.isEmpty && ![front isEqualToString:@".priority"]) { return self; } else { - NSAssert(![front isEqualToString:@".priority"] || path.length == 1, @".priority must be the last token in a path."); - return [self updateImmediateChild:front withNewChild: - [[FEmptyNode emptyNode] updateChild:[path popFront] withNewChild:newChildNode]]; + NSAssert(![front isEqualToString:@".priority"] || path.length == 1, + @".priority must be the last token in a path."); + return [self updateImmediateChild:front + withNewChild:[[FEmptyNode emptyNode] + updateChild:[path popFront] + withNewChild:newChildNode]]; } } -- (id) val { +- (id)val { return [self valForExport:NO]; } -- (id) valForExport:(BOOL)exp { - if(exp && !self.getPriority.isEmpty) { - return @{kPayloadValue : self.value, - kPayloadPriority : [[self getPriority] val]}; - } - else { +- (id)valForExport:(BOOL)exp { + if (exp && !self.getPriority.isEmpty) { + return @{ + kPayloadValue : self.value, + kPayloadPriority : [[self getPriority] val] + }; + } else { return self.value; } } -- (BOOL)isEqual:(id )other { - if(other == self) { +- (BOOL)isEqual:(id)other { + if (other == self) { return YES; } else if (other.isLeafNode) { FLeafNode *otherLeaf = other; - if ([FUtilities getJavascriptType:self.value] != [FUtilities getJavascriptType:otherLeaf.value]) { + if ([FUtilities getJavascriptType:self.value] != + [FUtilities getJavascriptType:otherLeaf.value]) { return NO; } - return [otherLeaf.value isEqual:self.value] && [otherLeaf.priorityNode isEqual:self.priorityNode]; + return [otherLeaf.value isEqual:self.value] && + [otherLeaf.priorityNode isEqual:self.priorityNode]; } else { return NO; } @@ -154,78 +161,87 @@ - (NSUInteger)hash { return [self.value hash] * 17 + self.priorityNode.hash; } -- (id )withIndex:(id )index { +- (id)withIndex:(id)index { return self; } -- (BOOL)isIndexed:(id )index { +- (BOOL)isIndexed:(id)index { return YES; } -- (BOOL) isEmpty { +- (BOOL)isEmpty { return NO; } -- (int) numChildren { +- (int)numChildren { return 0; } -- (void) enumerateChildrenUsingBlock:(void (^)(NSString *, id, BOOL *))block -{ +- (void)enumerateChildrenUsingBlock:(void (^)(NSString *, id, + BOOL *))block { // Nothing to iterate over } -- (void) enumerateChildrenReverse:(BOOL)reverse usingBlock:(void (^)(NSString *, id, BOOL *))block -{ +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock: + (void (^)(NSString *, id, BOOL *))block { // Nothing to iterate over } -- (NSEnumerator *)childEnumerator -{ +- (NSEnumerator *)childEnumerator { // Nothing to iterate over return [@[] objectEnumerator]; } -- (NSString *) dataHash { +- (NSString *)dataHash { if (self.lazyHash == nil) { NSMutableString *toHash = [[NSMutableString alloc] init]; - [FSnapshotUtilities appendHashRepresentationForLeafNode:self toString:toHash hashVersion:FDataHashVersionV1]; + [FSnapshotUtilities + appendHashRepresentationForLeafNode:self + toString:toHash + hashVersion:FDataHashVersionV1]; self.lazyHash = [FStringUtilities base64EncodedSha1:toHash]; } return self.lazyHash; } -- (NSComparisonResult)compare:(id )other { +- (NSComparisonResult)compare:(id)other { if (other == [FEmptyNode emptyNode]) { return NSOrderedDescending; } else if ([other isKindOfClass:[FChildrenNode class]]) { return NSOrderedAscending; } else { NSAssert(other.isLeafNode, @"Compared against unknown type of node."); - return [self compareToLeafNode:(FLeafNode*)other]; + return [self compareToLeafNode:(FLeafNode *)other]; } } -+ (NSArray*) valueTypeOrder { - static NSArray* valueOrder = nil; ++ (NSArray *)valueTypeOrder { + static NSArray *valueOrder = nil; static dispatch_once_t once; dispatch_once(&once, ^{ - valueOrder = @[kJavaScriptObject, kJavaScriptBoolean, kJavaScriptNumber, kJavaScriptString]; + valueOrder = @[ + kJavaScriptObject, kJavaScriptBoolean, kJavaScriptNumber, + kJavaScriptString + ]; }); return valueOrder; } -- (NSComparisonResult) compareToLeafNode:(FLeafNode*)other { - NSString* thisLeafType = [FUtilities getJavascriptType:self.value]; - NSString* otherLeafType = [FUtilities getJavascriptType:other.value]; - NSUInteger thisIndex = [[FLeafNode valueTypeOrder] indexOfObject:thisLeafType]; - NSUInteger otherIndex = [[FLeafNode valueTypeOrder] indexOfObject:otherLeafType]; +- (NSComparisonResult)compareToLeafNode:(FLeafNode *)other { + NSString *thisLeafType = [FUtilities getJavascriptType:self.value]; + NSString *otherLeafType = [FUtilities getJavascriptType:other.value]; + NSUInteger thisIndex = + [[FLeafNode valueTypeOrder] indexOfObject:thisLeafType]; + NSUInteger otherIndex = + [[FLeafNode valueTypeOrder] indexOfObject:otherLeafType]; assert(thisIndex >= 0 && otherIndex >= 0); if (otherIndex == thisIndex) { // Same type. Compare values. if (thisLeafType == kJavaScriptObject) { - // Deferred value nodes are all equal, but we should also never get to this point... + // Deferred value nodes are all equal, but we should also never get + // to this point... return NSOrderedSame; } else if (thisLeafType == kJavaScriptString) { return [self.value compare:other.value options:NSLiteralSearch]; @@ -233,18 +249,18 @@ - (NSComparisonResult) compareToLeafNode:(FLeafNode*)other { return [self.value compare:other.value]; } } else { - return thisIndex > otherIndex ? NSOrderedDescending : NSOrderedAscending; + return thisIndex > otherIndex ? NSOrderedDescending + : NSOrderedAscending; } } -- (NSString *) description { +- (NSString *)description { return [[self valForExport:YES] description]; } -- (void) forEachChildDo:(fbt_bool_nsstring_node)action { +- (void)forEachChildDo:(fbt_bool_nsstring_node)action { // There are no children, so there is nothing to do. return; } - @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FNode.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FNode.h index 1316756..ea251b6 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FNode.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FNode.h @@ -14,32 +14,36 @@ * limitations under the License. */ -#import #import "FPath.h" #import "FTypedefs_Private.h" +#import @protocol FIndex; @protocol FNode -- (BOOL) isLeafNode; -- (id) getPriority; -- (id) updatePriority:(id)priority; -- (id) getImmediateChild:(NSString *)childKey; -- (id) getChild:(FPath *)path; -- (NSString *) predecessorChildKey:(NSString *)childKey; -- (id) updateImmediateChild:(NSString *)childKey withNewChild:(id)newChildNode; -- (id) updateChild:(FPath *)path withNewChild:(id)newChildNode; -- (BOOL) hasChild:(NSString*)childKey; -- (BOOL) isEmpty; -- (int) numChildren; -- (id) val; -- (id) valForExport:(BOOL)exp; -- (NSString *) dataHash; -- (NSComparisonResult) compare:(id)other; -- (BOOL) isEqual:(id)other; -- (void)enumerateChildrenUsingBlock:(void (^)(NSString *key, id node, BOOL *stop))block; -- (void)enumerateChildrenReverse:(BOOL)reverse usingBlock:(void (^)(NSString *key, id node, BOOL *stop))block; +- (BOOL)isLeafNode; +- (id)getPriority; +- (id)updatePriority:(id)priority; +- (id)getImmediateChild:(NSString *)childKey; +- (id)getChild:(FPath *)path; +- (NSString *)predecessorChildKey:(NSString *)childKey; +- (id)updateImmediateChild:(NSString *)childKey + withNewChild:(id)newChildNode; +- (id)updateChild:(FPath *)path withNewChild:(id)newChildNode; +- (BOOL)hasChild:(NSString *)childKey; +- (BOOL)isEmpty; +- (int)numChildren; +- (id)val; +- (id)valForExport:(BOOL)exp; +- (NSString *)dataHash; +- (NSComparisonResult)compare:(id)other; +- (BOOL)isEqual:(id)other; +- (void)enumerateChildrenUsingBlock:(void (^)(NSString *key, id node, + BOOL *stop))block; +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock:(void (^)(NSString *key, id node, + BOOL *stop))block; - (NSEnumerator *)childEnumerator; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FSnapshotUtilities.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FSnapshotUtilities.h index 2a28788..bf44660 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FSnapshotUtilities.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FSnapshotUtilities.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#import #import "FNode.h" +#import @class FImmutableSortedDictionary; @class FCompoundWrite; @@ -29,16 +29,20 @@ typedef NS_ENUM(NSInteger, FDataHashVersion) { @interface FSnapshotUtilities : NSObject -+ (id) nodeFrom:(id)val; -+ (id) nodeFrom:(id)val priority:(id)priority; -+ (id) nodeFrom:(id)val withValidationFrom:(NSString *)fn; -+ (id) nodeFrom:(id)val priority:(id)priority withValidationFrom:(NSString *)fn; -+ (FCompoundWrite *) compoundWriteFromDictionary:(NSDictionary *)values withValidationFrom:(NSString *)fn; -+ (void) validatePriorityNode:(id)priorityNode; ++ (id)nodeFrom:(id)val; ++ (id)nodeFrom:(id)val priority:(id)priority; ++ (id)nodeFrom:(id)val withValidationFrom:(NSString *)fn; ++ (id)nodeFrom:(id)val + priority:(id)priority + withValidationFrom:(NSString *)fn; ++ (FCompoundWrite *)compoundWriteFromDictionary:(NSDictionary *)values + withValidationFrom:(NSString *)fn; ++ (void)validatePriorityNode:(id)priorityNode; + (void)appendHashRepresentationForLeafNode:(FLeafNode *)val toString:(NSMutableString *)string hashVersion:(FDataHashVersion)hashVersion; -+ (void)appendHashV2RepresentationForString:(NSString *)string toString:(NSMutableString *)mutableString; ++ (void)appendHashV2RepresentationForString:(NSString *)string + toString:(NSMutableString *)mutableString; + (NSUInteger)estimateSerializedNodeSize:(id)node; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FSnapshotUtilities.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FSnapshotUtilities.m index c6012d3..f3f9ed5 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FSnapshotUtilities.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Snapshot/FSnapshotUtilities.m @@ -15,50 +15,75 @@ */ #import "FSnapshotUtilities.h" -#import "FEmptyNode.h" -#import "FLeafNode.h" -#import "FConstants.h" -#import "FUtilities.h" #import "FChildrenNode.h" +#import "FCompoundWrite.h" +#import "FConstants.h" +#import "FEmptyNode.h" #import "FLLRBValueNode.h" -#import "FValidation.h" +#import "FLeafNode.h" #import "FMaxNode.h" #import "FNamedNode.h" -#import "FCompoundWrite.h" +#import "FUtilities.h" +#import "FValidation.h" @implementation FSnapshotUtilities -+ (id) nodeFrom:(id)val { ++ (id)nodeFrom:(id)val { return [FSnapshotUtilities nodeFrom:val priority:nil]; } -+ (id) nodeFrom:(id)val priority:(id)priority { - return [FSnapshotUtilities nodeFrom:val priority:priority withValidationFrom:@"nodeFrom:priority:"]; ++ (id)nodeFrom:(id)val priority:(id)priority { + return [FSnapshotUtilities nodeFrom:val + priority:priority + withValidationFrom:@"nodeFrom:priority:"]; } -+ (id) nodeFrom:(id)val withValidationFrom:(NSString *)fn { ++ (id)nodeFrom:(id)val withValidationFrom:(NSString *)fn { return [FSnapshotUtilities nodeFrom:val priority:nil withValidationFrom:fn]; } -+ (id) nodeFrom:(id)val priority:(id)priority withValidationFrom:(NSString *)fn { - return [FSnapshotUtilities nodeFrom:val priority:priority withValidationFrom:fn atDepth:0 path:[[NSMutableArray alloc] init]]; ++ (id)nodeFrom:(id)val + priority:(id)priority + withValidationFrom:(NSString *)fn { + return [FSnapshotUtilities nodeFrom:val + priority:priority + withValidationFrom:fn + atDepth:0 + path:[[NSMutableArray alloc] init]]; } -+ (id) nodeFrom:(id)val priority:(id)aPriority withValidationFrom:(NSString *)fn atDepth:(int)depth path:(NSMutableArray *)path { ++ (id)nodeFrom:(id)val + priority:(id)aPriority + withValidationFrom:(NSString *)fn + atDepth:(int)depth + path:(NSMutableArray *)path { @autoreleasepool { - return [FSnapshotUtilities internalNodeFrom:val priority:aPriority withValidationFrom:fn atDepth:depth path:path]; + return [FSnapshotUtilities internalNodeFrom:val + priority:aPriority + withValidationFrom:fn + atDepth:depth + path:path]; } } -+ (id) internalNodeFrom:(id)val priority:(id)aPriority withValidationFrom:(NSString *)fn atDepth:(int)depth path:(NSMutableArray *)path { - ++ (id)internalNodeFrom:(id)val + priority:(id)aPriority + withValidationFrom:(NSString *)fn + atDepth:(int)depth + path:(NSMutableArray *)path { if (depth > kFirebaseMaxObjectDepth) { NSRange range; range.location = 0; range.length = 100; - NSString* pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; - @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Max object depth exceeded: %@...", fn, pathString] userInfo:nil]; + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Max object depth exceeded: %@...", + fn, pathString] + userInfo:nil]; } if (val == nil || val == [NSNull null]) { @@ -72,29 +97,37 @@ @implementation FSnapshotUtilities id value = val; BOOL isLeafNode = NO; - if([value isKindOfClass:[NSDictionary class]]) { - NSDictionary* dict = val; - if(dict[kPayloadPriority] != nil) { + if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dict = val; + if (dict[kPayloadPriority] != nil) { id rawPriority = [dict objectForKey:kPayloadPriority]; - [FValidation validateFrom:fn isValidPriorityValue:rawPriority withPath:path]; + [FValidation validateFrom:fn + isValidPriorityValue:rawPriority + withPath:path]; priority = [FSnapshotUtilities nodeFrom:rawPriority]; } - if(dict[kPayloadValue] != nil) { + if (dict[kPayloadValue] != nil) { value = [dict objectForKey:kPayloadValue]; - if ([FValidation validateFrom:fn isValidLeafValue:value withPath:path]) { + if ([FValidation validateFrom:fn + isValidLeafValue:value + withPath:path]) { isLeafNode = YES; } else { @throw [[NSException alloc] - initWithName:@"InvalidLeafValueType" - reason:[NSString stringWithFormat:@"(%@) Invalid data type used with .value. Can only use " - "NSString and NSNumber or be null. Found %@ instead.", - fn, [[value class] description]] userInfo:nil]; + initWithName:@"InvalidLeafValueType" + reason:[NSString stringWithFormat: + @"(%@) Invalid data type used " + @"with .value. Can only use " + "NSString and NSNumber or be " + "null. Found %@ instead.", + fn, [[value class] description]] + userInfo:nil]; } } } - if([FValidation validateFrom:fn isValidLeafValue:value withPath:path]) { + if ([FValidation validateFrom:fn isValidLeafValue:value withPath:path]) { isLeafNode = YES; } @@ -102,19 +135,27 @@ @implementation FSnapshotUtilities return [[FLeafNode alloc] initWithValue:value withPriority:priority]; } - // Unlike with JS, we have to handle the dictionary and array cases separately. + // Unlike with JS, we have to handle the dictionary and array cases + // separately. if ([value isKindOfClass:[NSDictionary class]]) { - NSDictionary* dval = (NSDictionary *)value; - NSMutableDictionary *children = [NSMutableDictionary dictionaryWithCapacity:dval.count]; + NSDictionary *dval = (NSDictionary *)value; + NSMutableDictionary *children = + [NSMutableDictionary dictionaryWithCapacity:dval.count]; // Avoid creating a million newPaths by appending to old one for (id keyId in dval) { - [FValidation validateFrom:fn validDictionaryKey:keyId withPath:path]; - NSString* key = (NSString*)keyId; + [FValidation validateFrom:fn + validDictionaryKey:keyId + withPath:path]; + NSString *key = (NSString *)keyId; if (![key hasPrefix:kPayloadMetadataPrefix]) { [path addObject:key]; - id childNode = [FSnapshotUtilities nodeFrom:dval[key] priority:nil withValidationFrom:fn atDepth:depth + 1 path:path]; + id childNode = [FSnapshotUtilities nodeFrom:dval[key] + priority:nil + withValidationFrom:fn + atDepth:depth + 1 + path:path]; [path removeLastObject]; if (![childNode isEmpty]) { @@ -126,18 +167,27 @@ @implementation FSnapshotUtilities if ([children count] == 0) { return [FEmptyNode emptyNode]; } else { - FImmutableSortedDictionary *childrenDict = [FImmutableSortedDictionary fromDictionary:children - withComparator:[FUtilities keyComparator]]; - return [[FChildrenNode alloc] initWithPriority:priority children:childrenDict]; + FImmutableSortedDictionary *childrenDict = + [FImmutableSortedDictionary + fromDictionary:children + withComparator:[FUtilities keyComparator]]; + return [[FChildrenNode alloc] initWithPriority:priority + children:childrenDict]; } - } else if([value isKindOfClass:[NSArray class]]) { - NSArray* aval = (NSArray *)value; - NSMutableDictionary* children = [NSMutableDictionary dictionaryWithCapacity:aval.count]; + } else if ([value isKindOfClass:[NSArray class]]) { + NSArray *aval = (NSArray *)value; + NSMutableDictionary *children = + [NSMutableDictionary dictionaryWithCapacity:aval.count]; - for(int i = 0; i < [aval count]; i++) { - NSString* key = [NSString stringWithFormat:@"%i", i]; + for (int i = 0; i < [aval count]; i++) { + NSString *key = [NSString stringWithFormat:@"%i", i]; [path addObject:key]; - id childNode = [FSnapshotUtilities nodeFrom:[aval objectAtIndex:i] priority:nil withValidationFrom:fn atDepth:depth + 1 path:path]; + id childNode = + [FSnapshotUtilities nodeFrom:[aval objectAtIndex:i] + priority:nil + withValidationFrom:fn + atDepth:depth + 1 + path:path]; [path removeLastObject]; if (![childNode isEmpty]) { @@ -148,46 +198,67 @@ @implementation FSnapshotUtilities if ([children count] == 0) { return [FEmptyNode emptyNode]; } else { - FImmutableSortedDictionary *childrenDict = [FImmutableSortedDictionary fromDictionary:children - withComparator:[FUtilities keyComparator]]; - return [[FChildrenNode alloc] initWithPriority:priority children:childrenDict]; + FImmutableSortedDictionary *childrenDict = + [FImmutableSortedDictionary + fromDictionary:children + withComparator:[FUtilities keyComparator]]; + return [[FChildrenNode alloc] initWithPriority:priority + children:childrenDict]; } } else { NSRange range; range.location = 0; range.length = MIN(path.count, 50); - NSString* pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; - - @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" - reason:[NSString stringWithFormat:@"(%@) Cannot store object of type %@ at %@. " - "Can only store objects of type NSNumber, NSString, NSDictionary, and NSArray.", - fn, [[value class] description], pathString] userInfo:nil]; + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Cannot store object of type %@ at %@. " + "Can only store objects of type NSNumber, " + "NSString, NSDictionary, and NSArray.", + fn, [[value class] description], pathString] + userInfo:nil]; } } -+ (FCompoundWrite *) compoundWriteFromDictionary:(NSDictionary *)values withValidationFrom:(NSString *)fn { ++ (FCompoundWrite *)compoundWriteFromDictionary:(NSDictionary *)values + withValidationFrom:(NSString *)fn { FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite]; - NSMutableArray *updatePaths = [NSMutableArray arrayWithCapacity:values.count]; + NSMutableArray *updatePaths = + [NSMutableArray arrayWithCapacity:values.count]; for (NSString *keyId in values) { id value = values[keyId]; - [FValidation validateFrom:fn validUpdateDictionaryKey:keyId withValue:value]; + [FValidation validateFrom:fn + validUpdateDictionaryKey:keyId + withValue:value]; - FPath* path = [FPath pathWithString:keyId]; - id node = [FSnapshotUtilities nodeFrom:value withValidationFrom:fn]; + FPath *path = [FPath pathWithString:keyId]; + id node = [FSnapshotUtilities nodeFrom:value + withValidationFrom:fn]; [updatePaths addObject:path]; compoundWrite = [compoundWrite addWrite:node atPath:path]; } // Check that the update paths are not descendants of each other. - [updatePaths sortUsingComparator:^NSComparisonResult(FPath* left, FPath* right) { - return [left compare:right]; - }]; + [updatePaths + sortUsingComparator:^NSComparisonResult(FPath *left, FPath *right) { + return [left compare:right]; + }]; FPath *prevPath = nil; for (FPath *path in updatePaths) { if (prevPath != nil && [prevPath contains:path]) { - @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Invalid path in object. Path (%@) is an ancestor of (%@).", fn, prevPath, path] userInfo:nil]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Invalid path in object. Path " + @"(%@) is an ancestor of (%@).", + fn, prevPath, path] + userInfo:nil]; } prevPath = path; } @@ -195,33 +266,41 @@ + (FCompoundWrite *) compoundWriteFromDictionary:(NSDictionary *)values withVali return compoundWrite; } -+ (void)validatePriorityNode:(id )priorityNode { ++ (void)validatePriorityNode:(id)priorityNode { assert(priorityNode != nil); if (priorityNode.isLeafNode) { id val = priorityNode.val; if ([val isKindOfClass:[NSDictionary class]]) { - NSDictionary* valDict __unused = (NSDictionary*)val; - NSAssert(valDict[kServerValueSubKey] != nil, @"Priority can't be object unless it's a deferred value"); + NSDictionary *valDict __unused = (NSDictionary *)val; + NSAssert(valDict[kServerValueSubKey] != nil, + @"Priority can't be object unless it's a deferred value"); } else { NSString *jsType __unused = [FUtilities getJavascriptType:val]; - NSAssert(jsType == kJavaScriptString || jsType == kJavaScriptNumber, @"Priority of unexpected type."); + NSAssert(jsType == kJavaScriptString || jsType == kJavaScriptNumber, + @"Priority of unexpected type."); } } else { - NSAssert(priorityNode == [FMaxNode maxNode] || priorityNode.isEmpty, @"Priority of unexpected type."); + NSAssert(priorityNode == [FMaxNode maxNode] || priorityNode.isEmpty, + @"Priority of unexpected type."); } // Don't call getPriority() on MAX_NODE to avoid hitting assertion. - NSAssert(priorityNode == [FMaxNode maxNode] || priorityNode.getPriority.isEmpty, - @"Priority nodes can't have a priority of their own."); + NSAssert(priorityNode == [FMaxNode maxNode] || + priorityNode.getPriority.isEmpty, + @"Priority nodes can't have a priority of their own."); } + (void)appendHashRepresentationForLeafNode:(FLeafNode *)leafNode toString:(NSMutableString *)string hashVersion:(FDataHashVersion)hashVersion { - NSAssert(hashVersion == FDataHashVersionV1 || hashVersion == FDataHashVersionV2, + NSAssert(hashVersion == FDataHashVersionV1 || + hashVersion == FDataHashVersionV2, @"Unknown hash version: %lu", (unsigned long)hashVersion); if (!leafNode.getPriority.isEmpty) { [string appendString:@"priority:"]; - [FSnapshotUtilities appendHashRepresentationForLeafNode:leafNode.getPriority toString:string hashVersion:hashVersion]; + [FSnapshotUtilities + appendHashRepresentationForLeafNode:leafNode.getPriority + toString:string + hashVersion:hashVersion]; [string appendString:@":"]; } @@ -229,29 +308,35 @@ + (void)appendHashRepresentationForLeafNode:(FLeafNode *)leafNode [string appendString:jsType]; [string appendString:@":"]; - if (jsType == kJavaScriptBoolean) { - NSString *boolString = [leafNode.val boolValue] ? kJavaScriptTrue : kJavaScriptFalse; + NSString *boolString = + [leafNode.val boolValue] ? kJavaScriptTrue : kJavaScriptFalse; [string appendString:boolString]; } else if (jsType == kJavaScriptNumber) { - NSString *numberString = [FUtilities ieee754StringForNumber:leafNode.val]; + NSString *numberString = + [FUtilities ieee754StringForNumber:leafNode.val]; [string appendString:numberString]; } else if (jsType == kJavaScriptString) { if (hashVersion == FDataHashVersionV1) { [string appendString:leafNode.val]; } else { - NSAssert(hashVersion == FDataHashVersionV2, @"Invalid hash version found"); - [FSnapshotUtilities appendHashV2RepresentationForString:leafNode.val toString:string]; + NSAssert(hashVersion == FDataHashVersionV2, + @"Invalid hash version found"); + [FSnapshotUtilities appendHashV2RepresentationForString:leafNode.val + toString:string]; } } else { - [NSException raise:NSInvalidArgumentException format:@"Unknown value for hashing: %@", leafNode]; + [NSException raise:NSInvalidArgumentException + format:@"Unknown value for hashing: %@", leafNode]; } } + (void)appendHashV2RepresentationForString:(NSString *)string toString:(NSMutableString *)mutableString { - string = [string stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; - string = [string stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; + string = [string stringByReplacingOccurrencesOfString:@"\\" + withString:@"\\\\"]; + string = [string stringByReplacingOccurrencesOfString:@"\"" + withString:@"\\\""]; [mutableString appendString:@"\""]; [mutableString appendString:string]; [mutableString appendString:@"\""]; @@ -259,7 +344,8 @@ + (void)appendHashV2RepresentationForString:(NSString *)string + (NSUInteger)estimateLeafNodeSize:(FLeafNode *)leafNode { NSString *jsType = [FUtilities getJavascriptType:leafNode.val]; - // These values are somewhat arbitrary, but we don't need an exact value so prefer performance over exact value + // These values are somewhat arbitrary, but we don't need an exact value so + // prefer performance over exact value NSUInteger valueSize; if (jsType == kJavaScriptNumber) { valueSize = 8; // estimate each float with 8 bytes @@ -268,16 +354,19 @@ + (NSUInteger)estimateLeafNodeSize:(FLeafNode *)leafNode { } else if (jsType == kJavaScriptString) { valueSize = 2 + [leafNode.val length]; // add 2 for quotes } else { - [NSException raise:NSInvalidArgumentException format:@"Unknown leaf type: %@", leafNode]; + [NSException raise:NSInvalidArgumentException + format:@"Unknown leaf type: %@", leafNode]; return 0; } if (leafNode.getPriority.isEmpty) { return valueSize; } else { - // Account for extra overhead due to the extra JSON object and the ".value" and ".priority" keys, colons, comma - NSUInteger leafPriorityOverhead = 2 + 8 + 11 + 2 + 1; - return leafPriorityOverhead + valueSize + [FSnapshotUtilities estimateLeafNodeSize:leafNode.getPriority]; + // Account for extra overhead due to the extra JSON object and the + // ".value" and ".priority" keys, colons, comma + NSUInteger leafPriorityOverhead = 2 + 8 + 11 + 2 + 1; + return leafPriorityOverhead + valueSize + + [FSnapshotUtilities estimateLeafNodeSize:leafNode.getPriority]; } } @@ -287,12 +376,16 @@ + (NSUInteger)estimateSerializedNodeSize:(id)node { } else if ([node isLeafNode]) { return [FSnapshotUtilities estimateLeafNodeSize:node]; } else { - NSAssert([node isKindOfClass:[FChildrenNode class]], @"Unexpected node type: %@", [node class]); + NSAssert([node isKindOfClass:[FChildrenNode class]], + @"Unexpected node type: %@", [node class]); __block NSUInteger sum = 1; // opening brackets - [((FChildrenNode *)node) enumerateChildrenAndPriorityUsingBlock:^(NSString *key, idchild, BOOL *stop) { - sum += key.length; - sum += 4; // quotes around key and colon and (comma or closing bracket) - sum += [FSnapshotUtilities estimateSerializedNodeSize:child]; + [((FChildrenNode *)node) enumerateChildrenAndPriorityUsingBlock:^( + NSString *key, id child, + BOOL *stop) { + sum += key.length; + sum += + 4; // quotes around key and colon and (comma or closing bracket) + sum += [FSnapshotUtilities estimateSerializedNodeSize:child]; }]; return sum; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FAtomicNumber.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FAtomicNumber.h index 589dc25..b8668d2 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FAtomicNumber.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FAtomicNumber.h @@ -18,6 +18,6 @@ @interface FAtomicNumber : NSObject -- (NSNumber *) getAndIncrement; +- (NSNumber *)getAndIncrement; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FAtomicNumber.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FAtomicNumber.m index 4a14caa..20cfd8d 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FAtomicNumber.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FAtomicNumber.m @@ -16,11 +16,11 @@ #import "FAtomicNumber.h" -@interface FAtomicNumber() { +@interface FAtomicNumber () { unsigned long number; } -@property (nonatomic, strong) NSLock* lock; +@property(nonatomic, strong) NSLock *lock; @end @@ -28,8 +28,7 @@ @implementation FAtomicNumber @synthesize lock; -- (id)init -{ +- (id)init { self = [super init]; if (self) { number = 1; @@ -38,10 +37,12 @@ - (id)init return self; } -- (NSNumber *) getAndIncrement { - NSNumber* result; +- (NSNumber *)getAndIncrement { + NSNumber *result; - // See: http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html#//apple_ref/doc/uid/10000057i-CH8-SW14 to improve, etc. + // See: + // http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html#//apple_ref/doc/uid/10000057i-CH8-SW14 + // to improve, etc. [self.lock lock]; result = [NSNumber numberWithUnsignedLong:number]; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FEventEmitter.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FEventEmitter.h index 069e10f..fc19ca7 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FEventEmitter.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FEventEmitter.h @@ -14,20 +14,23 @@ * limitations under the License. */ -#import "FIRDatabaseQuery.h" #import "FIRDatabaseConfig.h" +#import "FIRDatabaseQuery.h" #import "FTypedefs_Private.h" @interface FEventEmitter : NSObject -- (id) initWithAllowedEvents:(NSArray *)theAllowedEvents queue:(dispatch_queue_t)queue; +- (id)initWithAllowedEvents:(NSArray *)theAllowedEvents + queue:(dispatch_queue_t)queue; -- (id) getInitialEventForType:(NSString *)eventType; -- (void) triggerEventType:(NSString *)eventType data:(id)data; +- (id)getInitialEventForType:(NSString *)eventType; +- (void)triggerEventType:(NSString *)eventType data:(id)data; -- (FIRDatabaseHandle)observeEventType:(NSString *)eventType withBlock:(fbt_void_id)block; -- (void) removeObserverForEventType:(NSString *)eventType withHandle:(FIRDatabaseHandle)handle; +- (FIRDatabaseHandle)observeEventType:(NSString *)eventType + withBlock:(fbt_void_id)block; +- (void)removeObserverForEventType:(NSString *)eventType + withHandle:(FIRDatabaseHandle)handle; -- (void) validateEventType:(NSString *)eventType; +- (void)validateEventType:(NSString *)eventType; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FEventEmitter.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FEventEmitter.m index f7c569b..7d02239 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FEventEmitter.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FEventEmitter.m @@ -14,16 +14,15 @@ * limitations under the License. */ - #import "FEventEmitter.h" -#import "FUtilities.h" -#import "FRepoManager.h" #import "FIRDatabaseQuery_Private.h" +#import "FRepoManager.h" +#import "FUtilities.h" @interface FEventListener : NSObject -@property (nonatomic, copy) fbt_void_id userCallback; -@property (nonatomic) FIRDatabaseHandle handle; +@property(nonatomic, copy) fbt_void_id userCallback; +@property(nonatomic) FIRDatabaseHandle handle; @end @@ -34,24 +33,27 @@ @implementation FEventListener @end - @interface FEventEmitter () -@property (nonatomic, strong) NSArray *allowedEvents; -@property (nonatomic, strong) NSMutableDictionary *listeners; -@property (nonatomic, strong) dispatch_queue_t queue; +@property(nonatomic, strong) NSArray *allowedEvents; +@property(nonatomic, strong) NSMutableDictionary *listeners; +@property(nonatomic, strong) dispatch_queue_t queue; @end - @implementation FEventEmitter @synthesize allowedEvents; @synthesize listeners; -- (id) initWithAllowedEvents:(NSArray *)theAllowedEvents queue:(dispatch_queue_t)queue { +- (id)initWithAllowedEvents:(NSArray *)theAllowedEvents + queue:(dispatch_queue_t)queue { if (theAllowedEvents == nil || [theAllowedEvents count] == 0) { - @throw [NSException exceptionWithName:@"AllowedEventsValidation" reason:@"FEventEmitters must be initialized with at least one valid event." userInfo:nil]; + @throw [NSException + exceptionWithName:@"AllowedEventsValidation" + reason:@"FEventEmitters must be initialized with at " + @"least one valid event." + userInfo:nil]; } self = [super init]; @@ -65,28 +67,34 @@ - (id) initWithAllowedEvents:(NSArray *)theAllowedEvents queue:(dispatch_queue_t return self; } -- (id) getInitialEventForType:(NSString *)eventType { - @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"You must override getInitialEvent: when subclassing FEventEmitter" userInfo:nil]; +- (id)getInitialEventForType:(NSString *)eventType { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"You must override getInitialEvent: " + @"when subclassing FEventEmitter" + userInfo:nil]; } -- (void) triggerEventType:(NSString *)eventType data:(id)data { +- (void)triggerEventType:(NSString *)eventType data:(id)data { [self validateEventType:eventType]; - NSMutableDictionary *eventTypeListeners = [self.listeners objectForKey:eventType]; + NSMutableDictionary *eventTypeListeners = + [self.listeners objectForKey:eventType]; for (FEventListener *listener in eventTypeListeners) { [self triggerListener:listener withData:data]; } } -- (void) triggerListener:(FEventListener *)listener withData:(id)data { - // TODO, should probably get this from FRepo or something although it ends up being the same. (Except maybe for testing) +- (void)triggerListener:(FEventListener *)listener withData:(id)data { + // TODO, should probably get this from FRepo or something although it ends + // up being the same. (Except maybe for testing) if (listener.userCallback) { dispatch_async(self.queue, ^{ - listener.userCallback(data); + listener.userCallback(data); }); } } -- (FIRDatabaseHandle)observeEventType:(NSString *)eventType withBlock:(fbt_void_id)block { +- (FIRDatabaseHandle)observeEventType:(NSString *)eventType + withBlock:(fbt_void_id)block { [self validateEventType:eventType]; // Create listener @@ -95,15 +103,18 @@ - (FIRDatabaseHandle)observeEventType:(NSString *)eventType withBlock:(fbt_void_ listener.userCallback = block; // copies block automatically dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self addEventListener:listener forEventType:eventType]; + [self addEventListener:listener forEventType:eventType]; }); return listener.handle; } -- (void) addEventListener:(FEventListener *)listener forEventType:(NSString *)eventType { - // Get or initializer listeners map [FIRDatabaseHandle -> callback block] for eventType - NSMutableArray *eventTypeListeners = [self.listeners objectForKey:eventType]; +- (void)addEventListener:(FEventListener *)listener + forEventType:(NSString *)eventType { + // Get or initializer listeners map [FIRDatabaseHandle -> callback block] + // for eventType + NSMutableArray *eventTypeListeners = + [self.listeners objectForKey:eventType]; if (eventTypeListeners == nil) { eventTypeListeners = [[NSMutableArray alloc] init]; [self.listeners setObject:eventTypeListeners forKey:eventType]; @@ -115,16 +126,19 @@ - (void) addEventListener:(FEventListener *)listener forEventType:(NSString *)ev [self triggerListener:listener withData:initialData]; } -- (void) removeObserverForEventType:(NSString *)eventType withHandle:(FIRDatabaseHandle)handle { +- (void)removeObserverForEventType:(NSString *)eventType + withHandle:(FIRDatabaseHandle)handle { [self validateEventType:eventType]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self removeEventListenerWithHandle:handle forEventType:eventType]; + [self removeEventListenerWithHandle:handle forEventType:eventType]; }); } -- (void)removeEventListenerWithHandle:(FIRDatabaseHandle)handle forEventType:(NSString *)eventType { - NSMutableArray *eventTypeListeners = [self.listeners objectForKey:eventType]; +- (void)removeEventListenerWithHandle:(FIRDatabaseHandle)handle + forEventType:(NSString *)eventType { + NSMutableArray *eventTypeListeners = + [self.listeners objectForKey:eventType]; for (FEventListener *listener in [eventTypeListeners copy]) { if (handle == NSNotFound || handle == listener.handle) { [eventTypeListeners removeObject:listener]; @@ -132,13 +146,15 @@ - (void)removeEventListenerWithHandle:(FIRDatabaseHandle)handle forEventType:(NS } } - -- (void) validateEventType:(NSString *)eventType { +- (void)validateEventType:(NSString *)eventType { if ([self.allowedEvents indexOfObject:eventType] == NSNotFound) { - @throw [NSException exceptionWithName:@"InvalidEventType" - reason:[NSString stringWithFormat:@"%@ is not a valid event type. %@ is the list of valid events.", - eventType, self.allowedEvents] - userInfo:nil]; + @throw [NSException + exceptionWithName:@"InvalidEventType" + reason:[NSString stringWithFormat: + @"%@ is not a valid event type. %@ " + @"is the list of valid events.", + eventType, self.allowedEvents] + userInfo:nil]; } } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FNextPushId.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FNextPushId.h index 2da54f0..5a66196 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FNextPushId.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FNextPushId.h @@ -18,6 +18,6 @@ @interface FNextPushId : NSObject -+ (NSString *) get:(NSTimeInterval)now; ++ (NSString *)get:(NSTimeInterval)now; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FNextPushId.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FNextPushId.m index ee3ba13..864e147 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FNextPushId.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FNextPushId.m @@ -17,11 +17,12 @@ #import "FNextPushId.h" #import "FUtilities.h" -static NSString *const PUSH_CHARS = @"-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; +static NSString *const PUSH_CHARS = + @"-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; @implementation FNextPushId -+ (NSString *) get:(NSTimeInterval)currentTime { ++ (NSString *)get:(NSTimeInterval)currentTime { static long long lastPushTime = 0; static int lastRandChars[12]; @@ -31,29 +32,27 @@ + (NSString *) get:(NSTimeInterval)currentTime { lastPushTime = now; unichar timeStampChars[8]; - for(int i = 7; i >= 0; i--) { + for (int i = 7; i >= 0; i--) { timeStampChars[i] = [PUSH_CHARS characterAtIndex:(now % 64)]; now = (long long)floor(now / 64); } - NSMutableString* id = [[NSMutableString alloc] init]; + NSMutableString *id = [[NSMutableString alloc] init]; [id appendString:[NSString stringWithCharacters:timeStampChars length:8]]; - - if(!duplicateTime) { - for(int i = 0; i < 12; i++) { + if (!duplicateTime) { + for (int i = 0; i < 12; i++) { lastRandChars[i] = (int)floor(arc4random() % 64); } - } - else { + } else { int i = 0; - for(i = 11; i >= 0 && lastRandChars[i] == 63; i--) { + for (i = 11; i >= 0 && lastRandChars[i] == 63; i--) { lastRandChars[i] = 0; } lastRandChars[i]++; } - for(int i = 0; i < 12; i++) { + for (int i = 0; i < 12; i++) { [id appendFormat:@"%C", [PUSH_CHARS characterAtIndex:lastRandChars[i]]]; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FParsedUrl.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FParsedUrl.h index 7145f86..1c07284 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FParsedUrl.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FParsedUrl.h @@ -14,12 +14,12 @@ * limitations under the License. */ -#import "FRepoInfo.h" #import "FPath.h" +#import "FRepoInfo.h" @interface FParsedUrl : NSObject -@property (nonatomic, strong) FRepoInfo* repoInfo; -@property (nonatomic, strong) FPath* path; +@property(nonatomic, strong) FRepoInfo *repoInfo; +@property(nonatomic, strong) FPath *path; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FStringUtilities.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FStringUtilities.h index 34ac9af..f7d19b6 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FStringUtilities.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FStringUtilities.h @@ -18,9 +18,9 @@ @interface FStringUtilities : NSObject -+ (NSString *) base64EncodedSha1:(NSString *)str; -+ (NSString *) urlDecoded:(NSString *)url; -+ (NSString *) urlEncoded:(NSString *)url; -+ (NSString *) sanitizedForUserAgent:(NSString *)str; ++ (NSString *)base64EncodedSha1:(NSString *)str; ++ (NSString *)urlDecoded:(NSString *)url; ++ (NSString *)urlEncoded:(NSString *)url; ++ (NSString *)sanitizedForUserAgent:(NSString *)str; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FStringUtilities.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FStringUtilities.m index dff58e0..2515257 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FStringUtilities.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FStringUtilities.m @@ -14,30 +14,34 @@ * limitations under the License. */ -#import #import "FStringUtilities.h" #import "NSData+SRB64Additions.h" +#import @implementation FStringUtilities // http://stackoverflow.com/questions/3468268/objective-c-sha1 // http://stackoverflow.com/questions/7310457/ios-objective-c-sha-1-and-base64-problem -+ (NSString *) base64EncodedSha1:(NSString *)str { ++ (NSString *)base64EncodedSha1:(NSString *)str { const char *cstr = [str cStringUsingEncoding:NSUTF8StringEncoding]; - // NSString reports length in characters, but we want it in bytes, which strlen will give us. + // NSString reports length in characters, but we want it in bytes, which + // strlen will give us. unsigned long dataLen = strlen(cstr); NSData *data = [NSData dataWithBytes:cstr length:dataLen]; uint8_t digest[CC_SHA1_DIGEST_LENGTH]; CC_SHA1(data.bytes, (unsigned int)data.length, digest); - NSData* output = [[NSData alloc] initWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]; + NSData *output = [[NSData alloc] initWithBytes:digest + length:CC_SHA1_DIGEST_LENGTH]; return [FSRUtilities base64EncodedStringFromData:output]; } -+ (NSString *) urlDecoded:(NSString *)url { - NSString* replaced = [url stringByReplacingOccurrencesOfString:@"+" withString:@" "]; - NSString* decoded = [replaced stringByRemovingPercentEncoding]; - // This is kind of a hack, but is generally how the js client works. We could run into trouble if - // some piece is a correctly escaped %-sequence, and another isn't. But, that's bad input anyways... ++ (NSString *)urlDecoded:(NSString *)url { + NSString *replaced = [url stringByReplacingOccurrencesOfString:@"+" + withString:@" "]; + NSString *decoded = [replaced stringByRemovingPercentEncoding]; + // This is kind of a hack, but is generally how the js client works. We + // could run into trouble if some piece is a correctly escaped %-sequence, + // and another isn't. But, that's bad input anyways... if (decoded) { return decoded; } else { @@ -45,17 +49,24 @@ + (NSString *) urlDecoded:(NSString *)url { } } -+ (NSString *) urlEncoded:(NSString *)url { - // Didn't seem like there was an Apple NSCharacterSet that had our version of the encoding - // So I made my own, following RFC 2396 https://www.ietf.org/rfc/rfc2396.txt - // allowedCharacters = alphanum | "-" | "_" | "~" - NSCharacterSet *allowedCharacters = [NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_~"]; - return [url stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters]; ++ (NSString *)urlEncoded:(NSString *)url { + // Didn't seem like there was an Apple NSCharacterSet that had our version + // of the encoding So I made my own, following RFC 2396 + // https://www.ietf.org/rfc/rfc2396.txt allowedCharacters = alphanum | "-" | + // "_" | "~" + NSCharacterSet *allowedCharacters = [NSCharacterSet + characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGH" + @"IJKLMNOPQRSTUVWXYZ0123456789-_~"]; + return [url + stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters]; } -+ (NSString *) sanitizedForUserAgent:(NSString *)str { - return [str stringByReplacingOccurrencesOfString:@"/|_" withString:@"|" options:NSRegularExpressionSearch range:NSMakeRange(0, [str length])]; ++ (NSString *)sanitizedForUserAgent:(NSString *)str { + return + [str stringByReplacingOccurrencesOfString:@"/|_" + withString:@"|" + options:NSRegularExpressionSearch + range:NSMakeRange(0, [str length])]; } - @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FTypedefs.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FTypedefs.h index 4a24ca5..56d97ff 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FTypedefs.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FTypedefs.h @@ -30,16 +30,17 @@ // fbt = Firebase Block Typedef typedef void (^fbt_void_void)(void); -typedef void (^fbt_void_datasnapshot_nsstring) (FIRDataSnapshot *snapshot, NSString *prevName); -typedef void (^fbt_void_datasnapshot) (FIRDataSnapshot *snapshot); +typedef void (^fbt_void_datasnapshot_nsstring)(FIRDataSnapshot *snapshot, + NSString *prevName); +typedef void (^fbt_void_datasnapshot)(FIRDataSnapshot *snapshot); typedef void (^fbt_void_user)(FAuthData *user); -typedef void (^fbt_void_nsstring_id)(NSString* status, id data); -typedef void (^fbt_void_nserror_id)(NSError* error, id data); +typedef void (^fbt_void_nsstring_id)(NSString *status, id data); +typedef void (^fbt_void_nserror_id)(NSError *error, id data); typedef void (^fbt_void_nserror)(NSError *error); -typedef void (^fbt_void_nserror_ref)(NSError* error, FIRDatabaseReference * ref); -typedef void (^fbt_void_nserror_user)(NSError* error, FAuthData * user); -typedef void (^fbt_void_nserror_json)(NSError* error, NSDictionary* json); +typedef void (^fbt_void_nserror_ref)(NSError *error, FIRDatabaseReference *ref); +typedef void (^fbt_void_nserror_user)(NSError *error, FAuthData *user); +typedef void (^fbt_void_nserror_json)(NSError *error, NSDictionary *json); typedef void (^fbt_void_nsdictionary)(NSDictionary *data); -typedef id (^fbt_id_node_nsstring)(id node, NSString* childName); +typedef id (^fbt_id_node_nsstring)(id node, NSString *childName); #endif diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FUtilities.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FUtilities.h index f7fe7a5..9458f24 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FUtilities.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FUtilities.h @@ -14,26 +14,28 @@ * limitations under the License. */ +#import #import + #import "FParsedUrl.h" @interface FUtilities : NSObject -+ (NSArray *) splitString:(NSString *)str intoMaxSize:(const unsigned int)size; -+ (NSNumber *) LUIDGenerator; -+ (FParsedUrl *) parseUrl:(NSString *)url; -+ (NSString *) getJavascriptType:(id)obj; -+ (NSError *) errorForStatus:(NSString *)status andReason:(NSString *)reason; -+ (NSNumber *) intForString:(NSString *)string; -+ (NSString *) ieee754StringForNumber:(NSNumber *)val; -+ (void) setLoggingEnabled:(BOOL)enabled; -+ (BOOL) getLoggingEnabled; ++ (NSArray *)splitString:(NSString *)str intoMaxSize:(const unsigned int)size; ++ (NSNumber *)LUIDGenerator; ++ (FParsedUrl *)parseUrl:(NSString *)url; ++ (NSString *)getJavascriptType:(id)obj; ++ (NSError *)errorForStatus:(NSString *)status andReason:(NSString *)reason; ++ (NSNumber *)intForString:(NSString *)string; ++ (NSString *)ieee754StringForNumber:(NSNumber *)val; ++ (void)setLoggingEnabled:(BOOL)enabled; ++ (BOOL)getLoggingEnabled; -+ (NSString*) minName; -+ (NSString*) maxName; -+ (NSComparisonResult) compareKey:(NSString *)a toKey:(NSString *)b; -+ (NSComparator) stringComparator; -+ (NSComparator) keyComparator; ++ (NSString *)minName; ++ (NSString *)maxName; ++ (NSComparisonResult)compareKey:(NSString *)a toKey:(NSString *)b; ++ (NSComparator)stringComparator; ++ (NSComparator)keyComparator; + (double)randomDouble; @@ -52,24 +54,29 @@ FOUNDATION_EXPORT NSString *const kFPersistenceLogTag; #define FFLog(code, format, ...) FFDebug((code), (format), ##__VA_ARGS__) -#define FFDebug(code, format, ...) do { \ - if (FFIsLoggingEnabled(FLogLevelDebug)) { \ - FIRLogDebug(kFIRLoggerDatabase, (code), (format), ##__VA_ARGS__); \ - } \ -} while(0) +#define FFDebug(code, format, ...) \ + do { \ + if (FFIsLoggingEnabled(FLogLevelDebug)) { \ + FIRLogDebug(kFIRLoggerDatabase, (code), (format), ##__VA_ARGS__); \ + } \ + } while (0) -#define FFInfo(code, format, ...) do { \ - if (FFIsLoggingEnabled(FLogLevelInfo)) { \ - FIRLogError(kFIRLoggerDatabase, (code), (format), ##__VA_ARGS__); \ - } \ -} while(0) +#define FFInfo(code, format, ...) \ + do { \ + if (FFIsLoggingEnabled(FLogLevelInfo)) { \ + FIRLogError(kFIRLoggerDatabase, (code), (format), ##__VA_ARGS__); \ + } \ + } while (0) -#define FFWarn(code, format, ...) do { \ - if (FFIsLoggingEnabled(FLogLevelWarn)) { \ - FIRLogWarning(kFIRLoggerDatabase, (code), (format), ##__VA_ARGS__); \ - } \ -} while(0) +#define FFWarn(code, format, ...) \ + do { \ + if (FFIsLoggingEnabled(FLogLevelWarn)) { \ + FIRLogWarning(kFIRLoggerDatabase, (code), (format), \ + ##__VA_ARGS__); \ + } \ + } while (0) +extern FIRLoggerService kFIRLoggerDatabase; BOOL FFIsLoggingEnabled(FLogLevel logLevel); void firebaseUncaughtExceptionHandler(NSException *exception); void firebaseJobsTroll(void); diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FUtilities.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FUtilities.m index d0a9a43..a24c134 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FUtilities.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FUtilities.m @@ -14,11 +14,11 @@ * limitations under the License. */ -#import #import "FUtilities.h" -#import "FStringUtilities.h" -#import "FConstants.h" #import "FAtomicNumber.h" +#import "FConstants.h" +#import "FStringUtilities.h" +#import #define ARC4RANDOM_MAX 0x100000000 #define INTEGER_32_MIN (-2147483648) @@ -27,27 +27,27 @@ #pragma mark - #pragma mark C functions +FIRLoggerService kFIRLoggerDatabase = @"[Firebase/Database]"; static FLogLevel logLevel = FLogLevelInfo; // Default log level is info -static NSMutableDictionary* options = nil; +static NSMutableDictionary *options = nil; -BOOL FFIsLoggingEnabled(FLogLevel level) { - return level >= logLevel; -} +BOOL FFIsLoggingEnabled(FLogLevel level) { return level >= logLevel; } void firebaseJobsTroll(void) { - FFLog(@"I-RDB095001", @"password super secret; JFK conspiracy; Hello there! Having fun digging through Firebase? We're always hiring! jobs@firebase.com"); + FFLog(@"I-RDB095001", + @"password super secret; JFK conspiracy; Hello there! Having fun " + @"digging through Firebase? We're always hiring! jobs@firebase.com"); } #pragma mark - #pragma mark Private property and singleton specification -@interface FUtilities() { - +@interface FUtilities () { } -@property (nonatomic, strong) FAtomicNumber* localUid; +@property(nonatomic, strong) FAtomicNumber *localUid; -+ (FUtilities*)singleton; ++ (FUtilities *)singleton; @end @@ -55,8 +55,7 @@ @implementation FUtilities @synthesize localUid; -- (id)init -{ +- (id)init { self = [super init]; if (self) { self.localUid = [[FAtomicNumber alloc] init]; @@ -65,112 +64,150 @@ - (id)init } // TODO: We really want to be able to set the log level -+ (void) setLoggingEnabled:(BOOL)enabled { ++ (void)setLoggingEnabled:(BOOL)enabled { logLevel = enabled ? FLogLevelDebug : FLogLevelInfo; } -+ (BOOL) getLoggingEnabled { ++ (BOOL)getLoggingEnabled { return logLevel == FLogLevelDebug; } -+ (FUtilities*) singleton -{ ++ (FUtilities *)singleton { static dispatch_once_t pred = 0; __strong static id _sharedObject = nil; dispatch_once(&pred, ^{ - _sharedObject = [[self alloc] init]; // or some other init method + _sharedObject = [[self alloc] init]; // or some other init method }); return _sharedObject; } // Refactor as a category of NSString -+ (NSArray *) splitString:(NSString *) str intoMaxSize:(const unsigned int) size { - if(str.length <= size) { ++ (NSArray *)splitString:(NSString *)str intoMaxSize:(const unsigned int)size { + if (str.length <= size) { return [NSArray arrayWithObject:str]; } - NSMutableArray* dataSegs = [[NSMutableArray alloc] init]; - for(int c = 0; c < str.length; c += size) { + NSMutableArray *dataSegs = [[NSMutableArray alloc] init]; + for (int c = 0; c < str.length; c += size) { if (c + size > str.length) { int rangeStart = c; unsigned long rangeLength = size - ((c + size) - str.length); - [dataSegs addObject:[str substringWithRange:NSMakeRange(rangeStart, rangeLength)]]; - } - else { + [dataSegs + addObject:[str substringWithRange:NSMakeRange(rangeStart, + rangeLength)]]; + } else { int rangeStart = c; int rangeLength = size; - [dataSegs addObject:[str substringWithRange:NSMakeRange(rangeStart, rangeLength)]]; + [dataSegs + addObject:[str substringWithRange:NSMakeRange(rangeStart, + rangeLength)]]; } } return dataSegs; } -+ (NSNumber *) LUIDGenerator { - FUtilities* f = [FUtilities singleton]; ++ (NSNumber *)LUIDGenerator { + FUtilities *f = [FUtilities singleton]; return [f.localUid getAndIncrement]; } -+ (NSString *) decodePath:(NSString *)pathString { - NSMutableArray* decodedPieces = [[NSMutableArray alloc] init]; - NSArray* pieces = [pathString componentsSeparatedByString:@"/"]; - for (NSString* piece in pieces) { ++ (NSString *)decodePath:(NSString *)pathString { + NSMutableArray *decodedPieces = [[NSMutableArray alloc] init]; + NSArray *pieces = [pathString componentsSeparatedByString:@"/"]; + for (NSString *piece in pieces) { if (piece.length > 0) { [decodedPieces addObject:[FStringUtilities urlDecoded:piece]]; } } - return [NSString stringWithFormat:@"/%@", [decodedPieces componentsJoinedByString:@"/"]]; + return [NSString + stringWithFormat:@"/%@", [decodedPieces componentsJoinedByString:@"/"]]; } -+ (FParsedUrl *) parseUrl:(NSString *)url { - NSString* original = url; - //NSURL* n = [[NSURL alloc] initWithString:url] ++ (NSString *)extractPathFromUrlString:(NSString *)url { + NSString *path = url; - NSString* host; - NSString* namespace; - bool secure; + NSRange schemeIndex = [path rangeOfString:@"//"]; + if (schemeIndex.location != NSNotFound) { + path = [path substringFromIndex:schemeIndex.location + 2]; + } - NSString* scheme = nil; - FPath* path = nil; - NSRange colonIndex = [url rangeOfString:@"//"]; - if (colonIndex.location != NSNotFound) { - scheme = [url substringToIndex:colonIndex.location - 1]; - url = [url substringFromIndex:colonIndex.location + 2]; + NSUInteger pathIndex = [path rangeOfString:@"/"].location; + if (pathIndex != NSNotFound) { + path = [path substringFromIndex:pathIndex + 1]; + } else { + path = @""; } - NSInteger slashIndex = [url rangeOfString:@"/"].location; - if (slashIndex == NSNotFound) { - slashIndex = url.length; + + NSUInteger queryParamIndex = [path rangeOfString:@"?"].location; + if (queryParamIndex != NSNotFound) { + path = [path substringToIndex:queryParamIndex]; } - host = [[url substringToIndex:slashIndex] lowercaseString]; - if (slashIndex >= url.length) { - url = @""; - } else { - url = [url substringFromIndex:slashIndex + 1]; + return path; +} + ++ (FParsedUrl *)parseUrl:(NSString *)url { + // For backwards compatibility, support URLs without schemes on iOS. + if (![url containsString:@"://"]) { + url = [@"http://" stringByAppendingString:url]; } - NSArray *parts = [host componentsSeparatedByString:@"."]; - if([parts count] == 3) { - NSInteger colonIndex = [[parts objectAtIndex:2] rangeOfString:@":"].location; - if (colonIndex != NSNotFound) { - // we have a port, use the provided scheme - secure = [scheme isEqualToString:@"https"]; - } else { - secure = YES; + NSString *originalPathString = [self extractPathFromUrlString:url]; + + // Sanitize the database URL by removing the path component, which may + // contain invalid URL characters. + NSString *sanitizedUrlWithoutPath = + [url stringByReplacingOccurrencesOfString:originalPathString + withString:@""]; + NSURLComponents *urlComponents = + [NSURLComponents componentsWithString:sanitizedUrlWithoutPath]; + if (!urlComponents) { + [NSException raise:@"Failed to parse database URL" + format:@"Failed to parse database URL: %@", url]; + } + + NSString *host = [urlComponents.host lowercaseString]; + NSString *namespace; + bool secure; + + if (urlComponents.port != nil) { + secure = [urlComponents.scheme isEqualToString:@"https"] || + [urlComponents.scheme isEqualToString:@"wss"]; + host = [host stringByAppendingFormat:@":%@", urlComponents.port]; + } else { + secure = YES; + }; + + NSArray *parts = [urlComponents.host componentsSeparatedByString:@"."]; + if ([parts count] == 3) { + namespace = [parts[0] lowercaseString]; + } else { + // Attempt to extract namespace from "ns" query param. + NSArray *queryItems = urlComponents.queryItems; + for (NSURLQueryItem *item in queryItems) { + if ([item.name isEqualToString:@"ns"]) { + namespace = item.value; + break; + } } - namespace = [[parts objectAtIndex:0] lowercaseString]; - NSString* pathString = [self decodePath:[NSString stringWithFormat:@"/%@", url]]; - path = [[FPath alloc] initWith:pathString]; - } - else { - [NSException raise:@"No Firebase database specified." format:@"No Firebase database found for input: %@", url]; + if (!namespace) { + namespace = [parts[0] lowercaseString]; + } } - FRepoInfo* repoInfo = [[FRepoInfo alloc] initWithHost:host isSecure:secure withNamespace:namespace]; + NSString *pathString = [self + decodePath:[NSString stringWithFormat:@"/%@", originalPathString]]; + FPath *path = [[FPath alloc] initWith:pathString]; + FRepoInfo *repoInfo = [[FRepoInfo alloc] initWithHost:host + isSecure:secure + withNamespace:namespace]; - FFLog(@"I-RDB095002", @"---> Parsed (%@) to: (%@,%@); ns=(%@); path=(%@)", original, [repoInfo description], [repoInfo connectionURL], repoInfo.namespace, [path description]); + FFLog(@"I-RDB095002", @"---> Parsed (%@) to: (%@,%@); ns=(%@); path=(%@)", + url, [repoInfo description], [repoInfo connectionURL], + repoInfo.namespace, [path description]); - FParsedUrl* parsedUrl = [[FParsedUrl alloc] init]; + FParsedUrl *parsedUrl = [[FParsedUrl alloc] init]; parsedUrl.repoInfo = repoInfo; parsedUrl.path = path; @@ -183,56 +220,55 @@ + (FParsedUrl *) parseUrl:(NSString *)url { case double: JDouble => priString + "number:" + double.num; case int: JInt => priString + "number:" + int.num; case _ => { - error("Leaf node has value '" + data.value + "' of invalid type '" + data.value.getClass.toString + "'"); + error("Leaf node has value '" + data.value + "' of invalid type '" + + data.value.getClass.toString + "'"); ""; } */ -+ (NSString *) getJavascriptType:(id)obj { ++ (NSString *)getJavascriptType:(id)obj { if ([obj isKindOfClass:[NSDictionary class]]) { return kJavaScriptObject; - } else if([obj isKindOfClass:[NSString class]]) { + } else if ([obj isKindOfClass:[NSString class]]) { return kJavaScriptString; - } - else if ([obj isKindOfClass:[NSNumber class]]) { + } else if ([obj isKindOfClass:[NSNumber class]]) { // We used to just compare to @encode(BOOL) as suggested at - // http://stackoverflow.com/questions/2518761/get-type-of-nsnumber, but on arm64, @encode(BOOL) returns "B" - // instead of "c" even though objCType still returns 'c' (signed char). So check both. - if(strcmp([obj objCType], @encode(BOOL)) == 0 || - strcmp([obj objCType], @encode(signed char)) == 0) { + // http://stackoverflow.com/questions/2518761/get-type-of-nsnumber, but + // on arm64, @encode(BOOL) returns "B" instead of "c" even though + // objCType still returns 'c' (signed char). So check both. + if (strcmp([obj objCType], @encode(BOOL)) == 0 || + strcmp([obj objCType], @encode(signed char)) == 0) { return kJavaScriptBoolean; - } - else { + } else { return kJavaScriptNumber; } - } - else { + } else { return kJavaScriptNull; } } -+ (NSError *) errorForStatus:(NSString *)status andReason:(NSString *)reason { ++ (NSError *)errorForStatus:(NSString *)status andReason:(NSString *)reason { static dispatch_once_t pred = 0; - __strong static NSDictionary* errorMap = nil; - __strong static NSDictionary* errorCodes = nil; + __strong static NSDictionary *errorMap = nil; + __strong static NSDictionary *errorCodes = nil; dispatch_once(&pred, ^{ - errorMap = @{ - @"permission_denied": @"Permission Denied", - @"unavailable": @"Service is unavailable", - kFErrorWriteCanceled: @"Write cancelled by user" - }; - errorCodes = @{ - @"permission_denied": @1, - @"unavailable": @2, - kFErrorWriteCanceled: @3 - }; + errorMap = @{ + @"permission_denied" : @"Permission Denied", + @"unavailable" : @"Service is unavailable", + kFErrorWriteCanceled : @"Write cancelled by user" + }; + errorCodes = @{ + @"permission_denied" : @1, + @"unavailable" : @2, + kFErrorWriteCanceled : @3 + }; }); if ([status isEqualToString:kFWPResponseForActionStatusOk]) { return nil; } else { NSInteger code; - NSString* desc = nil; + NSString *desc = nil; if (reason) { desc = reason; } else if ([errorMap objectForKey:status] != nil) { @@ -242,25 +278,28 @@ + (NSError *) errorForStatus:(NSString *)status andReason:(NSString *)reason { } if ([errorCodes objectForKey:status] != nil) { - NSNumber* num = [errorCodes objectForKey:status]; + NSNumber *num = [errorCodes objectForKey:status]; code = [num integerValue]; } else { // XXX what to do here? code = 9999; } - return [[NSError alloc] initWithDomain:kFErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey: desc}]; + return [[NSError alloc] + initWithDomain:kFErrorDomain + code:code + userInfo:@{NSLocalizedDescriptionKey : desc}]; } } -+ (NSNumber *) intForString:(NSString *)string { ++ (NSNumber *)intForString:(NSString *)string { static NSCharacterSet *notDigits = nil; if (!notDigits) { notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet]; } if ([string rangeOfCharacterFromSet:notDigits].length == 0) { NSInteger num; - NSScanner* scanner = [NSScanner scannerWithString:string]; + NSScanner *scanner = [NSScanner scannerWithString:string]; if ([scanner scanInteger:&num]) { return [NSNumber numberWithInteger:num]; } @@ -268,11 +307,11 @@ + (NSNumber *) intForString:(NSString *)string { return nil; } -+ (NSString *) ieee754StringForNumber:(NSNumber *)val { ++ (NSString *)ieee754StringForNumber:(NSNumber *)val { double d = [val doubleValue]; - NSData* data = [NSData dataWithBytes:&d length:sizeof(double)]; - NSMutableString* str = [[NSMutableString alloc] init]; - const unsigned char* buffer = (const unsigned char*)[data bytes]; + NSData *data = [NSData dataWithBytes:&d length:sizeof(double)]; + NSMutableString *str = [[NSMutableString alloc] init]; + const unsigned char *buffer = (const unsigned char *)[data bytes]; for (int i = 0; i < data.length; i++) { unsigned char byte = buffer[7 - i]; [str appendFormat:@"%02x", byte]; @@ -280,8 +319,10 @@ + (NSString *) ieee754StringForNumber:(NSNumber *)val { return str; } -static inline BOOL tryParseStringToInt(__unsafe_unretained NSString* str, NSInteger* integer) { - // First do some cheap checks (NOTE: The below checks are significantly faster than an equivalent regex :-( ). +static inline BOOL tryParseStringToInt(__unsafe_unretained NSString *str, + NSInteger *integer) { + // First do some cheap checks (NOTE: The below checks are significantly + // faster than an equivalent regex :-( ). NSUInteger length = str.length; if (length > 11 || length == 0) { return NO; @@ -296,14 +337,14 @@ static inline BOOL tryParseStringToInt(__unsafe_unretained NSString* str, NSInte negative = YES; i = 1; } - for(; i < length; i++) { + for (; i < length; i++) { unichar c = [str characterAtIndex:i]; // Must be a digit, or '-' if it's the first char. if (c < '0' || c > '9') { return NO; } else { int charValue = c - '0'; - value = value*10 + charValue; + value = value * 10 + charValue; } } @@ -317,25 +358,25 @@ static inline BOOL tryParseStringToInt(__unsafe_unretained NSString* str, NSInte } } -+ (NSString *) maxName { ++ (NSString *)maxName { static dispatch_once_t once; static NSString *maxName; dispatch_once(&once, ^{ - maxName = [[NSString alloc] initWithFormat:@"[MAX_NAME]"]; + maxName = [[NSString alloc] initWithFormat:@"[MAX_NAME]"]; }); return maxName; } -+ (NSString *) minName { ++ (NSString *)minName { static dispatch_once_t once; static NSString *minName; dispatch_once(&once, ^{ - minName = [[NSString alloc] initWithFormat:@"[MIN_NAME]"]; + minName = [[NSString alloc] initWithFormat:@"[MIN_NAME]"]; }); return minName; } -+ (NSComparisonResult) compareKey:(NSString *)a toKey:(NSString *)b { ++ (NSComparisonResult)compareKey:(NSString *)a toKey:(NSString *)b { if (a == b) { return NSOrderedSame; } else if (a == [FUtilities minName] || b == [FUtilities maxName]) { @@ -358,33 +399,35 @@ + (NSComparisonResult) compareKey:(NSString *)a toKey:(NSString *)b { return NSOrderedSame; } } else { - return (NSComparisonResult) NSOrderedAscending; + return (NSComparisonResult)NSOrderedAscending; } } else if (tryParseStringToInt(b, &bAsInt)) { - return (NSComparisonResult) NSOrderedDescending; + return (NSComparisonResult)NSOrderedDescending; } else { - // Perform literal character by character search to prevent a > b && b > a issues. - // Note that calling -(NSString *)decomposedStringWithCanonicalMapping also works. + // Perform literal character by character search to prevent a > b && + // b > a issues. Note that calling -(NSString + // *)decomposedStringWithCanonicalMapping also works. return [a compare:b options:NSLiteralSearch]; } } } -+ (NSComparator) keyComparator { - return ^NSComparisonResult(__unsafe_unretained NSString *a, __unsafe_unretained NSString *b) { - return [FUtilities compareKey:a toKey:b]; ++ (NSComparator)keyComparator { + return ^NSComparisonResult(__unsafe_unretained NSString *a, + __unsafe_unretained NSString *b) { + return [FUtilities compareKey:a toKey:b]; }; } -+ (NSComparator) stringComparator { - return ^NSComparisonResult(__unsafe_unretained NSString *a, __unsafe_unretained NSString *b) { - return [a compare:b]; ++ (NSComparator)stringComparator { + return ^NSComparisonResult(__unsafe_unretained NSString *a, + __unsafe_unretained NSString *b) { + return [a compare:b]; }; } -+ (double) randomDouble { - return ((double) arc4random() / ARC4RANDOM_MAX); ++ (double)randomDouble { + return ((double)arc4random() / ARC4RANDOM_MAX); } @end - diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FValidation.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FValidation.h index faa8f76..276eb26 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FValidation.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FValidation.h @@ -14,32 +14,42 @@ * limitations under the License. */ -#import -#import "FPath.h" #import "FIRDataEventType.h" #import "FParsedUrl.h" +#import "FPath.h" #import "FTypedefs.h" +#import @interface FValidation : NSObject -+ (void) validateFrom:(NSString *)fn writablePath:(FPath *)path; -+ (void) validateFrom:(NSString *)fn knownEventType:(FIRDataEventType)event; -+ (void) validateFrom:(NSString *)fn validPathString:(NSString *)pathString; -+ (void) validateFrom:(NSString *)fn validRootPathString:(NSString *)pathString; -+ (void) validateFrom:(NSString *)fn validKey:(NSString *)key; -+ (void) validateFrom:(NSString *)fn validURL:(FParsedUrl *)parsedUrl; ++ (void)validateFrom:(NSString *)fn writablePath:(FPath *)path; ++ (void)validateFrom:(NSString *)fn knownEventType:(FIRDataEventType)event; ++ (void)validateFrom:(NSString *)fn validPathString:(NSString *)pathString; ++ (void)validateFrom:(NSString *)fn validRootPathString:(NSString *)pathString; ++ (void)validateFrom:(NSString *)fn validKey:(NSString *)key; ++ (void)validateFrom:(NSString *)fn validURL:(FParsedUrl *)parsedUrl; -+ (void) validateToken:(NSString *)token; ++ (void)validateToken:(NSString *)token; // Functions for handling passing errors back -+ (void) handleError:(NSError *)error withUserCallback:(fbt_void_nserror_id)userCallback; -+ (void) handleError:(NSError *)error withSuccessCallback:(fbt_void_nserror)userCallback; ++ (void)handleError:(NSError *)error + withUserCallback:(fbt_void_nserror_id)userCallback; ++ (void)handleError:(NSError *)error + withSuccessCallback:(fbt_void_nserror)userCallback; // Functions used for validating while creating snapshots in FSnapshotUtilities -+ (BOOL) validateFrom:(NSString*)fn isValidLeafValue:(id)value withPath:(NSArray*)path; -+ (void) validateFrom:(NSString*)fn validDictionaryKey:(id)keyId withPath:(NSArray*)path; -+ (void) validateFrom:(NSString*)fn validUpdateDictionaryKey:(id)keyId withValue:(id)value; -+ (void) validateFrom:(NSString*)fn isValidPriorityValue:(id)value withPath:(NSArray*)path; -+ (BOOL) validatePriorityValue:value; ++ (BOOL)validateFrom:(NSString *)fn + isValidLeafValue:(id)value + withPath:(NSArray *)path; ++ (void)validateFrom:(NSString *)fn + validDictionaryKey:(id)keyId + withPath:(NSArray *)path; ++ (void)validateFrom:(NSString *)fn + validUpdateDictionaryKey:(id)keyId + withValue:(id)value; ++ (void)validateFrom:(NSString *)fn + isValidPriorityValue:(id)value + withPath:(NSArray *)path; ++ (BOOL)validatePriorityValue:value; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FValidation.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FValidation.m index f088da2..c700b9c 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FValidation.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/FValidation.m @@ -19,97 +19,135 @@ #import "FParsedUrl.h" #import "FTypedefs.h" - // Have to escape: * ? + [ ( ) { } ^ $ | \ . / -// See: https://developer.apple.com/library/mac/#documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html +// See: +// https://developer.apple.com/library/mac/#documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html NSString *const kInvalidPathCharacters = @"[].#$"; -NSString *const kInvalidKeyCharacters = @"[].#$/"; +NSString *const kInvalidKeyCharacters = @"[].#$/"; @implementation FValidation -+ (void) validateFrom:(NSString *)fn writablePath:(FPath *)path { - if([[path getFront] isEqualToString:kDotInfoPrefix]) { - @throw [[NSException alloc] initWithName:@"WritablePathValidation" reason:[NSString stringWithFormat:@"(%@) failed to path %@: Can't modify data under %@", fn, [path description], kDotInfoPrefix] userInfo:nil]; ++ (void)validateFrom:(NSString *)fn writablePath:(FPath *)path { + if ([[path getFront] isEqualToString:kDotInfoPrefix]) { + @throw [[NSException alloc] + initWithName:@"WritablePathValidation" + reason:[NSString + stringWithFormat:@"(%@) failed to path %@: Can't " + @"modify data under %@", + fn, [path description], + kDotInfoPrefix] + userInfo:nil]; } } -+ (void) validateFrom:(NSString*)fn knownEventType:(FIRDataEventType)event { ++ (void)validateFrom:(NSString *)fn knownEventType:(FIRDataEventType)event { switch (event) { - case FIRDataEventTypeValue: - case FIRDataEventTypeChildAdded: - case FIRDataEventTypeChildChanged: - case FIRDataEventTypeChildMoved: - case FIRDataEventTypeChildRemoved: - return; - break; - default: - @throw [[NSException alloc] initWithName:@"KnownEventTypeValidation" reason:[NSString stringWithFormat:@"(%@) Unknown event type: %d", fn, (int) event] userInfo:nil]; - break; + case FIRDataEventTypeValue: + case FIRDataEventTypeChildAdded: + case FIRDataEventTypeChildChanged: + case FIRDataEventTypeChildMoved: + case FIRDataEventTypeChildRemoved: + return; + break; + default: + @throw [[NSException alloc] + initWithName:@"KnownEventTypeValidation" + reason:[NSString + stringWithFormat:@"(%@) Unknown event type: %d", + fn, (int)event] + userInfo:nil]; + break; } } -+ (BOOL) isValidPathString:(NSString *)pathString { ++ (BOOL)isValidPathString:(NSString *)pathString { static dispatch_once_t token; static NSCharacterSet *badPathChars = nil; dispatch_once(&token, ^{ - badPathChars = [NSCharacterSet characterSetWithCharactersInString:kInvalidPathCharacters]; + badPathChars = [NSCharacterSet + characterSetWithCharactersInString:kInvalidPathCharacters]; }); return pathString != nil && [pathString length] != 0 && - [pathString rangeOfCharacterFromSet:badPathChars].location == NSNotFound; + [pathString rangeOfCharacterFromSet:badPathChars].location == + NSNotFound; } -+ (void) validateFrom:(NSString *)fn validPathString:(NSString *)pathString { - if(! [self isValidPathString:pathString]) { - @throw [[NSException alloc] initWithName:@"InvalidPathValidation" reason:[NSString stringWithFormat:@"(%@) Must be a non-empty string and not contain '.' '#' '$' '[' or ']'", fn] userInfo:nil]; ++ (void)validateFrom:(NSString *)fn validPathString:(NSString *)pathString { + if (![self isValidPathString:pathString]) { + @throw [[NSException alloc] + initWithName:@"InvalidPathValidation" + reason:[NSString stringWithFormat: + @"(%@) Must be a non-empty string and " + @"not contain '.' '#' '$' '[' or ']'", + fn] + userInfo:nil]; } } -+ (void) validateFrom:(NSString *)fn validRootPathString:(NSString *)pathString { ++ (void)validateFrom:(NSString *)fn validRootPathString:(NSString *)pathString { static dispatch_once_t token; static NSRegularExpression *dotInfoRegex = nil; dispatch_once(&token, ^{ - dotInfoRegex = [NSRegularExpression regularExpressionWithPattern:@"^\\/*\\.info(\\/|$)" options:0 error:nil]; + dotInfoRegex = [NSRegularExpression + regularExpressionWithPattern:@"^\\/*\\.info(\\/|$)" + options:0 + error:nil]; }); NSString *tempPath = pathString; - // HACK: Obj-C regex are kinda' slow. Do a plain string search first before bothering with the regex. + // HACK: Obj-C regex are kinda' slow. Do a plain string search first before + // bothering with the regex. if ([pathString rangeOfString:@".info"].location != NSNotFound) { - tempPath = [dotInfoRegex stringByReplacingMatchesInString:pathString options:0 range:NSMakeRange(0, pathString.length) withTemplate:@"/"]; + tempPath = [dotInfoRegex + stringByReplacingMatchesInString:pathString + options:0 + range:NSMakeRange(0, pathString.length) + withTemplate:@"/"]; } [self validateFrom:fn validPathString:tempPath]; } -+ (BOOL) isValidKey:(NSString *)key { ++ (BOOL)isValidKey:(NSString *)key { static dispatch_once_t token; static NSCharacterSet *badKeyChars = nil; dispatch_once(&token, ^{ - badKeyChars = [NSCharacterSet characterSetWithCharactersInString:kInvalidKeyCharacters]; + badKeyChars = [NSCharacterSet + characterSetWithCharactersInString:kInvalidKeyCharacters]; }); - return key != nil && key.length > 0 && [key rangeOfCharacterFromSet:badKeyChars].location == NSNotFound; + return key != nil && key.length > 0 && + [key rangeOfCharacterFromSet:badKeyChars].location == NSNotFound; } -+ (void) validateFrom:(NSString *)fn validKey:(NSString *)key { ++ (void)validateFrom:(NSString *)fn validKey:(NSString *)key { if (![self isValidKey:key]) { - @throw [[NSException alloc] initWithName:@"InvalidKeyValidation" reason:[NSString stringWithFormat:@"(%@) Must be a non-empty string and not contain '/' '.' '#' '$' '[' or ']'", fn] userInfo:nil]; + @throw [[NSException alloc] + initWithName:@"InvalidKeyValidation" + reason:[NSString + stringWithFormat: + @"(%@) Must be a non-empty string and not " + @"contain '/' '.' '#' '$' '[' or ']'", + fn] + userInfo:nil]; } } -+ (void) validateFrom:(NSString *)fn validURL:(FParsedUrl *)parsedUrl { - NSString* pathString = [parsedUrl.path description]; ++ (void)validateFrom:(NSString *)fn validURL:(FParsedUrl *)parsedUrl { + NSString *pathString = [parsedUrl.path description]; [self validateFrom:fn validRootPathString:pathString]; } #pragma mark - #pragma mark Authentication validation -+ (BOOL) stringNonempty:(NSString *)str { ++ (BOOL)stringNonempty:(NSString *)str { return str != nil && ![str isKindOfClass:[NSNull class]] && str.length > 0; } -+ (void) validateToken:(NSString *)token { ++ (void)validateToken:(NSString *)token { if (![FValidation stringNonempty:token]) { - [NSException raise:NSInvalidArgumentException format:@"Can't have empty string or nil for custom token"]; + [NSException raise:NSInvalidArgumentException + format:@"Can't have empty string or nil for custom token"]; } } @@ -117,22 +155,24 @@ + (void) validateToken:(NSString *)token { #pragma mark Handling authentication errors /** -* This function immediately calls the callback. -* It assumes that it is not on FirebaseWorker thread. -* It assumes it's on a user-controlled thread. -*/ -+ (void) handleError:(NSError *)error withUserCallback:(fbt_void_nserror_id)userCallback { + * This function immediately calls the callback. + * It assumes that it is not on FirebaseWorker thread. + * It assumes it's on a user-controlled thread. + */ ++ (void)handleError:(NSError *)error + withUserCallback:(fbt_void_nserror_id)userCallback { if (userCallback) { userCallback(error, nil); } } /** -* This function immediately calls the callback. -* It assumes that it is not on FirebaseWorker thread. -* It assumes it's on a user-controlled thread. -*/ -+ (void) handleError:(NSError *)error withSuccessCallback:(fbt_void_nserror)userCallback { + * This function immediately calls the callback. + * It assumes that it is not on FirebaseWorker thread. + * It assumes it's on a user-controlled thread. + */ ++ (void)handleError:(NSError *)error + withSuccessCallback:(fbt_void_nserror)userCallback { if (userCallback) { userCallback(error); } @@ -141,17 +181,29 @@ + (void) handleError:(NSError *)error withSuccessCallback:(fbt_void_nserror)user #pragma mark - #pragma mark Snapshot validation -+ (BOOL) validateFrom:(NSString*)fn isValidLeafValue:(id)value withPath:(NSArray*)path { ++ (BOOL)validateFrom:(NSString *)fn + isValidLeafValue:(id)value + withPath:(NSArray *)path { if ([value isKindOfClass:[NSString class]]) { // Try to avoid conversion to bytes if possible - NSString* theString = value; - if ([theString maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] > kFirebaseMaxLeafSize && - [theString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] > kFirebaseMaxLeafSize) { + NSString *theString = value; + if ([theString maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] > + kFirebaseMaxLeafSize && + [theString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] > + kFirebaseMaxLeafSize) { NSRange range; range.location = 0; range.length = MIN(path.count, 50); - NSString* pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; - @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) String exceeds max size of %u utf8 bytes: %@", fn, (int)kFirebaseMaxLeafSize, pathString] userInfo:nil]; + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat:@"(%@) String exceeds max " + @"size of %u utf8 bytes: %@", + fn, (int)kFirebaseMaxLeafSize, + pathString] + userInfo:nil]; } return YES; } @@ -162,21 +214,35 @@ + (BOOL) validateFrom:(NSString*)fn isValidLeafValue:(id)value withPath:(NSArray NSRange range; range.location = 0; range.length = MIN(path.count, 50); - NSString* pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; - @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Cannot store NaN at path: %@.", fn, pathString] userInfo:nil]; + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Cannot store NaN at path: %@.", fn, + pathString] + userInfo:nil]; } return YES; } else if ([value isKindOfClass:[NSDictionary class]]) { - NSDictionary* dval = value; + NSDictionary *dval = value; if (dval[kServerValueSubKey] != nil) { if ([dval count] > 1) { NSRange range; range.location = 0; range.length = MIN(path.count, 50); - NSString* pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; - @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Cannot store other keys with server value keys.%@.", fn, pathString] userInfo:nil]; + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Cannot store other keys " + @"with server value keys.%@.", + fn, pathString] + userInfo:nil]; } return YES; } @@ -191,84 +257,144 @@ + (BOOL) validateFrom:(NSString*)fn isValidLeafValue:(id)value withPath:(NSArray return NO; } -+ (NSString*) parseAndValidateKey:(id)keyId fromFunction:(NSString*)fn path:(NSArray*)path { ++ (NSString *)parseAndValidateKey:(id)keyId + fromFunction:(NSString *)fn + path:(NSArray *)path { if (![keyId isKindOfClass:[NSString class]]) { NSRange range; range.location = 0; range.length = MIN(path.count, 50); - NSString* pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; - @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Non-string keys are not allowed in object at path: %@", fn, pathString] userInfo:nil]; + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat:@"(%@) Non-string keys are not " + @"allowed in object at path: %@", + fn, pathString] + userInfo:nil]; } - return (NSString*)keyId; + return (NSString *)keyId; } -+ (void) validateFrom:(NSString*)fn validDictionaryKey:(id)keyId withPath:(NSArray*)path { ++ (void)validateFrom:(NSString *)fn + validDictionaryKey:(id)keyId + withPath:(NSArray *)path { NSString *key = [self parseAndValidateKey:keyId fromFunction:fn path:path]; - if (![key isEqualToString:kPayloadPriority] && ![key isEqualToString:kPayloadValue] && ![key isEqualToString:kServerValueSubKey] && ![FValidation isValidKey:key]) { + if (![key isEqualToString:kPayloadPriority] && + ![key isEqualToString:kPayloadValue] && + ![key isEqualToString:kServerValueSubKey] && + ![FValidation isValidKey:key]) { NSRange range; range.location = 0; range.length = MIN(path.count, 50); - NSString *pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; - @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Invalid key in object at path: %@. Keys must be non-empty and cannot contain '/' '.' '#' '$' '[' or ']'", fn, pathString] userInfo:nil]; + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Invalid key in object at path: " + @"%@. Keys must be non-empty and cannot " + @"contain '/' '.' '#' '$' '[' or ']'", + fn, pathString] + userInfo:nil]; } } -+ (void) validateFrom:(NSString*)fn validUpdateDictionaryKey:(id)keyId withValue:(id)value { - FPath *path = [FPath pathWithString:[self parseAndValidateKey:keyId fromFunction:fn path:@[]]]; ++ (void)validateFrom:(NSString *)fn + validUpdateDictionaryKey:(id)keyId + withValue:(id)value { + FPath *path = [FPath pathWithString:[self parseAndValidateKey:keyId + fromFunction:fn + path:@[]]]; __block NSInteger keyNum = 0; - [path enumerateComponentsUsingBlock:^void (NSString *key, BOOL *stop) { - if ([key isEqualToString:kPayloadPriority] && keyNum == [path length] - 1) { - [self validateFrom:fn isValidPriorityValue:value withPath:@[]]; - } else { + [path enumerateComponentsUsingBlock:^void(NSString *key, BOOL *stop) { + if ([key isEqualToString:kPayloadPriority] && + keyNum == [path length] - 1) { + [self validateFrom:fn isValidPriorityValue:value withPath:@[]]; + } else { keyNum++; if (![FValidation isValidKey:key]) { - @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Invalid key in object. Keys must be non-empty and cannot contain '.' '#' '$' '[' or ']'", fn] userInfo:nil]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Invalid key in object. Keys must " + @"be non-empty and cannot contain '.' " + @"'#' '$' '[' or ']'", + fn] + userInfo:nil]; } - } + } }]; } -+ (void) validateFrom:(NSString*)fn isValidPriorityValue:(id)value withPath:(NSArray*)path { - [self validateFrom:fn isValidPriorityValue:value withPath:path throwError:YES]; ++ (void)validateFrom:(NSString *)fn + isValidPriorityValue:(id)value + withPath:(NSArray *)path { + [self validateFrom:fn + isValidPriorityValue:value + withPath:path + throwError:YES]; } /** -* Returns YES if priority is valid. -*/ + * Returns YES if priority is valid. + */ + (BOOL)validatePriorityValue:value { - return [self validateFrom:nil isValidPriorityValue:value withPath:nil throwError:NO]; + return [self validateFrom:nil + isValidPriorityValue:value + withPath:nil + throwError:NO]; } /** -* Helper for validating priorities. If passed YES for throwError, it'll throw descriptive errors on validation -* problems. Else, it'll just return YES/NO. -*/ -+ (BOOL) validateFrom:(NSString*)fn isValidPriorityValue:(id)value withPath:(NSArray*)path throwError:(BOOL)throwError { + * Helper for validating priorities. If passed YES for throwError, it'll throw + * descriptive errors on validation problems. Else, it'll just return YES/NO. + */ ++ (BOOL)validateFrom:(NSString *)fn + isValidPriorityValue:(id)value + withPath:(NSArray *)path + throwError:(BOOL)throwError { if ([value isKindOfClass:[NSNumber class]]) { if ([[NSDecimalNumber notANumber] isEqualToNumber:value]) { if (throwError) { NSRange range; range.location = 0; range.length = MIN(path.count, 50); - NSString *pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; - @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Cannot store NaN as priority at path: %@.", fn, pathString] userInfo:nil]; + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Cannot store NaN as " + @"priority at path: %@.", + fn, pathString] + userInfo:nil]; } else { return NO; } - } else if (value == (id) kCFBooleanFalse || value == (id) kCFBooleanTrue) { + } else if (value == (id)kCFBooleanFalse || + value == (id)kCFBooleanTrue) { if (throwError) { NSRange range; range.location = 0; range.length = MIN(path.count, 50); - NSString *pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; - @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Cannot store true/false as priority at path: %@.", fn, pathString] userInfo:nil]; + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Cannot store true/false " + @"as priority at path: %@.", + fn, pathString] + userInfo:nil]; } else { return NO; } } - } - else if ([value isKindOfClass:[NSDictionary class]]) { + } else if ([value isKindOfClass:[NSDictionary class]]) { NSDictionary *dval = value; if (dval[kServerValueSubKey] != nil) { if ([dval count] > 1) { @@ -276,8 +402,17 @@ + (BOOL) validateFrom:(NSString*)fn isValidPriorityValue:(id)value withPath:(NSA NSRange range; range.location = 0; range.length = MIN(path.count, 50); - NSString *pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; - @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Cannot store other keys with server value keys as priority at path: %@.", fn, pathString] userInfo:nil]; + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Cannot store other keys " + @"with server value keys as " + @"priority at path: %@.", + fn, pathString] + userInfo:nil]; } else { return NO; } @@ -287,20 +422,34 @@ + (BOOL) validateFrom:(NSString*)fn isValidPriorityValue:(id)value withPath:(NSA NSRange range; range.location = 0; range.length = MIN(path.count, 50); - NSString *pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; - @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Cannot store an NSDictionary as priority at path: %@.", fn, pathString] userInfo:nil]; + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Cannot store an NSDictionary " + @"as priority at path: %@.", + fn, pathString] + userInfo:nil]; } else { return NO; } } - } - else if ([value isKindOfClass:[NSArray class]]) { + } else if ([value isKindOfClass:[NSArray class]]) { if (throwError) { NSRange range; range.location = 0; range.length = MIN(path.count, 50); - NSString *pathString = [[path subarrayWithRange:range] componentsJoinedByString:@"."]; - @throw [[NSException alloc] initWithName:@"InvalidFirebaseData" reason:[NSString stringWithFormat:@"(%@) Cannot store an NSArray as priority at path: %@.", fn, pathString] userInfo:nil]; + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Cannot store an NSArray as " + @"priority at path: %@.", + fn, pathString] + userInfo:nil]; } else { return NO; } diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleBoolBlock.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleBoolBlock.h index bceeed2..f5c0859 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleBoolBlock.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleBoolBlock.h @@ -14,12 +14,12 @@ * limitations under the License. */ -#import #import "FTypedefs.h" +#import @interface FTupleBoolBlock : NSObject -@property (nonatomic, readwrite) BOOL boolean; -@property (nonatomic, copy) fbt_void_void block; +@property(nonatomic, readwrite) BOOL boolean; +@property(nonatomic, copy) fbt_void_void block; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleCallbackStatus.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleCallbackStatus.h index 6ec2375..bd8c4a9 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleCallbackStatus.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleCallbackStatus.h @@ -14,11 +14,11 @@ * limitations under the License. */ -#import #import "FTypedefs_Private.h" +#import @interface FTupleCallbackStatus : NSObject -@property (nonatomic, copy) fbt_void_nsstring_nsstring block; -@property (nonatomic) NSString* status; -@property (nonatomic) NSString* errorReason; +@property(nonatomic, copy) fbt_void_nsstring_nsstring block; +@property(nonatomic) NSString *status; +@property(nonatomic) NSString *errorReason; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleFirebase.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleFirebase.h index ff84bbb..5e41f9e 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleFirebase.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleFirebase.h @@ -14,13 +14,13 @@ * limitations under the License. */ -#import #import "FIRDatabaseReference.h" +#import @interface FTupleFirebase : NSObject -@property (nonatomic, strong) FIRDatabaseReference * one; -@property (nonatomic, strong) FIRDatabaseReference * two; -@property (nonatomic, strong) FIRDatabaseReference * three; +@property(nonatomic, strong) FIRDatabaseReference *one; +@property(nonatomic, strong) FIRDatabaseReference *two; +@property(nonatomic, strong) FIRDatabaseReference *three; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleNodePath.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleNodePath.h index fbf62c7..19b5217 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleNodePath.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleNodePath.h @@ -14,15 +14,15 @@ * limitations under the License. */ -#import -#import "FPath.h" #import "FNode.h" +#import "FPath.h" +#import @interface FTupleNodePath : NSObject -@property (nonatomic, strong) FPath* path; -@property (nonatomic, strong) id node; +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) id node; -- (id) initWithNode:(id)aNode andPath:(FPath *)aPath; +- (id)initWithNode:(id)aNode andPath:(FPath *)aPath; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleNodePath.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleNodePath.m index eefc0c2..620ae76 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleNodePath.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleNodePath.m @@ -21,7 +21,7 @@ @implementation FTupleNodePath @synthesize path; @synthesize node; -- (id) initWithNode:(id)aNode andPath:(FPath *)aPath { +- (id)initWithNode:(id)aNode andPath:(FPath *)aPath { self = [super init]; if (self) { self.path = aPath; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleObjectNode.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleObjectNode.h index 6fcb746..1717a22 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleObjectNode.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleObjectNode.h @@ -14,14 +14,14 @@ * limitations under the License. */ -#import #import "FNode.h" +#import @interface FTupleObjectNode : NSObject - (id)initWithObject:(id)aObj andNode:(id)aNode; -@property (nonatomic, strong) id node; -@property (nonatomic, strong) id obj; +@property(nonatomic, strong) id node; +@property(nonatomic, strong) id obj; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleObjects.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleObjects.h index 4ff1fcf..05b3141 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleObjects.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleObjects.h @@ -18,7 +18,7 @@ @interface FTupleObjects : NSObject -@property (nonatomic, strong) id objA; -@property (nonatomic, strong) id objB; +@property(nonatomic, strong) id objA; +@property(nonatomic, strong) id objB; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleOnDisconnect.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleOnDisconnect.h index 91ad5e4..e68ab71 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleOnDisconnect.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleOnDisconnect.h @@ -14,14 +14,14 @@ * limitations under the License. */ -#import #import "FTypedefs_Private.h" +#import @interface FTupleOnDisconnect : NSObject -@property (strong, nonatomic) NSString* pathString; -@property (strong, nonatomic) NSString* action; -@property (strong, nonatomic) id data; -@property (strong, nonatomic) fbt_void_nsstring_nsstring onComplete; +@property(strong, nonatomic) NSString *pathString; +@property(strong, nonatomic) NSString *action; +@property(strong, nonatomic) id data; +@property(strong, nonatomic) fbt_void_nsstring_nsstring onComplete; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTuplePathValue.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTuplePathValue.h index f7ed423..b0a515c 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTuplePathValue.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTuplePathValue.h @@ -19,7 +19,7 @@ @class FPath; @interface FTuplePathValue : NSObject -@property (nonatomic, strong, readonly) FPath *path; -@property (nonatomic, strong, readonly) id value; -- (id) initWithPath:(FPath *)aPath value:(id)aValue; +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) id value; +- (id)initWithPath:(FPath *)aPath value:(id)aValue; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTuplePathValue.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTuplePathValue.m index 49240aa..91de883 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTuplePathValue.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTuplePathValue.m @@ -18,15 +18,15 @@ #import "FPath.h" @interface FTuplePathValue () -@property (nonatomic, strong, readwrite) id value; -@property (nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, strong, readwrite) id value; +@property(nonatomic, strong, readwrite) FPath *path; @end @implementation FTuplePathValue @synthesize path; @synthesize value; -- (id) initWithPath:(FPath *)aPath value:(id)aValue { +- (id)initWithPath:(FPath *)aPath value:(id)aValue { self = [super init]; if (self) { self.value = aValue; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleRemovedQueriesEvents.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleRemovedQueriesEvents.h index f986916..7269c2f 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleRemovedQueriesEvents.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleRemovedQueriesEvents.h @@ -18,13 +18,13 @@ @interface FTupleRemovedQueriesEvents : NSObject /** -* `FIRDatabaseQuery`s removed with [SyncPoint removeEventRegistration:] -*/ -@property (nonatomic, strong, readonly) NSArray *removedQueries; + * `FIRDatabaseQuery`s removed with [SyncPoint removeEventRegistration:] + */ +@property(nonatomic, strong, readonly) NSArray *removedQueries; /** -* cancel events as FEvent -*/ -@property (nonatomic, strong, readonly) NSArray *cancelEvents; + * cancel events as FEvent + */ +@property(nonatomic, strong, readonly) NSArray *cancelEvents; -- (id) initWithRemovedQueries:(NSArray *)removed cancelEvents:(NSArray *)events; +- (id)initWithRemovedQueries:(NSArray *)removed cancelEvents:(NSArray *)events; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleRemovedQueriesEvents.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleRemovedQueriesEvents.m index 818d16b..324cfcb 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleRemovedQueriesEvents.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleRemovedQueriesEvents.m @@ -17,15 +17,15 @@ #import "FTupleRemovedQueriesEvents.h" @interface FTupleRemovedQueriesEvents () -@property (nonatomic, strong, readwrite) NSArray *removedQueries; -@property (nonatomic, strong, readwrite) NSArray *cancelEvents; +@property(nonatomic, strong, readwrite) NSArray *removedQueries; +@property(nonatomic, strong, readwrite) NSArray *cancelEvents; @end @implementation FTupleRemovedQueriesEvents @synthesize removedQueries; @synthesize cancelEvents; -- (id) initWithRemovedQueries:(NSArray *)removed cancelEvents:(NSArray *)events { +- (id)initWithRemovedQueries:(NSArray *)removed cancelEvents:(NSArray *)events { self = [super init]; if (self) { self.removedQueries = removed; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleSetIdPath.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleSetIdPath.h index 5133d6d..337f8d6 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleSetIdPath.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleSetIdPath.h @@ -14,14 +14,14 @@ * limitations under the License. */ -#import #import "FPath.h" +#import @interface FTupleSetIdPath : NSObject -- (id) initWithSetId:(NSNumber *)aSetId andPath:(FPath *)aPath; +- (id)initWithSetId:(NSNumber *)aSetId andPath:(FPath *)aPath; -@property (strong, nonatomic) NSNumber* setId; -@property (strong, nonatomic) FPath* path; +@property(strong, nonatomic) NSNumber *setId; +@property(strong, nonatomic) FPath *path; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleSetIdPath.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleSetIdPath.m index 5d3312b..2763c83 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleSetIdPath.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleSetIdPath.m @@ -21,7 +21,7 @@ @implementation FTupleSetIdPath @synthesize path; @synthesize setId; -- (id) initWithSetId:(NSNumber *)aSetId andPath:(FPath *)aPath { +- (id)initWithSetId:(NSNumber *)aSetId andPath:(FPath *)aPath { self = [super init]; if (self) { self.setId = aSetId; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleStringNode.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleStringNode.h index e3fec80..0e3d7fa 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleStringNode.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleStringNode.h @@ -14,14 +14,14 @@ * limitations under the License. */ -#import #import "FNode.h" +#import @interface FTupleStringNode : NSObject - (id)initWithString:(NSString *)aString andNode:(id)aNode; -@property (nonatomic, strong) id node; -@property (nonatomic, strong) NSString* string; +@property(nonatomic, strong) id node; +@property(nonatomic, strong) NSString *string; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleStringNode.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleStringNode.m index f058a8e..d820ef8 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleStringNode.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleStringNode.m @@ -30,5 +30,4 @@ - (id)initWithString:(NSString *)aString andNode:(id)aNode { return self; } - @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleTSN.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleTSN.h index bc62b2d..b1052da 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleTSN.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleTSN.h @@ -14,12 +14,12 @@ * limitations under the License. */ -#import #import "FTupleStringNode.h" +#import @interface FTupleTSN : NSObject -@property (nonatomic, strong) FTupleStringNode* from; -@property (nonatomic, strong) FTupleStringNode* to; +@property(nonatomic, strong) FTupleStringNode *from; +@property(nonatomic, strong) FTupleStringNode *to; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleTransaction.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleTransaction.h index c9dcf4b..82f4495 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleTransaction.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleTransaction.h @@ -14,61 +14,62 @@ * limitations under the License. */ -#import #import "FPath.h" -#import "FTypedefs_Private.h" #import "FTypedefs.h" +#import "FTypedefs_Private.h" +#import @interface FTupleTransaction : NSObject -@property (nonatomic, strong) FPath* path; -@property (nonatomic, copy) fbt_transactionresult_mutabledata update; -@property (nonatomic, copy) fbt_void_nserror_bool_datasnapshot onComplete; -@property (nonatomic) FTransactionStatus status; +@property(nonatomic, strong) FPath *path; +@property(nonatomic, copy) fbt_transactionresult_mutabledata update; +@property(nonatomic, copy) fbt_void_nserror_bool_datasnapshot onComplete; +@property(nonatomic) FTransactionStatus status; /** -* Used when combining transaction at different locations to figure out which one goes first. -*/ -@property (nonatomic, strong) NSNumber* order; + * Used when combining transaction at different locations to figure out which + * one goes first. + */ +@property(nonatomic, strong) NSNumber *order; /** -* Whether to raise local events for this transaction -*/ -@property (nonatomic) BOOL applyLocally; + * Whether to raise local events for this transaction + */ +@property(nonatomic) BOOL applyLocally; /** -* Count how many times we've retried the transaction -*/ -@property (nonatomic) int retryCount; + * Count how many times we've retried the transaction + */ +@property(nonatomic) int retryCount; /** -* Function to call to clean up our listener -*/ -@property (nonatomic, copy) fbt_void_void unwatcher; + * Function to call to clean up our listener + */ +@property(nonatomic, copy) fbt_void_void unwatcher; /** -* Stores why a transaction was aborted -*/ -@property (nonatomic, strong, readonly) NSString* abortStatus; -@property (nonatomic, strong, readonly) NSString* abortReason; + * Stores why a transaction was aborted + */ +@property(nonatomic, strong, readonly) NSString *abortStatus; +@property(nonatomic, strong, readonly) NSString *abortReason; - (void)setAbortStatus:(NSString *)abortStatus reason:(NSString *)reason; - (NSError *)abortError; -@property (nonatomic, strong) NSNumber *currentWriteId; +@property(nonatomic, strong) NSNumber *currentWriteId; /** -* Stores the input snapshot, before the update -*/ -@property (nonatomic, strong) id currentInputSnapshot; + * Stores the input snapshot, before the update + */ +@property(nonatomic, strong) id currentInputSnapshot; /** -* Stores the unresolved (for server values) output snapshot, after the update -*/ -@property (nonatomic, strong) id currentOutputSnapshotRaw; + * Stores the unresolved (for server values) output snapshot, after the update + */ +@property(nonatomic, strong) id currentOutputSnapshotRaw; /** * Stores the resolved (for server values) output snapshot, after the update */ -@property (nonatomic, strong) id currentOutputSnapshotResolved; +@property(nonatomic, strong) id currentOutputSnapshotResolved; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleTransaction.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleTransaction.m index bcff54e..68977ef 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleTransaction.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleTransaction.m @@ -19,8 +19,8 @@ @interface FTupleTransaction () -@property (nonatomic, strong) NSString *abortStatus; -@property (nonatomic, strong) NSString *abortReason; +@property(nonatomic, strong) NSString *abortStatus; +@property(nonatomic, strong) NSString *abortReason; @end @@ -32,7 +32,10 @@ - (void)setAbortStatus:(NSString *)abortStatus reason:(NSString *)reason { } - (NSError *)abortError { - return (self.abortStatus != nil) ? [FUtilities errorForStatus:self.abortStatus andReason:self.abortReason] : nil; + return (self.abortStatus != nil) + ? [FUtilities errorForStatus:self.abortStatus + andReason:self.abortReason] + : nil; } @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleUserCallback.h b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleUserCallback.h index d598217..b94eef6 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleUserCallback.h +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleUserCallback.h @@ -14,18 +14,19 @@ * limitations under the License. */ -#import -#import "FTypedefs.h" #import "FQueryParams.h" +#import "FTypedefs.h" +#import @interface FTupleUserCallback : NSObject -- (id) initWithHandle:(NSUInteger)handle; +- (id)initWithHandle:(NSUInteger)handle; -@property (nonatomic, copy) fbt_void_datasnapshot_nsstring datasnapshotPrevnameCallback; -@property (nonatomic, copy) fbt_void_datasnapshot datasnapshotCallback; -@property (nonatomic, copy) fbt_void_nserror cancelCallback; -@property (nonatomic, copy) FQueryParams* queryParams; -@property (nonatomic) NSUInteger handle; +@property(nonatomic, copy) + fbt_void_datasnapshot_nsstring datasnapshotPrevnameCallback; +@property(nonatomic, copy) fbt_void_datasnapshot datasnapshotCallback; +@property(nonatomic, copy) fbt_void_nserror cancelCallback; +@property(nonatomic, copy) FQueryParams *queryParams; +@property(nonatomic) NSUInteger handle; @end diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleUserCallback.m b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleUserCallback.m index dc33bbd..ba5861f 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleUserCallback.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/Utilities/Tuples/FTupleUserCallback.m @@ -24,7 +24,7 @@ @implementation FTupleUserCallback @synthesize queryParams; @synthesize handle; -- (id) initWithHandle:(NSUInteger)theHandle { +- (id)initWithHandle:(NSUInteger)theHandle { self = [super init]; if (self) { self.handle = theHandle; diff --git a/Example/Pods/FirebaseDatabase/Firebase/Database/third_party/SocketRocket/FSRWebSocket.m b/Example/Pods/FirebaseDatabase/Firebase/Database/third_party/SocketRocket/FSRWebSocket.m index d0c1e20..92d9d55 100644 --- a/Example/Pods/FirebaseDatabase/Firebase/Database/third_party/SocketRocket/FSRWebSocket.m +++ b/Example/Pods/FirebaseDatabase/Firebase/Database/third_party/SocketRocket/FSRWebSocket.m @@ -18,7 +18,7 @@ #import "FSRWebSocket.h" -#if TARGET_OS_IOS || TARGET_OS_TV +#if __has_include() #define HAS_ICU #endif @@ -28,9 +28,9 @@ #import #endif -#if TARGET_OS_IOS || TARGET_OS_TV +#if __has_include() #import -#elif TARGET_OS_OSX +#else #import #endif @@ -1510,7 +1510,9 @@ - (void)safeHandleEvent:(NSStreamEvent)eventCode stream:(NSStream *)aStream } case NSStreamEventErrorOccurred: { - SRFastLog(@"NSStreamEventErrorOccurred %@ %@", aStream, [[aStream streamError] copy]); + // Note: The upstream code for SocketRocket logs the error message, but this causes + // crashes on iOS 13 (https://github.com/firebase/firebase-ios-sdk/issues/3950) + SRFastLog(@"NSStreamEventErrorOccurred %@", aStream); /// TODO specify error better! [self _failWithError:aStream.streamError]; _readBufferOffset = 0; diff --git a/Example/Pods/FirebaseDatabase/README.md b/Example/Pods/FirebaseDatabase/README.md index 903fc9f..3ddc8fb 100644 --- a/Example/Pods/FirebaseDatabase/README.md +++ b/Example/Pods/FirebaseDatabase/README.md @@ -1,9 +1,10 @@ # Firebase iOS Open Source Development [![Build Status](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk) This repository contains a subset of the Firebase iOS SDK source. It currently -includes FirebaseCore, FirebaseAuth, FirebaseDatabase, FirebaseFirestore, -FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging, -FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage. +includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase, +FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging, +FirebaseInAppMessagingDisplay, FirebaseMessaging, FirebaseRemoteConfig, and +FirebaseStorage. The repository also includes GoogleUtilities source. The [GoogleUtilities](GoogleUtilities/README.md) pod is @@ -70,19 +71,39 @@ Instructions for installing binary frameworks via ## Development -Follow the subsequent instructions to develop, debug, unit test, run integration -tests, and try out reference samples: +To develop Firebase software in this repository, ensure that you have at least +the following software: -``` -$ git clone git@github.com:firebase/firebase-ios-sdk.git -$ cd firebase-ios-sdk/Example -$ pod update -$ open Firebase.xcworkspace -``` + * Xcode 10.1 (or later) + * CocoaPods 1.7.2 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self contained Xcode project. See +[Firestore/README.md](Firestore/README.md). + +### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +### Adding a New Firebase Pod -Firestore and Functions have self contained Xcode projects. See -[Firestore/README.md](Firestore/README.md) and -[Functions/README.md](Functions/README.md). +See [AddNewPod.md](AddNewPod.md). ### Code Formatting @@ -92,9 +113,19 @@ before creating a PR. Travis will verify that any code changes are done in a style compliant way. Install `clang-format` and `swiftformat`. -This command will get the right `clang-format` version: +These commands will get the right versions: -`brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/773cb75d360b58f32048f5964038d09825a507c8/Formula/clang-format.rb` +``` +brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/e3496d9/Formula/clang-format.rb +brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/7963c3d/Formula/swiftformat.rb +``` + +Note: if you already have a newer version of these installed you may need to +`brew switch` to this version. + +To update this section, find the versions of clang-format and swiftformat.rb to +match the versions in the CI failure logs +[here](https://github.com/Homebrew/homebrew-core/tree/master/Formula). ### Running Unit Tests @@ -168,24 +199,38 @@ We've seen an amazing amount of interest and contributions to improve the Fireba very grateful! We'd like to empower as many developers as we can to be able to use Firebase and participate in the Firebase community. -### macOS and tvOS -FirebaseAuth, FirebaseCore, FirebaseDatabase, FirebaseFunctions and FirebaseStorage now compile, run -unit tests, and work on macOS and tvOS, thanks to contributions from the community. There are a few -tweaks needed, like ensuring iOS-only, macOS-only, or tvOS-only code is correctly guarded with checks -for `TARGET_OS_IOS`, `TARGET_OS_OSX` and `TARGET_OS_TV`. +### tvOS, macOS, and Catalyst +Thanks to contributions from the community, FirebaseABTesting, FirebaseAuth, FirebaseCore, +FirebaseDatabase, FirebaseMessaging, FirebaseFirestore, +FirebaseFunctions, FirebaseRemoteConfig, and FirebaseStorage now compile, run unit tests, and work on +tvOS, macOS, and Catalyst. For tvOS, checkout the [Sample](Example/tvOSSample). -Keep in mind that macOS and tvOS are not officially supported by Firebase, and this repository is -actively developed primarily for iOS. While we can catch basic unit test issues with Travis, there -may be some changes where the SDK no longer works as expected on macOS or tvOS. If you encounter -this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues). +Keep in mind that macOS, Catalyst and tvOS are not officially supported by Firebase, and this +repository is actively developed primarily for iOS. While we can catch basic unit test issues with +Travis, there may be some changes where the SDK no longer works as expected on macOS or tvOS. If you +encounter this, please [file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +To install, add a subset of the following to the Podfile: + +``` +pod 'Firebase/ABTesting' +pod 'Firebase/Auth' +pod 'Firebase/Database' +pod 'Firebase/Firestore' +pod 'Firebase/Functions' +pod 'Firebase/Messaging' +pod 'Firebase/RemoteConfig' +pod 'Firebase/Storage' +``` -For installation instructions, see [above](README.md#accessing-firebase-source-snapshots). +#### Additional Catalyst Notes -Note that the Firebase pod is not available for macOS and tvOS. Install a selection of the -`FirebaseAuth`, `FirebaseCore`, `FirebaseDatabase`, `FirebaseFunctions`, and `FirebaseStorage` -CocoaPods. +* FirebaseAuth and FirebaseMessaging require adding `Keychain Sharing Capability` +to Build Settings. +* FirebaseFirestore requires signing the +[gRPC Resource target](https://github.com/firebase/firebase-ios-sdk/issues/3500#issuecomment-518741681). ## Roadmap diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.cc index 0295f6e..2ea2444 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "maybe_document.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -74,6 +82,57 @@ PB_STATIC_ASSERT((pb_membersize(firestore_client_NoDocument, read_time) < 256 && #endif +std::string firestore_client_NoDocument::ToString(int indent) const { + std::string header = PrintHeader(indent, "NoDocument", this); + std::string result; + + result += PrintPrimitiveField("name: ", name, indent + 1, false); + result += PrintMessageField("read_time ", read_time, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string firestore_client_UnknownDocument::ToString(int indent) const { + std::string header = PrintHeader(indent, "UnknownDocument", this); + std::string result; + + result += PrintPrimitiveField("name: ", name, indent + 1, false); + result += PrintMessageField("version ", version, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string firestore_client_MaybeDocument::ToString(int indent) const { + std::string header = PrintHeader(indent, "MaybeDocument", this); + std::string result; + + switch (which_document_type) { + case firestore_client_MaybeDocument_no_document_tag: + result += PrintMessageField("no_document ", + no_document, indent + 1, true); + break; + case firestore_client_MaybeDocument_document_tag: + result += PrintMessageField("document ", document, indent + 1, true); + break; + case firestore_client_MaybeDocument_unknown_document_tag: + result += PrintMessageField("unknown_document ", + unknown_document, indent + 1, true); + break; + } + result += PrintPrimitiveField("has_committed_mutations: ", + has_committed_mutations, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.h index 5422e41..677fc47 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.h @@ -15,7 +15,7 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_FIRESTORE_CLIENT_MAYBE_DOCUMENT_NANOPB_H_INCLUDED #define PB_FIRESTORE_CLIENT_MAYBE_DOCUMENT_NANOPB_H_INCLUDED @@ -25,6 +25,8 @@ #include "google/protobuf/timestamp.nanopb.h" +#include + namespace firebase { namespace firestore { @@ -38,12 +40,16 @@ namespace firestore { typedef struct _firestore_client_NoDocument { pb_bytes_array_t *name; google_protobuf_Timestamp read_time; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:firestore_client_NoDocument) */ } firestore_client_NoDocument; typedef struct _firestore_client_UnknownDocument { pb_bytes_array_t *name; google_protobuf_Timestamp version; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:firestore_client_UnknownDocument) */ } firestore_client_UnknownDocument; @@ -55,6 +61,8 @@ typedef struct _firestore_client_MaybeDocument { firestore_client_UnknownDocument unknown_document; }; bool has_committed_mutations; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:firestore_client_MaybeDocument) */ } firestore_client_MaybeDocument; @@ -86,7 +94,7 @@ extern const pb_field_t firestore_client_MaybeDocument_fields[5]; /* Maximum encoded size of messages (where known) */ /* firestore_client_NoDocument_size depends on runtime parameters */ /* firestore_client_UnknownDocument_size depends on runtime parameters */ -#define firestore_client_MaybeDocument_size (2 + (((firestore_client_NoDocument_size > firestore_client_UnknownDocument_size ? firestore_client_NoDocument_size : firestore_client_UnknownDocument_size) > google_firestore_v1_Document_size ? (firestore_client_NoDocument_size > firestore_client_UnknownDocument_size ? firestore_client_NoDocument_size : firestore_client_UnknownDocument_size) : google_firestore_v1_Document_size) > 0 ? ((firestore_client_NoDocument_size > firestore_client_UnknownDocument_size ? firestore_client_NoDocument_size : firestore_client_UnknownDocument_size) > google_firestore_v1_Document_size ? (firestore_client_NoDocument_size > firestore_client_UnknownDocument_size ? firestore_client_NoDocument_size : firestore_client_UnknownDocument_size) : google_firestore_v1_Document_size) : 0)) +/* firestore_client_MaybeDocument_size depends on runtime parameters */ /* Message IDs (where set with "msgid" option) */ #ifdef PB_MSGID diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.cc index c9e68d8..54c06f6 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "mutation.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -68,6 +76,43 @@ PB_STATIC_ASSERT((pb_membersize(firestore_client_WriteBatch, local_write_time) < #endif +std::string firestore_client_MutationQueue::ToString(int indent) const { + std::string header = PrintHeader(indent, "MutationQueue", this); + std::string result; + + result += PrintPrimitiveField("last_acknowledged_batch_id: ", + last_acknowledged_batch_id, indent + 1, false); + result += PrintPrimitiveField("last_stream_token: ", + last_stream_token, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string firestore_client_WriteBatch::ToString(int indent) const { + std::string header = PrintHeader(indent, "WriteBatch", this); + std::string result; + + result += PrintPrimitiveField("batch_id: ", batch_id, indent + 1, false); + for (pb_size_t i = 0; i != writes_count; ++i) { + result += PrintMessageField("writes ", writes[i], indent + 1, true); + } + result += PrintMessageField("local_write_time ", + local_write_time, indent + 1, false); + for (pb_size_t i = 0; i != base_writes_count; ++i) { + result += PrintMessageField("base_writes ", + base_writes[i], indent + 1, true); + } + + std::string tail = PrintTail(indent); + return header + result + tail; +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.h index 59efa45..a518026 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/mutation.nanopb.h @@ -15,7 +15,7 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_FIRESTORE_CLIENT_MUTATION_NANOPB_H_INCLUDED #define PB_FIRESTORE_CLIENT_MUTATION_NANOPB_H_INCLUDED @@ -25,6 +25,8 @@ #include "google/protobuf/timestamp.nanopb.h" +#include + namespace firebase { namespace firestore { @@ -38,6 +40,8 @@ namespace firestore { typedef struct _firestore_client_MutationQueue { int32_t last_acknowledged_batch_id; pb_bytes_array_t *last_stream_token; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:firestore_client_MutationQueue) */ } firestore_client_MutationQueue; @@ -48,6 +52,8 @@ typedef struct _firestore_client_WriteBatch { google_protobuf_Timestamp local_write_time; pb_size_t base_writes_count; struct _google_firestore_v1_Write *base_writes; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:firestore_client_WriteBatch) */ } firestore_client_WriteBatch; diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/target.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/target.nanopb.cc index 74223ca..1912c9c 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/target.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/target.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "target.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -29,13 +37,14 @@ namespace firestore { -const pb_field_t firestore_client_Target_fields[7] = { +const pb_field_t firestore_client_Target_fields[8] = { PB_FIELD( 1, INT32 , SINGULAR, STATIC , FIRST, firestore_client_Target, target_id, target_id, 0), PB_FIELD( 2, MESSAGE , SINGULAR, STATIC , OTHER, firestore_client_Target, snapshot_version, target_id, &google_protobuf_Timestamp_fields), PB_FIELD( 3, BYTES , SINGULAR, POINTER , OTHER, firestore_client_Target, resume_token, snapshot_version, 0), PB_FIELD( 4, INT64 , SINGULAR, STATIC , OTHER, firestore_client_Target, last_listen_sequence_number, resume_token, 0), PB_ANONYMOUS_ONEOF_FIELD(target_type, 5, MESSAGE , ONEOF, STATIC , OTHER, firestore_client_Target, query, last_listen_sequence_number, &google_firestore_v1_Target_QueryTarget_fields), PB_ANONYMOUS_ONEOF_FIELD(target_type, 6, MESSAGE , ONEOF, STATIC , UNION, firestore_client_Target, documents, last_listen_sequence_number, &google_firestore_v1_Target_DocumentsTarget_fields), + PB_FIELD( 7, MESSAGE , SINGULAR, STATIC , OTHER, firestore_client_Target, last_limbo_free_snapshot_version, documents, &google_protobuf_Timestamp_fields), PB_LAST_FIELD }; @@ -57,7 +66,7 @@ const pb_field_t firestore_client_TargetGlobal_fields[5] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -PB_STATIC_ASSERT((pb_membersize(firestore_client_Target, query) < 65536 && pb_membersize(firestore_client_Target, documents) < 65536 && pb_membersize(firestore_client_Target, snapshot_version) < 65536 && pb_membersize(firestore_client_TargetGlobal, last_remote_snapshot_version) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_firestore_client_Target_firestore_client_TargetGlobal) +PB_STATIC_ASSERT((pb_membersize(firestore_client_Target, query) < 65536 && pb_membersize(firestore_client_Target, documents) < 65536 && pb_membersize(firestore_client_Target, snapshot_version) < 65536 && pb_membersize(firestore_client_Target, last_limbo_free_snapshot_version) < 65536 && pb_membersize(firestore_client_TargetGlobal, last_remote_snapshot_version) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_firestore_client_Target_firestore_client_TargetGlobal) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) @@ -68,10 +77,53 @@ PB_STATIC_ASSERT((pb_membersize(firestore_client_Target, query) < 65536 && pb_me * numbers or field sizes that are larger than what can fit in the default * 8 bit descriptors. */ -PB_STATIC_ASSERT((pb_membersize(firestore_client_Target, query) < 256 && pb_membersize(firestore_client_Target, documents) < 256 && pb_membersize(firestore_client_Target, snapshot_version) < 256 && pb_membersize(firestore_client_TargetGlobal, last_remote_snapshot_version) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_firestore_client_Target_firestore_client_TargetGlobal) +PB_STATIC_ASSERT((pb_membersize(firestore_client_Target, query) < 256 && pb_membersize(firestore_client_Target, documents) < 256 && pb_membersize(firestore_client_Target, snapshot_version) < 256 && pb_membersize(firestore_client_Target, last_limbo_free_snapshot_version) < 256 && pb_membersize(firestore_client_TargetGlobal, last_remote_snapshot_version) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_firestore_client_Target_firestore_client_TargetGlobal) #endif +std::string firestore_client_Target::ToString(int indent) const { + std::string header = PrintHeader(indent, "Target", this); + std::string result; + + result += PrintPrimitiveField("target_id: ", target_id, indent + 1, false); + result += PrintMessageField("snapshot_version ", + snapshot_version, indent + 1, false); + result += PrintPrimitiveField("resume_token: ", + resume_token, indent + 1, false); + result += PrintPrimitiveField("last_listen_sequence_number: ", + last_listen_sequence_number, indent + 1, false); + switch (which_target_type) { + case firestore_client_Target_query_tag: + result += PrintMessageField("query ", query, indent + 1, true); + break; + case firestore_client_Target_documents_tag: + result += PrintMessageField("documents ", documents, indent + 1, true); + break; + } + result += PrintMessageField("last_limbo_free_snapshot_version ", + last_limbo_free_snapshot_version, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string firestore_client_TargetGlobal::ToString(int indent) const { + std::string header = PrintHeader(indent, "TargetGlobal", this); + std::string result; + + result += PrintPrimitiveField("highest_target_id: ", + highest_target_id, indent + 1, false); + result += PrintPrimitiveField("highest_listen_sequence_number: ", + highest_listen_sequence_number, indent + 1, false); + result += PrintMessageField("last_remote_snapshot_version ", + last_remote_snapshot_version, indent + 1, false); + result += PrintPrimitiveField("target_count: ", + target_count, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/target.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/target.nanopb.h index 5feacc3..f9de4cd 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/target.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/firestore/local/target.nanopb.h @@ -15,7 +15,7 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_FIRESTORE_CLIENT_TARGET_NANOPB_H_INCLUDED #define PB_FIRESTORE_CLIENT_TARGET_NANOPB_H_INCLUDED @@ -25,6 +25,8 @@ #include "google/protobuf/timestamp.nanopb.h" +#include + namespace firebase { namespace firestore { @@ -45,6 +47,9 @@ typedef struct _firestore_client_Target { google_firestore_v1_Target_QueryTarget query; google_firestore_v1_Target_DocumentsTarget documents; }; + google_protobuf_Timestamp last_limbo_free_snapshot_version; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:firestore_client_Target) */ } firestore_client_Target; @@ -53,15 +58,17 @@ typedef struct _firestore_client_TargetGlobal { int64_t highest_listen_sequence_number; google_protobuf_Timestamp last_remote_snapshot_version; int32_t target_count; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:firestore_client_TargetGlobal) */ } firestore_client_TargetGlobal; /* Default values for struct fields */ /* Initializer values for message structs */ -#define firestore_client_Target_init_default {0, google_protobuf_Timestamp_init_default, NULL, 0, 0, {google_firestore_v1_Target_QueryTarget_init_default}} +#define firestore_client_Target_init_default {0, google_protobuf_Timestamp_init_default, NULL, 0, 0, {google_firestore_v1_Target_QueryTarget_init_default}, google_protobuf_Timestamp_init_default} #define firestore_client_TargetGlobal_init_default {0, 0, google_protobuf_Timestamp_init_default, 0} -#define firestore_client_Target_init_zero {0, google_protobuf_Timestamp_init_zero, NULL, 0, 0, {google_firestore_v1_Target_QueryTarget_init_zero}} +#define firestore_client_Target_init_zero {0, google_protobuf_Timestamp_init_zero, NULL, 0, 0, {google_firestore_v1_Target_QueryTarget_init_zero}, google_protobuf_Timestamp_init_zero} #define firestore_client_TargetGlobal_init_zero {0, 0, google_protobuf_Timestamp_init_zero, 0} /* Field tags (for use in manual encoding/decoding) */ @@ -71,13 +78,14 @@ typedef struct _firestore_client_TargetGlobal { #define firestore_client_Target_snapshot_version_tag 2 #define firestore_client_Target_resume_token_tag 3 #define firestore_client_Target_last_listen_sequence_number_tag 4 +#define firestore_client_Target_last_limbo_free_snapshot_version_tag 7 #define firestore_client_TargetGlobal_highest_target_id_tag 1 #define firestore_client_TargetGlobal_highest_listen_sequence_number_tag 2 #define firestore_client_TargetGlobal_last_remote_snapshot_version_tag 3 #define firestore_client_TargetGlobal_target_count_tag 4 /* Struct field encoding specification for nanopb */ -extern const pb_field_t firestore_client_Target_fields[7]; +extern const pb_field_t firestore_client_Target_fields[8]; extern const pb_field_t firestore_client_TargetGlobal_fields[5]; /* Maximum encoded size of messages (where known) */ diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/annotations.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/annotations.nanopb.cc index 613bcf6..d31f898 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/annotations.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/annotations.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "annotations.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/annotations.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/annotations.nanopb.h index 2ef2a03..380e51a 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/annotations.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/annotations.nanopb.h @@ -15,7 +15,7 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_GOOGLE_API_ANNOTATIONS_NANOPB_H_INCLUDED #define PB_GOOGLE_API_ANNOTATIONS_NANOPB_H_INCLUDED @@ -23,6 +23,8 @@ #include "google/api/http.nanopb.h" +#include + namespace firebase { namespace firestore { diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/http.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/http.nanopb.cc index 151b1fc..f19442b 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/http.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/http.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "http.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -79,6 +87,81 @@ PB_STATIC_ASSERT((pb_membersize(google_api_HttpRule, custom) < 256), YOU_MUST_DE #endif +std::string google_api_Http::ToString(int indent) const { + std::string header = PrintHeader(indent, "Http", this); + std::string result; + + for (pb_size_t i = 0; i != rules_count; ++i) { + result += PrintMessageField("rules ", rules[i], indent + 1, true); + } + result += PrintPrimitiveField("fully_decode_reserved_expansion: ", + fully_decode_reserved_expansion, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_api_HttpRule::ToString(int indent) const { + std::string header = PrintHeader(indent, "HttpRule", this); + std::string result; + + result += PrintPrimitiveField("selector: ", selector, indent + 1, false); + switch (which_pattern) { + case google_api_HttpRule_get_tag: + result += PrintPrimitiveField("get: ", get, indent + 1, true); + break; + case google_api_HttpRule_put_tag: + result += PrintPrimitiveField("put: ", put, indent + 1, true); + break; + case google_api_HttpRule_post_tag: + result += PrintPrimitiveField("post: ", post, indent + 1, true); + break; + case google_api_HttpRule_delete_tag: + result += PrintPrimitiveField("delete: ", delete_, indent + 1, true); + break; + case google_api_HttpRule_patch_tag: + result += PrintPrimitiveField("patch: ", patch, indent + 1, true); + break; + case google_api_HttpRule_custom_tag: + result += PrintMessageField("custom ", custom, indent + 1, true); + break; + } + result += PrintPrimitiveField("body: ", body, indent + 1, false); + for (pb_size_t i = 0; i != additional_bindings_count; ++i) { + result += PrintMessageField("additional_bindings ", + additional_bindings[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_api_CustomHttpPattern::ToString(int indent) const { + std::string header = PrintHeader(indent, "CustomHttpPattern", this); + std::string result; + + result += PrintPrimitiveField("kind: ", kind, indent + 1, false); + result += PrintPrimitiveField("path: ", path, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/http.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/http.nanopb.h index 9e8ea1e..fbca8d3 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/http.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/api/http.nanopb.h @@ -15,12 +15,14 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_GOOGLE_API_HTTP_NANOPB_H_INCLUDED #define PB_GOOGLE_API_HTTP_NANOPB_H_INCLUDED #include +#include + namespace firebase { namespace firestore { @@ -34,6 +36,8 @@ namespace firestore { typedef struct _google_api_CustomHttpPattern { pb_bytes_array_t *kind; pb_bytes_array_t *path; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_api_CustomHttpPattern) */ } google_api_CustomHttpPattern; @@ -41,6 +45,8 @@ typedef struct _google_api_Http { pb_size_t rules_count; struct _google_api_HttpRule *rules; bool fully_decode_reserved_expansion; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_api_Http) */ } google_api_Http; @@ -58,6 +64,8 @@ typedef struct _google_api_HttpRule { pb_bytes_array_t *body; pb_size_t additional_bindings_count; struct _google_api_HttpRule *additional_bindings; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_api_HttpRule) */ } google_api_HttpRule; diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.cc index 08db6cc..73bdf27 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "common.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -81,6 +89,105 @@ PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_Precondition, update_time) < #endif +std::string google_firestore_v1_DocumentMask::ToString(int indent) const { + std::string header = PrintHeader(indent, "DocumentMask", this); + std::string result; + + for (pb_size_t i = 0; i != field_paths_count; ++i) { + result += PrintPrimitiveField("field_paths: ", + field_paths[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_Precondition::ToString(int indent) const { + std::string header = PrintHeader(indent, "Precondition", this); + std::string result; + + switch (which_condition_type) { + case google_firestore_v1_Precondition_exists_tag: + result += PrintPrimitiveField("exists: ", exists, indent + 1, true); + break; + case google_firestore_v1_Precondition_update_time_tag: + result += PrintMessageField("update_time ", + update_time, indent + 1, true); + break; + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_TransactionOptions::ToString(int indent) const { + std::string header = PrintHeader(indent, "TransactionOptions", this); + std::string result; + + switch (which_mode) { + case google_firestore_v1_TransactionOptions_read_only_tag: + result += PrintMessageField("read_only ", read_only, indent + 1, true); + break; + case google_firestore_v1_TransactionOptions_read_write_tag: + result += PrintMessageField("read_write ", + read_write, indent + 1, true); + break; + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_TransactionOptions_ReadWrite::ToString(int indent) const { + std::string header = PrintHeader(indent, "ReadWrite", this); + std::string result; + + result += PrintPrimitiveField("retry_transaction: ", + retry_transaction, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_TransactionOptions_ReadOnly::ToString(int indent) const { + std::string header = PrintHeader(indent, "ReadOnly", this); + std::string result; + + switch (which_consistency_selector) { + case google_firestore_v1_TransactionOptions_ReadOnly_read_time_tag: + result += PrintMessageField("read_time ", read_time, indent + 1, true); + break; + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.h index c650f80..792a9d9 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/common.nanopb.h @@ -15,7 +15,7 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_GOOGLE_FIRESTORE_V1_COMMON_NANOPB_H_INCLUDED #define PB_GOOGLE_FIRESTORE_V1_COMMON_NANOPB_H_INCLUDED @@ -25,6 +25,8 @@ #include "google/protobuf/timestamp.nanopb.h" +#include + namespace firebase { namespace firestore { @@ -38,11 +40,15 @@ namespace firestore { typedef struct _google_firestore_v1_DocumentMask { pb_size_t field_paths_count; pb_bytes_array_t **field_paths; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_DocumentMask) */ } google_firestore_v1_DocumentMask; typedef struct _google_firestore_v1_TransactionOptions_ReadWrite { pb_bytes_array_t *retry_transaction; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_TransactionOptions_ReadWrite) */ } google_firestore_v1_TransactionOptions_ReadWrite; @@ -52,6 +58,8 @@ typedef struct _google_firestore_v1_Precondition { bool exists; google_protobuf_Timestamp update_time; }; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_Precondition) */ } google_firestore_v1_Precondition; @@ -60,6 +68,8 @@ typedef struct _google_firestore_v1_TransactionOptions_ReadOnly { union { google_protobuf_Timestamp read_time; }; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_TransactionOptions_ReadOnly) */ } google_firestore_v1_TransactionOptions_ReadOnly; @@ -69,6 +79,8 @@ typedef struct _google_firestore_v1_TransactionOptions { google_firestore_v1_TransactionOptions_ReadOnly read_only; google_firestore_v1_TransactionOptions_ReadWrite read_write; }; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_TransactionOptions) */ } google_firestore_v1_TransactionOptions; @@ -105,7 +117,7 @@ extern const pb_field_t google_firestore_v1_TransactionOptions_ReadOnly_fields[2 /* Maximum encoded size of messages (where known) */ /* google_firestore_v1_DocumentMask_size depends on runtime parameters */ #define google_firestore_v1_Precondition_size 24 -#define google_firestore_v1_TransactionOptions_size (0 + (google_firestore_v1_TransactionOptions_ReadWrite_size > 26 ? google_firestore_v1_TransactionOptions_ReadWrite_size : 26)) +/* google_firestore_v1_TransactionOptions_size depends on runtime parameters */ /* google_firestore_v1_TransactionOptions_ReadWrite_size depends on runtime parameters */ #define google_firestore_v1_TransactionOptions_ReadOnly_size 24 diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.cc index 00e15d5..b2cc297 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "document.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -33,7 +41,7 @@ const pb_field_t google_firestore_v1_Document_fields[5] = { PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, google_firestore_v1_Document, name, name, 0), PB_FIELD( 2, MESSAGE , REPEATED, POINTER , OTHER, google_firestore_v1_Document, fields, name, &google_firestore_v1_Document_FieldsEntry_fields), PB_FIELD( 3, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_Document, create_time, fields, &google_protobuf_Timestamp_fields), - PB_FIELD( 4, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_Document, update_time, create_time, &google_protobuf_Timestamp_fields), + PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, google_firestore_v1_Document, update_time, create_time, &google_protobuf_Timestamp_fields), PB_LAST_FIELD }; @@ -99,6 +107,139 @@ PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_Document, create_time) < 256 #endif +std::string google_firestore_v1_Document::ToString(int indent) const { + std::string header = PrintHeader(indent, "Document", this); + std::string result; + + result += PrintPrimitiveField("name: ", name, indent + 1, false); + for (pb_size_t i = 0; i != fields_count; ++i) { + result += PrintMessageField("fields ", fields[i], indent + 1, true); + } + result += PrintMessageField("create_time ", + create_time, indent + 1, false); + if (has_update_time) { + result += PrintMessageField("update_time ", + update_time, indent + 1, true); + } + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_Document_FieldsEntry::ToString(int indent) const { + std::string header = PrintHeader(indent, "FieldsEntry", this); + std::string result; + + result += PrintPrimitiveField("key: ", key, indent + 1, false); + result += PrintMessageField("value ", value, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_Value::ToString(int indent) const { + std::string header = PrintHeader(indent, "Value", this); + std::string result; + + switch (which_value_type) { + case google_firestore_v1_Value_boolean_value_tag: + result += PrintPrimitiveField("boolean_value: ", + boolean_value, indent + 1, true); + break; + case google_firestore_v1_Value_integer_value_tag: + result += PrintPrimitiveField("integer_value: ", + integer_value, indent + 1, true); + break; + case google_firestore_v1_Value_double_value_tag: + result += PrintPrimitiveField("double_value: ", + double_value, indent + 1, true); + break; + case google_firestore_v1_Value_reference_value_tag: + result += PrintPrimitiveField("reference_value: ", + reference_value, indent + 1, true); + break; + case google_firestore_v1_Value_map_value_tag: + result += PrintMessageField("map_value ", map_value, indent + 1, true); + break; + case google_firestore_v1_Value_geo_point_value_tag: + result += PrintMessageField("geo_point_value ", + geo_point_value, indent + 1, true); + break; + case google_firestore_v1_Value_array_value_tag: + result += PrintMessageField("array_value ", + array_value, indent + 1, true); + break; + case google_firestore_v1_Value_timestamp_value_tag: + result += PrintMessageField("timestamp_value ", + timestamp_value, indent + 1, true); + break; + case google_firestore_v1_Value_null_value_tag: + result += PrintEnumField("null_value: ", null_value, indent + 1, true); + break; + case google_firestore_v1_Value_string_value_tag: + result += PrintPrimitiveField("string_value: ", + string_value, indent + 1, true); + break; + case google_firestore_v1_Value_bytes_value_tag: + result += PrintPrimitiveField("bytes_value: ", + bytes_value, indent + 1, true); + break; + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_ArrayValue::ToString(int indent) const { + std::string header = PrintHeader(indent, "ArrayValue", this); + std::string result; + + for (pb_size_t i = 0; i != values_count; ++i) { + result += PrintMessageField("values ", values[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_MapValue::ToString(int indent) const { + std::string header = PrintHeader(indent, "MapValue", this); + std::string result; + + for (pb_size_t i = 0; i != fields_count; ++i) { + result += PrintMessageField("fields ", fields[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_MapValue_FieldsEntry::ToString(int indent) const { + std::string header = PrintHeader(indent, "FieldsEntry", this); + std::string result; + + result += PrintPrimitiveField("key: ", key, indent + 1, false); + result += PrintMessageField("value ", value, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h index c07959d..346efb5 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h @@ -15,7 +15,7 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_GOOGLE_FIRESTORE_V1_DOCUMENT_NANOPB_H_INCLUDED #define PB_GOOGLE_FIRESTORE_V1_DOCUMENT_NANOPB_H_INCLUDED @@ -29,6 +29,8 @@ #include "google/type/latlng.nanopb.h" +#include + namespace firebase { namespace firestore { @@ -42,12 +44,16 @@ namespace firestore { typedef struct _google_firestore_v1_ArrayValue { pb_size_t values_count; struct _google_firestore_v1_Value *values; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_ArrayValue) */ } google_firestore_v1_ArrayValue; typedef struct _google_firestore_v1_MapValue { pb_size_t fields_count; struct _google_firestore_v1_MapValue_FieldsEntry *fields; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_MapValue) */ } google_firestore_v1_MapValue; @@ -56,7 +62,10 @@ typedef struct _google_firestore_v1_Document { pb_size_t fields_count; struct _google_firestore_v1_Document_FieldsEntry *fields; google_protobuf_Timestamp create_time; + bool has_update_time; google_protobuf_Timestamp update_time; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_Document) */ } google_firestore_v1_Document; @@ -75,31 +84,37 @@ typedef struct _google_firestore_v1_Value { pb_bytes_array_t *string_value; pb_bytes_array_t *bytes_value; }; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_Value) */ } google_firestore_v1_Value; typedef struct _google_firestore_v1_Document_FieldsEntry { pb_bytes_array_t *key; google_firestore_v1_Value value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_Document_FieldsEntry) */ } google_firestore_v1_Document_FieldsEntry; typedef struct _google_firestore_v1_MapValue_FieldsEntry { pb_bytes_array_t *key; google_firestore_v1_Value value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_MapValue_FieldsEntry) */ } google_firestore_v1_MapValue_FieldsEntry; /* Default values for struct fields */ /* Initializer values for message structs */ -#define google_firestore_v1_Document_init_default {NULL, 0, NULL, google_protobuf_Timestamp_init_default, google_protobuf_Timestamp_init_default} +#define google_firestore_v1_Document_init_default {NULL, 0, NULL, google_protobuf_Timestamp_init_default, false, google_protobuf_Timestamp_init_default} #define google_firestore_v1_Document_FieldsEntry_init_default {NULL, google_firestore_v1_Value_init_default} #define google_firestore_v1_Value_init_default {0, {0}} #define google_firestore_v1_ArrayValue_init_default {0, NULL} #define google_firestore_v1_MapValue_init_default {0, NULL} #define google_firestore_v1_MapValue_FieldsEntry_init_default {NULL, google_firestore_v1_Value_init_default} -#define google_firestore_v1_Document_init_zero {NULL, 0, NULL, google_protobuf_Timestamp_init_zero, google_protobuf_Timestamp_init_zero} +#define google_firestore_v1_Document_init_zero {NULL, 0, NULL, google_protobuf_Timestamp_init_zero, false, google_protobuf_Timestamp_init_zero} #define google_firestore_v1_Document_FieldsEntry_init_zero {NULL, google_firestore_v1_Value_init_zero} #define google_firestore_v1_Value_init_zero {0, {0}} #define google_firestore_v1_ArrayValue_init_zero {0, NULL} diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.cc index 50508a9..2b5e20a 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "firestore.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -214,7 +222,7 @@ const pb_field_t google_firestore_v1_Target_QueryTarget_fields[3] = { const pb_field_t google_firestore_v1_TargetChange_fields[6] = { PB_FIELD( 1, UENUM , SINGULAR, STATIC , FIRST, google_firestore_v1_TargetChange, target_change_type, target_change_type, 0), PB_FIELD( 2, INT32 , REPEATED, POINTER , OTHER, google_firestore_v1_TargetChange, target_ids, target_change_type, 0), - PB_FIELD( 3, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_TargetChange, cause, target_ids, &google_rpc_Status_fields), + PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, google_firestore_v1_TargetChange, cause, target_ids, &google_rpc_Status_fields), PB_FIELD( 4, BYTES , SINGULAR, POINTER , OTHER, google_firestore_v1_TargetChange, resume_token, cause, 0), PB_FIELD( 6, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_TargetChange, read_time, resume_token, &google_protobuf_Timestamp_fields), PB_LAST_FIELD @@ -259,6 +267,582 @@ PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_GetDocumentRequest, read_tim #endif +const char* EnumToString( + google_firestore_v1_TargetChange_TargetChangeType value) { + switch (value) { + case google_firestore_v1_TargetChange_TargetChangeType_NO_CHANGE: + return "NO_CHANGE"; + case google_firestore_v1_TargetChange_TargetChangeType_ADD: + return "ADD"; + case google_firestore_v1_TargetChange_TargetChangeType_REMOVE: + return "REMOVE"; + case google_firestore_v1_TargetChange_TargetChangeType_CURRENT: + return "CURRENT"; + case google_firestore_v1_TargetChange_TargetChangeType_RESET: + return "RESET"; + } + return ""; +} + +std::string google_firestore_v1_GetDocumentRequest::ToString(int indent) const { + std::string header = PrintHeader(indent, "GetDocumentRequest", this); + std::string result; + + result += PrintPrimitiveField("name: ", name, indent + 1, false); + result += PrintMessageField("mask ", mask, indent + 1, false); + switch (which_consistency_selector) { + case google_firestore_v1_GetDocumentRequest_transaction_tag: + result += PrintPrimitiveField("transaction: ", + transaction, indent + 1, true); + break; + case google_firestore_v1_GetDocumentRequest_read_time_tag: + result += PrintMessageField("read_time ", read_time, indent + 1, true); + break; + } + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_ListDocumentsRequest::ToString(int indent) const { + std::string header = PrintHeader(indent, "ListDocumentsRequest", this); + std::string result; + + result += PrintPrimitiveField("parent: ", parent, indent + 1, false); + result += PrintPrimitiveField("collection_id: ", + collection_id, indent + 1, false); + result += PrintPrimitiveField("page_size: ", page_size, indent + 1, false); + result += PrintPrimitiveField("page_token: ", + page_token, indent + 1, false); + result += PrintPrimitiveField("order_by: ", order_by, indent + 1, false); + result += PrintMessageField("mask ", mask, indent + 1, false); + switch (which_consistency_selector) { + case google_firestore_v1_ListDocumentsRequest_transaction_tag: + result += PrintPrimitiveField("transaction: ", + transaction, indent + 1, true); + break; + case google_firestore_v1_ListDocumentsRequest_read_time_tag: + result += PrintMessageField("read_time ", read_time, indent + 1, true); + break; + } + result += PrintPrimitiveField("show_missing: ", + show_missing, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_ListDocumentsResponse::ToString(int indent) const { + std::string header = PrintHeader(indent, "ListDocumentsResponse", this); + std::string result; + + for (pb_size_t i = 0; i != documents_count; ++i) { + result += PrintMessageField("documents ", + documents[i], indent + 1, true); + } + result += PrintPrimitiveField("next_page_token: ", + next_page_token, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_CreateDocumentRequest::ToString(int indent) const { + std::string header = PrintHeader(indent, "CreateDocumentRequest", this); + std::string result; + + result += PrintPrimitiveField("parent: ", parent, indent + 1, false); + result += PrintPrimitiveField("collection_id: ", + collection_id, indent + 1, false); + result += PrintPrimitiveField("document_id: ", + document_id, indent + 1, false); + result += PrintMessageField("document ", document, indent + 1, false); + result += PrintMessageField("mask ", mask, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_UpdateDocumentRequest::ToString(int indent) const { + std::string header = PrintHeader(indent, "UpdateDocumentRequest", this); + std::string result; + + result += PrintMessageField("document ", document, indent + 1, false); + result += PrintMessageField("update_mask ", + update_mask, indent + 1, false); + result += PrintMessageField("mask ", mask, indent + 1, false); + result += PrintMessageField("current_document ", + current_document, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_DeleteDocumentRequest::ToString(int indent) const { + std::string header = PrintHeader(indent, "DeleteDocumentRequest", this); + std::string result; + + result += PrintPrimitiveField("name: ", name, indent + 1, false); + result += PrintMessageField("current_document ", + current_document, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_BatchGetDocumentsRequest::ToString(int indent) const { + std::string header = PrintHeader(indent, "BatchGetDocumentsRequest", this); + std::string result; + + result += PrintPrimitiveField("database: ", database, indent + 1, false); + for (pb_size_t i = 0; i != documents_count; ++i) { + result += PrintPrimitiveField("documents: ", + documents[i], indent + 1, true); + } + result += PrintMessageField("mask ", mask, indent + 1, false); + switch (which_consistency_selector) { + case google_firestore_v1_BatchGetDocumentsRequest_transaction_tag: + result += PrintPrimitiveField("transaction: ", + transaction, indent + 1, true); + break; + case google_firestore_v1_BatchGetDocumentsRequest_new_transaction_tag: + result += PrintMessageField("new_transaction ", + new_transaction, indent + 1, true); + break; + case google_firestore_v1_BatchGetDocumentsRequest_read_time_tag: + result += PrintMessageField("read_time ", read_time, indent + 1, true); + break; + } + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_BatchGetDocumentsResponse::ToString(int indent) const { + std::string header = PrintHeader(indent, "BatchGetDocumentsResponse", this); + std::string result; + + switch (which_result) { + case google_firestore_v1_BatchGetDocumentsResponse_found_tag: + result += PrintMessageField("found ", found, indent + 1, true); + break; + case google_firestore_v1_BatchGetDocumentsResponse_missing_tag: + result += PrintPrimitiveField("missing: ", missing, indent + 1, true); + break; + } + result += PrintPrimitiveField("transaction: ", + transaction, indent + 1, false); + result += PrintMessageField("read_time ", read_time, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_BeginTransactionRequest::ToString(int indent) const { + std::string header = PrintHeader(indent, "BeginTransactionRequest", this); + std::string result; + + result += PrintPrimitiveField("database: ", database, indent + 1, false); + result += PrintMessageField("options ", options, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_BeginTransactionResponse::ToString(int indent) const { + std::string header = PrintHeader(indent, "BeginTransactionResponse", this); + std::string result; + + result += PrintPrimitiveField("transaction: ", + transaction, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_CommitRequest::ToString(int indent) const { + std::string header = PrintHeader(indent, "CommitRequest", this); + std::string result; + + result += PrintPrimitiveField("database: ", database, indent + 1, false); + for (pb_size_t i = 0; i != writes_count; ++i) { + result += PrintMessageField("writes ", writes[i], indent + 1, true); + } + result += PrintPrimitiveField("transaction: ", + transaction, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_CommitResponse::ToString(int indent) const { + std::string header = PrintHeader(indent, "CommitResponse", this); + std::string result; + + for (pb_size_t i = 0; i != write_results_count; ++i) { + result += PrintMessageField("write_results ", + write_results[i], indent + 1, true); + } + result += PrintMessageField("commit_time ", + commit_time, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_RollbackRequest::ToString(int indent) const { + std::string header = PrintHeader(indent, "RollbackRequest", this); + std::string result; + + result += PrintPrimitiveField("database: ", database, indent + 1, false); + result += PrintPrimitiveField("transaction: ", + transaction, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_RunQueryRequest::ToString(int indent) const { + std::string header = PrintHeader(indent, "RunQueryRequest", this); + std::string result; + + result += PrintPrimitiveField("parent: ", parent, indent + 1, false); + switch (which_query_type) { + case google_firestore_v1_RunQueryRequest_structured_query_tag: + result += PrintMessageField("structured_query ", + query_type.structured_query, indent + 1, true); + break; + } + switch (which_consistency_selector) { + case google_firestore_v1_RunQueryRequest_transaction_tag: + result += PrintPrimitiveField("transaction: ", + consistency_selector.transaction, indent + 1, true); + break; + case google_firestore_v1_RunQueryRequest_new_transaction_tag: + result += PrintMessageField("new_transaction ", + consistency_selector.new_transaction, indent + 1, true); + break; + case google_firestore_v1_RunQueryRequest_read_time_tag: + result += PrintMessageField("read_time ", + consistency_selector.read_time, indent + 1, true); + break; + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_RunQueryResponse::ToString(int indent) const { + std::string header = PrintHeader(indent, "RunQueryResponse", this); + std::string result; + + result += PrintMessageField("document ", document, indent + 1, false); + result += PrintPrimitiveField("transaction: ", + transaction, indent + 1, false); + result += PrintMessageField("read_time ", read_time, indent + 1, false); + result += PrintPrimitiveField("skipped_results: ", + skipped_results, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_WriteRequest::ToString(int indent) const { + std::string header = PrintHeader(indent, "WriteRequest", this); + std::string result; + + result += PrintPrimitiveField("database: ", database, indent + 1, false); + result += PrintPrimitiveField("stream_id: ", stream_id, indent + 1, false); + for (pb_size_t i = 0; i != writes_count; ++i) { + result += PrintMessageField("writes ", writes[i], indent + 1, true); + } + result += PrintPrimitiveField("stream_token: ", + stream_token, indent + 1, false); + for (pb_size_t i = 0; i != labels_count; ++i) { + result += PrintMessageField("labels ", labels[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_WriteRequest_LabelsEntry::ToString(int indent) const { + std::string header = PrintHeader(indent, "LabelsEntry", this); + std::string result; + + result += PrintPrimitiveField("key: ", key, indent + 1, false); + result += PrintPrimitiveField("value: ", value, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_WriteResponse::ToString(int indent) const { + std::string header = PrintHeader(indent, "WriteResponse", this); + std::string result; + + result += PrintPrimitiveField("stream_id: ", stream_id, indent + 1, false); + result += PrintPrimitiveField("stream_token: ", + stream_token, indent + 1, false); + for (pb_size_t i = 0; i != write_results_count; ++i) { + result += PrintMessageField("write_results ", + write_results[i], indent + 1, true); + } + result += PrintMessageField("commit_time ", + commit_time, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_ListenRequest::ToString(int indent) const { + std::string header = PrintHeader(indent, "ListenRequest", this); + std::string result; + + result += PrintPrimitiveField("database: ", database, indent + 1, false); + switch (which_target_change) { + case google_firestore_v1_ListenRequest_add_target_tag: + result += PrintMessageField("add_target ", + add_target, indent + 1, true); + break; + case google_firestore_v1_ListenRequest_remove_target_tag: + result += PrintPrimitiveField("remove_target: ", + remove_target, indent + 1, true); + break; + } + for (pb_size_t i = 0; i != labels_count; ++i) { + result += PrintMessageField("labels ", labels[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_ListenRequest_LabelsEntry::ToString(int indent) const { + std::string header = PrintHeader(indent, "LabelsEntry", this); + std::string result; + + result += PrintPrimitiveField("key: ", key, indent + 1, false); + result += PrintPrimitiveField("value: ", value, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_ListenResponse::ToString(int indent) const { + std::string header = PrintHeader(indent, "ListenResponse", this); + std::string result; + + switch (which_response_type) { + case google_firestore_v1_ListenResponse_target_change_tag: + result += PrintMessageField("target_change ", + target_change, indent + 1, true); + break; + case google_firestore_v1_ListenResponse_document_change_tag: + result += PrintMessageField("document_change ", + document_change, indent + 1, true); + break; + case google_firestore_v1_ListenResponse_document_delete_tag: + result += PrintMessageField("document_delete ", + document_delete, indent + 1, true); + break; + case google_firestore_v1_ListenResponse_filter_tag: + result += PrintMessageField("filter ", filter, indent + 1, true); + break; + case google_firestore_v1_ListenResponse_document_remove_tag: + result += PrintMessageField("document_remove ", + document_remove, indent + 1, true); + break; + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_Target::ToString(int indent) const { + std::string header = PrintHeader(indent, "Target", this); + std::string result; + + switch (which_target_type) { + case google_firestore_v1_Target_query_tag: + result += PrintMessageField("query ", + target_type.query, indent + 1, true); + break; + case google_firestore_v1_Target_documents_tag: + result += PrintMessageField("documents ", + target_type.documents, indent + 1, true); + break; + } + switch (which_resume_type) { + case google_firestore_v1_Target_resume_token_tag: + result += PrintPrimitiveField("resume_token: ", + resume_type.resume_token, indent + 1, true); + break; + case google_firestore_v1_Target_read_time_tag: + result += PrintMessageField("read_time ", + resume_type.read_time, indent + 1, true); + break; + } + result += PrintPrimitiveField("target_id: ", target_id, indent + 1, false); + result += PrintPrimitiveField("once: ", once, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_Target_DocumentsTarget::ToString(int indent) const { + std::string header = PrintHeader(indent, "DocumentsTarget", this); + std::string result; + + for (pb_size_t i = 0; i != documents_count; ++i) { + result += PrintPrimitiveField("documents: ", + documents[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_Target_QueryTarget::ToString(int indent) const { + std::string header = PrintHeader(indent, "QueryTarget", this); + std::string result; + + result += PrintPrimitiveField("parent: ", parent, indent + 1, false); + switch (which_query_type) { + case google_firestore_v1_Target_QueryTarget_structured_query_tag: + result += PrintMessageField("structured_query ", + structured_query, indent + 1, true); + break; + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_TargetChange::ToString(int indent) const { + std::string header = PrintHeader(indent, "TargetChange", this); + std::string result; + + result += PrintEnumField("target_change_type: ", + target_change_type, indent + 1, false); + for (pb_size_t i = 0; i != target_ids_count; ++i) { + result += PrintPrimitiveField("target_ids: ", + target_ids[i], indent + 1, true); + } + if (has_cause) { + result += PrintMessageField("cause ", cause, indent + 1, true); + } + result += PrintPrimitiveField("resume_token: ", + resume_token, indent + 1, false); + result += PrintMessageField("read_time ", read_time, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_ListCollectionIdsRequest::ToString(int indent) const { + std::string header = PrintHeader(indent, "ListCollectionIdsRequest", this); + std::string result; + + result += PrintPrimitiveField("parent: ", parent, indent + 1, false); + result += PrintPrimitiveField("page_size: ", page_size, indent + 1, false); + result += PrintPrimitiveField("page_token: ", + page_token, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_ListCollectionIdsResponse::ToString(int indent) const { + std::string header = PrintHeader(indent, "ListCollectionIdsResponse", this); + std::string result; + + for (pb_size_t i = 0; i != collection_ids_count; ++i) { + result += PrintPrimitiveField("collection_ids: ", + collection_ids[i], indent + 1, true); + } + result += PrintPrimitiveField("next_page_token: ", + next_page_token, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.h index 3b949de..784571f 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.h @@ -15,7 +15,7 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_GOOGLE_FIRESTORE_V1_FIRESTORE_NANOPB_H_INCLUDED #define PB_GOOGLE_FIRESTORE_V1_FIRESTORE_NANOPB_H_INCLUDED @@ -37,6 +37,8 @@ #include "google/rpc/status.nanopb.h" +#include + namespace firebase { namespace firestore { @@ -61,6 +63,8 @@ typedef enum _google_firestore_v1_TargetChange_TargetChangeType { /* Struct definitions */ typedef struct _google_firestore_v1_BeginTransactionResponse { pb_bytes_array_t *transaction; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_BeginTransactionResponse) */ } google_firestore_v1_BeginTransactionResponse; @@ -69,6 +73,8 @@ typedef struct _google_firestore_v1_CommitRequest { pb_size_t writes_count; struct _google_firestore_v1_Write *writes; pb_bytes_array_t *transaction; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_CommitRequest) */ } google_firestore_v1_CommitRequest; @@ -76,6 +82,8 @@ typedef struct _google_firestore_v1_ListCollectionIdsResponse { pb_size_t collection_ids_count; pb_bytes_array_t **collection_ids; pb_bytes_array_t *next_page_token; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_ListCollectionIdsResponse) */ } google_firestore_v1_ListCollectionIdsResponse; @@ -83,24 +91,32 @@ typedef struct _google_firestore_v1_ListDocumentsResponse { pb_size_t documents_count; struct _google_firestore_v1_Document *documents; pb_bytes_array_t *next_page_token; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_ListDocumentsResponse) */ } google_firestore_v1_ListDocumentsResponse; typedef struct _google_firestore_v1_ListenRequest_LabelsEntry { pb_bytes_array_t *key; pb_bytes_array_t *value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_ListenRequest_LabelsEntry) */ } google_firestore_v1_ListenRequest_LabelsEntry; typedef struct _google_firestore_v1_RollbackRequest { pb_bytes_array_t *database; pb_bytes_array_t *transaction; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_RollbackRequest) */ } google_firestore_v1_RollbackRequest; typedef struct _google_firestore_v1_Target_DocumentsTarget { pb_size_t documents_count; pb_bytes_array_t **documents; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_Target_DocumentsTarget) */ } google_firestore_v1_Target_DocumentsTarget; @@ -112,12 +128,16 @@ typedef struct _google_firestore_v1_WriteRequest { pb_bytes_array_t *stream_token; pb_size_t labels_count; struct _google_firestore_v1_WriteRequest_LabelsEntry *labels; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_WriteRequest) */ } google_firestore_v1_WriteRequest; typedef struct _google_firestore_v1_WriteRequest_LabelsEntry { pb_bytes_array_t *key; pb_bytes_array_t *value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_WriteRequest_LabelsEntry) */ } google_firestore_v1_WriteRequest_LabelsEntry; @@ -132,6 +152,8 @@ typedef struct _google_firestore_v1_BatchGetDocumentsRequest { google_firestore_v1_TransactionOptions new_transaction; google_protobuf_Timestamp read_time; }; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_BatchGetDocumentsRequest) */ } google_firestore_v1_BatchGetDocumentsRequest; @@ -143,12 +165,16 @@ typedef struct _google_firestore_v1_BatchGetDocumentsResponse { }; pb_bytes_array_t *transaction; google_protobuf_Timestamp read_time; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_BatchGetDocumentsResponse) */ } google_firestore_v1_BatchGetDocumentsResponse; typedef struct _google_firestore_v1_BeginTransactionRequest { pb_bytes_array_t *database; google_firestore_v1_TransactionOptions options; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_BeginTransactionRequest) */ } google_firestore_v1_BeginTransactionRequest; @@ -156,6 +182,8 @@ typedef struct _google_firestore_v1_CommitResponse { pb_size_t write_results_count; struct _google_firestore_v1_WriteResult *write_results; google_protobuf_Timestamp commit_time; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_CommitResponse) */ } google_firestore_v1_CommitResponse; @@ -165,12 +193,16 @@ typedef struct _google_firestore_v1_CreateDocumentRequest { pb_bytes_array_t *document_id; google_firestore_v1_Document document; google_firestore_v1_DocumentMask mask; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_CreateDocumentRequest) */ } google_firestore_v1_CreateDocumentRequest; typedef struct _google_firestore_v1_DeleteDocumentRequest { pb_bytes_array_t *name; google_firestore_v1_Precondition current_document; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_DeleteDocumentRequest) */ } google_firestore_v1_DeleteDocumentRequest; @@ -182,6 +214,8 @@ typedef struct _google_firestore_v1_GetDocumentRequest { pb_bytes_array_t *transaction; google_protobuf_Timestamp read_time; }; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_GetDocumentRequest) */ } google_firestore_v1_GetDocumentRequest; @@ -189,6 +223,8 @@ typedef struct _google_firestore_v1_ListCollectionIdsRequest { pb_bytes_array_t *parent; int32_t page_size; pb_bytes_array_t *page_token; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_ListCollectionIdsRequest) */ } google_firestore_v1_ListCollectionIdsRequest; @@ -205,6 +241,8 @@ typedef struct _google_firestore_v1_ListDocumentsRequest { google_protobuf_Timestamp read_time; }; bool show_missing; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_ListDocumentsRequest) */ } google_firestore_v1_ListDocumentsRequest; @@ -220,6 +258,8 @@ typedef struct _google_firestore_v1_RunQueryRequest { google_firestore_v1_TransactionOptions new_transaction; google_protobuf_Timestamp read_time; } consistency_selector; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_RunQueryRequest) */ } google_firestore_v1_RunQueryRequest; @@ -228,6 +268,8 @@ typedef struct _google_firestore_v1_RunQueryResponse { pb_bytes_array_t *transaction; google_protobuf_Timestamp read_time; int32_t skipped_results; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_RunQueryResponse) */ } google_firestore_v1_RunQueryResponse; @@ -235,9 +277,12 @@ typedef struct _google_firestore_v1_TargetChange { google_firestore_v1_TargetChange_TargetChangeType target_change_type; pb_size_t target_ids_count; int32_t *target_ids; + bool has_cause; google_rpc_Status cause; pb_bytes_array_t *resume_token; google_protobuf_Timestamp read_time; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_TargetChange) */ } google_firestore_v1_TargetChange; @@ -247,6 +292,8 @@ typedef struct _google_firestore_v1_Target_QueryTarget { union { google_firestore_v1_StructuredQuery structured_query; }; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_Target_QueryTarget) */ } google_firestore_v1_Target_QueryTarget; @@ -255,6 +302,8 @@ typedef struct _google_firestore_v1_UpdateDocumentRequest { google_firestore_v1_DocumentMask update_mask; google_firestore_v1_DocumentMask mask; google_firestore_v1_Precondition current_document; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_UpdateDocumentRequest) */ } google_firestore_v1_UpdateDocumentRequest; @@ -264,6 +313,8 @@ typedef struct _google_firestore_v1_WriteResponse { pb_size_t write_results_count; struct _google_firestore_v1_WriteResult *write_results; google_protobuf_Timestamp commit_time; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_WriteResponse) */ } google_firestore_v1_WriteResponse; @@ -276,6 +327,8 @@ typedef struct _google_firestore_v1_ListenResponse { google_firestore_v1_ExistenceFilter filter; google_firestore_v1_DocumentRemove document_remove; }; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_ListenResponse) */ } google_firestore_v1_ListenResponse; @@ -292,6 +345,8 @@ typedef struct _google_firestore_v1_Target { } resume_type; int32_t target_id; bool once; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_Target) */ } google_firestore_v1_Target; @@ -304,6 +359,8 @@ typedef struct _google_firestore_v1_ListenRequest { }; pb_size_t labels_count; struct _google_firestore_v1_ListenRequest_LabelsEntry *labels; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_ListenRequest) */ } google_firestore_v1_ListenRequest; @@ -334,7 +391,7 @@ typedef struct _google_firestore_v1_ListenRequest { #define google_firestore_v1_Target_init_default {0, {google_firestore_v1_Target_QueryTarget_init_default}, 0, {NULL}, 0, 0} #define google_firestore_v1_Target_DocumentsTarget_init_default {0, NULL} #define google_firestore_v1_Target_QueryTarget_init_default {NULL, 0, {google_firestore_v1_StructuredQuery_init_default}} -#define google_firestore_v1_TargetChange_init_default {_google_firestore_v1_TargetChange_TargetChangeType_MIN, 0, NULL, google_rpc_Status_init_default, NULL, google_protobuf_Timestamp_init_default} +#define google_firestore_v1_TargetChange_init_default {_google_firestore_v1_TargetChange_TargetChangeType_MIN, 0, NULL, false, google_rpc_Status_init_default, NULL, google_protobuf_Timestamp_init_default} #define google_firestore_v1_ListCollectionIdsRequest_init_default {NULL, 0, NULL} #define google_firestore_v1_ListCollectionIdsResponse_init_default {0, NULL, NULL} #define google_firestore_v1_GetDocumentRequest_init_zero {NULL, google_firestore_v1_DocumentMask_init_zero, 0, {NULL}} @@ -361,7 +418,7 @@ typedef struct _google_firestore_v1_ListenRequest { #define google_firestore_v1_Target_init_zero {0, {google_firestore_v1_Target_QueryTarget_init_zero}, 0, {NULL}, 0, 0} #define google_firestore_v1_Target_DocumentsTarget_init_zero {0, NULL} #define google_firestore_v1_Target_QueryTarget_init_zero {NULL, 0, {google_firestore_v1_StructuredQuery_init_zero}} -#define google_firestore_v1_TargetChange_init_zero {_google_firestore_v1_TargetChange_TargetChangeType_MIN, 0, NULL, google_rpc_Status_init_zero, NULL, google_protobuf_Timestamp_init_zero} +#define google_firestore_v1_TargetChange_init_zero {_google_firestore_v1_TargetChange_TargetChangeType_MIN, 0, NULL, false, google_rpc_Status_init_zero, NULL, google_protobuf_Timestamp_init_zero} #define google_firestore_v1_ListCollectionIdsRequest_init_zero {NULL, 0, NULL} #define google_firestore_v1_ListCollectionIdsResponse_init_zero {0, NULL, NULL} @@ -513,7 +570,7 @@ extern const pb_field_t google_firestore_v1_ListCollectionIdsResponse_fields[3]; /* google_firestore_v1_WriteResponse_size depends on runtime parameters */ /* google_firestore_v1_ListenRequest_size depends on runtime parameters */ /* google_firestore_v1_ListenRequest_LabelsEntry_size depends on runtime parameters */ -#define google_firestore_v1_ListenResponse_size (0 + ((((google_firestore_v1_TargetChange_size > google_firestore_v1_DocumentChange_size ? google_firestore_v1_TargetChange_size : google_firestore_v1_DocumentChange_size) > google_firestore_v1_DocumentRemove_size ? (google_firestore_v1_TargetChange_size > google_firestore_v1_DocumentChange_size ? google_firestore_v1_TargetChange_size : google_firestore_v1_DocumentChange_size) : google_firestore_v1_DocumentRemove_size) > google_firestore_v1_DocumentDelete_size ? ((google_firestore_v1_TargetChange_size > google_firestore_v1_DocumentChange_size ? google_firestore_v1_TargetChange_size : google_firestore_v1_DocumentChange_size) > google_firestore_v1_DocumentRemove_size ? (google_firestore_v1_TargetChange_size > google_firestore_v1_DocumentChange_size ? google_firestore_v1_TargetChange_size : google_firestore_v1_DocumentChange_size) : google_firestore_v1_DocumentRemove_size) : google_firestore_v1_DocumentDelete_size) > 24 ? (((google_firestore_v1_TargetChange_size > google_firestore_v1_DocumentChange_size ? google_firestore_v1_TargetChange_size : google_firestore_v1_DocumentChange_size) > google_firestore_v1_DocumentRemove_size ? (google_firestore_v1_TargetChange_size > google_firestore_v1_DocumentChange_size ? google_firestore_v1_TargetChange_size : google_firestore_v1_DocumentChange_size) : google_firestore_v1_DocumentRemove_size) > google_firestore_v1_DocumentDelete_size ? ((google_firestore_v1_TargetChange_size > google_firestore_v1_DocumentChange_size ? google_firestore_v1_TargetChange_size : google_firestore_v1_DocumentChange_size) > google_firestore_v1_DocumentRemove_size ? (google_firestore_v1_TargetChange_size > google_firestore_v1_DocumentChange_size ? google_firestore_v1_TargetChange_size : google_firestore_v1_DocumentChange_size) : google_firestore_v1_DocumentRemove_size) : google_firestore_v1_DocumentDelete_size) : 24)) +/* google_firestore_v1_ListenResponse_size depends on runtime parameters */ /* google_firestore_v1_Target_size depends on runtime parameters */ /* google_firestore_v1_Target_DocumentsTarget_size depends on runtime parameters */ /* google_firestore_v1_Target_QueryTarget_size depends on runtime parameters */ @@ -529,6 +586,8 @@ extern const pb_field_t google_firestore_v1_ListCollectionIdsResponse_fields[3]; #endif +const char* EnumToString( + google_firestore_v1_TargetChange_TargetChangeType value); } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.cc index 7e63a72..e8e89fe 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "query.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -34,7 +42,7 @@ const pb_field_t google_firestore_v1_StructuredQuery_fields[9] = { PB_FIELD( 2, MESSAGE , REPEATED, POINTER , OTHER, google_firestore_v1_StructuredQuery, from, select, &google_firestore_v1_StructuredQuery_CollectionSelector_fields), PB_FIELD( 3, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_StructuredQuery, where, from, &google_firestore_v1_StructuredQuery_Filter_fields), PB_FIELD( 4, MESSAGE , REPEATED, POINTER , OTHER, google_firestore_v1_StructuredQuery, order_by, where, &google_firestore_v1_StructuredQuery_Order_fields), - PB_FIELD( 5, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_StructuredQuery, limit, order_by, &google_protobuf_Int32Value_fields), + PB_FIELD( 5, MESSAGE , OPTIONAL, STATIC , OTHER, google_firestore_v1_StructuredQuery, limit, order_by, &google_protobuf_Int32Value_fields), PB_FIELD( 6, INT32 , SINGULAR, STATIC , OTHER, google_firestore_v1_StructuredQuery, offset, limit, 0), PB_FIELD( 7, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_StructuredQuery, start_at, offset, &google_firestore_v1_Cursor_fields), PB_FIELD( 8, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_StructuredQuery, end_at, start_at, &google_firestore_v1_Cursor_fields), @@ -124,6 +132,250 @@ PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_StructuredQuery, select) < 2 #endif +const char* EnumToString( + google_firestore_v1_StructuredQuery_Direction value) { + switch (value) { + case google_firestore_v1_StructuredQuery_Direction_DIRECTION_UNSPECIFIED: + return "DIRECTION_UNSPECIFIED"; + case google_firestore_v1_StructuredQuery_Direction_ASCENDING: + return "ASCENDING"; + case google_firestore_v1_StructuredQuery_Direction_DESCENDING: + return "DESCENDING"; + } + return ""; +} + +const char* EnumToString( + google_firestore_v1_StructuredQuery_CompositeFilter_Operator value) { + switch (value) { + case google_firestore_v1_StructuredQuery_CompositeFilter_Operator_OPERATOR_UNSPECIFIED: + return "OPERATOR_UNSPECIFIED"; + case google_firestore_v1_StructuredQuery_CompositeFilter_Operator_AND: + return "AND"; + } + return ""; +} + +const char* EnumToString( + google_firestore_v1_StructuredQuery_FieldFilter_Operator value) { + switch (value) { + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_OPERATOR_UNSPECIFIED: + return "OPERATOR_UNSPECIFIED"; + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_LESS_THAN: + return "LESS_THAN"; + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_LESS_THAN_OR_EQUAL: + return "LESS_THAN_OR_EQUAL"; + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_GREATER_THAN: + return "GREATER_THAN"; + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_GREATER_THAN_OR_EQUAL: + return "GREATER_THAN_OR_EQUAL"; + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_EQUAL: + return "EQUAL"; + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAY_CONTAINS: + return "ARRAY_CONTAINS"; + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_IN: + return "IN"; + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAY_CONTAINS_ANY: + return "ARRAY_CONTAINS_ANY"; + } + return ""; +} + +const char* EnumToString( + google_firestore_v1_StructuredQuery_UnaryFilter_Operator value) { + switch (value) { + case google_firestore_v1_StructuredQuery_UnaryFilter_Operator_OPERATOR_UNSPECIFIED: + return "OPERATOR_UNSPECIFIED"; + case google_firestore_v1_StructuredQuery_UnaryFilter_Operator_IS_NAN: + return "IS_NAN"; + case google_firestore_v1_StructuredQuery_UnaryFilter_Operator_IS_NULL: + return "IS_NULL"; + } + return ""; +} + +std::string google_firestore_v1_StructuredQuery::ToString(int indent) const { + std::string header = PrintHeader(indent, "StructuredQuery", this); + std::string result; + + result += PrintMessageField("select ", select, indent + 1, false); + for (pb_size_t i = 0; i != from_count; ++i) { + result += PrintMessageField("from ", from[i], indent + 1, true); + } + result += PrintMessageField("where ", where, indent + 1, false); + for (pb_size_t i = 0; i != order_by_count; ++i) { + result += PrintMessageField("order_by ", + order_by[i], indent + 1, true); + } + if (has_limit) { + result += PrintMessageField("limit ", limit, indent + 1, true); + } + result += PrintPrimitiveField("offset: ", offset, indent + 1, false); + result += PrintMessageField("start_at ", start_at, indent + 1, false); + result += PrintMessageField("end_at ", end_at, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_StructuredQuery_CollectionSelector::ToString(int indent) const { + std::string header = PrintHeader(indent, "CollectionSelector", this); + std::string result; + + result += PrintPrimitiveField("collection_id: ", + collection_id, indent + 1, false); + result += PrintPrimitiveField("all_descendants: ", + all_descendants, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_StructuredQuery_Filter::ToString(int indent) const { + std::string header = PrintHeader(indent, "Filter", this); + std::string result; + + switch (which_filter_type) { + case google_firestore_v1_StructuredQuery_Filter_composite_filter_tag: + result += PrintMessageField("composite_filter ", + composite_filter, indent + 1, true); + break; + case google_firestore_v1_StructuredQuery_Filter_field_filter_tag: + result += PrintMessageField("field_filter ", + field_filter, indent + 1, true); + break; + case google_firestore_v1_StructuredQuery_Filter_unary_filter_tag: + result += PrintMessageField("unary_filter ", + unary_filter, indent + 1, true); + break; + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_StructuredQuery_CompositeFilter::ToString(int indent) const { + std::string header = PrintHeader(indent, "CompositeFilter", this); + std::string result; + + result += PrintEnumField("op: ", op, indent + 1, false); + for (pb_size_t i = 0; i != filters_count; ++i) { + result += PrintMessageField("filters ", filters[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_StructuredQuery_FieldFilter::ToString(int indent) const { + std::string header = PrintHeader(indent, "FieldFilter", this); + std::string result; + + result += PrintMessageField("field ", field, indent + 1, false); + result += PrintEnumField("op: ", op, indent + 1, false); + result += PrintMessageField("value ", value, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_StructuredQuery_UnaryFilter::ToString(int indent) const { + std::string header = PrintHeader(indent, "UnaryFilter", this); + std::string result; + + result += PrintEnumField("op: ", op, indent + 1, false); + switch (which_operand_type) { + case google_firestore_v1_StructuredQuery_UnaryFilter_field_tag: + result += PrintMessageField("field ", field, indent + 1, true); + break; + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_StructuredQuery_Order::ToString(int indent) const { + std::string header = PrintHeader(indent, "Order", this); + std::string result; + + result += PrintMessageField("field ", field, indent + 1, false); + result += PrintEnumField("direction: ", direction, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_StructuredQuery_FieldReference::ToString(int indent) const { + std::string header = PrintHeader(indent, "FieldReference", this); + std::string result; + + result += PrintPrimitiveField("field_path: ", + field_path, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_StructuredQuery_Projection::ToString(int indent) const { + std::string header = PrintHeader(indent, "Projection", this); + std::string result; + + for (pb_size_t i = 0; i != fields_count; ++i) { + result += PrintMessageField("fields ", fields[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_Cursor::ToString(int indent) const { + std::string header = PrintHeader(indent, "Cursor", this); + std::string result; + + for (pb_size_t i = 0; i != values_count; ++i) { + result += PrintMessageField("values ", values[i], indent + 1, true); + } + result += PrintPrimitiveField("before: ", before, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.h index 70a7de2..6749445 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/query.nanopb.h @@ -15,7 +15,7 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_GOOGLE_FIRESTORE_V1_QUERY_NANOPB_H_INCLUDED #define PB_GOOGLE_FIRESTORE_V1_QUERY_NANOPB_H_INCLUDED @@ -27,6 +27,8 @@ #include "google/protobuf/wrappers.nanopb.h" +#include + namespace firebase { namespace firestore { @@ -61,11 +63,13 @@ typedef enum _google_firestore_v1_StructuredQuery_FieldFilter_Operator { google_firestore_v1_StructuredQuery_FieldFilter_Operator_GREATER_THAN = 3, google_firestore_v1_StructuredQuery_FieldFilter_Operator_GREATER_THAN_OR_EQUAL = 4, google_firestore_v1_StructuredQuery_FieldFilter_Operator_EQUAL = 5, - google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAY_CONTAINS = 7 + google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAY_CONTAINS = 7, + google_firestore_v1_StructuredQuery_FieldFilter_Operator_IN = 8, + google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAY_CONTAINS_ANY = 9 } google_firestore_v1_StructuredQuery_FieldFilter_Operator; #define _google_firestore_v1_StructuredQuery_FieldFilter_Operator_MIN google_firestore_v1_StructuredQuery_FieldFilter_Operator_OPERATOR_UNSPECIFIED -#define _google_firestore_v1_StructuredQuery_FieldFilter_Operator_MAX google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAY_CONTAINS -#define _google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAYSIZE ((google_firestore_v1_StructuredQuery_FieldFilter_Operator)(google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAY_CONTAINS+1)) +#define _google_firestore_v1_StructuredQuery_FieldFilter_Operator_MAX google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAY_CONTAINS_ANY +#define _google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAYSIZE ((google_firestore_v1_StructuredQuery_FieldFilter_Operator)(google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAY_CONTAINS_ANY+1)) typedef enum _google_firestore_v1_StructuredQuery_UnaryFilter_Operator { google_firestore_v1_StructuredQuery_UnaryFilter_Operator_OPERATOR_UNSPECIFIED = 0, @@ -79,12 +83,16 @@ typedef enum _google_firestore_v1_StructuredQuery_UnaryFilter_Operator { /* Struct definitions */ typedef struct _google_firestore_v1_StructuredQuery_FieldReference { pb_bytes_array_t *field_path; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_StructuredQuery_FieldReference) */ } google_firestore_v1_StructuredQuery_FieldReference; typedef struct _google_firestore_v1_StructuredQuery_Projection { pb_size_t fields_count; struct _google_firestore_v1_StructuredQuery_FieldReference *fields; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_StructuredQuery_Projection) */ } google_firestore_v1_StructuredQuery_Projection; @@ -92,12 +100,16 @@ typedef struct _google_firestore_v1_Cursor { pb_size_t values_count; struct _google_firestore_v1_Value *values; bool before; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_Cursor) */ } google_firestore_v1_Cursor; typedef struct _google_firestore_v1_StructuredQuery_CollectionSelector { pb_bytes_array_t *collection_id; bool all_descendants; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_StructuredQuery_CollectionSelector) */ } google_firestore_v1_StructuredQuery_CollectionSelector; @@ -105,6 +117,8 @@ typedef struct _google_firestore_v1_StructuredQuery_CompositeFilter { google_firestore_v1_StructuredQuery_CompositeFilter_Operator op; pb_size_t filters_count; struct _google_firestore_v1_StructuredQuery_Filter *filters; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_StructuredQuery_CompositeFilter) */ } google_firestore_v1_StructuredQuery_CompositeFilter; @@ -112,12 +126,16 @@ typedef struct _google_firestore_v1_StructuredQuery_FieldFilter { google_firestore_v1_StructuredQuery_FieldReference field; google_firestore_v1_StructuredQuery_FieldFilter_Operator op; google_firestore_v1_Value value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_StructuredQuery_FieldFilter) */ } google_firestore_v1_StructuredQuery_FieldFilter; typedef struct _google_firestore_v1_StructuredQuery_Order { google_firestore_v1_StructuredQuery_FieldReference field; google_firestore_v1_StructuredQuery_Direction direction; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_StructuredQuery_Order) */ } google_firestore_v1_StructuredQuery_Order; @@ -127,6 +145,8 @@ typedef struct _google_firestore_v1_StructuredQuery_UnaryFilter { union { google_firestore_v1_StructuredQuery_FieldReference field; }; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_StructuredQuery_UnaryFilter) */ } google_firestore_v1_StructuredQuery_UnaryFilter; @@ -137,6 +157,8 @@ typedef struct _google_firestore_v1_StructuredQuery_Filter { google_firestore_v1_StructuredQuery_FieldFilter field_filter; google_firestore_v1_StructuredQuery_UnaryFilter unary_filter; }; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_StructuredQuery_Filter) */ } google_firestore_v1_StructuredQuery_Filter; @@ -147,17 +169,20 @@ typedef struct _google_firestore_v1_StructuredQuery { google_firestore_v1_StructuredQuery_Filter where; pb_size_t order_by_count; struct _google_firestore_v1_StructuredQuery_Order *order_by; + bool has_limit; google_protobuf_Int32Value limit; int32_t offset; google_firestore_v1_Cursor start_at; google_firestore_v1_Cursor end_at; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_StructuredQuery) */ } google_firestore_v1_StructuredQuery; /* Default values for struct fields */ /* Initializer values for message structs */ -#define google_firestore_v1_StructuredQuery_init_default {google_firestore_v1_StructuredQuery_Projection_init_default, 0, NULL, google_firestore_v1_StructuredQuery_Filter_init_default, 0, NULL, google_protobuf_Int32Value_init_default, 0, google_firestore_v1_Cursor_init_default, google_firestore_v1_Cursor_init_default} +#define google_firestore_v1_StructuredQuery_init_default {google_firestore_v1_StructuredQuery_Projection_init_default, 0, NULL, google_firestore_v1_StructuredQuery_Filter_init_default, 0, NULL, false, google_protobuf_Int32Value_init_default, 0, google_firestore_v1_Cursor_init_default, google_firestore_v1_Cursor_init_default} #define google_firestore_v1_StructuredQuery_CollectionSelector_init_default {NULL, 0} #define google_firestore_v1_StructuredQuery_Filter_init_default {0, {google_firestore_v1_StructuredQuery_CompositeFilter_init_default}} #define google_firestore_v1_StructuredQuery_CompositeFilter_init_default {_google_firestore_v1_StructuredQuery_CompositeFilter_Operator_MIN, 0, NULL} @@ -167,7 +192,7 @@ typedef struct _google_firestore_v1_StructuredQuery { #define google_firestore_v1_StructuredQuery_FieldReference_init_default {NULL} #define google_firestore_v1_StructuredQuery_Projection_init_default {0, NULL} #define google_firestore_v1_Cursor_init_default {0, NULL, 0} -#define google_firestore_v1_StructuredQuery_init_zero {google_firestore_v1_StructuredQuery_Projection_init_zero, 0, NULL, google_firestore_v1_StructuredQuery_Filter_init_zero, 0, NULL, google_protobuf_Int32Value_init_zero, 0, google_firestore_v1_Cursor_init_zero, google_firestore_v1_Cursor_init_zero} +#define google_firestore_v1_StructuredQuery_init_zero {google_firestore_v1_StructuredQuery_Projection_init_zero, 0, NULL, google_firestore_v1_StructuredQuery_Filter_init_zero, 0, NULL, false, google_protobuf_Int32Value_init_zero, 0, google_firestore_v1_Cursor_init_zero, google_firestore_v1_Cursor_init_zero} #define google_firestore_v1_StructuredQuery_CollectionSelector_init_zero {NULL, 0} #define google_firestore_v1_StructuredQuery_Filter_init_zero {0, {google_firestore_v1_StructuredQuery_CompositeFilter_init_zero}} #define google_firestore_v1_StructuredQuery_CompositeFilter_init_zero {_google_firestore_v1_StructuredQuery_CompositeFilter_Operator_MIN, 0, NULL} @@ -221,11 +246,11 @@ extern const pb_field_t google_firestore_v1_Cursor_fields[3]; /* Maximum encoded size of messages (where known) */ /* google_firestore_v1_StructuredQuery_size depends on runtime parameters */ /* google_firestore_v1_StructuredQuery_CollectionSelector_size depends on runtime parameters */ -#define google_firestore_v1_StructuredQuery_Filter_size (0 + (((google_firestore_v1_StructuredQuery_UnaryFilter_size > google_firestore_v1_StructuredQuery_CompositeFilter_size ? google_firestore_v1_StructuredQuery_UnaryFilter_size : google_firestore_v1_StructuredQuery_CompositeFilter_size) > google_firestore_v1_StructuredQuery_FieldFilter_size ? (google_firestore_v1_StructuredQuery_UnaryFilter_size > google_firestore_v1_StructuredQuery_CompositeFilter_size ? google_firestore_v1_StructuredQuery_UnaryFilter_size : google_firestore_v1_StructuredQuery_CompositeFilter_size) : google_firestore_v1_StructuredQuery_FieldFilter_size) > 0 ? ((google_firestore_v1_StructuredQuery_UnaryFilter_size > google_firestore_v1_StructuredQuery_CompositeFilter_size ? google_firestore_v1_StructuredQuery_UnaryFilter_size : google_firestore_v1_StructuredQuery_CompositeFilter_size) > google_firestore_v1_StructuredQuery_FieldFilter_size ? (google_firestore_v1_StructuredQuery_UnaryFilter_size > google_firestore_v1_StructuredQuery_CompositeFilter_size ? google_firestore_v1_StructuredQuery_UnaryFilter_size : google_firestore_v1_StructuredQuery_CompositeFilter_size) : google_firestore_v1_StructuredQuery_FieldFilter_size) : 0)) +/* google_firestore_v1_StructuredQuery_Filter_size depends on runtime parameters */ /* google_firestore_v1_StructuredQuery_CompositeFilter_size depends on runtime parameters */ -#define google_firestore_v1_StructuredQuery_FieldFilter_size (14 + google_firestore_v1_StructuredQuery_FieldReference_size + google_firestore_v1_Value_size) -#define google_firestore_v1_StructuredQuery_UnaryFilter_size (2 + (google_firestore_v1_StructuredQuery_FieldReference_size > 0 ? google_firestore_v1_StructuredQuery_FieldReference_size : 0)) -#define google_firestore_v1_StructuredQuery_Order_size (8 + google_firestore_v1_StructuredQuery_FieldReference_size) +/* google_firestore_v1_StructuredQuery_FieldFilter_size depends on runtime parameters */ +/* google_firestore_v1_StructuredQuery_UnaryFilter_size depends on runtime parameters */ +/* google_firestore_v1_StructuredQuery_Order_size depends on runtime parameters */ /* google_firestore_v1_StructuredQuery_FieldReference_size depends on runtime parameters */ /* google_firestore_v1_StructuredQuery_Projection_size depends on runtime parameters */ /* google_firestore_v1_Cursor_size depends on runtime parameters */ @@ -238,6 +263,13 @@ extern const pb_field_t google_firestore_v1_Cursor_fields[3]; #endif +const char* EnumToString(google_firestore_v1_StructuredQuery_Direction value); +const char* EnumToString( + google_firestore_v1_StructuredQuery_CompositeFilter_Operator value); +const char* EnumToString( + google_firestore_v1_StructuredQuery_FieldFilter_Operator value); +const char* EnumToString( + google_firestore_v1_StructuredQuery_UnaryFilter_Operator value); } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.cc index 98cb7da..6bf2507 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "write.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -29,12 +37,13 @@ namespace firestore { -const pb_field_t google_firestore_v1_Write_fields[6] = { +const pb_field_t google_firestore_v1_Write_fields[7] = { PB_ANONYMOUS_ONEOF_FIELD(operation, 1, MESSAGE , ONEOF, STATIC , FIRST, google_firestore_v1_Write, update, update, &google_firestore_v1_Document_fields), PB_ANONYMOUS_ONEOF_FIELD(operation, 2, BYTES , ONEOF, POINTER , UNION, google_firestore_v1_Write, delete_, delete_, 0), + PB_ANONYMOUS_ONEOF_FIELD(operation, 5, BYTES , ONEOF, POINTER , UNION, google_firestore_v1_Write, verify, verify, 0), PB_ANONYMOUS_ONEOF_FIELD(operation, 6, MESSAGE , ONEOF, STATIC , UNION, google_firestore_v1_Write, transform, transform, &google_firestore_v1_DocumentTransform_fields), - PB_FIELD( 3, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_Write, update_mask, transform, &google_firestore_v1_DocumentMask_fields), - PB_FIELD( 4, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_Write, current_document, update_mask, &google_firestore_v1_Precondition_fields), + PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, google_firestore_v1_Write, update_mask, transform, &google_firestore_v1_DocumentMask_fields), + PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, google_firestore_v1_Write, current_document, update_mask, &google_firestore_v1_Precondition_fields), PB_LAST_FIELD }; @@ -56,7 +65,7 @@ const pb_field_t google_firestore_v1_DocumentTransform_FieldTransform_fields[8] }; const pb_field_t google_firestore_v1_WriteResult_fields[3] = { - PB_FIELD( 1, MESSAGE , SINGULAR, STATIC , FIRST, google_firestore_v1_WriteResult, update_time, update_time, &google_protobuf_Timestamp_fields), + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, google_firestore_v1_WriteResult, update_time, update_time, &google_protobuf_Timestamp_fields), PB_FIELD( 2, MESSAGE , REPEATED, POINTER , OTHER, google_firestore_v1_WriteResult, transform_results, update_time, &google_firestore_v1_Value_fields), PB_LAST_FIELD }; @@ -70,7 +79,7 @@ const pb_field_t google_firestore_v1_DocumentChange_fields[4] = { const pb_field_t google_firestore_v1_DocumentDelete_fields[4] = { PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, google_firestore_v1_DocumentDelete, document, document, 0), - PB_FIELD( 4, MESSAGE , SINGULAR, STATIC , OTHER, google_firestore_v1_DocumentDelete, read_time, document, &google_protobuf_Timestamp_fields), + PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, google_firestore_v1_DocumentDelete, read_time, document, &google_protobuf_Timestamp_fields), PB_FIELD( 6, INT32 , REPEATED, POINTER , OTHER, google_firestore_v1_DocumentDelete, removed_target_ids, read_time, 0), PB_LAST_FIELD }; @@ -114,6 +123,189 @@ PB_STATIC_ASSERT((pb_membersize(google_firestore_v1_Write, update) < 256 && pb_m #endif +const char* EnumToString( + google_firestore_v1_DocumentTransform_FieldTransform_ServerValue value) { + switch (value) { + case google_firestore_v1_DocumentTransform_FieldTransform_ServerValue_SERVER_VALUE_UNSPECIFIED: + return "SERVER_VALUE_UNSPECIFIED"; + case google_firestore_v1_DocumentTransform_FieldTransform_ServerValue_REQUEST_TIME: + return "REQUEST_TIME"; + } + return ""; +} + +std::string google_firestore_v1_Write::ToString(int indent) const { + std::string header = PrintHeader(indent, "Write", this); + std::string result; + + switch (which_operation) { + case google_firestore_v1_Write_update_tag: + result += PrintMessageField("update ", update, indent + 1, true); + break; + case google_firestore_v1_Write_delete_tag: + result += PrintPrimitiveField("delete: ", delete_, indent + 1, true); + break; + case google_firestore_v1_Write_verify_tag: + result += PrintPrimitiveField("verify: ", verify, indent + 1, true); + break; + case google_firestore_v1_Write_transform_tag: + result += PrintMessageField("transform ", transform, indent + 1, true); + break; + } + if (has_update_mask) { + result += PrintMessageField("update_mask ", + update_mask, indent + 1, true); + } + if (has_current_document) { + result += PrintMessageField("current_document ", + current_document, indent + 1, true); + } + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_DocumentTransform::ToString(int indent) const { + std::string header = PrintHeader(indent, "DocumentTransform", this); + std::string result; + + result += PrintPrimitiveField("document: ", document, indent + 1, false); + for (pb_size_t i = 0; i != field_transforms_count; ++i) { + result += PrintMessageField("field_transforms ", + field_transforms[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_DocumentTransform_FieldTransform::ToString(int indent) const { + std::string header = PrintHeader(indent, "FieldTransform", this); + std::string result; + + result += PrintPrimitiveField("field_path: ", + field_path, indent + 1, false); + switch (which_transform_type) { + case google_firestore_v1_DocumentTransform_FieldTransform_set_to_server_value_tag: + result += PrintEnumField("set_to_server_value: ", + set_to_server_value, indent + 1, true); + break; + case google_firestore_v1_DocumentTransform_FieldTransform_increment_tag: + result += PrintMessageField("increment ", increment, indent + 1, true); + break; + case google_firestore_v1_DocumentTransform_FieldTransform_maximum_tag: + result += PrintMessageField("maximum ", maximum, indent + 1, true); + break; + case google_firestore_v1_DocumentTransform_FieldTransform_minimum_tag: + result += PrintMessageField("minimum ", minimum, indent + 1, true); + break; + case google_firestore_v1_DocumentTransform_FieldTransform_append_missing_elements_tag: + result += PrintMessageField("append_missing_elements ", + append_missing_elements, indent + 1, true); + break; + case google_firestore_v1_DocumentTransform_FieldTransform_remove_all_from_array_tag: + result += PrintMessageField("remove_all_from_array ", + remove_all_from_array, indent + 1, true); + break; + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_firestore_v1_WriteResult::ToString(int indent) const { + std::string header = PrintHeader(indent, "WriteResult", this); + std::string result; + + if (has_update_time) { + result += PrintMessageField("update_time ", + update_time, indent + 1, true); + } + for (pb_size_t i = 0; i != transform_results_count; ++i) { + result += PrintMessageField("transform_results ", + transform_results[i], indent + 1, true); + } + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_DocumentChange::ToString(int indent) const { + std::string header = PrintHeader(indent, "DocumentChange", this); + std::string result; + + result += PrintMessageField("document ", document, indent + 1, false); + for (pb_size_t i = 0; i != target_ids_count; ++i) { + result += PrintPrimitiveField("target_ids: ", + target_ids[i], indent + 1, true); + } + for (pb_size_t i = 0; i != removed_target_ids_count; ++i) { + result += PrintPrimitiveField("removed_target_ids: ", + removed_target_ids[i], indent + 1, true); + } + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_DocumentDelete::ToString(int indent) const { + std::string header = PrintHeader(indent, "DocumentDelete", this); + std::string result; + + result += PrintPrimitiveField("document: ", document, indent + 1, false); + if (has_read_time) { + result += PrintMessageField("read_time ", read_time, indent + 1, true); + } + for (pb_size_t i = 0; i != removed_target_ids_count; ++i) { + result += PrintPrimitiveField("removed_target_ids: ", + removed_target_ids[i], indent + 1, true); + } + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_DocumentRemove::ToString(int indent) const { + std::string header = PrintHeader(indent, "DocumentRemove", this); + std::string result; + + result += PrintPrimitiveField("document: ", document, indent + 1, false); + for (pb_size_t i = 0; i != removed_target_ids_count; ++i) { + result += PrintPrimitiveField("removed_target_ids: ", + removed_target_ids[i], indent + 1, true); + } + result += PrintMessageField("read_time ", read_time, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_firestore_v1_ExistenceFilter::ToString(int indent) const { + std::string header = PrintHeader(indent, "ExistenceFilter", this); + std::string result; + + result += PrintPrimitiveField("target_id: ", target_id, indent + 1, false); + result += PrintPrimitiveField("count: ", count, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.h index fb9c54e..35bd822 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/firestore/v1/write.nanopb.h @@ -15,7 +15,7 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_GOOGLE_FIRESTORE_V1_WRITE_NANOPB_H_INCLUDED #define PB_GOOGLE_FIRESTORE_V1_WRITE_NANOPB_H_INCLUDED @@ -29,6 +29,8 @@ #include "google/protobuf/timestamp.nanopb.h" +#include + namespace firebase { namespace firestore { @@ -52,6 +54,8 @@ typedef struct _google_firestore_v1_DocumentTransform { pb_bytes_array_t *document; pb_size_t field_transforms_count; struct _google_firestore_v1_DocumentTransform_FieldTransform *field_transforms; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_DocumentTransform) */ } google_firestore_v1_DocumentTransform; @@ -61,14 +65,19 @@ typedef struct _google_firestore_v1_DocumentChange { int32_t *target_ids; pb_size_t removed_target_ids_count; int32_t *removed_target_ids; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_DocumentChange) */ } google_firestore_v1_DocumentChange; typedef struct _google_firestore_v1_DocumentDelete { pb_bytes_array_t *document; + bool has_read_time; google_protobuf_Timestamp read_time; pb_size_t removed_target_ids_count; int32_t *removed_target_ids; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_DocumentDelete) */ } google_firestore_v1_DocumentDelete; @@ -77,6 +86,8 @@ typedef struct _google_firestore_v1_DocumentRemove { pb_size_t removed_target_ids_count; int32_t *removed_target_ids; google_protobuf_Timestamp read_time; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_DocumentRemove) */ } google_firestore_v1_DocumentRemove; @@ -91,12 +102,16 @@ typedef struct _google_firestore_v1_DocumentTransform_FieldTransform { google_firestore_v1_ArrayValue append_missing_elements; google_firestore_v1_ArrayValue remove_all_from_array; }; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_DocumentTransform_FieldTransform) */ } google_firestore_v1_DocumentTransform_FieldTransform; typedef struct _google_firestore_v1_ExistenceFilter { int32_t target_id; int32_t count; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_ExistenceFilter) */ } google_firestore_v1_ExistenceFilter; @@ -105,37 +120,45 @@ typedef struct _google_firestore_v1_Write { union { google_firestore_v1_Document update; pb_bytes_array_t *delete_; + pb_bytes_array_t *verify; google_firestore_v1_DocumentTransform transform; }; + bool has_update_mask; google_firestore_v1_DocumentMask update_mask; + bool has_current_document; google_firestore_v1_Precondition current_document; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_Write) */ } google_firestore_v1_Write; typedef struct _google_firestore_v1_WriteResult { + bool has_update_time; google_protobuf_Timestamp update_time; pb_size_t transform_results_count; struct _google_firestore_v1_Value *transform_results; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_firestore_v1_WriteResult) */ } google_firestore_v1_WriteResult; /* Default values for struct fields */ /* Initializer values for message structs */ -#define google_firestore_v1_Write_init_default {0, {google_firestore_v1_Document_init_default}, google_firestore_v1_DocumentMask_init_default, google_firestore_v1_Precondition_init_default} +#define google_firestore_v1_Write_init_default {0, {google_firestore_v1_Document_init_default}, false, google_firestore_v1_DocumentMask_init_default, false, google_firestore_v1_Precondition_init_default} #define google_firestore_v1_DocumentTransform_init_default {NULL, 0, NULL} #define google_firestore_v1_DocumentTransform_FieldTransform_init_default {NULL, 0, {_google_firestore_v1_DocumentTransform_FieldTransform_ServerValue_MIN}} -#define google_firestore_v1_WriteResult_init_default {google_protobuf_Timestamp_init_default, 0, NULL} +#define google_firestore_v1_WriteResult_init_default {false, google_protobuf_Timestamp_init_default, 0, NULL} #define google_firestore_v1_DocumentChange_init_default {google_firestore_v1_Document_init_default, 0, NULL, 0, NULL} -#define google_firestore_v1_DocumentDelete_init_default {NULL, google_protobuf_Timestamp_init_default, 0, NULL} +#define google_firestore_v1_DocumentDelete_init_default {NULL, false, google_protobuf_Timestamp_init_default, 0, NULL} #define google_firestore_v1_DocumentRemove_init_default {NULL, 0, NULL, google_protobuf_Timestamp_init_default} #define google_firestore_v1_ExistenceFilter_init_default {0, 0} -#define google_firestore_v1_Write_init_zero {0, {google_firestore_v1_Document_init_zero}, google_firestore_v1_DocumentMask_init_zero, google_firestore_v1_Precondition_init_zero} +#define google_firestore_v1_Write_init_zero {0, {google_firestore_v1_Document_init_zero}, false, google_firestore_v1_DocumentMask_init_zero, false, google_firestore_v1_Precondition_init_zero} #define google_firestore_v1_DocumentTransform_init_zero {NULL, 0, NULL} #define google_firestore_v1_DocumentTransform_FieldTransform_init_zero {NULL, 0, {_google_firestore_v1_DocumentTransform_FieldTransform_ServerValue_MIN}} -#define google_firestore_v1_WriteResult_init_zero {google_protobuf_Timestamp_init_zero, 0, NULL} +#define google_firestore_v1_WriteResult_init_zero {false, google_protobuf_Timestamp_init_zero, 0, NULL} #define google_firestore_v1_DocumentChange_init_zero {google_firestore_v1_Document_init_zero, 0, NULL, 0, NULL} -#define google_firestore_v1_DocumentDelete_init_zero {NULL, google_protobuf_Timestamp_init_zero, 0, NULL} +#define google_firestore_v1_DocumentDelete_init_zero {NULL, false, google_protobuf_Timestamp_init_zero, 0, NULL} #define google_firestore_v1_DocumentRemove_init_zero {NULL, 0, NULL, google_protobuf_Timestamp_init_zero} #define google_firestore_v1_ExistenceFilter_init_zero {0, 0} @@ -162,6 +185,7 @@ typedef struct _google_firestore_v1_WriteResult { #define google_firestore_v1_ExistenceFilter_count_tag 2 #define google_firestore_v1_Write_update_tag 1 #define google_firestore_v1_Write_delete_tag 2 +#define google_firestore_v1_Write_verify_tag 5 #define google_firestore_v1_Write_transform_tag 6 #define google_firestore_v1_Write_update_mask_tag 3 #define google_firestore_v1_Write_current_document_tag 4 @@ -169,7 +193,7 @@ typedef struct _google_firestore_v1_WriteResult { #define google_firestore_v1_WriteResult_transform_results_tag 2 /* Struct field encoding specification for nanopb */ -extern const pb_field_t google_firestore_v1_Write_fields[6]; +extern const pb_field_t google_firestore_v1_Write_fields[7]; extern const pb_field_t google_firestore_v1_DocumentTransform_fields[3]; extern const pb_field_t google_firestore_v1_DocumentTransform_FieldTransform_fields[8]; extern const pb_field_t google_firestore_v1_WriteResult_fields[3]; @@ -196,6 +220,8 @@ extern const pb_field_t google_firestore_v1_ExistenceFilter_fields[3]; #endif +const char* EnumToString( + google_firestore_v1_DocumentTransform_FieldTransform_ServerValue value); } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/any.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/any.nanopb.cc index f88662d..a845648 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/any.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/any.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "any.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -36,6 +44,22 @@ const pb_field_t google_protobuf_Any_fields[3] = { }; +std::string google_protobuf_Any::ToString(int indent) const { + std::string header = PrintHeader(indent, "Any", this); + std::string result; + + result += PrintPrimitiveField("type_url: ", type_url, indent + 1, false); + result += PrintPrimitiveField("value: ", value, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/any.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/any.nanopb.h index a9ca0c1..f2c498f 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/any.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/any.nanopb.h @@ -15,12 +15,14 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_GOOGLE_PROTOBUF_ANY_NANOPB_H_INCLUDED #define PB_GOOGLE_PROTOBUF_ANY_NANOPB_H_INCLUDED #include +#include + namespace firebase { namespace firestore { @@ -34,6 +36,8 @@ namespace firestore { typedef struct _google_protobuf_Any { pb_bytes_array_t *type_url; pb_bytes_array_t *value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_Any) */ } google_protobuf_Any; diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.cc index adce8fc..86dc49c 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "empty.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -34,6 +42,20 @@ const pb_field_t google_protobuf_Empty_fields[1] = { }; +std::string google_protobuf_Empty::ToString(int indent) const { + std::string header = PrintHeader(indent, "Empty", this); + std::string result; + + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.h index 59070a0..f3b062b 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/empty.nanopb.h @@ -15,12 +15,14 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_GOOGLE_PROTOBUF_EMPTY_NANOPB_H_INCLUDED #define PB_GOOGLE_PROTOBUF_EMPTY_NANOPB_H_INCLUDED #include +#include + namespace firebase { namespace firestore { @@ -33,6 +35,8 @@ namespace firestore { /* Struct definitions */ typedef struct _google_protobuf_Empty { char dummy_field; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_Empty) */ } google_protobuf_Empty; diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.cc index 37644b1..b7e4bbf 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "struct.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -81,6 +89,99 @@ PB_STATIC_ASSERT((pb_membersize(google_protobuf_Struct_FieldsEntry, value) < 256 #endif +const char* EnumToString( + google_protobuf_NullValue value) { + switch (value) { + case google_protobuf_NullValue_NULL_VALUE: + return "NULL_VALUE"; + } + return ""; +} + +std::string google_protobuf_Struct::ToString(int indent) const { + std::string header = PrintHeader(indent, "Struct", this); + std::string result; + + for (pb_size_t i = 0; i != fields_count; ++i) { + result += PrintMessageField("fields ", fields[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_protobuf_Struct_FieldsEntry::ToString(int indent) const { + std::string header = PrintHeader(indent, "FieldsEntry", this); + std::string result; + + result += PrintPrimitiveField("key: ", key, indent + 1, false); + result += PrintMessageField("value ", value, indent + 1, false); + + std::string tail = PrintTail(indent); + return header + result + tail; +} + +std::string google_protobuf_Value::ToString(int indent) const { + std::string header = PrintHeader(indent, "Value", this); + std::string result; + + switch (which_kind) { + case google_protobuf_Value_null_value_tag: + result += PrintEnumField("null_value: ", null_value, indent + 1, true); + break; + case google_protobuf_Value_number_value_tag: + result += PrintPrimitiveField("number_value: ", + number_value, indent + 1, true); + break; + case google_protobuf_Value_string_value_tag: + result += PrintPrimitiveField("string_value: ", + string_value, indent + 1, true); + break; + case google_protobuf_Value_bool_value_tag: + result += PrintPrimitiveField("bool_value: ", + bool_value, indent + 1, true); + break; + case google_protobuf_Value_struct_value_tag: + result += PrintMessageField("struct_value ", + struct_value, indent + 1, true); + break; + case google_protobuf_Value_list_value_tag: + result += PrintMessageField("list_value ", + list_value, indent + 1, true); + break; + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_protobuf_ListValue::ToString(int indent) const { + std::string header = PrintHeader(indent, "ListValue", this); + std::string result; + + for (pb_size_t i = 0; i != values_count; ++i) { + result += PrintMessageField("values ", values[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.h index a71439e..d77df42 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/struct.nanopb.h @@ -15,12 +15,14 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_GOOGLE_PROTOBUF_STRUCT_NANOPB_H_INCLUDED #define PB_GOOGLE_PROTOBUF_STRUCT_NANOPB_H_INCLUDED #include +#include + namespace firebase { namespace firestore { @@ -42,12 +44,16 @@ typedef enum _google_protobuf_NullValue { typedef struct _google_protobuf_ListValue { pb_size_t values_count; struct _google_protobuf_Value *values; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_ListValue) */ } google_protobuf_ListValue; typedef struct _google_protobuf_Struct { pb_size_t fields_count; struct _google_protobuf_Struct_FieldsEntry *fields; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_Struct) */ } google_protobuf_Struct; @@ -61,12 +67,16 @@ typedef struct _google_protobuf_Value { google_protobuf_Struct struct_value; google_protobuf_ListValue list_value; }; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_Value) */ } google_protobuf_Value; typedef struct _google_protobuf_Struct_FieldsEntry { pb_bytes_array_t *key; google_protobuf_Value value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_Struct_FieldsEntry) */ } google_protobuf_Struct_FieldsEntry; @@ -114,6 +124,7 @@ extern const pb_field_t google_protobuf_ListValue_fields[2]; #endif +const char* EnumToString(google_protobuf_NullValue value); } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.cc index 9814b20..2d752e3 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "timestamp.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -36,6 +44,22 @@ const pb_field_t google_protobuf_Timestamp_fields[3] = { }; +std::string google_protobuf_Timestamp::ToString(int indent) const { + std::string header = PrintHeader(indent, "Timestamp", this); + std::string result; + + result += PrintPrimitiveField("seconds: ", seconds, indent + 1, false); + result += PrintPrimitiveField("nanos: ", nanos, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.h index 57ac091..effb7a6 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/timestamp.nanopb.h @@ -15,12 +15,14 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_GOOGLE_PROTOBUF_TIMESTAMP_NANOPB_H_INCLUDED #define PB_GOOGLE_PROTOBUF_TIMESTAMP_NANOPB_H_INCLUDED #include +#include + namespace firebase { namespace firestore { @@ -34,6 +36,8 @@ namespace firestore { typedef struct _google_protobuf_Timestamp { int64_t seconds; int32_t nanos; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_Timestamp) */ } google_protobuf_Timestamp; diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.cc index 915459a..5e166b4 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "wrappers.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -81,6 +89,141 @@ const pb_field_t google_protobuf_BytesValue_fields[2] = { */ PB_STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES) +std::string google_protobuf_DoubleValue::ToString(int indent) const { + std::string header = PrintHeader(indent, "DoubleValue", this); + std::string result; + + result += PrintPrimitiveField("value: ", value, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_protobuf_FloatValue::ToString(int indent) const { + std::string header = PrintHeader(indent, "FloatValue", this); + std::string result; + + result += PrintPrimitiveField("value: ", value, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_protobuf_Int64Value::ToString(int indent) const { + std::string header = PrintHeader(indent, "Int64Value", this); + std::string result; + + result += PrintPrimitiveField("value: ", value, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_protobuf_UInt64Value::ToString(int indent) const { + std::string header = PrintHeader(indent, "UInt64Value", this); + std::string result; + + result += PrintPrimitiveField("value: ", value, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_protobuf_Int32Value::ToString(int indent) const { + std::string header = PrintHeader(indent, "Int32Value", this); + std::string result; + + result += PrintPrimitiveField("value: ", value, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_protobuf_UInt32Value::ToString(int indent) const { + std::string header = PrintHeader(indent, "UInt32Value", this); + std::string result; + + result += PrintPrimitiveField("value: ", value, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_protobuf_BoolValue::ToString(int indent) const { + std::string header = PrintHeader(indent, "BoolValue", this); + std::string result; + + result += PrintPrimitiveField("value: ", value, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_protobuf_StringValue::ToString(int indent) const { + std::string header = PrintHeader(indent, "StringValue", this); + std::string result; + + result += PrintPrimitiveField("value: ", value, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + +std::string google_protobuf_BytesValue::ToString(int indent) const { + std::string header = PrintHeader(indent, "BytesValue", this); + std::string result; + + result += PrintPrimitiveField("value: ", value, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.h index de0ed65..f6116e6 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/protobuf/wrappers.nanopb.h @@ -15,12 +15,14 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_GOOGLE_PROTOBUF_WRAPPERS_NANOPB_H_INCLUDED #define PB_GOOGLE_PROTOBUF_WRAPPERS_NANOPB_H_INCLUDED #include +#include + namespace firebase { namespace firestore { @@ -33,46 +35,64 @@ namespace firestore { /* Struct definitions */ typedef struct _google_protobuf_BytesValue { pb_bytes_array_t *value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_BytesValue) */ } google_protobuf_BytesValue; typedef struct _google_protobuf_StringValue { pb_bytes_array_t *value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_StringValue) */ } google_protobuf_StringValue; typedef struct _google_protobuf_BoolValue { bool value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_BoolValue) */ } google_protobuf_BoolValue; typedef struct _google_protobuf_DoubleValue { double value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_DoubleValue) */ } google_protobuf_DoubleValue; typedef struct _google_protobuf_FloatValue { float value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_FloatValue) */ } google_protobuf_FloatValue; typedef struct _google_protobuf_Int32Value { int32_t value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_Int32Value) */ } google_protobuf_Int32Value; typedef struct _google_protobuf_Int64Value { int64_t value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_Int64Value) */ } google_protobuf_Int64Value; typedef struct _google_protobuf_UInt32Value { uint32_t value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_UInt32Value) */ } google_protobuf_UInt32Value; typedef struct _google_protobuf_UInt64Value { uint64_t value; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_protobuf_UInt64Value) */ } google_protobuf_UInt64Value; diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/rpc/status.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/rpc/status.nanopb.cc index e340d83..e6e3f75 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/rpc/status.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/rpc/status.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "status.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -37,6 +45,25 @@ const pb_field_t google_rpc_Status_fields[4] = { }; +std::string google_rpc_Status::ToString(int indent) const { + std::string header = PrintHeader(indent, "Status", this); + std::string result; + + result += PrintPrimitiveField("code: ", code, indent + 1, false); + result += PrintPrimitiveField("message: ", message, indent + 1, false); + for (pb_size_t i = 0; i != details_count; ++i) { + result += PrintMessageField("details ", details[i], indent + 1, true); + } + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/rpc/status.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/rpc/status.nanopb.h index 6186d61..a17f46a 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/rpc/status.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/rpc/status.nanopb.h @@ -15,7 +15,7 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_GOOGLE_RPC_STATUS_NANOPB_H_INCLUDED #define PB_GOOGLE_RPC_STATUS_NANOPB_H_INCLUDED @@ -23,6 +23,8 @@ #include "google/protobuf/any.nanopb.h" +#include + namespace firebase { namespace firestore { @@ -38,6 +40,8 @@ typedef struct _google_rpc_Status { pb_bytes_array_t *message; pb_size_t details_count; struct _google_protobuf_Any *details; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_rpc_Status) */ } google_rpc_Status; diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/type/latlng.nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/type/latlng.nanopb.cc index 53a7d70..c2c664f 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/type/latlng.nanopb.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/type/latlng.nanopb.cc @@ -15,13 +15,21 @@ */ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #include "latlng.nanopb.h" +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + namespace firebase { namespace firestore { +using nanopb::PrintEnumField; +using nanopb::PrintHeader; +using nanopb::PrintMessageField; +using nanopb::PrintPrimitiveField; +using nanopb::PrintTail; + /* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 30 #error Regenerate this file with the current version of nanopb generator. @@ -42,6 +50,22 @@ const pb_field_t google_type_LatLng_fields[3] = { */ PB_STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES) +std::string google_type_LatLng::ToString(int indent) const { + std::string header = PrintHeader(indent, "LatLng", this); + std::string result; + + result += PrintPrimitiveField("latitude: ", latitude, indent + 1, false); + result += PrintPrimitiveField("longitude: ", longitude, indent + 1, false); + + bool is_root = indent == 0; + if (!result.empty() || is_root) { + std::string tail = PrintTail(indent); + return header + result + tail; + } else { + return ""; + } +} + } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/type/latlng.nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/type/latlng.nanopb.h index 2b756f5..27f059e 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/type/latlng.nanopb.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Protos/nanopb/google/type/latlng.nanopb.h @@ -15,12 +15,14 @@ */ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.9.1 */ +/* Generated by nanopb-0.3.9.2 */ #ifndef PB_GOOGLE_TYPE_LATLNG_NANOPB_H_INCLUDED #define PB_GOOGLE_TYPE_LATLNG_NANOPB_H_INCLUDED #include +#include + namespace firebase { namespace firestore { @@ -34,6 +36,8 @@ namespace firestore { typedef struct _google_type_LatLng { double latitude; double longitude; + + std::string ToString(int indent = 0) const; /* @@protoc_insertion_point(struct:google_type_LatLng) */ } google_type_LatLng; diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h deleted file mode 100644 index cac8209..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: firestore/local/maybe_document.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers.h" -#endif - -#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002 -#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources. -#endif -#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION -#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -@class FSTPBNoDocument; -@class FSTPBUnknownDocument; -@class GCFSDocument; -@class GPBTimestamp; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - FSTPBMaybeDocumentRoot - -/** - * Exposes the extension registry for this file. - * - * The base class provides: - * @code - * + (GPBExtensionRegistry *)extensionRegistry; - * @endcode - * which is a @c GPBExtensionRegistry that includes all the extensions defined by - * this file and all files that it depends on. - **/ -@interface FSTPBMaybeDocumentRoot : GPBRootObject -@end - -#pragma mark - FSTPBNoDocument - -typedef GPB_ENUM(FSTPBNoDocument_FieldNumber) { - FSTPBNoDocument_FieldNumber_Name = 1, - FSTPBNoDocument_FieldNumber_ReadTime = 2, -}; - -/** - * A message indicating that the document is known to not exist. - **/ -@interface FSTPBNoDocument : GPBMessage - -/** - * The name of the document that does not exist, in the standard format: - * `projects/{project_id}/databases/{database_id}/documents/{document_path}` - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; - -/** The time at which we observed that it does not exist. */ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *readTime; -/** Test to see if @c readTime has been set. */ -@property(nonatomic, readwrite) BOOL hasReadTime; - -@end - -#pragma mark - FSTPBUnknownDocument - -typedef GPB_ENUM(FSTPBUnknownDocument_FieldNumber) { - FSTPBUnknownDocument_FieldNumber_Name = 1, - FSTPBUnknownDocument_FieldNumber_Version = 2, -}; - -/** - * A message indicating that the document that is known to exist but its data - * is unknown. - **/ -@interface FSTPBUnknownDocument : GPBMessage - -/** - * The name of the document that is known to exist, in the standard format: - * `projects/{project_id}/databases/{database_id}/documents/{document_path}` - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; - -/** The version at which we know the document exists. */ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *version; -/** Test to see if @c version has been set. */ -@property(nonatomic, readwrite) BOOL hasVersion; - -@end - -#pragma mark - FSTPBMaybeDocument - -typedef GPB_ENUM(FSTPBMaybeDocument_FieldNumber) { - FSTPBMaybeDocument_FieldNumber_NoDocument = 1, - FSTPBMaybeDocument_FieldNumber_Document = 2, - FSTPBMaybeDocument_FieldNumber_UnknownDocument = 3, - FSTPBMaybeDocument_FieldNumber_HasCommittedMutations = 4, -}; - -typedef GPB_ENUM(FSTPBMaybeDocument_DocumentType_OneOfCase) { - FSTPBMaybeDocument_DocumentType_OneOfCase_GPBUnsetOneOfCase = 0, - FSTPBMaybeDocument_DocumentType_OneOfCase_NoDocument = 1, - FSTPBMaybeDocument_DocumentType_OneOfCase_Document = 2, - FSTPBMaybeDocument_DocumentType_OneOfCase_UnknownDocument = 3, -}; - -/** - * Represents either an existing document, the explicitly known absence of a - * document, or a document that is known to exist (at some version) but whose - * contents are unknown. - **/ -@interface FSTPBMaybeDocument : GPBMessage - -@property(nonatomic, readonly) FSTPBMaybeDocument_DocumentType_OneOfCase documentTypeOneOfCase; - -/** Used if the document is known to not exist. */ -@property(nonatomic, readwrite, strong, null_resettable) FSTPBNoDocument *noDocument; - -/** The document (if it exists). */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocument *document; - -/** Used if the document is known to exist but its data is unknown. */ -@property(nonatomic, readwrite, strong, null_resettable) FSTPBUnknownDocument *unknownDocument; - -/** - * `has_committed_mutations` marks documents that were written to the remote - * document store based on a write acknowledgment. These documents are - * potentially inconsistent with the backend's copy and use the write's - * commit version as their document version. - **/ -@property(nonatomic, readwrite) BOOL hasCommittedMutations; - -@end - -/** - * Clears whatever value was set for the oneof 'documentType'. - **/ -void FSTPBMaybeDocument_ClearDocumentTypeOneOfCase(FSTPBMaybeDocument *message); - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.m b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.m deleted file mode 100644 index 83bed77..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.m +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: firestore/local/maybe_document.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers_RuntimeSupport.h" -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "Timestamp.pbobjc.h" -#endif - - #import "MaybeDocument.pbobjc.h" - #import "Document.pbobjc.h" - #import "Annotations.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#pragma clang diagnostic ignored "-Wdirect-ivar-access" - -#pragma mark - FSTPBMaybeDocumentRoot - -@implementation FSTPBMaybeDocumentRoot - - -@end - -#pragma mark - FSTPBMaybeDocumentRoot_FileDescriptor - -static GPBFileDescriptor *FSTPBMaybeDocumentRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPB_DEBUG_CHECK_RUNTIME_VERSIONS(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"firestore.client" - objcPrefix:@"FSTPB" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - FSTPBNoDocument - -@implementation FSTPBNoDocument - -@dynamic name; -@dynamic hasReadTime, readTime; - -typedef struct FSTPBNoDocument__storage_ { - uint32_t _has_storage_[1]; - NSString *name; - GPBTimestamp *readTime; -} FSTPBNoDocument__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .dataTypeSpecific.className = NULL, - .number = FSTPBNoDocument_FieldNumber_Name, - .hasIndex = 0, - .offset = (uint32_t)offsetof(FSTPBNoDocument__storage_, name), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "readTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = FSTPBNoDocument_FieldNumber_ReadTime, - .hasIndex = 1, - .offset = (uint32_t)offsetof(FSTPBNoDocument__storage_, readTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[FSTPBNoDocument class] - rootClass:[FSTPBMaybeDocumentRoot class] - file:FSTPBMaybeDocumentRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(FSTPBNoDocument__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - FSTPBUnknownDocument - -@implementation FSTPBUnknownDocument - -@dynamic name; -@dynamic hasVersion, version; - -typedef struct FSTPBUnknownDocument__storage_ { - uint32_t _has_storage_[1]; - NSString *name; - GPBTimestamp *version; -} FSTPBUnknownDocument__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .dataTypeSpecific.className = NULL, - .number = FSTPBUnknownDocument_FieldNumber_Name, - .hasIndex = 0, - .offset = (uint32_t)offsetof(FSTPBUnknownDocument__storage_, name), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "version", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = FSTPBUnknownDocument_FieldNumber_Version, - .hasIndex = 1, - .offset = (uint32_t)offsetof(FSTPBUnknownDocument__storage_, version), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[FSTPBUnknownDocument class] - rootClass:[FSTPBMaybeDocumentRoot class] - file:FSTPBMaybeDocumentRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(FSTPBUnknownDocument__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - FSTPBMaybeDocument - -@implementation FSTPBMaybeDocument - -@dynamic documentTypeOneOfCase; -@dynamic noDocument; -@dynamic document; -@dynamic unknownDocument; -@dynamic hasCommittedMutations; - -typedef struct FSTPBMaybeDocument__storage_ { - uint32_t _has_storage_[2]; - FSTPBNoDocument *noDocument; - GCFSDocument *document; - FSTPBUnknownDocument *unknownDocument; -} FSTPBMaybeDocument__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "noDocument", - .dataTypeSpecific.className = GPBStringifySymbol(FSTPBNoDocument), - .number = FSTPBMaybeDocument_FieldNumber_NoDocument, - .hasIndex = -1, - .offset = (uint32_t)offsetof(FSTPBMaybeDocument__storage_, noDocument), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "document", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocument), - .number = FSTPBMaybeDocument_FieldNumber_Document, - .hasIndex = -1, - .offset = (uint32_t)offsetof(FSTPBMaybeDocument__storage_, document), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "unknownDocument", - .dataTypeSpecific.className = GPBStringifySymbol(FSTPBUnknownDocument), - .number = FSTPBMaybeDocument_FieldNumber_UnknownDocument, - .hasIndex = -1, - .offset = (uint32_t)offsetof(FSTPBMaybeDocument__storage_, unknownDocument), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "hasCommittedMutations", - .dataTypeSpecific.className = NULL, - .number = FSTPBMaybeDocument_FieldNumber_HasCommittedMutations, - .hasIndex = 0, - .offset = 1, // Stored in _has_storage_ to save space. - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[FSTPBMaybeDocument class] - rootClass:[FSTPBMaybeDocumentRoot class] - file:FSTPBMaybeDocumentRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(FSTPBMaybeDocument__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "documentType", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void FSTPBMaybeDocument_ClearDocumentTypeOneOfCase(FSTPBMaybeDocument *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h deleted file mode 100644 index 9091ba6..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: firestore/local/mutation.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers.h" -#endif - -#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002 -#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources. -#endif -#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION -#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -@class GCFSWrite; -@class GPBTimestamp; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - FSTPBMutationRoot - -/** - * Exposes the extension registry for this file. - * - * The base class provides: - * @code - * + (GPBExtensionRegistry *)extensionRegistry; - * @endcode - * which is a @c GPBExtensionRegistry that includes all the extensions defined by - * this file and all files that it depends on. - **/ -@interface FSTPBMutationRoot : GPBRootObject -@end - -#pragma mark - FSTPBMutationQueue - -typedef GPB_ENUM(FSTPBMutationQueue_FieldNumber) { - FSTPBMutationQueue_FieldNumber_LastAcknowledgedBatchId = 1, - FSTPBMutationQueue_FieldNumber_LastStreamToken = 2, -}; - -/** - * Each user gets a single queue of WriteBatches to apply to the server. - * MutationQueue tracks the metadata about the queue. - **/ -@interface FSTPBMutationQueue : GPBMessage - -/** - * An identifier for the highest numbered batch that has been acknowledged by - * the server. All WriteBatches in this queue with batch_ids less than or - * equal to this value are considered to have been acknowledged by the - * server. - **/ -@property(nonatomic, readwrite) int32_t lastAcknowledgedBatchId; - -/** - * A stream token that was previously sent by the server. - * - * See StreamingWriteRequest in datastore.proto for more details about usage. - * - * After sending this token, earlier tokens may not be used anymore so only a - * single stream token is retained. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSData *lastStreamToken; - -@end - -#pragma mark - FSTPBWriteBatch - -typedef GPB_ENUM(FSTPBWriteBatch_FieldNumber) { - FSTPBWriteBatch_FieldNumber_BatchId = 1, - FSTPBWriteBatch_FieldNumber_WritesArray = 2, - FSTPBWriteBatch_FieldNumber_LocalWriteTime = 3, - FSTPBWriteBatch_FieldNumber_BaseWritesArray = 4, -}; - -/** - * Message containing a batch of user-level writes intended to be sent to - * the server in a single call. Each user-level batch gets a separate - * WriteBatch with a new batch_id. - **/ -@interface FSTPBWriteBatch : GPBMessage - -/** - * An identifier for this batch, allocated by the mutation queue in a - * monotonically increasing manner. - **/ -@property(nonatomic, readwrite) int32_t batchId; - -/** A list of writes to apply. All writes will be applied atomically. */ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *writesArray; -/** The number of items in @c writesArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger writesArray_Count; - -/** The local time at which the write batch was initiated. */ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *localWriteTime; -/** Test to see if @c localWriteTime has been set. */ -@property(nonatomic, readwrite) BOOL hasLocalWriteTime; - -/** - * A list of pseudo-writes that represent a partial base state from when this - * write batch was initially created. When computing the local view batch, - * these base_writes are applied prior to the real writes in order to - * override certain document fields from the remote document cache. This is - * necessary in the case of non-idempotent writes (e.g. numericAdd - * transforms) to make sure that the local view of the modified documents - * doesn't flicker if the remote document cache receives the result of the - * non-idempotent write before the write is removed from the queue. - * - * These writes are never sent to the backend. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *baseWritesArray; -/** The number of items in @c baseWritesArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger baseWritesArray_Count; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/Mutation.pbobjc.m b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/Mutation.pbobjc.m deleted file mode 100644 index 5c88e90..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/Mutation.pbobjc.m +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: firestore/local/mutation.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers_RuntimeSupport.h" -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "Timestamp.pbobjc.h" -#endif - - #import "Mutation.pbobjc.h" - #import "Write.pbobjc.h" - #import "Annotations.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#pragma mark - FSTPBMutationRoot - -@implementation FSTPBMutationRoot - - -@end - -#pragma mark - FSTPBMutationRoot_FileDescriptor - -static GPBFileDescriptor *FSTPBMutationRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPB_DEBUG_CHECK_RUNTIME_VERSIONS(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"firestore.client" - objcPrefix:@"FSTPB" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - FSTPBMutationQueue - -@implementation FSTPBMutationQueue - -@dynamic lastAcknowledgedBatchId; -@dynamic lastStreamToken; - -typedef struct FSTPBMutationQueue__storage_ { - uint32_t _has_storage_[1]; - int32_t lastAcknowledgedBatchId; - NSData *lastStreamToken; -} FSTPBMutationQueue__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "lastAcknowledgedBatchId", - .dataTypeSpecific.className = NULL, - .number = FSTPBMutationQueue_FieldNumber_LastAcknowledgedBatchId, - .hasIndex = 0, - .offset = (uint32_t)offsetof(FSTPBMutationQueue__storage_, lastAcknowledgedBatchId), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - { - .name = "lastStreamToken", - .dataTypeSpecific.className = NULL, - .number = FSTPBMutationQueue_FieldNumber_LastStreamToken, - .hasIndex = 1, - .offset = (uint32_t)offsetof(FSTPBMutationQueue__storage_, lastStreamToken), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[FSTPBMutationQueue class] - rootClass:[FSTPBMutationRoot class] - file:FSTPBMutationRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(FSTPBMutationQueue__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - FSTPBWriteBatch - -@implementation FSTPBWriteBatch - -@dynamic batchId; -@dynamic writesArray, writesArray_Count; -@dynamic hasLocalWriteTime, localWriteTime; -@dynamic baseWritesArray, baseWritesArray_Count; - -typedef struct FSTPBWriteBatch__storage_ { - uint32_t _has_storage_[1]; - int32_t batchId; - NSMutableArray *writesArray; - GPBTimestamp *localWriteTime; - NSMutableArray *baseWritesArray; -} FSTPBWriteBatch__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "batchId", - .dataTypeSpecific.className = NULL, - .number = FSTPBWriteBatch_FieldNumber_BatchId, - .hasIndex = 0, - .offset = (uint32_t)offsetof(FSTPBWriteBatch__storage_, batchId), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - { - .name = "writesArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSWrite), - .number = FSTPBWriteBatch_FieldNumber_WritesArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(FSTPBWriteBatch__storage_, writesArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "localWriteTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = FSTPBWriteBatch_FieldNumber_LocalWriteTime, - .hasIndex = 1, - .offset = (uint32_t)offsetof(FSTPBWriteBatch__storage_, localWriteTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "baseWritesArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSWrite), - .number = FSTPBWriteBatch_FieldNumber_BaseWritesArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(FSTPBWriteBatch__storage_, baseWritesArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[FSTPBWriteBatch class] - rootClass:[FSTPBMutationRoot class] - file:FSTPBMutationRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(FSTPBWriteBatch__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/Target.pbobjc.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/Target.pbobjc.h deleted file mode 100644 index 88d9bff..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/Target.pbobjc.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: firestore/local/target.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers.h" -#endif - -#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002 -#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources. -#endif -#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION -#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -@class GCFSTarget_DocumentsTarget; -@class GCFSTarget_QueryTarget; -@class GPBTimestamp; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - FSTPBTargetRoot - -/** - * Exposes the extension registry for this file. - * - * The base class provides: - * @code - * + (GPBExtensionRegistry *)extensionRegistry; - * @endcode - * which is a @c GPBExtensionRegistry that includes all the extensions defined by - * this file and all files that it depends on. - **/ -@interface FSTPBTargetRoot : GPBRootObject -@end - -#pragma mark - FSTPBTarget - -typedef GPB_ENUM(FSTPBTarget_FieldNumber) { - FSTPBTarget_FieldNumber_TargetId = 1, - FSTPBTarget_FieldNumber_SnapshotVersion = 2, - FSTPBTarget_FieldNumber_ResumeToken = 3, - FSTPBTarget_FieldNumber_LastListenSequenceNumber = 4, - FSTPBTarget_FieldNumber_Query = 5, - FSTPBTarget_FieldNumber_Documents = 6, -}; - -typedef GPB_ENUM(FSTPBTarget_TargetType_OneOfCase) { - FSTPBTarget_TargetType_OneOfCase_GPBUnsetOneOfCase = 0, - FSTPBTarget_TargetType_OneOfCase_Query = 5, - FSTPBTarget_TargetType_OneOfCase_Documents = 6, -}; - -/** - * A Target is a long-lived data structure representing a resumable listen on a - * particular user query. While the query describes what to listen to, the - * Target records data about when the results were last updated and enough - * information to be able to resume listening later. - **/ -@interface FSTPBTarget : GPBMessage - -/** - * An auto-generated sequential numeric identifier for the target. This - * serves as the identity of the target, and once assigned never changes. - **/ -@property(nonatomic, readwrite) int32_t targetId; - -/** - * The last snapshot version received from the Watch Service for this target. - * - * This is the same value as TargetChange.read_time - * https://github.com/googleapis/googleapis/blob/master/google/firestore/v1/firestore.proto#L734 - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *snapshotVersion; -/** Test to see if @c snapshotVersion has been set. */ -@property(nonatomic, readwrite) BOOL hasSnapshotVersion; - -/** - * An opaque, server-assigned token that allows watching a query to be - * resumed after disconnecting without retransmitting all the data that - * matches the query. The resume token essentially identifies a point in - * time from which the server should resume sending results. - * - * This is related to the snapshot_version in that the resume_token - * effectively also encodes that value, but the resume_token is opaque and - * sometimes encodes additional information. - * - * A consequence of this is that the resume_token should be used when asking - * the server to reason about where this client is in the watch stream, but - * the client should use the snapshot_version for its own purposes. - * - * This is the same value as TargetChange.resume_token - * https://github.com/googleapis/googleapis/blob/master/google/firestore/v1/firestore.proto#L722 - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSData *resumeToken; - -/** - * A sequence number representing the last time this query was listened to, - * used for garbage collection purposes. - * - * Conventionally this would be a timestamp value, but device-local clocks - * are unreliable and they must be able to create new listens even while - * disconnected. Instead this should be a monotonically increasing number - * that's incremented on each listen call. - * - * This is different from the target_id since the target_id is an immutable - * identifier assigned to the Target on first use while - * last_listen_sequence_number is updated every time the query is listened - * to. - **/ -@property(nonatomic, readwrite) int64_t lastListenSequenceNumber; - -/** The server-side type of target to listen to. */ -@property(nonatomic, readonly) FSTPBTarget_TargetType_OneOfCase targetTypeOneOfCase; - -/** A target specified by a query. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSTarget_QueryTarget *query; - -/** A target specified by a set of document names. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSTarget_DocumentsTarget *documents; - -@end - -/** - * Clears whatever value was set for the oneof 'targetType'. - **/ -void FSTPBTarget_ClearTargetTypeOneOfCase(FSTPBTarget *message); - -#pragma mark - FSTPBTargetGlobal - -typedef GPB_ENUM(FSTPBTargetGlobal_FieldNumber) { - FSTPBTargetGlobal_FieldNumber_HighestTargetId = 1, - FSTPBTargetGlobal_FieldNumber_HighestListenSequenceNumber = 2, - FSTPBTargetGlobal_FieldNumber_LastRemoteSnapshotVersion = 3, - FSTPBTargetGlobal_FieldNumber_TargetCount = 4, -}; - -/** - * Global state tracked across all Targets, tracked separately to avoid the - * need for extra indexes. - **/ -@interface FSTPBTargetGlobal : GPBMessage - -/** - * The highest numbered target id across all Targets. - * - * See Target.target_id. - **/ -@property(nonatomic, readwrite) int32_t highestTargetId; - -/** - * The highest numbered last_listen_sequence_number across all Targets. - * - * See Target.last_listen_sequence_number. - **/ -@property(nonatomic, readwrite) int64_t highestListenSequenceNumber; - -/** - * A global snapshot version representing the last consistent snapshot we - * received from the backend. This is monotonically increasing and any - * snapshots received from the backend prior to this version (e.g. for - * targets resumed with a resume_token) should be suppressed (buffered) until - * the backend has caught up to this snapshot_version again. This prevents - * our cache from ever going backwards in time. - * - * This is updated whenever our we get a TargetChange with a read_time and - * empty target_ids. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *lastRemoteSnapshotVersion; -/** Test to see if @c lastRemoteSnapshotVersion has been set. */ -@property(nonatomic, readwrite) BOOL hasLastRemoteSnapshotVersion; - -/** On platforms that need it, holds the number of targets persisted. */ -@property(nonatomic, readwrite) int32_t targetCount; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/Target.pbobjc.m b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/Target.pbobjc.m deleted file mode 100644 index 2c41472..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/firestore/local/Target.pbobjc.m +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: firestore/local/target.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers_RuntimeSupport.h" -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "Timestamp.pbobjc.h" -#endif - - #import "Target.pbobjc.h" - #import "Firestore.pbobjc.h" - #import "Annotations.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#pragma clang diagnostic ignored "-Wdirect-ivar-access" - -#pragma mark - FSTPBTargetRoot - -@implementation FSTPBTargetRoot - - -@end - -#pragma mark - FSTPBTargetRoot_FileDescriptor - -static GPBFileDescriptor *FSTPBTargetRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPB_DEBUG_CHECK_RUNTIME_VERSIONS(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"firestore.client" - objcPrefix:@"FSTPB" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - FSTPBTarget - -@implementation FSTPBTarget - -@dynamic targetTypeOneOfCase; -@dynamic targetId; -@dynamic hasSnapshotVersion, snapshotVersion; -@dynamic resumeToken; -@dynamic lastListenSequenceNumber; -@dynamic query; -@dynamic documents; - -typedef struct FSTPBTarget__storage_ { - uint32_t _has_storage_[2]; - int32_t targetId; - GPBTimestamp *snapshotVersion; - NSData *resumeToken; - GCFSTarget_QueryTarget *query; - GCFSTarget_DocumentsTarget *documents; - int64_t lastListenSequenceNumber; -} FSTPBTarget__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "targetId", - .dataTypeSpecific.className = NULL, - .number = FSTPBTarget_FieldNumber_TargetId, - .hasIndex = 0, - .offset = (uint32_t)offsetof(FSTPBTarget__storage_, targetId), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - { - .name = "snapshotVersion", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = FSTPBTarget_FieldNumber_SnapshotVersion, - .hasIndex = 1, - .offset = (uint32_t)offsetof(FSTPBTarget__storage_, snapshotVersion), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "resumeToken", - .dataTypeSpecific.className = NULL, - .number = FSTPBTarget_FieldNumber_ResumeToken, - .hasIndex = 2, - .offset = (uint32_t)offsetof(FSTPBTarget__storage_, resumeToken), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - { - .name = "lastListenSequenceNumber", - .dataTypeSpecific.className = NULL, - .number = FSTPBTarget_FieldNumber_LastListenSequenceNumber, - .hasIndex = 3, - .offset = (uint32_t)offsetof(FSTPBTarget__storage_, lastListenSequenceNumber), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt64, - }, - { - .name = "query", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSTarget_QueryTarget), - .number = FSTPBTarget_FieldNumber_Query, - .hasIndex = -1, - .offset = (uint32_t)offsetof(FSTPBTarget__storage_, query), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "documents", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSTarget_DocumentsTarget), - .number = FSTPBTarget_FieldNumber_Documents, - .hasIndex = -1, - .offset = (uint32_t)offsetof(FSTPBTarget__storage_, documents), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[FSTPBTarget class] - rootClass:[FSTPBTargetRoot class] - file:FSTPBTargetRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(FSTPBTarget__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "targetType", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void FSTPBTarget_ClearTargetTypeOneOfCase(FSTPBTarget *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - FSTPBTargetGlobal - -@implementation FSTPBTargetGlobal - -@dynamic highestTargetId; -@dynamic highestListenSequenceNumber; -@dynamic hasLastRemoteSnapshotVersion, lastRemoteSnapshotVersion; -@dynamic targetCount; - -typedef struct FSTPBTargetGlobal__storage_ { - uint32_t _has_storage_[1]; - int32_t highestTargetId; - int32_t targetCount; - GPBTimestamp *lastRemoteSnapshotVersion; - int64_t highestListenSequenceNumber; -} FSTPBTargetGlobal__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "highestTargetId", - .dataTypeSpecific.className = NULL, - .number = FSTPBTargetGlobal_FieldNumber_HighestTargetId, - .hasIndex = 0, - .offset = (uint32_t)offsetof(FSTPBTargetGlobal__storage_, highestTargetId), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - { - .name = "highestListenSequenceNumber", - .dataTypeSpecific.className = NULL, - .number = FSTPBTargetGlobal_FieldNumber_HighestListenSequenceNumber, - .hasIndex = 1, - .offset = (uint32_t)offsetof(FSTPBTargetGlobal__storage_, highestListenSequenceNumber), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt64, - }, - { - .name = "lastRemoteSnapshotVersion", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = FSTPBTargetGlobal_FieldNumber_LastRemoteSnapshotVersion, - .hasIndex = 2, - .offset = (uint32_t)offsetof(FSTPBTargetGlobal__storage_, lastRemoteSnapshotVersion), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "targetCount", - .dataTypeSpecific.className = NULL, - .number = FSTPBTargetGlobal_FieldNumber_TargetCount, - .hasIndex = 3, - .offset = (uint32_t)offsetof(FSTPBTargetGlobal__storage_, targetCount), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[FSTPBTargetGlobal class] - rootClass:[FSTPBTargetRoot class] - file:FSTPBTargetRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(FSTPBTargetGlobal__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/api/Annotations.pbobjc.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/api/Annotations.pbobjc.h deleted file mode 100644 index 02b99dd..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/api/Annotations.pbobjc.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Empty stub file diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/api/Annotations.pbobjc.m b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/api/Annotations.pbobjc.m deleted file mode 100644 index 71f8ef2..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/api/Annotations.pbobjc.m +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -static int annotations_stub __attribute__((unused,used)) = 0; diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/api/HTTP.pbobjc.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/api/HTTP.pbobjc.h deleted file mode 100644 index 0b7da83..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/api/HTTP.pbobjc.h +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/api/http.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers.h" -#endif - -#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002 -#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources. -#endif -#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION -#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -@class GAPICustomHttpPattern; -@class GAPIHttpRule; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - GAPIHTTPRoot - -/** - * Exposes the extension registry for this file. - * - * The base class provides: - * @code - * + (GPBExtensionRegistry *)extensionRegistry; - * @endcode - * which is a @c GPBExtensionRegistry that includes all the extensions defined by - * this file and all files that it depends on. - **/ -@interface GAPIHTTPRoot : GPBRootObject -@end - -#pragma mark - GAPIHttp - -typedef GPB_ENUM(GAPIHttp_FieldNumber) { - GAPIHttp_FieldNumber_RulesArray = 1, - GAPIHttp_FieldNumber_FullyDecodeReservedExpansion = 2, -}; - -/** - * Defines the HTTP configuration for an API service. It contains a list of - * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method - * to one or more HTTP REST API methods. - **/ -@interface GAPIHttp : GPBMessage - -/** - * A list of HTTP configuration rules that apply to individual API methods. - * - * **NOTE:** All service configuration rules follow "last one wins" order. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *rulesArray; -/** The number of items in @c rulesArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger rulesArray_Count; - -/** - * When set to true, URL path parmeters will be fully URI-decoded except in - * cases of single segment matches in reserved expansion, where "%2F" will be - * left encoded. - * - * The default behavior is to not decode RFC 6570 reserved characters in multi - * segment matches. - **/ -@property(nonatomic, readwrite) BOOL fullyDecodeReservedExpansion; - -@end - -#pragma mark - GAPIHttpRule - -typedef GPB_ENUM(GAPIHttpRule_FieldNumber) { - GAPIHttpRule_FieldNumber_Selector = 1, - GAPIHttpRule_FieldNumber_Get = 2, - GAPIHttpRule_FieldNumber_Put = 3, - GAPIHttpRule_FieldNumber_Post = 4, - GAPIHttpRule_FieldNumber_Delete_p = 5, - GAPIHttpRule_FieldNumber_Patch = 6, - GAPIHttpRule_FieldNumber_Body = 7, - GAPIHttpRule_FieldNumber_Custom = 8, - GAPIHttpRule_FieldNumber_AdditionalBindingsArray = 11, -}; - -typedef GPB_ENUM(GAPIHttpRule_Pattern_OneOfCase) { - GAPIHttpRule_Pattern_OneOfCase_GPBUnsetOneOfCase = 0, - GAPIHttpRule_Pattern_OneOfCase_Get = 2, - GAPIHttpRule_Pattern_OneOfCase_Put = 3, - GAPIHttpRule_Pattern_OneOfCase_Post = 4, - GAPIHttpRule_Pattern_OneOfCase_Delete_p = 5, - GAPIHttpRule_Pattern_OneOfCase_Patch = 6, - GAPIHttpRule_Pattern_OneOfCase_Custom = 8, -}; - -/** - * `HttpRule` defines the mapping of an RPC method to one or more HTTP - * REST API methods. The mapping specifies how different portions of the RPC - * request message are mapped to URL path, URL query parameters, and - * HTTP request body. The mapping is typically specified as an - * `google.api.http` annotation on the RPC method, - * see "google/api/annotations.proto" for details. - * - * The mapping consists of a field specifying the path template and - * method kind. The path template can refer to fields in the request - * message, as in the example below which describes a REST GET - * operation on a resource collection of messages: - * - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http).get = "/v1/messages/{message_id}/{sub.subfield}"; - * } - * } - * message GetMessageRequest { - * message SubMessage { - * string subfield = 1; - * } - * string message_id = 1; // mapped to the URL - * SubMessage sub = 2; // `sub.subfield` is url-mapped - * } - * message Message { - * string text = 1; // content of the resource - * } - * - * The same http annotation can alternatively be expressed inside the - * `GRPC API Configuration` YAML file. - * - * http: - * rules: - * - selector: .Messaging.GetMessage - * get: /v1/messages/{message_id}/{sub.subfield} - * - * This definition enables an automatic, bidrectional mapping of HTTP - * JSON to RPC. Example: - * - * HTTP | RPC - * -----|----- - * `GET /v1/messages/123456/foo` | `GetMessage(message_id: "123456" sub: SubMessage(subfield: "foo"))` - * - * In general, not only fields but also field paths can be referenced - * from a path pattern. Fields mapped to the path pattern cannot be - * repeated and must have a primitive (non-message) type. - * - * Any fields in the request message which are not bound by the path - * pattern automatically become (optional) HTTP query - * parameters. Assume the following definition of the request message: - * - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http).get = "/v1/messages/{message_id}"; - * } - * } - * message GetMessageRequest { - * message SubMessage { - * string subfield = 1; - * } - * string message_id = 1; // mapped to the URL - * int64 revision = 2; // becomes a parameter - * SubMessage sub = 3; // `sub.subfield` becomes a parameter - * } - * - * - * This enables a HTTP JSON to RPC mapping as below: - * - * HTTP | RPC - * -----|----- - * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: "foo"))` - * - * Note that fields which are mapped to HTTP parameters must have a - * primitive type or a repeated primitive type. Message types are not - * allowed. In the case of a repeated type, the parameter can be - * repeated in the URL, as in `...?param=A¶m=B`. - * - * For HTTP method kinds which allow a request body, the `body` field - * specifies the mapping. Consider a REST update method on the - * message resource collection: - * - * - * service Messaging { - * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { - * option (google.api.http) = { - * put: "/v1/messages/{message_id}" - * body: "message" - * }; - * } - * } - * message UpdateMessageRequest { - * string message_id = 1; // mapped to the URL - * Message message = 2; // mapped to the body - * } - * - * - * The following HTTP JSON to RPC mapping is enabled, where the - * representation of the JSON in the request body is determined by - * protos JSON encoding: - * - * HTTP | RPC - * -----|----- - * `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" message { text: "Hi!" })` - * - * The special name `*` can be used in the body mapping to define that - * every field not bound by the path template should be mapped to the - * request body. This enables the following alternative definition of - * the update method: - * - * service Messaging { - * rpc UpdateMessage(Message) returns (Message) { - * option (google.api.http) = { - * put: "/v1/messages/{message_id}" - * body: "*" - * }; - * } - * } - * message Message { - * string message_id = 1; - * string text = 2; - * } - * - * - * The following HTTP JSON to RPC mapping is enabled: - * - * HTTP | RPC - * -----|----- - * `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" text: "Hi!")` - * - * Note that when using `*` in the body mapping, it is not possible to - * have HTTP parameters, as all fields not bound by the path end in - * the body. This makes this option more rarely used in practice of - * defining REST APIs. The common usage of `*` is in custom methods - * which don't use the URL at all for transferring data. - * - * It is possible to define multiple HTTP methods for one RPC by using - * the `additional_bindings` option. Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/messages/{message_id}" - * additional_bindings { - * get: "/v1/users/{user_id}/messages/{message_id}" - * } - * }; - * } - * } - * message GetMessageRequest { - * string message_id = 1; - * string user_id = 2; - * } - * - * - * This enables the following two alternative HTTP JSON to RPC - * mappings: - * - * HTTP | RPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` - * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: "123456")` - * - * # Rules for HTTP mapping - * - * The rules for mapping HTTP path, query parameters, and body fields - * to the request message are as follows: - * - * 1. The `body` field specifies either `*` or a field path, or is - * omitted. If omitted, it indicates there is no HTTP request body. - * 2. Leaf fields (recursive expansion of nested messages in the - * request) can be classified into three types: - * (a) Matched in the URL template. - * (b) Covered by body (if body is `*`, everything except (a) fields; - * else everything under the body field) - * (c) All other fields. - * 3. URL query parameters found in the HTTP request are mapped to (c) fields. - * 4. Any body sent with an HTTP request can contain only (b) fields. - * - * The syntax of the path template is as follows: - * - * Template = "/" Segments [ Verb ] ; - * Segments = Segment { "/" Segment } ; - * Segment = "*" | "**" | LITERAL | Variable ; - * Variable = "{" FieldPath [ "=" Segments ] "}" ; - * FieldPath = IDENT { "." IDENT } ; - * Verb = ":" LITERAL ; - * - * The syntax `*` matches a single path segment. The syntax `**` matches zero - * or more path segments, which must be the last part of the path except the - * `Verb`. The syntax `LITERAL` matches literal text in the path. - * - * The syntax `Variable` matches part of the URL path as specified by its - * template. A variable template must not contain other variables. If a variable - * matches a single path segment, its template may be omitted, e.g. `{var}` - * is equivalent to `{var=*}`. - * - * If a variable contains exactly one path segment, such as `"{var}"` or - * `"{var=*}"`, when such a variable is expanded into a URL path, all characters - * except `[-_.~0-9a-zA-Z]` are percent-encoded. Such variables show up in the - * Discovery Document as `{var}`. - * - * If a variable contains one or more path segments, such as `"{var=foo/\*}"` - * or `"{var=**}"`, when such a variable is expanded into a URL path, all - * characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. Such variables - * show up in the Discovery Document as `{+var}`. - * - * NOTE: While the single segment variable matches the semantics of - * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 - * Simple String Expansion, the multi segment variable **does not** match - * RFC 6570 Reserved Expansion. The reason is that the Reserved Expansion - * does not expand special characters like `?` and `#`, which would lead - * to invalid URLs. - * - * NOTE: the field paths in variables and in the `body` must not refer to - * repeated fields or map fields. - **/ -@interface GAPIHttpRule : GPBMessage - -/** - * Selects methods to which this rule applies. - * - * Refer to [selector][google.api.DocumentationRule.selector] for syntax details. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *selector; - -/** - * Determines the URL pattern is matched by this rules. This pattern can be - * used with any of the {get|put|post|delete|patch} methods. A custom method - * can be defined using the 'custom' field. - **/ -@property(nonatomic, readonly) GAPIHttpRule_Pattern_OneOfCase patternOneOfCase; - -/** Used for listing and getting information about resources. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *get; - -/** Used for updating a resource. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *put; - -/** Used for creating a resource. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *post; - -/** Used for deleting a resource. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *delete_p; - -/** Used for updating a resource. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *patch; - -/** - * The custom pattern is used for specifying an HTTP method that is not - * included in the `pattern` field, such as HEAD, or "*" to leave the - * HTTP method unspecified for this rule. The wild-card rule is useful - * for services that provide content to Web (HTML) clients. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GAPICustomHttpPattern *custom; - -/** - * The name of the request field whose value is mapped to the HTTP body, or - * `*` for mapping all fields not captured by the path pattern to the HTTP - * body. NOTE: the referred field must not be a repeated field and must be - * present at the top-level of request message type. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *body; - -/** - * Additional HTTP bindings for the selector. Nested bindings must - * not contain an `additional_bindings` field themselves (that is, - * the nesting may only be one level deep). - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *additionalBindingsArray; -/** The number of items in @c additionalBindingsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger additionalBindingsArray_Count; - -@end - -/** - * Clears whatever value was set for the oneof 'pattern'. - **/ -void GAPIHttpRule_ClearPatternOneOfCase(GAPIHttpRule *message); - -#pragma mark - GAPICustomHttpPattern - -typedef GPB_ENUM(GAPICustomHttpPattern_FieldNumber) { - GAPICustomHttpPattern_FieldNumber_Kind = 1, - GAPICustomHttpPattern_FieldNumber_Path = 2, -}; - -/** - * A custom pattern is used for defining custom HTTP verb. - **/ -@interface GAPICustomHttpPattern : GPBMessage - -/** The name of this custom HTTP verb. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *kind; - -/** The path matched by this custom verb. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *path; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/api/HTTP.pbobjc.m b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/api/HTTP.pbobjc.m deleted file mode 100644 index 4ae8e11..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/api/HTTP.pbobjc.m +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/api/http.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers_RuntimeSupport.h" -#endif - - #import "HTTP.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#pragma clang diagnostic ignored "-Wdirect-ivar-access" - -#pragma mark - GAPIHTTPRoot - -@implementation GAPIHTTPRoot - -// No extensions in the file and no imports, so no need to generate -// +extensionRegistry. - -@end - -#pragma mark - GAPIHTTPRoot_FileDescriptor - -static GPBFileDescriptor *GAPIHTTPRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPB_DEBUG_CHECK_RUNTIME_VERSIONS(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.api" - objcPrefix:@"GAPI" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GAPIHttp - -@implementation GAPIHttp - -@dynamic rulesArray, rulesArray_Count; -@dynamic fullyDecodeReservedExpansion; - -typedef struct GAPIHttp__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *rulesArray; -} GAPIHttp__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "rulesArray", - .dataTypeSpecific.className = GPBStringifySymbol(GAPIHttpRule), - .number = GAPIHttp_FieldNumber_RulesArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GAPIHttp__storage_, rulesArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "fullyDecodeReservedExpansion", - .dataTypeSpecific.className = NULL, - .number = GAPIHttp_FieldNumber_FullyDecodeReservedExpansion, - .hasIndex = 0, - .offset = 1, // Stored in _has_storage_ to save space. - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GAPIHttp class] - rootClass:[GAPIHTTPRoot class] - file:GAPIHTTPRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GAPIHttp__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GAPIHttpRule - -@implementation GAPIHttpRule - -@dynamic patternOneOfCase; -@dynamic selector; -@dynamic get; -@dynamic put; -@dynamic post; -@dynamic delete_p; -@dynamic patch; -@dynamic custom; -@dynamic body; -@dynamic additionalBindingsArray, additionalBindingsArray_Count; - -typedef struct GAPIHttpRule__storage_ { - uint32_t _has_storage_[2]; - NSString *selector; - NSString *get; - NSString *put; - NSString *post; - NSString *delete_p; - NSString *patch; - NSString *body; - GAPICustomHttpPattern *custom; - NSMutableArray *additionalBindingsArray; -} GAPIHttpRule__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "selector", - .dataTypeSpecific.className = NULL, - .number = GAPIHttpRule_FieldNumber_Selector, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GAPIHttpRule__storage_, selector), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "get", - .dataTypeSpecific.className = NULL, - .number = GAPIHttpRule_FieldNumber_Get, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GAPIHttpRule__storage_, get), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "put", - .dataTypeSpecific.className = NULL, - .number = GAPIHttpRule_FieldNumber_Put, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GAPIHttpRule__storage_, put), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "post", - .dataTypeSpecific.className = NULL, - .number = GAPIHttpRule_FieldNumber_Post, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GAPIHttpRule__storage_, post), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "delete_p", - .dataTypeSpecific.className = NULL, - .number = GAPIHttpRule_FieldNumber_Delete_p, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GAPIHttpRule__storage_, delete_p), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "patch", - .dataTypeSpecific.className = NULL, - .number = GAPIHttpRule_FieldNumber_Patch, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GAPIHttpRule__storage_, patch), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "body", - .dataTypeSpecific.className = NULL, - .number = GAPIHttpRule_FieldNumber_Body, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GAPIHttpRule__storage_, body), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "custom", - .dataTypeSpecific.className = GPBStringifySymbol(GAPICustomHttpPattern), - .number = GAPIHttpRule_FieldNumber_Custom, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GAPIHttpRule__storage_, custom), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "additionalBindingsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GAPIHttpRule), - .number = GAPIHttpRule_FieldNumber_AdditionalBindingsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GAPIHttpRule__storage_, additionalBindingsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GAPIHttpRule class] - rootClass:[GAPIHTTPRoot class] - file:GAPIHTTPRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GAPIHttpRule__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "pattern", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GAPIHttpRule_ClearPatternOneOfCase(GAPIHttpRule *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - GAPICustomHttpPattern - -@implementation GAPICustomHttpPattern - -@dynamic kind; -@dynamic path; - -typedef struct GAPICustomHttpPattern__storage_ { - uint32_t _has_storage_[1]; - NSString *kind; - NSString *path; -} GAPICustomHttpPattern__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "kind", - .dataTypeSpecific.className = NULL, - .number = GAPICustomHttpPattern_FieldNumber_Kind, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GAPICustomHttpPattern__storage_, kind), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "path", - .dataTypeSpecific.className = NULL, - .number = GAPICustomHttpPattern_FieldNumber_Path, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GAPICustomHttpPattern__storage_, path), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GAPICustomHttpPattern class] - rootClass:[GAPIHTTPRoot class] - file:GAPIHTTPRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GAPICustomHttpPattern__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Common.pbobjc.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Common.pbobjc.h deleted file mode 100644 index 0ffe06a..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Common.pbobjc.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/firestore/v1/common.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers.h" -#endif - -#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002 -#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources. -#endif -#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION -#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -@class GCFSTransactionOptions_ReadOnly; -@class GCFSTransactionOptions_ReadWrite; -@class GPBTimestamp; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - GCFSCommonRoot - -/** - * Exposes the extension registry for this file. - * - * The base class provides: - * @code - * + (GPBExtensionRegistry *)extensionRegistry; - * @endcode - * which is a @c GPBExtensionRegistry that includes all the extensions defined by - * this file and all files that it depends on. - **/ -@interface GCFSCommonRoot : GPBRootObject -@end - -#pragma mark - GCFSDocumentMask - -typedef GPB_ENUM(GCFSDocumentMask_FieldNumber) { - GCFSDocumentMask_FieldNumber_FieldPathsArray = 1, -}; - -/** - * A set of field paths on a document. - * Used to restrict a get or update operation on a document to a subset of its - * fields. - * This is different from standard field masks, as this is always scoped to a - * [Document][google.firestore.v1.Document], and takes in account the dynamic nature of [Value][google.firestore.v1.Value]. - **/ -@interface GCFSDocumentMask : GPBMessage - -/** - * The list of field paths in the mask. See [Document.fields][google.firestore.v1.Document.fields] for a field - * path syntax reference. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *fieldPathsArray; -/** The number of items in @c fieldPathsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger fieldPathsArray_Count; - -@end - -#pragma mark - GCFSPrecondition - -typedef GPB_ENUM(GCFSPrecondition_FieldNumber) { - GCFSPrecondition_FieldNumber_Exists = 1, - GCFSPrecondition_FieldNumber_UpdateTime = 2, -}; - -typedef GPB_ENUM(GCFSPrecondition_ConditionType_OneOfCase) { - GCFSPrecondition_ConditionType_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSPrecondition_ConditionType_OneOfCase_Exists = 1, - GCFSPrecondition_ConditionType_OneOfCase_UpdateTime = 2, -}; - -/** - * A precondition on a document, used for conditional operations. - **/ -@interface GCFSPrecondition : GPBMessage - -/** The type of precondition. */ -@property(nonatomic, readonly) GCFSPrecondition_ConditionType_OneOfCase conditionTypeOneOfCase; - -/** - * When set to `true`, the target document must exist. - * When set to `false`, the target document must not exist. - **/ -@property(nonatomic, readwrite) BOOL exists; - -/** - * When set, the target document must exist and have been last updated at - * that time. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *updateTime; - -@end - -/** - * Clears whatever value was set for the oneof 'conditionType'. - **/ -void GCFSPrecondition_ClearConditionTypeOneOfCase(GCFSPrecondition *message); - -#pragma mark - GCFSTransactionOptions - -typedef GPB_ENUM(GCFSTransactionOptions_FieldNumber) { - GCFSTransactionOptions_FieldNumber_ReadOnly = 2, - GCFSTransactionOptions_FieldNumber_ReadWrite = 3, -}; - -typedef GPB_ENUM(GCFSTransactionOptions_Mode_OneOfCase) { - GCFSTransactionOptions_Mode_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSTransactionOptions_Mode_OneOfCase_ReadOnly = 2, - GCFSTransactionOptions_Mode_OneOfCase_ReadWrite = 3, -}; - -/** - * Options for creating a new transaction. - **/ -@interface GCFSTransactionOptions : GPBMessage - -/** The mode of the transaction. */ -@property(nonatomic, readonly) GCFSTransactionOptions_Mode_OneOfCase modeOneOfCase; - -/** The transaction can only be used for read operations. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSTransactionOptions_ReadOnly *readOnly; - -/** The transaction can be used for both read and write operations. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSTransactionOptions_ReadWrite *readWrite; - -@end - -/** - * Clears whatever value was set for the oneof 'mode'. - **/ -void GCFSTransactionOptions_ClearModeOneOfCase(GCFSTransactionOptions *message); - -#pragma mark - GCFSTransactionOptions_ReadWrite - -typedef GPB_ENUM(GCFSTransactionOptions_ReadWrite_FieldNumber) { - GCFSTransactionOptions_ReadWrite_FieldNumber_RetryTransaction = 1, -}; - -/** - * Options for a transaction that can be used to read and write documents. - **/ -@interface GCFSTransactionOptions_ReadWrite : GPBMessage - -/** An optional transaction to retry. */ -@property(nonatomic, readwrite, copy, null_resettable) NSData *retryTransaction; - -@end - -#pragma mark - GCFSTransactionOptions_ReadOnly - -typedef GPB_ENUM(GCFSTransactionOptions_ReadOnly_FieldNumber) { - GCFSTransactionOptions_ReadOnly_FieldNumber_ReadTime = 2, -}; - -typedef GPB_ENUM(GCFSTransactionOptions_ReadOnly_ConsistencySelector_OneOfCase) { - GCFSTransactionOptions_ReadOnly_ConsistencySelector_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSTransactionOptions_ReadOnly_ConsistencySelector_OneOfCase_ReadTime = 2, -}; - -/** - * Options for a transaction that can only be used to read documents. - **/ -@interface GCFSTransactionOptions_ReadOnly : GPBMessage - -/** - * The consistency mode for this transaction. If not set, defaults to strong - * consistency. - **/ -@property(nonatomic, readonly) GCFSTransactionOptions_ReadOnly_ConsistencySelector_OneOfCase consistencySelectorOneOfCase; - -/** - * Reads documents at the given time. - * This may not be older than 60 seconds. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *readTime; - -@end - -/** - * Clears whatever value was set for the oneof 'consistencySelector'. - **/ -void GCFSTransactionOptions_ReadOnly_ClearConsistencySelectorOneOfCase(GCFSTransactionOptions_ReadOnly *message); - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Common.pbobjc.m b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Common.pbobjc.m deleted file mode 100644 index cf112ba..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Common.pbobjc.m +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/firestore/v1/common.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers_RuntimeSupport.h" -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "Timestamp.pbobjc.h" -#endif - - #import "Common.pbobjc.h" - #import "Annotations.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#pragma clang diagnostic ignored "-Wdirect-ivar-access" - -#pragma mark - GCFSCommonRoot - -@implementation GCFSCommonRoot - - -@end - -#pragma mark - GCFSCommonRoot_FileDescriptor - -static GPBFileDescriptor *GCFSCommonRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPB_DEBUG_CHECK_RUNTIME_VERSIONS(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.firestore.v1" - objcPrefix:@"GCFS" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GCFSDocumentMask - -@implementation GCFSDocumentMask - -@dynamic fieldPathsArray, fieldPathsArray_Count; - -typedef struct GCFSDocumentMask__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *fieldPathsArray; -} GCFSDocumentMask__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "fieldPathsArray", - .dataTypeSpecific.className = NULL, - .number = GCFSDocumentMask_FieldNumber_FieldPathsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSDocumentMask__storage_, fieldPathsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeString, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSDocumentMask class] - rootClass:[GCFSCommonRoot class] - file:GCFSCommonRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSDocumentMask__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSPrecondition - -@implementation GCFSPrecondition - -@dynamic conditionTypeOneOfCase; -@dynamic exists; -@dynamic updateTime; - -typedef struct GCFSPrecondition__storage_ { - uint32_t _has_storage_[2]; - GPBTimestamp *updateTime; -} GCFSPrecondition__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "exists", - .dataTypeSpecific.className = NULL, - .number = GCFSPrecondition_FieldNumber_Exists, - .hasIndex = -1, - .offset = 0, // Stored in _has_storage_ to save space. - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - }, - { - .name = "updateTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSPrecondition_FieldNumber_UpdateTime, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSPrecondition__storage_, updateTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSPrecondition class] - rootClass:[GCFSCommonRoot class] - file:GCFSCommonRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSPrecondition__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "conditionType", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GCFSPrecondition_ClearConditionTypeOneOfCase(GCFSPrecondition *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - GCFSTransactionOptions - -@implementation GCFSTransactionOptions - -@dynamic modeOneOfCase; -@dynamic readOnly; -@dynamic readWrite; - -typedef struct GCFSTransactionOptions__storage_ { - uint32_t _has_storage_[2]; - GCFSTransactionOptions_ReadOnly *readOnly; - GCFSTransactionOptions_ReadWrite *readWrite; -} GCFSTransactionOptions__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "readOnly", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSTransactionOptions_ReadOnly), - .number = GCFSTransactionOptions_FieldNumber_ReadOnly, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSTransactionOptions__storage_, readOnly), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "readWrite", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSTransactionOptions_ReadWrite), - .number = GCFSTransactionOptions_FieldNumber_ReadWrite, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSTransactionOptions__storage_, readWrite), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSTransactionOptions class] - rootClass:[GCFSCommonRoot class] - file:GCFSCommonRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSTransactionOptions__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "mode", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GCFSTransactionOptions_ClearModeOneOfCase(GCFSTransactionOptions *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - GCFSTransactionOptions_ReadWrite - -@implementation GCFSTransactionOptions_ReadWrite - -@dynamic retryTransaction; - -typedef struct GCFSTransactionOptions_ReadWrite__storage_ { - uint32_t _has_storage_[1]; - NSData *retryTransaction; -} GCFSTransactionOptions_ReadWrite__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "retryTransaction", - .dataTypeSpecific.className = NULL, - .number = GCFSTransactionOptions_ReadWrite_FieldNumber_RetryTransaction, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSTransactionOptions_ReadWrite__storage_, retryTransaction), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSTransactionOptions_ReadWrite class] - rootClass:[GCFSCommonRoot class] - file:GCFSCommonRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSTransactionOptions_ReadWrite__storage_) - flags:GPBDescriptorInitializationFlag_None]; - [localDescriptor setupContainingMessageClassName:GPBStringifySymbol(GCFSTransactionOptions)]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSTransactionOptions_ReadOnly - -@implementation GCFSTransactionOptions_ReadOnly - -@dynamic consistencySelectorOneOfCase; -@dynamic readTime; - -typedef struct GCFSTransactionOptions_ReadOnly__storage_ { - uint32_t _has_storage_[2]; - GPBTimestamp *readTime; -} GCFSTransactionOptions_ReadOnly__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "readTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSTransactionOptions_ReadOnly_FieldNumber_ReadTime, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSTransactionOptions_ReadOnly__storage_, readTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSTransactionOptions_ReadOnly class] - rootClass:[GCFSCommonRoot class] - file:GCFSCommonRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSTransactionOptions_ReadOnly__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "consistencySelector", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - [localDescriptor setupContainingMessageClassName:GPBStringifySymbol(GCFSTransactionOptions)]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GCFSTransactionOptions_ReadOnly_ClearConsistencySelectorOneOfCase(GCFSTransactionOptions_ReadOnly *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Document.pbobjc.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Document.pbobjc.h deleted file mode 100644 index f474724..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Document.pbobjc.h +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/firestore/v1/document.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers.h" -#endif - -#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002 -#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources. -#endif -#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION -#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -@class GCFSArrayValue; -@class GCFSMapValue; -@class GCFSValue; -@class GPBTimestamp; -@class GTPLatLng; -GPB_ENUM_FWD_DECLARE(GPBNullValue); - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - GCFSDocumentRoot - -/** - * Exposes the extension registry for this file. - * - * The base class provides: - * @code - * + (GPBExtensionRegistry *)extensionRegistry; - * @endcode - * which is a @c GPBExtensionRegistry that includes all the extensions defined by - * this file and all files that it depends on. - **/ -@interface GCFSDocumentRoot : GPBRootObject -@end - -#pragma mark - GCFSDocument - -typedef GPB_ENUM(GCFSDocument_FieldNumber) { - GCFSDocument_FieldNumber_Name = 1, - GCFSDocument_FieldNumber_Fields = 2, - GCFSDocument_FieldNumber_CreateTime = 3, - GCFSDocument_FieldNumber_UpdateTime = 4, -}; - -/** - * A Firestore document. - * - * Must not exceed 1 MiB - 4 bytes. - **/ -@interface GCFSDocument : GPBMessage - -/** - * The resource name of the document, for example - * `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; - -/** - * The document's fields. - * - * The map keys represent field names. - * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * - * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be - * empty. - * - * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. - * - * Within a field path, a quoted field name starts and ends with `` ` `` and - * may contain any character. Some characters, including `` ` ``, must be - * escaped using a `\\`. For example, `` `x&y` `` represents `x&y` and - * `` `bak\\`tik` `` represents `` bak`tik ``. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary *fields; -/** The number of items in @c fields without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger fields_Count; - -/** - * Output only. The time at which the document was created. - * - * This value increases monotonically when a document is deleted then - * recreated. It can also be compared to values from other documents and - * the `read_time` of a query. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *createTime; -/** Test to see if @c createTime has been set. */ -@property(nonatomic, readwrite) BOOL hasCreateTime; - -/** - * Output only. The time at which the document was last changed. - * - * This value is initially set to the `create_time` then increases - * monotonically with each change to the document. It can also be - * compared to values from other documents and the `read_time` of a query. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *updateTime; -/** Test to see if @c updateTime has been set. */ -@property(nonatomic, readwrite) BOOL hasUpdateTime; - -@end - -#pragma mark - GCFSValue - -typedef GPB_ENUM(GCFSValue_FieldNumber) { - GCFSValue_FieldNumber_BooleanValue = 1, - GCFSValue_FieldNumber_IntegerValue = 2, - GCFSValue_FieldNumber_DoubleValue = 3, - GCFSValue_FieldNumber_ReferenceValue = 5, - GCFSValue_FieldNumber_MapValue = 6, - GCFSValue_FieldNumber_GeoPointValue = 8, - GCFSValue_FieldNumber_ArrayValue = 9, - GCFSValue_FieldNumber_TimestampValue = 10, - GCFSValue_FieldNumber_NullValue = 11, - GCFSValue_FieldNumber_StringValue = 17, - GCFSValue_FieldNumber_BytesValue = 18, -}; - -typedef GPB_ENUM(GCFSValue_ValueType_OneOfCase) { - GCFSValue_ValueType_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSValue_ValueType_OneOfCase_NullValue = 11, - GCFSValue_ValueType_OneOfCase_BooleanValue = 1, - GCFSValue_ValueType_OneOfCase_IntegerValue = 2, - GCFSValue_ValueType_OneOfCase_DoubleValue = 3, - GCFSValue_ValueType_OneOfCase_TimestampValue = 10, - GCFSValue_ValueType_OneOfCase_StringValue = 17, - GCFSValue_ValueType_OneOfCase_BytesValue = 18, - GCFSValue_ValueType_OneOfCase_ReferenceValue = 5, - GCFSValue_ValueType_OneOfCase_GeoPointValue = 8, - GCFSValue_ValueType_OneOfCase_ArrayValue = 9, - GCFSValue_ValueType_OneOfCase_MapValue = 6, -}; - -/** - * A message that can hold any of the supported value types. - **/ -@interface GCFSValue : GPBMessage - -/** Must have a value set. */ -@property(nonatomic, readonly) GCFSValue_ValueType_OneOfCase valueTypeOneOfCase; - -/** A null value. */ -@property(nonatomic, readwrite) enum GPBNullValue nullValue; - -/** A boolean value. */ -@property(nonatomic, readwrite) BOOL booleanValue; - -/** An integer value. */ -@property(nonatomic, readwrite) int64_t integerValue; - -/** A double value. */ -@property(nonatomic, readwrite) double doubleValue; - -/** - * A timestamp value. - * - * Precise only to microseconds. When stored, any additional precision is - * rounded down. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *timestampValue; - -/** - * A string value. - * - * The string, represented as UTF-8, must not exceed 1 MiB - 89 bytes. - * Only the first 1,500 bytes of the UTF-8 representation are considered by - * queries. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *stringValue; - -/** - * A bytes value. - * - * Must not exceed 1 MiB - 89 bytes. - * Only the first 1,500 bytes are considered by queries. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSData *bytesValue; - -/** - * A reference to a document. For example: - * `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *referenceValue; - -/** A geo point value representing a point on the surface of Earth. */ -@property(nonatomic, readwrite, strong, null_resettable) GTPLatLng *geoPointValue; - -/** - * An array value. - * - * Cannot directly contain another array value, though can contain an - * map which contains another array. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSArrayValue *arrayValue; - -/** A map value. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSMapValue *mapValue; - -@end - -/** - * Fetches the raw value of a @c GCFSValue's @c nullValue property, even - * if the value was not defined by the enum at the time the code was generated. - **/ -int32_t GCFSValue_NullValue_RawValue(GCFSValue *message); -/** - * Sets the raw value of an @c GCFSValue's @c nullValue property, allowing - * it to be set to a value that was not defined by the enum at the time the code - * was generated. - **/ -void SetGCFSValue_NullValue_RawValue(GCFSValue *message, int32_t value); - -/** - * Clears whatever value was set for the oneof 'valueType'. - **/ -void GCFSValue_ClearValueTypeOneOfCase(GCFSValue *message); - -#pragma mark - GCFSArrayValue - -typedef GPB_ENUM(GCFSArrayValue_FieldNumber) { - GCFSArrayValue_FieldNumber_ValuesArray = 1, -}; - -/** - * An array value. - **/ -@interface GCFSArrayValue : GPBMessage - -/** Values in the array. */ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *valuesArray; -/** The number of items in @c valuesArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger valuesArray_Count; - -@end - -#pragma mark - GCFSMapValue - -typedef GPB_ENUM(GCFSMapValue_FieldNumber) { - GCFSMapValue_FieldNumber_Fields = 1, -}; - -/** - * A map value. - **/ -@interface GCFSMapValue : GPBMessage - -/** - * The map's fields. - * - * The map keys represent field names. Field names matching the regular - * expression `__.*__` are reserved. Reserved field names are forbidden except - * in certain documented contexts. The map keys, represented as UTF-8, must - * not exceed 1,500 bytes and cannot be empty. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary *fields; -/** The number of items in @c fields without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger fields_Count; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Document.pbobjc.m b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Document.pbobjc.m deleted file mode 100644 index 0d1c2da..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Document.pbobjc.m +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/firestore/v1/document.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers_RuntimeSupport.h" -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import - #import -#else - #import "Struct.pbobjc.h" - #import "Timestamp.pbobjc.h" -#endif - - #import "Document.pbobjc.h" - #import "Annotations.pbobjc.h" - #import "Latlng.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#pragma clang diagnostic ignored "-Wdirect-ivar-access" - -#pragma mark - GCFSDocumentRoot - -@implementation GCFSDocumentRoot - - -@end - -#pragma mark - GCFSDocumentRoot_FileDescriptor - -static GPBFileDescriptor *GCFSDocumentRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPB_DEBUG_CHECK_RUNTIME_VERSIONS(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.firestore.v1" - objcPrefix:@"GCFS" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GCFSDocument - -@implementation GCFSDocument - -@dynamic name; -@dynamic fields, fields_Count; -@dynamic hasCreateTime, createTime; -@dynamic hasUpdateTime, updateTime; - -typedef struct GCFSDocument__storage_ { - uint32_t _has_storage_[1]; - NSString *name; - NSMutableDictionary *fields; - GPBTimestamp *createTime; - GPBTimestamp *updateTime; -} GCFSDocument__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .dataTypeSpecific.className = NULL, - .number = GCFSDocument_FieldNumber_Name, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSDocument__storage_, name), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "fields", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSValue), - .number = GCFSDocument_FieldNumber_Fields, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSDocument__storage_, fields), - .flags = GPBFieldMapKeyString, - .dataType = GPBDataTypeMessage, - }, - { - .name = "createTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSDocument_FieldNumber_CreateTime, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSDocument__storage_, createTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "updateTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSDocument_FieldNumber_UpdateTime, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GCFSDocument__storage_, updateTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSDocument class] - rootClass:[GCFSDocumentRoot class] - file:GCFSDocumentRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSDocument__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSValue - -@implementation GCFSValue - -@dynamic valueTypeOneOfCase; -@dynamic nullValue; -@dynamic booleanValue; -@dynamic integerValue; -@dynamic doubleValue; -@dynamic timestampValue; -@dynamic stringValue; -@dynamic bytesValue; -@dynamic referenceValue; -@dynamic geoPointValue; -@dynamic arrayValue; -@dynamic mapValue; - -typedef struct GCFSValue__storage_ { - uint32_t _has_storage_[2]; - GPBNullValue nullValue; - NSString *referenceValue; - GCFSMapValue *mapValue; - GTPLatLng *geoPointValue; - GCFSArrayValue *arrayValue; - GPBTimestamp *timestampValue; - NSString *stringValue; - NSData *bytesValue; - int64_t integerValue; - double doubleValue; -} GCFSValue__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "booleanValue", - .dataTypeSpecific.className = NULL, - .number = GCFSValue_FieldNumber_BooleanValue, - .hasIndex = -1, - .offset = 0, // Stored in _has_storage_ to save space. - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - }, - { - .name = "integerValue", - .dataTypeSpecific.className = NULL, - .number = GCFSValue_FieldNumber_IntegerValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSValue__storage_, integerValue), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt64, - }, - { - .name = "doubleValue", - .dataTypeSpecific.className = NULL, - .number = GCFSValue_FieldNumber_DoubleValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSValue__storage_, doubleValue), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeDouble, - }, - { - .name = "referenceValue", - .dataTypeSpecific.className = NULL, - .number = GCFSValue_FieldNumber_ReferenceValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSValue__storage_, referenceValue), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "mapValue", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSMapValue), - .number = GCFSValue_FieldNumber_MapValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSValue__storage_, mapValue), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "geoPointValue", - .dataTypeSpecific.className = GPBStringifySymbol(GTPLatLng), - .number = GCFSValue_FieldNumber_GeoPointValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSValue__storage_, geoPointValue), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "arrayValue", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSArrayValue), - .number = GCFSValue_FieldNumber_ArrayValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSValue__storage_, arrayValue), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "timestampValue", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSValue_FieldNumber_TimestampValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSValue__storage_, timestampValue), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "nullValue", - .dataTypeSpecific.enumDescFunc = GPBNullValue_EnumDescriptor, - .number = GCFSValue_FieldNumber_NullValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSValue__storage_, nullValue), - .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor), - .dataType = GPBDataTypeEnum, - }, - { - .name = "stringValue", - .dataTypeSpecific.className = NULL, - .number = GCFSValue_FieldNumber_StringValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSValue__storage_, stringValue), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "bytesValue", - .dataTypeSpecific.className = NULL, - .number = GCFSValue_FieldNumber_BytesValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSValue__storage_, bytesValue), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSValue class] - rootClass:[GCFSDocumentRoot class] - file:GCFSDocumentRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSValue__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "valueType", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -int32_t GCFSValue_NullValue_RawValue(GCFSValue *message) { - GPBDescriptor *descriptor = [GCFSValue descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GCFSValue_FieldNumber_NullValue]; - return GPBGetMessageInt32Field(message, field); -} - -void SetGCFSValue_NullValue_RawValue(GCFSValue *message, int32_t value) { - GPBDescriptor *descriptor = [GCFSValue descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GCFSValue_FieldNumber_NullValue]; - GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); -} - -void GCFSValue_ClearValueTypeOneOfCase(GCFSValue *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - GCFSArrayValue - -@implementation GCFSArrayValue - -@dynamic valuesArray, valuesArray_Count; - -typedef struct GCFSArrayValue__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *valuesArray; -} GCFSArrayValue__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "valuesArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSValue), - .number = GCFSArrayValue_FieldNumber_ValuesArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSArrayValue__storage_, valuesArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSArrayValue class] - rootClass:[GCFSDocumentRoot class] - file:GCFSDocumentRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSArrayValue__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSMapValue - -@implementation GCFSMapValue - -@dynamic fields, fields_Count; - -typedef struct GCFSMapValue__storage_ { - uint32_t _has_storage_[1]; - NSMutableDictionary *fields; -} GCFSMapValue__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "fields", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSValue), - .number = GCFSMapValue_FieldNumber_Fields, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSMapValue__storage_, fields), - .flags = GPBFieldMapKeyString, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSMapValue class] - rootClass:[GCFSDocumentRoot class] - file:GCFSDocumentRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSMapValue__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Firestore.pbobjc.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Firestore.pbobjc.h deleted file mode 100644 index 8833c84..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Firestore.pbobjc.h +++ /dev/null @@ -1,1339 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/firestore/v1/firestore.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers.h" -#endif - -#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002 -#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources. -#endif -#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION -#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -@class GCFSDocument; -@class GCFSDocumentChange; -@class GCFSDocumentDelete; -@class GCFSDocumentMask; -@class GCFSDocumentRemove; -@class GCFSExistenceFilter; -@class GCFSPrecondition; -@class GCFSStructuredQuery; -@class GCFSTarget; -@class GCFSTargetChange; -@class GCFSTarget_DocumentsTarget; -@class GCFSTarget_QueryTarget; -@class GCFSTransactionOptions; -@class GCFSWrite; -@class GCFSWriteResult; -@class GPBTimestamp; -@class RPCStatus; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - Enum GCFSTargetChange_TargetChangeType - -/** The type of change. */ -typedef GPB_ENUM(GCFSTargetChange_TargetChangeType) { - /** - * Value used if any message's field encounters a value that is not defined - * by this enum. The message will also have C functions to get/set the rawValue - * of the field. - **/ - GCFSTargetChange_TargetChangeType_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, - /** No change has occurred. Used only to send an updated `resume_token`. */ - GCFSTargetChange_TargetChangeType_NoChange = 0, - - /** The targets have been added. */ - GCFSTargetChange_TargetChangeType_Add = 1, - - /** The targets have been removed. */ - GCFSTargetChange_TargetChangeType_Remove = 2, - - /** - * The targets reflect all changes committed before the targets were added - * to the stream. - * - * This will be sent after or with a `read_time` that is greater than or - * equal to the time at which the targets were added. - * - * Listeners can wait for this change if read-after-write semantics - * are desired. - **/ - GCFSTargetChange_TargetChangeType_Current = 3, - - /** - * The targets have been reset, and a new initial state for the targets - * will be returned in subsequent changes. - * - * After the initial state is complete, `CURRENT` will be returned even - * if the target was previously indicated to be `CURRENT`. - **/ - GCFSTargetChange_TargetChangeType_Reset = 4, -}; - -GPBEnumDescriptor *GCFSTargetChange_TargetChangeType_EnumDescriptor(void); - -/** - * Checks to see if the given value is defined by the enum or was not known at - * the time this source was generated. - **/ -BOOL GCFSTargetChange_TargetChangeType_IsValidValue(int32_t value); - -#pragma mark - GCFSFirestoreRoot - -/** - * Exposes the extension registry for this file. - * - * The base class provides: - * @code - * + (GPBExtensionRegistry *)extensionRegistry; - * @endcode - * which is a @c GPBExtensionRegistry that includes all the extensions defined by - * this file and all files that it depends on. - **/ -@interface GCFSFirestoreRoot : GPBRootObject -@end - -#pragma mark - GCFSGetDocumentRequest - -typedef GPB_ENUM(GCFSGetDocumentRequest_FieldNumber) { - GCFSGetDocumentRequest_FieldNumber_Name = 1, - GCFSGetDocumentRequest_FieldNumber_Mask = 2, - GCFSGetDocumentRequest_FieldNumber_Transaction = 3, - GCFSGetDocumentRequest_FieldNumber_ReadTime = 5, -}; - -typedef GPB_ENUM(GCFSGetDocumentRequest_ConsistencySelector_OneOfCase) { - GCFSGetDocumentRequest_ConsistencySelector_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSGetDocumentRequest_ConsistencySelector_OneOfCase_Transaction = 3, - GCFSGetDocumentRequest_ConsistencySelector_OneOfCase_ReadTime = 5, -}; - -/** - * The request for [Firestore.GetDocument][google.firestore.v1.Firestore.GetDocument]. - **/ -@interface GCFSGetDocumentRequest : GPBMessage - -/** - * The resource name of the Document to get. In the format: - * `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; - -/** - * The fields to return. If not set, returns all fields. - * - * If the document has a field that is not present in this mask, that field - * will not be returned in the response. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocumentMask *mask; -/** Test to see if @c mask has been set. */ -@property(nonatomic, readwrite) BOOL hasMask; - -/** - * The consistency mode for this transaction. - * If not set, defaults to strong consistency. - **/ -@property(nonatomic, readonly) GCFSGetDocumentRequest_ConsistencySelector_OneOfCase consistencySelectorOneOfCase; - -/** Reads the document in a transaction. */ -@property(nonatomic, readwrite, copy, null_resettable) NSData *transaction; - -/** - * Reads the version of the document at the given time. - * This may not be older than 60 seconds. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *readTime; - -@end - -/** - * Clears whatever value was set for the oneof 'consistencySelector'. - **/ -void GCFSGetDocumentRequest_ClearConsistencySelectorOneOfCase(GCFSGetDocumentRequest *message); - -#pragma mark - GCFSListDocumentsRequest - -typedef GPB_ENUM(GCFSListDocumentsRequest_FieldNumber) { - GCFSListDocumentsRequest_FieldNumber_Parent = 1, - GCFSListDocumentsRequest_FieldNumber_CollectionId = 2, - GCFSListDocumentsRequest_FieldNumber_PageSize = 3, - GCFSListDocumentsRequest_FieldNumber_PageToken = 4, - GCFSListDocumentsRequest_FieldNumber_OrderBy = 6, - GCFSListDocumentsRequest_FieldNumber_Mask = 7, - GCFSListDocumentsRequest_FieldNumber_Transaction = 8, - GCFSListDocumentsRequest_FieldNumber_ReadTime = 10, - GCFSListDocumentsRequest_FieldNumber_ShowMissing = 12, -}; - -typedef GPB_ENUM(GCFSListDocumentsRequest_ConsistencySelector_OneOfCase) { - GCFSListDocumentsRequest_ConsistencySelector_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSListDocumentsRequest_ConsistencySelector_OneOfCase_Transaction = 8, - GCFSListDocumentsRequest_ConsistencySelector_OneOfCase_ReadTime = 10, -}; - -/** - * The request for [Firestore.ListDocuments][google.firestore.v1.Firestore.ListDocuments]. - **/ -@interface GCFSListDocumentsRequest : GPBMessage - -/** - * The parent resource name. In the format: - * `projects/{project_id}/databases/{database_id}/documents` or - * `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - * For example: - * `projects/my-project/databases/my-database/documents` or - * `projects/my-project/databases/my-database/documents/chatrooms/my-chatroom` - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *parent; - -/** - * The collection ID, relative to `parent`, to list. For example: `chatrooms` - * or `messages`. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *collectionId; - -/** The maximum number of documents to return. */ -@property(nonatomic, readwrite) int32_t pageSize; - -/** The `next_page_token` value returned from a previous List request, if any. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *pageToken; - -/** The order to sort results by. For example: `priority desc, name`. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *orderBy; - -/** - * The fields to return. If not set, returns all fields. - * - * If a document has a field that is not present in this mask, that field - * will not be returned in the response. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocumentMask *mask; -/** Test to see if @c mask has been set. */ -@property(nonatomic, readwrite) BOOL hasMask; - -/** - * The consistency mode for this transaction. - * If not set, defaults to strong consistency. - **/ -@property(nonatomic, readonly) GCFSListDocumentsRequest_ConsistencySelector_OneOfCase consistencySelectorOneOfCase; - -/** Reads documents in a transaction. */ -@property(nonatomic, readwrite, copy, null_resettable) NSData *transaction; - -/** - * Reads documents as they were at the given time. - * This may not be older than 60 seconds. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *readTime; - -/** - * If the list should show missing documents. A missing document is a - * document that does not exist but has sub-documents. These documents will - * be returned with a key but will not have fields, [Document.create_time][google.firestore.v1.Document.create_time], - * or [Document.update_time][google.firestore.v1.Document.update_time] set. - * - * Requests with `show_missing` may not specify `where` or - * `order_by`. - **/ -@property(nonatomic, readwrite) BOOL showMissing; - -@end - -/** - * Clears whatever value was set for the oneof 'consistencySelector'. - **/ -void GCFSListDocumentsRequest_ClearConsistencySelectorOneOfCase(GCFSListDocumentsRequest *message); - -#pragma mark - GCFSListDocumentsResponse - -typedef GPB_ENUM(GCFSListDocumentsResponse_FieldNumber) { - GCFSListDocumentsResponse_FieldNumber_DocumentsArray = 1, - GCFSListDocumentsResponse_FieldNumber_NextPageToken = 2, -}; - -/** - * The response for [Firestore.ListDocuments][google.firestore.v1.Firestore.ListDocuments]. - **/ -@interface GCFSListDocumentsResponse : GPBMessage - -/** The Documents found. */ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *documentsArray; -/** The number of items in @c documentsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger documentsArray_Count; - -/** The next page token. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *nextPageToken; - -@end - -#pragma mark - GCFSCreateDocumentRequest - -typedef GPB_ENUM(GCFSCreateDocumentRequest_FieldNumber) { - GCFSCreateDocumentRequest_FieldNumber_Parent = 1, - GCFSCreateDocumentRequest_FieldNumber_CollectionId = 2, - GCFSCreateDocumentRequest_FieldNumber_DocumentId = 3, - GCFSCreateDocumentRequest_FieldNumber_Document = 4, - GCFSCreateDocumentRequest_FieldNumber_Mask = 5, -}; - -/** - * The request for [Firestore.CreateDocument][google.firestore.v1.Firestore.CreateDocument]. - **/ -@interface GCFSCreateDocumentRequest : GPBMessage - -/** - * The parent resource. For example: - * `projects/{project_id}/databases/{database_id}/documents` or - * `projects/{project_id}/databases/{database_id}/documents/chatrooms/{chatroom_id}` - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *parent; - -/** The collection ID, relative to `parent`, to list. For example: `chatrooms`. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *collectionId; - -/** - * The client-assigned document ID to use for this document. - * - * Optional. If not specified, an ID will be assigned by the service. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *documentId; - -/** The document to create. `name` must not be set. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocument *document; -/** Test to see if @c document has been set. */ -@property(nonatomic, readwrite) BOOL hasDocument; - -/** - * The fields to return. If not set, returns all fields. - * - * If the document has a field that is not present in this mask, that field - * will not be returned in the response. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocumentMask *mask; -/** Test to see if @c mask has been set. */ -@property(nonatomic, readwrite) BOOL hasMask; - -@end - -#pragma mark - GCFSUpdateDocumentRequest - -typedef GPB_ENUM(GCFSUpdateDocumentRequest_FieldNumber) { - GCFSUpdateDocumentRequest_FieldNumber_Document = 1, - GCFSUpdateDocumentRequest_FieldNumber_UpdateMask = 2, - GCFSUpdateDocumentRequest_FieldNumber_Mask = 3, - GCFSUpdateDocumentRequest_FieldNumber_CurrentDocument = 4, -}; - -/** - * The request for [Firestore.UpdateDocument][google.firestore.v1.Firestore.UpdateDocument]. - **/ -@interface GCFSUpdateDocumentRequest : GPBMessage - -/** - * The updated document. - * Creates the document if it does not already exist. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocument *document; -/** Test to see if @c document has been set. */ -@property(nonatomic, readwrite) BOOL hasDocument; - -/** - * The fields to update. - * None of the field paths in the mask may contain a reserved name. - * - * If the document exists on the server and has fields not referenced in the - * mask, they are left unchanged. - * Fields referenced in the mask, but not present in the input document, are - * deleted from the document on the server. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocumentMask *updateMask; -/** Test to see if @c updateMask has been set. */ -@property(nonatomic, readwrite) BOOL hasUpdateMask; - -/** - * The fields to return. If not set, returns all fields. - * - * If the document has a field that is not present in this mask, that field - * will not be returned in the response. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocumentMask *mask; -/** Test to see if @c mask has been set. */ -@property(nonatomic, readwrite) BOOL hasMask; - -/** - * An optional precondition on the document. - * The request will fail if this is set and not met by the target document. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSPrecondition *currentDocument; -/** Test to see if @c currentDocument has been set. */ -@property(nonatomic, readwrite) BOOL hasCurrentDocument; - -@end - -#pragma mark - GCFSDeleteDocumentRequest - -typedef GPB_ENUM(GCFSDeleteDocumentRequest_FieldNumber) { - GCFSDeleteDocumentRequest_FieldNumber_Name = 1, - GCFSDeleteDocumentRequest_FieldNumber_CurrentDocument = 2, -}; - -/** - * The request for [Firestore.DeleteDocument][google.firestore.v1.Firestore.DeleteDocument]. - **/ -@interface GCFSDeleteDocumentRequest : GPBMessage - -/** - * The resource name of the Document to delete. In the format: - * `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; - -/** - * An optional precondition on the document. - * The request will fail if this is set and not met by the target document. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSPrecondition *currentDocument; -/** Test to see if @c currentDocument has been set. */ -@property(nonatomic, readwrite) BOOL hasCurrentDocument; - -@end - -#pragma mark - GCFSBatchGetDocumentsRequest - -typedef GPB_ENUM(GCFSBatchGetDocumentsRequest_FieldNumber) { - GCFSBatchGetDocumentsRequest_FieldNumber_Database = 1, - GCFSBatchGetDocumentsRequest_FieldNumber_DocumentsArray = 2, - GCFSBatchGetDocumentsRequest_FieldNumber_Mask = 3, - GCFSBatchGetDocumentsRequest_FieldNumber_Transaction = 4, - GCFSBatchGetDocumentsRequest_FieldNumber_NewTransaction = 5, - GCFSBatchGetDocumentsRequest_FieldNumber_ReadTime = 7, -}; - -typedef GPB_ENUM(GCFSBatchGetDocumentsRequest_ConsistencySelector_OneOfCase) { - GCFSBatchGetDocumentsRequest_ConsistencySelector_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSBatchGetDocumentsRequest_ConsistencySelector_OneOfCase_Transaction = 4, - GCFSBatchGetDocumentsRequest_ConsistencySelector_OneOfCase_NewTransaction = 5, - GCFSBatchGetDocumentsRequest_ConsistencySelector_OneOfCase_ReadTime = 7, -}; - -/** - * The request for [Firestore.BatchGetDocuments][google.firestore.v1.Firestore.BatchGetDocuments]. - **/ -@interface GCFSBatchGetDocumentsRequest : GPBMessage - -/** - * The database name. In the format: - * `projects/{project_id}/databases/{database_id}`. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *database; - -/** - * The names of the documents to retrieve. In the format: - * `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - * The request will fail if any of the document is not a child resource of the - * given `database`. Duplicate names will be elided. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *documentsArray; -/** The number of items in @c documentsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger documentsArray_Count; - -/** - * The fields to return. If not set, returns all fields. - * - * If a document has a field that is not present in this mask, that field will - * not be returned in the response. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocumentMask *mask; -/** Test to see if @c mask has been set. */ -@property(nonatomic, readwrite) BOOL hasMask; - -/** - * The consistency mode for this transaction. - * If not set, defaults to strong consistency. - **/ -@property(nonatomic, readonly) GCFSBatchGetDocumentsRequest_ConsistencySelector_OneOfCase consistencySelectorOneOfCase; - -/** Reads documents in a transaction. */ -@property(nonatomic, readwrite, copy, null_resettable) NSData *transaction; - -/** - * Starts a new transaction and reads the documents. - * Defaults to a read-only transaction. - * The new transaction ID will be returned as the first response in the - * stream. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSTransactionOptions *newTransaction NS_RETURNS_NOT_RETAINED; - -/** - * Reads documents as they were at the given time. - * This may not be older than 60 seconds. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *readTime; - -@end - -/** - * Clears whatever value was set for the oneof 'consistencySelector'. - **/ -void GCFSBatchGetDocumentsRequest_ClearConsistencySelectorOneOfCase(GCFSBatchGetDocumentsRequest *message); - -#pragma mark - GCFSBatchGetDocumentsResponse - -typedef GPB_ENUM(GCFSBatchGetDocumentsResponse_FieldNumber) { - GCFSBatchGetDocumentsResponse_FieldNumber_Found = 1, - GCFSBatchGetDocumentsResponse_FieldNumber_Missing = 2, - GCFSBatchGetDocumentsResponse_FieldNumber_Transaction = 3, - GCFSBatchGetDocumentsResponse_FieldNumber_ReadTime = 4, -}; - -typedef GPB_ENUM(GCFSBatchGetDocumentsResponse_Result_OneOfCase) { - GCFSBatchGetDocumentsResponse_Result_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSBatchGetDocumentsResponse_Result_OneOfCase_Found = 1, - GCFSBatchGetDocumentsResponse_Result_OneOfCase_Missing = 2, -}; - -/** - * The streamed response for [Firestore.BatchGetDocuments][google.firestore.v1.Firestore.BatchGetDocuments]. - **/ -@interface GCFSBatchGetDocumentsResponse : GPBMessage - -/** - * A single result. - * This can be empty if the server is just returning a transaction. - **/ -@property(nonatomic, readonly) GCFSBatchGetDocumentsResponse_Result_OneOfCase resultOneOfCase; - -/** A document that was requested. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocument *found; - -/** - * A document name that was requested but does not exist. In the format: - * `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *missing; - -/** - * The transaction that was started as part of this request. - * Will only be set in the first response, and only if - * [BatchGetDocumentsRequest.new_transaction][google.firestore.v1.BatchGetDocumentsRequest.new_transaction] was set in the request. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSData *transaction; - -/** - * The time at which the document was read. - * This may be monotically increasing, in this case the previous documents in - * the result stream are guaranteed not to have changed between their - * read_time and this one. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *readTime; -/** Test to see if @c readTime has been set. */ -@property(nonatomic, readwrite) BOOL hasReadTime; - -@end - -/** - * Clears whatever value was set for the oneof 'result'. - **/ -void GCFSBatchGetDocumentsResponse_ClearResultOneOfCase(GCFSBatchGetDocumentsResponse *message); - -#pragma mark - GCFSBeginTransactionRequest - -typedef GPB_ENUM(GCFSBeginTransactionRequest_FieldNumber) { - GCFSBeginTransactionRequest_FieldNumber_Database = 1, - GCFSBeginTransactionRequest_FieldNumber_Options = 2, -}; - -/** - * The request for [Firestore.BeginTransaction][google.firestore.v1.Firestore.BeginTransaction]. - **/ -@interface GCFSBeginTransactionRequest : GPBMessage - -/** - * The database name. In the format: - * `projects/{project_id}/databases/{database_id}`. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *database; - -/** - * The options for the transaction. - * Defaults to a read-write transaction. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSTransactionOptions *options; -/** Test to see if @c options has been set. */ -@property(nonatomic, readwrite) BOOL hasOptions; - -@end - -#pragma mark - GCFSBeginTransactionResponse - -typedef GPB_ENUM(GCFSBeginTransactionResponse_FieldNumber) { - GCFSBeginTransactionResponse_FieldNumber_Transaction = 1, -}; - -/** - * The response for [Firestore.BeginTransaction][google.firestore.v1.Firestore.BeginTransaction]. - **/ -@interface GCFSBeginTransactionResponse : GPBMessage - -/** The transaction that was started. */ -@property(nonatomic, readwrite, copy, null_resettable) NSData *transaction; - -@end - -#pragma mark - GCFSCommitRequest - -typedef GPB_ENUM(GCFSCommitRequest_FieldNumber) { - GCFSCommitRequest_FieldNumber_Database = 1, - GCFSCommitRequest_FieldNumber_WritesArray = 2, - GCFSCommitRequest_FieldNumber_Transaction = 3, -}; - -/** - * The request for [Firestore.Commit][google.firestore.v1.Firestore.Commit]. - **/ -@interface GCFSCommitRequest : GPBMessage - -/** - * The database name. In the format: - * `projects/{project_id}/databases/{database_id}`. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *database; - -/** - * The writes to apply. - * - * Always executed atomically and in order. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *writesArray; -/** The number of items in @c writesArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger writesArray_Count; - -/** If set, applies all writes in this transaction, and commits it. */ -@property(nonatomic, readwrite, copy, null_resettable) NSData *transaction; - -@end - -#pragma mark - GCFSCommitResponse - -typedef GPB_ENUM(GCFSCommitResponse_FieldNumber) { - GCFSCommitResponse_FieldNumber_WriteResultsArray = 1, - GCFSCommitResponse_FieldNumber_CommitTime = 2, -}; - -/** - * The response for [Firestore.Commit][google.firestore.v1.Firestore.Commit]. - **/ -@interface GCFSCommitResponse : GPBMessage - -/** - * The result of applying the writes. - * - * This i-th write result corresponds to the i-th write in the - * request. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *writeResultsArray; -/** The number of items in @c writeResultsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger writeResultsArray_Count; - -/** The time at which the commit occurred. */ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *commitTime; -/** Test to see if @c commitTime has been set. */ -@property(nonatomic, readwrite) BOOL hasCommitTime; - -@end - -#pragma mark - GCFSRollbackRequest - -typedef GPB_ENUM(GCFSRollbackRequest_FieldNumber) { - GCFSRollbackRequest_FieldNumber_Database = 1, - GCFSRollbackRequest_FieldNumber_Transaction = 2, -}; - -/** - * The request for [Firestore.Rollback][google.firestore.v1.Firestore.Rollback]. - **/ -@interface GCFSRollbackRequest : GPBMessage - -/** - * The database name. In the format: - * `projects/{project_id}/databases/{database_id}`. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *database; - -/** The transaction to roll back. */ -@property(nonatomic, readwrite, copy, null_resettable) NSData *transaction; - -@end - -#pragma mark - GCFSRunQueryRequest - -typedef GPB_ENUM(GCFSRunQueryRequest_FieldNumber) { - GCFSRunQueryRequest_FieldNumber_Parent = 1, - GCFSRunQueryRequest_FieldNumber_StructuredQuery = 2, - GCFSRunQueryRequest_FieldNumber_Transaction = 5, - GCFSRunQueryRequest_FieldNumber_NewTransaction = 6, - GCFSRunQueryRequest_FieldNumber_ReadTime = 7, -}; - -typedef GPB_ENUM(GCFSRunQueryRequest_QueryType_OneOfCase) { - GCFSRunQueryRequest_QueryType_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSRunQueryRequest_QueryType_OneOfCase_StructuredQuery = 2, -}; - -typedef GPB_ENUM(GCFSRunQueryRequest_ConsistencySelector_OneOfCase) { - GCFSRunQueryRequest_ConsistencySelector_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSRunQueryRequest_ConsistencySelector_OneOfCase_Transaction = 5, - GCFSRunQueryRequest_ConsistencySelector_OneOfCase_NewTransaction = 6, - GCFSRunQueryRequest_ConsistencySelector_OneOfCase_ReadTime = 7, -}; - -/** - * The request for [Firestore.RunQuery][google.firestore.v1.Firestore.RunQuery]. - **/ -@interface GCFSRunQueryRequest : GPBMessage - -/** - * The parent resource name. In the format: - * `projects/{project_id}/databases/{database_id}/documents` or - * `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - * For example: - * `projects/my-project/databases/my-database/documents` or - * `projects/my-project/databases/my-database/documents/chatrooms/my-chatroom` - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *parent; - -/** The query to run. */ -@property(nonatomic, readonly) GCFSRunQueryRequest_QueryType_OneOfCase queryTypeOneOfCase; - -/** A structured query. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSStructuredQuery *structuredQuery; - -/** - * The consistency mode for this transaction. - * If not set, defaults to strong consistency. - **/ -@property(nonatomic, readonly) GCFSRunQueryRequest_ConsistencySelector_OneOfCase consistencySelectorOneOfCase; - -/** Reads documents in a transaction. */ -@property(nonatomic, readwrite, copy, null_resettable) NSData *transaction; - -/** - * Starts a new transaction and reads the documents. - * Defaults to a read-only transaction. - * The new transaction ID will be returned as the first response in the - * stream. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSTransactionOptions *newTransaction NS_RETURNS_NOT_RETAINED; - -/** - * Reads documents as they were at the given time. - * This may not be older than 60 seconds. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *readTime; - -@end - -/** - * Clears whatever value was set for the oneof 'queryType'. - **/ -void GCFSRunQueryRequest_ClearQueryTypeOneOfCase(GCFSRunQueryRequest *message); -/** - * Clears whatever value was set for the oneof 'consistencySelector'. - **/ -void GCFSRunQueryRequest_ClearConsistencySelectorOneOfCase(GCFSRunQueryRequest *message); - -#pragma mark - GCFSRunQueryResponse - -typedef GPB_ENUM(GCFSRunQueryResponse_FieldNumber) { - GCFSRunQueryResponse_FieldNumber_Document = 1, - GCFSRunQueryResponse_FieldNumber_Transaction = 2, - GCFSRunQueryResponse_FieldNumber_ReadTime = 3, - GCFSRunQueryResponse_FieldNumber_SkippedResults = 4, -}; - -/** - * The response for [Firestore.RunQuery][google.firestore.v1.Firestore.RunQuery]. - **/ -@interface GCFSRunQueryResponse : GPBMessage - -/** - * The transaction that was started as part of this request. - * Can only be set in the first response, and only if - * [RunQueryRequest.new_transaction][google.firestore.v1.RunQueryRequest.new_transaction] was set in the request. - * If set, no other fields will be set in this response. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSData *transaction; - -/** - * A query result. - * Not set when reporting partial progress. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocument *document; -/** Test to see if @c document has been set. */ -@property(nonatomic, readwrite) BOOL hasDocument; - -/** - * The time at which the document was read. This may be monotonically - * increasing; in this case, the previous documents in the result stream are - * guaranteed not to have changed between their `read_time` and this one. - * - * If the query returns no results, a response with `read_time` and no - * `document` will be sent, and this represents the time at which the query - * was run. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *readTime; -/** Test to see if @c readTime has been set. */ -@property(nonatomic, readwrite) BOOL hasReadTime; - -/** - * The number of results that have been skipped due to an offset between - * the last response and the current response. - **/ -@property(nonatomic, readwrite) int32_t skippedResults; - -@end - -#pragma mark - GCFSWriteRequest - -typedef GPB_ENUM(GCFSWriteRequest_FieldNumber) { - GCFSWriteRequest_FieldNumber_Database = 1, - GCFSWriteRequest_FieldNumber_StreamId = 2, - GCFSWriteRequest_FieldNumber_WritesArray = 3, - GCFSWriteRequest_FieldNumber_StreamToken = 4, - GCFSWriteRequest_FieldNumber_Labels = 5, -}; - -/** - * The request for [Firestore.Write][google.firestore.v1.Firestore.Write]. - * - * The first request creates a stream, or resumes an existing one from a token. - * - * When creating a new stream, the server replies with a response containing - * only an ID and a token, to use in the next request. - * - * When resuming a stream, the server first streams any responses later than the - * given token, then a response containing only an up-to-date token, to use in - * the next request. - **/ -@interface GCFSWriteRequest : GPBMessage - -/** - * The database name. In the format: - * `projects/{project_id}/databases/{database_id}`. - * This is only required in the first message. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *database; - -/** - * The ID of the write stream to resume. - * This may only be set in the first message. When left empty, a new write - * stream will be created. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *streamId; - -/** - * The writes to apply. - * - * Always executed atomically and in order. - * This must be empty on the first request. - * This may be empty on the last request. - * This must not be empty on all other requests. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *writesArray; -/** The number of items in @c writesArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger writesArray_Count; - -/** - * A stream token that was previously sent by the server. - * - * The client should set this field to the token from the most recent - * [WriteResponse][google.firestore.v1.WriteResponse] it has received. This acknowledges that the client has - * received responses up to this token. After sending this token, earlier - * tokens may not be used anymore. - * - * The server may close the stream if there are too many unacknowledged - * responses. - * - * Leave this field unset when creating a new stream. To resume a stream at - * a specific point, set this field and the `stream_id` field. - * - * Leave this field unset when creating a new stream. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSData *streamToken; - -/** Labels associated with this write request. */ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary *labels; -/** The number of items in @c labels without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger labels_Count; - -@end - -#pragma mark - GCFSWriteResponse - -typedef GPB_ENUM(GCFSWriteResponse_FieldNumber) { - GCFSWriteResponse_FieldNumber_StreamId = 1, - GCFSWriteResponse_FieldNumber_StreamToken = 2, - GCFSWriteResponse_FieldNumber_WriteResultsArray = 3, - GCFSWriteResponse_FieldNumber_CommitTime = 4, -}; - -/** - * The response for [Firestore.Write][google.firestore.v1.Firestore.Write]. - **/ -@interface GCFSWriteResponse : GPBMessage - -/** - * The ID of the stream. - * Only set on the first message, when a new stream was created. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *streamId; - -/** - * A token that represents the position of this response in the stream. - * This can be used by a client to resume the stream at this point. - * - * This field is always set. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSData *streamToken; - -/** - * The result of applying the writes. - * - * This i-th write result corresponds to the i-th write in the - * request. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *writeResultsArray; -/** The number of items in @c writeResultsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger writeResultsArray_Count; - -/** The time at which the commit occurred. */ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *commitTime; -/** Test to see if @c commitTime has been set. */ -@property(nonatomic, readwrite) BOOL hasCommitTime; - -@end - -#pragma mark - GCFSListenRequest - -typedef GPB_ENUM(GCFSListenRequest_FieldNumber) { - GCFSListenRequest_FieldNumber_Database = 1, - GCFSListenRequest_FieldNumber_AddTarget = 2, - GCFSListenRequest_FieldNumber_RemoveTarget = 3, - GCFSListenRequest_FieldNumber_Labels = 4, -}; - -typedef GPB_ENUM(GCFSListenRequest_TargetChange_OneOfCase) { - GCFSListenRequest_TargetChange_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSListenRequest_TargetChange_OneOfCase_AddTarget = 2, - GCFSListenRequest_TargetChange_OneOfCase_RemoveTarget = 3, -}; - -/** - * A request for [Firestore.Listen][google.firestore.v1.Firestore.Listen] - **/ -@interface GCFSListenRequest : GPBMessage - -/** - * The database name. In the format: - * `projects/{project_id}/databases/{database_id}`. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *database; - -/** The supported target changes. */ -@property(nonatomic, readonly) GCFSListenRequest_TargetChange_OneOfCase targetChangeOneOfCase; - -/** A target to add to this stream. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSTarget *addTarget; - -/** The ID of a target to remove from this stream. */ -@property(nonatomic, readwrite) int32_t removeTarget; - -/** Labels associated with this target change. */ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary *labels; -/** The number of items in @c labels without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger labels_Count; - -@end - -/** - * Clears whatever value was set for the oneof 'targetChange'. - **/ -void GCFSListenRequest_ClearTargetChangeOneOfCase(GCFSListenRequest *message); - -#pragma mark - GCFSListenResponse - -typedef GPB_ENUM(GCFSListenResponse_FieldNumber) { - GCFSListenResponse_FieldNumber_TargetChange = 2, - GCFSListenResponse_FieldNumber_DocumentChange = 3, - GCFSListenResponse_FieldNumber_DocumentDelete = 4, - GCFSListenResponse_FieldNumber_Filter = 5, - GCFSListenResponse_FieldNumber_DocumentRemove = 6, -}; - -typedef GPB_ENUM(GCFSListenResponse_ResponseType_OneOfCase) { - GCFSListenResponse_ResponseType_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSListenResponse_ResponseType_OneOfCase_TargetChange = 2, - GCFSListenResponse_ResponseType_OneOfCase_DocumentChange = 3, - GCFSListenResponse_ResponseType_OneOfCase_DocumentDelete = 4, - GCFSListenResponse_ResponseType_OneOfCase_DocumentRemove = 6, - GCFSListenResponse_ResponseType_OneOfCase_Filter = 5, -}; - -/** - * The response for [Firestore.Listen][google.firestore.v1.Firestore.Listen]. - **/ -@interface GCFSListenResponse : GPBMessage - -/** The supported responses. */ -@property(nonatomic, readonly) GCFSListenResponse_ResponseType_OneOfCase responseTypeOneOfCase; - -/** Targets have changed. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSTargetChange *targetChange; - -/** A [Document][google.firestore.v1.Document] has changed. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocumentChange *documentChange; - -/** A [Document][google.firestore.v1.Document] has been deleted. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocumentDelete *documentDelete; - -/** - * A [Document][google.firestore.v1.Document] has been removed from a target (because it is no longer - * relevant to that target). - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocumentRemove *documentRemove; - -/** - * A filter to apply to the set of documents previously returned for the - * given target. - * - * Returned when documents may have been removed from the given target, but - * the exact documents are unknown. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSExistenceFilter *filter; - -@end - -/** - * Clears whatever value was set for the oneof 'responseType'. - **/ -void GCFSListenResponse_ClearResponseTypeOneOfCase(GCFSListenResponse *message); - -#pragma mark - GCFSTarget - -typedef GPB_ENUM(GCFSTarget_FieldNumber) { - GCFSTarget_FieldNumber_Query = 2, - GCFSTarget_FieldNumber_Documents = 3, - GCFSTarget_FieldNumber_ResumeToken = 4, - GCFSTarget_FieldNumber_TargetId = 5, - GCFSTarget_FieldNumber_Once = 6, - GCFSTarget_FieldNumber_ReadTime = 11, -}; - -typedef GPB_ENUM(GCFSTarget_TargetType_OneOfCase) { - GCFSTarget_TargetType_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSTarget_TargetType_OneOfCase_Query = 2, - GCFSTarget_TargetType_OneOfCase_Documents = 3, -}; - -typedef GPB_ENUM(GCFSTarget_ResumeType_OneOfCase) { - GCFSTarget_ResumeType_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSTarget_ResumeType_OneOfCase_ResumeToken = 4, - GCFSTarget_ResumeType_OneOfCase_ReadTime = 11, -}; - -/** - * A specification of a set of documents to listen to. - **/ -@interface GCFSTarget : GPBMessage - -/** The type of target to listen to. */ -@property(nonatomic, readonly) GCFSTarget_TargetType_OneOfCase targetTypeOneOfCase; - -/** A target specified by a query. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSTarget_QueryTarget *query; - -/** A target specified by a set of document names. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSTarget_DocumentsTarget *documents; - -/** - * When to start listening. - * - * If not specified, all matching Documents are returned before any - * subsequent changes. - **/ -@property(nonatomic, readonly) GCFSTarget_ResumeType_OneOfCase resumeTypeOneOfCase; - -/** - * A resume token from a prior [TargetChange][google.firestore.v1.TargetChange] for an identical target. - * - * Using a resume token with a different target is unsupported and may fail. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSData *resumeToken; - -/** - * Start listening after a specific `read_time`. - * - * The client must know the state of matching documents at this time. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *readTime; - -/** - * A client provided target ID. - * - * If not set, the server will assign an ID for the target. - * - * Used for resuming a target without changing IDs. The IDs can either be - * client-assigned or be server-assigned in a previous stream. All targets - * with client provided IDs must be added before adding a target that needs - * a server-assigned id. - **/ -@property(nonatomic, readwrite) int32_t targetId; - -/** If the target should be removed once it is current and consistent. */ -@property(nonatomic, readwrite) BOOL once; - -@end - -/** - * Clears whatever value was set for the oneof 'targetType'. - **/ -void GCFSTarget_ClearTargetTypeOneOfCase(GCFSTarget *message); -/** - * Clears whatever value was set for the oneof 'resumeType'. - **/ -void GCFSTarget_ClearResumeTypeOneOfCase(GCFSTarget *message); - -#pragma mark - GCFSTarget_DocumentsTarget - -typedef GPB_ENUM(GCFSTarget_DocumentsTarget_FieldNumber) { - GCFSTarget_DocumentsTarget_FieldNumber_DocumentsArray = 2, -}; - -/** - * A target specified by a set of documents names. - **/ -@interface GCFSTarget_DocumentsTarget : GPBMessage - -/** - * The names of the documents to retrieve. In the format: - * `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - * The request will fail if any of the document is not a child resource of - * the given `database`. Duplicate names will be elided. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *documentsArray; -/** The number of items in @c documentsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger documentsArray_Count; - -@end - -#pragma mark - GCFSTarget_QueryTarget - -typedef GPB_ENUM(GCFSTarget_QueryTarget_FieldNumber) { - GCFSTarget_QueryTarget_FieldNumber_Parent = 1, - GCFSTarget_QueryTarget_FieldNumber_StructuredQuery = 2, -}; - -typedef GPB_ENUM(GCFSTarget_QueryTarget_QueryType_OneOfCase) { - GCFSTarget_QueryTarget_QueryType_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSTarget_QueryTarget_QueryType_OneOfCase_StructuredQuery = 2, -}; - -/** - * A target specified by a query. - **/ -@interface GCFSTarget_QueryTarget : GPBMessage - -/** - * The parent resource name. In the format: - * `projects/{project_id}/databases/{database_id}/documents` or - * `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - * For example: - * `projects/my-project/databases/my-database/documents` or - * `projects/my-project/databases/my-database/documents/chatrooms/my-chatroom` - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *parent; - -/** The query to run. */ -@property(nonatomic, readonly) GCFSTarget_QueryTarget_QueryType_OneOfCase queryTypeOneOfCase; - -/** A structured query. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSStructuredQuery *structuredQuery; - -@end - -/** - * Clears whatever value was set for the oneof 'queryType'. - **/ -void GCFSTarget_QueryTarget_ClearQueryTypeOneOfCase(GCFSTarget_QueryTarget *message); - -#pragma mark - GCFSTargetChange - -typedef GPB_ENUM(GCFSTargetChange_FieldNumber) { - GCFSTargetChange_FieldNumber_TargetChangeType = 1, - GCFSTargetChange_FieldNumber_TargetIdsArray = 2, - GCFSTargetChange_FieldNumber_Cause = 3, - GCFSTargetChange_FieldNumber_ResumeToken = 4, - GCFSTargetChange_FieldNumber_ReadTime = 6, -}; - -/** - * Targets being watched have changed. - **/ -@interface GCFSTargetChange : GPBMessage - -/** The type of change that occurred. */ -@property(nonatomic, readwrite) GCFSTargetChange_TargetChangeType targetChangeType; - -/** - * The target IDs of targets that have changed. - * - * If empty, the change applies to all targets. - * - * For `target_change_type=ADD`, the order of the target IDs matches the order - * of the requests to add the targets. This allows clients to unambiguously - * associate server-assigned target IDs with added targets. - * - * For other states, the order of the target IDs is not defined. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *targetIdsArray; -/** The number of items in @c targetIdsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger targetIdsArray_Count; - -/** The error that resulted in this change, if applicable. */ -@property(nonatomic, readwrite, strong, null_resettable) RPCStatus *cause; -/** Test to see if @c cause has been set. */ -@property(nonatomic, readwrite) BOOL hasCause; - -/** - * A token that can be used to resume the stream for the given `target_ids`, - * or all targets if `target_ids` is empty. - * - * Not set on every target change. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSData *resumeToken; - -/** - * The consistent `read_time` for the given `target_ids` (omitted when the - * target_ids are not at a consistent snapshot). - * - * The stream is guaranteed to send a `read_time` with `target_ids` empty - * whenever the entire stream reaches a new consistent snapshot. ADD, - * CURRENT, and RESET messages are guaranteed to (eventually) result in a - * new consistent snapshot (while NO_CHANGE and REMOVE messages are not). - * - * For a given stream, `read_time` is guaranteed to be monotonically - * increasing. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *readTime; -/** Test to see if @c readTime has been set. */ -@property(nonatomic, readwrite) BOOL hasReadTime; - -@end - -/** - * Fetches the raw value of a @c GCFSTargetChange's @c targetChangeType property, even - * if the value was not defined by the enum at the time the code was generated. - **/ -int32_t GCFSTargetChange_TargetChangeType_RawValue(GCFSTargetChange *message); -/** - * Sets the raw value of an @c GCFSTargetChange's @c targetChangeType property, allowing - * it to be set to a value that was not defined by the enum at the time the code - * was generated. - **/ -void SetGCFSTargetChange_TargetChangeType_RawValue(GCFSTargetChange *message, int32_t value); - -#pragma mark - GCFSListCollectionIdsRequest - -typedef GPB_ENUM(GCFSListCollectionIdsRequest_FieldNumber) { - GCFSListCollectionIdsRequest_FieldNumber_Parent = 1, - GCFSListCollectionIdsRequest_FieldNumber_PageSize = 2, - GCFSListCollectionIdsRequest_FieldNumber_PageToken = 3, -}; - -/** - * The request for [Firestore.ListCollectionIds][google.firestore.v1.Firestore.ListCollectionIds]. - **/ -@interface GCFSListCollectionIdsRequest : GPBMessage - -/** - * The parent document. In the format: - * `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - * For example: - * `projects/my-project/databases/my-database/documents/chatrooms/my-chatroom` - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *parent; - -/** The maximum number of results to return. */ -@property(nonatomic, readwrite) int32_t pageSize; - -/** - * A page token. Must be a value from - * [ListCollectionIdsResponse][google.firestore.v1.ListCollectionIdsResponse]. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *pageToken; - -@end - -#pragma mark - GCFSListCollectionIdsResponse - -typedef GPB_ENUM(GCFSListCollectionIdsResponse_FieldNumber) { - GCFSListCollectionIdsResponse_FieldNumber_CollectionIdsArray = 1, - GCFSListCollectionIdsResponse_FieldNumber_NextPageToken = 2, -}; - -/** - * The response from [Firestore.ListCollectionIds][google.firestore.v1.Firestore.ListCollectionIds]. - **/ -@interface GCFSListCollectionIdsResponse : GPBMessage - -/** The collection ids. */ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *collectionIdsArray; -/** The number of items in @c collectionIdsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger collectionIdsArray_Count; - -/** A page token that may be used to continue the list. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *nextPageToken; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Firestore.pbobjc.m b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Firestore.pbobjc.m deleted file mode 100644 index 8ab8ca1..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Firestore.pbobjc.m +++ /dev/null @@ -1,2064 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/firestore/v1/firestore.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers_RuntimeSupport.h" -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import - #import -#else - #import "Empty.pbobjc.h" - #import "Timestamp.pbobjc.h" -#endif - - #import "Firestore.pbobjc.h" - #import "Annotations.pbobjc.h" - #import "Common.pbobjc.h" - #import "Document.pbobjc.h" - #import "Query.pbobjc.h" - #import "Write.pbobjc.h" - #import "Status.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#pragma clang diagnostic ignored "-Wdirect-ivar-access" - -#pragma mark - GCFSFirestoreRoot - -@implementation GCFSFirestoreRoot - - -@end - -#pragma mark - GCFSFirestoreRoot_FileDescriptor - -static GPBFileDescriptor *GCFSFirestoreRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPB_DEBUG_CHECK_RUNTIME_VERSIONS(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.firestore.v1" - objcPrefix:@"GCFS" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GCFSGetDocumentRequest - -@implementation GCFSGetDocumentRequest - -@dynamic consistencySelectorOneOfCase; -@dynamic name; -@dynamic hasMask, mask; -@dynamic transaction; -@dynamic readTime; - -typedef struct GCFSGetDocumentRequest__storage_ { - uint32_t _has_storage_[2]; - NSString *name; - GCFSDocumentMask *mask; - NSData *transaction; - GPBTimestamp *readTime; -} GCFSGetDocumentRequest__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .dataTypeSpecific.className = NULL, - .number = GCFSGetDocumentRequest_FieldNumber_Name, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSGetDocumentRequest__storage_, name), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "mask", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocumentMask), - .number = GCFSGetDocumentRequest_FieldNumber_Mask, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSGetDocumentRequest__storage_, mask), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "transaction", - .dataTypeSpecific.className = NULL, - .number = GCFSGetDocumentRequest_FieldNumber_Transaction, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSGetDocumentRequest__storage_, transaction), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - { - .name = "readTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSGetDocumentRequest_FieldNumber_ReadTime, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSGetDocumentRequest__storage_, readTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSGetDocumentRequest class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSGetDocumentRequest__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "consistencySelector", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GCFSGetDocumentRequest_ClearConsistencySelectorOneOfCase(GCFSGetDocumentRequest *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - GCFSListDocumentsRequest - -@implementation GCFSListDocumentsRequest - -@dynamic consistencySelectorOneOfCase; -@dynamic parent; -@dynamic collectionId; -@dynamic pageSize; -@dynamic pageToken; -@dynamic orderBy; -@dynamic hasMask, mask; -@dynamic transaction; -@dynamic readTime; -@dynamic showMissing; - -typedef struct GCFSListDocumentsRequest__storage_ { - uint32_t _has_storage_[2]; - int32_t pageSize; - NSString *parent; - NSString *collectionId; - NSString *pageToken; - NSString *orderBy; - GCFSDocumentMask *mask; - NSData *transaction; - GPBTimestamp *readTime; -} GCFSListDocumentsRequest__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "parent", - .dataTypeSpecific.className = NULL, - .number = GCFSListDocumentsRequest_FieldNumber_Parent, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSListDocumentsRequest__storage_, parent), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "collectionId", - .dataTypeSpecific.className = NULL, - .number = GCFSListDocumentsRequest_FieldNumber_CollectionId, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSListDocumentsRequest__storage_, collectionId), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "pageSize", - .dataTypeSpecific.className = NULL, - .number = GCFSListDocumentsRequest_FieldNumber_PageSize, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GCFSListDocumentsRequest__storage_, pageSize), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - { - .name = "pageToken", - .dataTypeSpecific.className = NULL, - .number = GCFSListDocumentsRequest_FieldNumber_PageToken, - .hasIndex = 3, - .offset = (uint32_t)offsetof(GCFSListDocumentsRequest__storage_, pageToken), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "orderBy", - .dataTypeSpecific.className = NULL, - .number = GCFSListDocumentsRequest_FieldNumber_OrderBy, - .hasIndex = 4, - .offset = (uint32_t)offsetof(GCFSListDocumentsRequest__storage_, orderBy), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "mask", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocumentMask), - .number = GCFSListDocumentsRequest_FieldNumber_Mask, - .hasIndex = 5, - .offset = (uint32_t)offsetof(GCFSListDocumentsRequest__storage_, mask), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "transaction", - .dataTypeSpecific.className = NULL, - .number = GCFSListDocumentsRequest_FieldNumber_Transaction, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSListDocumentsRequest__storage_, transaction), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - { - .name = "readTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSListDocumentsRequest_FieldNumber_ReadTime, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSListDocumentsRequest__storage_, readTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "showMissing", - .dataTypeSpecific.className = NULL, - .number = GCFSListDocumentsRequest_FieldNumber_ShowMissing, - .hasIndex = 6, - .offset = 7, // Stored in _has_storage_ to save space. - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSListDocumentsRequest class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSListDocumentsRequest__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "consistencySelector", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GCFSListDocumentsRequest_ClearConsistencySelectorOneOfCase(GCFSListDocumentsRequest *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - GCFSListDocumentsResponse - -@implementation GCFSListDocumentsResponse - -@dynamic documentsArray, documentsArray_Count; -@dynamic nextPageToken; - -typedef struct GCFSListDocumentsResponse__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *documentsArray; - NSString *nextPageToken; -} GCFSListDocumentsResponse__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "documentsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocument), - .number = GCFSListDocumentsResponse_FieldNumber_DocumentsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSListDocumentsResponse__storage_, documentsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "nextPageToken", - .dataTypeSpecific.className = NULL, - .number = GCFSListDocumentsResponse_FieldNumber_NextPageToken, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSListDocumentsResponse__storage_, nextPageToken), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSListDocumentsResponse class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSListDocumentsResponse__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSCreateDocumentRequest - -@implementation GCFSCreateDocumentRequest - -@dynamic parent; -@dynamic collectionId; -@dynamic documentId; -@dynamic hasDocument, document; -@dynamic hasMask, mask; - -typedef struct GCFSCreateDocumentRequest__storage_ { - uint32_t _has_storage_[1]; - NSString *parent; - NSString *collectionId; - NSString *documentId; - GCFSDocument *document; - GCFSDocumentMask *mask; -} GCFSCreateDocumentRequest__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "parent", - .dataTypeSpecific.className = NULL, - .number = GCFSCreateDocumentRequest_FieldNumber_Parent, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSCreateDocumentRequest__storage_, parent), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "collectionId", - .dataTypeSpecific.className = NULL, - .number = GCFSCreateDocumentRequest_FieldNumber_CollectionId, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSCreateDocumentRequest__storage_, collectionId), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "documentId", - .dataTypeSpecific.className = NULL, - .number = GCFSCreateDocumentRequest_FieldNumber_DocumentId, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GCFSCreateDocumentRequest__storage_, documentId), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "document", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocument), - .number = GCFSCreateDocumentRequest_FieldNumber_Document, - .hasIndex = 3, - .offset = (uint32_t)offsetof(GCFSCreateDocumentRequest__storage_, document), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "mask", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocumentMask), - .number = GCFSCreateDocumentRequest_FieldNumber_Mask, - .hasIndex = 4, - .offset = (uint32_t)offsetof(GCFSCreateDocumentRequest__storage_, mask), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSCreateDocumentRequest class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSCreateDocumentRequest__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSUpdateDocumentRequest - -@implementation GCFSUpdateDocumentRequest - -@dynamic hasDocument, document; -@dynamic hasUpdateMask, updateMask; -@dynamic hasMask, mask; -@dynamic hasCurrentDocument, currentDocument; - -typedef struct GCFSUpdateDocumentRequest__storage_ { - uint32_t _has_storage_[1]; - GCFSDocument *document; - GCFSDocumentMask *updateMask; - GCFSDocumentMask *mask; - GCFSPrecondition *currentDocument; -} GCFSUpdateDocumentRequest__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "document", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocument), - .number = GCFSUpdateDocumentRequest_FieldNumber_Document, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSUpdateDocumentRequest__storage_, document), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "updateMask", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocumentMask), - .number = GCFSUpdateDocumentRequest_FieldNumber_UpdateMask, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSUpdateDocumentRequest__storage_, updateMask), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "mask", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocumentMask), - .number = GCFSUpdateDocumentRequest_FieldNumber_Mask, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GCFSUpdateDocumentRequest__storage_, mask), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "currentDocument", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSPrecondition), - .number = GCFSUpdateDocumentRequest_FieldNumber_CurrentDocument, - .hasIndex = 3, - .offset = (uint32_t)offsetof(GCFSUpdateDocumentRequest__storage_, currentDocument), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSUpdateDocumentRequest class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSUpdateDocumentRequest__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSDeleteDocumentRequest - -@implementation GCFSDeleteDocumentRequest - -@dynamic name; -@dynamic hasCurrentDocument, currentDocument; - -typedef struct GCFSDeleteDocumentRequest__storage_ { - uint32_t _has_storage_[1]; - NSString *name; - GCFSPrecondition *currentDocument; -} GCFSDeleteDocumentRequest__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .dataTypeSpecific.className = NULL, - .number = GCFSDeleteDocumentRequest_FieldNumber_Name, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSDeleteDocumentRequest__storage_, name), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "currentDocument", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSPrecondition), - .number = GCFSDeleteDocumentRequest_FieldNumber_CurrentDocument, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSDeleteDocumentRequest__storage_, currentDocument), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSDeleteDocumentRequest class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSDeleteDocumentRequest__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSBatchGetDocumentsRequest - -@implementation GCFSBatchGetDocumentsRequest - -@dynamic consistencySelectorOneOfCase; -@dynamic database; -@dynamic documentsArray, documentsArray_Count; -@dynamic hasMask, mask; -@dynamic transaction; -@dynamic newTransaction; -@dynamic readTime; - -typedef struct GCFSBatchGetDocumentsRequest__storage_ { - uint32_t _has_storage_[2]; - NSString *database; - NSMutableArray *documentsArray; - GCFSDocumentMask *mask; - NSData *transaction; - GCFSTransactionOptions *newTransaction; - GPBTimestamp *readTime; -} GCFSBatchGetDocumentsRequest__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "database", - .dataTypeSpecific.className = NULL, - .number = GCFSBatchGetDocumentsRequest_FieldNumber_Database, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSBatchGetDocumentsRequest__storage_, database), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "documentsArray", - .dataTypeSpecific.className = NULL, - .number = GCFSBatchGetDocumentsRequest_FieldNumber_DocumentsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSBatchGetDocumentsRequest__storage_, documentsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeString, - }, - { - .name = "mask", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocumentMask), - .number = GCFSBatchGetDocumentsRequest_FieldNumber_Mask, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSBatchGetDocumentsRequest__storage_, mask), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "transaction", - .dataTypeSpecific.className = NULL, - .number = GCFSBatchGetDocumentsRequest_FieldNumber_Transaction, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSBatchGetDocumentsRequest__storage_, transaction), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - { - .name = "newTransaction", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSTransactionOptions), - .number = GCFSBatchGetDocumentsRequest_FieldNumber_NewTransaction, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSBatchGetDocumentsRequest__storage_, newTransaction), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "readTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSBatchGetDocumentsRequest_FieldNumber_ReadTime, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSBatchGetDocumentsRequest__storage_, readTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSBatchGetDocumentsRequest class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSBatchGetDocumentsRequest__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "consistencySelector", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GCFSBatchGetDocumentsRequest_ClearConsistencySelectorOneOfCase(GCFSBatchGetDocumentsRequest *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - GCFSBatchGetDocumentsResponse - -@implementation GCFSBatchGetDocumentsResponse - -@dynamic resultOneOfCase; -@dynamic found; -@dynamic missing; -@dynamic transaction; -@dynamic hasReadTime, readTime; - -typedef struct GCFSBatchGetDocumentsResponse__storage_ { - uint32_t _has_storage_[2]; - GCFSDocument *found; - NSString *missing; - NSData *transaction; - GPBTimestamp *readTime; -} GCFSBatchGetDocumentsResponse__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "found", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocument), - .number = GCFSBatchGetDocumentsResponse_FieldNumber_Found, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSBatchGetDocumentsResponse__storage_, found), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "missing", - .dataTypeSpecific.className = NULL, - .number = GCFSBatchGetDocumentsResponse_FieldNumber_Missing, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSBatchGetDocumentsResponse__storage_, missing), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "transaction", - .dataTypeSpecific.className = NULL, - .number = GCFSBatchGetDocumentsResponse_FieldNumber_Transaction, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSBatchGetDocumentsResponse__storage_, transaction), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - { - .name = "readTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSBatchGetDocumentsResponse_FieldNumber_ReadTime, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSBatchGetDocumentsResponse__storage_, readTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSBatchGetDocumentsResponse class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSBatchGetDocumentsResponse__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "result", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GCFSBatchGetDocumentsResponse_ClearResultOneOfCase(GCFSBatchGetDocumentsResponse *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - GCFSBeginTransactionRequest - -@implementation GCFSBeginTransactionRequest - -@dynamic database; -@dynamic hasOptions, options; - -typedef struct GCFSBeginTransactionRequest__storage_ { - uint32_t _has_storage_[1]; - NSString *database; - GCFSTransactionOptions *options; -} GCFSBeginTransactionRequest__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "database", - .dataTypeSpecific.className = NULL, - .number = GCFSBeginTransactionRequest_FieldNumber_Database, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSBeginTransactionRequest__storage_, database), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "options", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSTransactionOptions), - .number = GCFSBeginTransactionRequest_FieldNumber_Options, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSBeginTransactionRequest__storage_, options), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSBeginTransactionRequest class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSBeginTransactionRequest__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSBeginTransactionResponse - -@implementation GCFSBeginTransactionResponse - -@dynamic transaction; - -typedef struct GCFSBeginTransactionResponse__storage_ { - uint32_t _has_storage_[1]; - NSData *transaction; -} GCFSBeginTransactionResponse__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "transaction", - .dataTypeSpecific.className = NULL, - .number = GCFSBeginTransactionResponse_FieldNumber_Transaction, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSBeginTransactionResponse__storage_, transaction), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSBeginTransactionResponse class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSBeginTransactionResponse__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSCommitRequest - -@implementation GCFSCommitRequest - -@dynamic database; -@dynamic writesArray, writesArray_Count; -@dynamic transaction; - -typedef struct GCFSCommitRequest__storage_ { - uint32_t _has_storage_[1]; - NSString *database; - NSMutableArray *writesArray; - NSData *transaction; -} GCFSCommitRequest__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "database", - .dataTypeSpecific.className = NULL, - .number = GCFSCommitRequest_FieldNumber_Database, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSCommitRequest__storage_, database), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "writesArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSWrite), - .number = GCFSCommitRequest_FieldNumber_WritesArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSCommitRequest__storage_, writesArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "transaction", - .dataTypeSpecific.className = NULL, - .number = GCFSCommitRequest_FieldNumber_Transaction, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSCommitRequest__storage_, transaction), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSCommitRequest class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSCommitRequest__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSCommitResponse - -@implementation GCFSCommitResponse - -@dynamic writeResultsArray, writeResultsArray_Count; -@dynamic hasCommitTime, commitTime; - -typedef struct GCFSCommitResponse__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *writeResultsArray; - GPBTimestamp *commitTime; -} GCFSCommitResponse__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "writeResultsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSWriteResult), - .number = GCFSCommitResponse_FieldNumber_WriteResultsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSCommitResponse__storage_, writeResultsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "commitTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSCommitResponse_FieldNumber_CommitTime, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSCommitResponse__storage_, commitTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSCommitResponse class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSCommitResponse__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSRollbackRequest - -@implementation GCFSRollbackRequest - -@dynamic database; -@dynamic transaction; - -typedef struct GCFSRollbackRequest__storage_ { - uint32_t _has_storage_[1]; - NSString *database; - NSData *transaction; -} GCFSRollbackRequest__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "database", - .dataTypeSpecific.className = NULL, - .number = GCFSRollbackRequest_FieldNumber_Database, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSRollbackRequest__storage_, database), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "transaction", - .dataTypeSpecific.className = NULL, - .number = GCFSRollbackRequest_FieldNumber_Transaction, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSRollbackRequest__storage_, transaction), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSRollbackRequest class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSRollbackRequest__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSRunQueryRequest - -@implementation GCFSRunQueryRequest - -@dynamic queryTypeOneOfCase; -@dynamic consistencySelectorOneOfCase; -@dynamic parent; -@dynamic structuredQuery; -@dynamic transaction; -@dynamic newTransaction; -@dynamic readTime; - -typedef struct GCFSRunQueryRequest__storage_ { - uint32_t _has_storage_[3]; - NSString *parent; - GCFSStructuredQuery *structuredQuery; - NSData *transaction; - GCFSTransactionOptions *newTransaction; - GPBTimestamp *readTime; -} GCFSRunQueryRequest__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "parent", - .dataTypeSpecific.className = NULL, - .number = GCFSRunQueryRequest_FieldNumber_Parent, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSRunQueryRequest__storage_, parent), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "structuredQuery", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSStructuredQuery), - .number = GCFSRunQueryRequest_FieldNumber_StructuredQuery, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSRunQueryRequest__storage_, structuredQuery), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "transaction", - .dataTypeSpecific.className = NULL, - .number = GCFSRunQueryRequest_FieldNumber_Transaction, - .hasIndex = -2, - .offset = (uint32_t)offsetof(GCFSRunQueryRequest__storage_, transaction), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - { - .name = "newTransaction", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSTransactionOptions), - .number = GCFSRunQueryRequest_FieldNumber_NewTransaction, - .hasIndex = -2, - .offset = (uint32_t)offsetof(GCFSRunQueryRequest__storage_, newTransaction), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "readTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSRunQueryRequest_FieldNumber_ReadTime, - .hasIndex = -2, - .offset = (uint32_t)offsetof(GCFSRunQueryRequest__storage_, readTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSRunQueryRequest class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSRunQueryRequest__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "queryType", - "consistencySelector", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GCFSRunQueryRequest_ClearQueryTypeOneOfCase(GCFSRunQueryRequest *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -void GCFSRunQueryRequest_ClearConsistencySelectorOneOfCase(GCFSRunQueryRequest *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:1]; - GPBMaybeClearOneof(message, oneof, -2, 0); -} -#pragma mark - GCFSRunQueryResponse - -@implementation GCFSRunQueryResponse - -@dynamic transaction; -@dynamic hasDocument, document; -@dynamic hasReadTime, readTime; -@dynamic skippedResults; - -typedef struct GCFSRunQueryResponse__storage_ { - uint32_t _has_storage_[1]; - int32_t skippedResults; - GCFSDocument *document; - NSData *transaction; - GPBTimestamp *readTime; -} GCFSRunQueryResponse__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "document", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocument), - .number = GCFSRunQueryResponse_FieldNumber_Document, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSRunQueryResponse__storage_, document), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "transaction", - .dataTypeSpecific.className = NULL, - .number = GCFSRunQueryResponse_FieldNumber_Transaction, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSRunQueryResponse__storage_, transaction), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - { - .name = "readTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSRunQueryResponse_FieldNumber_ReadTime, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GCFSRunQueryResponse__storage_, readTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "skippedResults", - .dataTypeSpecific.className = NULL, - .number = GCFSRunQueryResponse_FieldNumber_SkippedResults, - .hasIndex = 3, - .offset = (uint32_t)offsetof(GCFSRunQueryResponse__storage_, skippedResults), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSRunQueryResponse class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSRunQueryResponse__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSWriteRequest - -@implementation GCFSWriteRequest - -@dynamic database; -@dynamic streamId; -@dynamic writesArray, writesArray_Count; -@dynamic streamToken; -@dynamic labels, labels_Count; - -typedef struct GCFSWriteRequest__storage_ { - uint32_t _has_storage_[1]; - NSString *database; - NSString *streamId; - NSMutableArray *writesArray; - NSData *streamToken; - NSMutableDictionary *labels; -} GCFSWriteRequest__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "database", - .dataTypeSpecific.className = NULL, - .number = GCFSWriteRequest_FieldNumber_Database, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSWriteRequest__storage_, database), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "streamId", - .dataTypeSpecific.className = NULL, - .number = GCFSWriteRequest_FieldNumber_StreamId, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSWriteRequest__storage_, streamId), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "writesArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSWrite), - .number = GCFSWriteRequest_FieldNumber_WritesArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSWriteRequest__storage_, writesArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "streamToken", - .dataTypeSpecific.className = NULL, - .number = GCFSWriteRequest_FieldNumber_StreamToken, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GCFSWriteRequest__storage_, streamToken), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - { - .name = "labels", - .dataTypeSpecific.className = NULL, - .number = GCFSWriteRequest_FieldNumber_Labels, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSWriteRequest__storage_, labels), - .flags = GPBFieldMapKeyString, - .dataType = GPBDataTypeString, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSWriteRequest class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSWriteRequest__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSWriteResponse - -@implementation GCFSWriteResponse - -@dynamic streamId; -@dynamic streamToken; -@dynamic writeResultsArray, writeResultsArray_Count; -@dynamic hasCommitTime, commitTime; - -typedef struct GCFSWriteResponse__storage_ { - uint32_t _has_storage_[1]; - NSString *streamId; - NSData *streamToken; - NSMutableArray *writeResultsArray; - GPBTimestamp *commitTime; -} GCFSWriteResponse__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "streamId", - .dataTypeSpecific.className = NULL, - .number = GCFSWriteResponse_FieldNumber_StreamId, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSWriteResponse__storage_, streamId), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "streamToken", - .dataTypeSpecific.className = NULL, - .number = GCFSWriteResponse_FieldNumber_StreamToken, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSWriteResponse__storage_, streamToken), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - { - .name = "writeResultsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSWriteResult), - .number = GCFSWriteResponse_FieldNumber_WriteResultsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSWriteResponse__storage_, writeResultsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "commitTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSWriteResponse_FieldNumber_CommitTime, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GCFSWriteResponse__storage_, commitTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSWriteResponse class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSWriteResponse__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSListenRequest - -@implementation GCFSListenRequest - -@dynamic targetChangeOneOfCase; -@dynamic database; -@dynamic addTarget; -@dynamic removeTarget; -@dynamic labels, labels_Count; - -typedef struct GCFSListenRequest__storage_ { - uint32_t _has_storage_[2]; - int32_t removeTarget; - NSString *database; - GCFSTarget *addTarget; - NSMutableDictionary *labels; -} GCFSListenRequest__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "database", - .dataTypeSpecific.className = NULL, - .number = GCFSListenRequest_FieldNumber_Database, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSListenRequest__storage_, database), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "addTarget", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSTarget), - .number = GCFSListenRequest_FieldNumber_AddTarget, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSListenRequest__storage_, addTarget), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "removeTarget", - .dataTypeSpecific.className = NULL, - .number = GCFSListenRequest_FieldNumber_RemoveTarget, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSListenRequest__storage_, removeTarget), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - { - .name = "labels", - .dataTypeSpecific.className = NULL, - .number = GCFSListenRequest_FieldNumber_Labels, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSListenRequest__storage_, labels), - .flags = GPBFieldMapKeyString, - .dataType = GPBDataTypeString, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSListenRequest class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSListenRequest__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "targetChange", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GCFSListenRequest_ClearTargetChangeOneOfCase(GCFSListenRequest *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - GCFSListenResponse - -@implementation GCFSListenResponse - -@dynamic responseTypeOneOfCase; -@dynamic targetChange; -@dynamic documentChange; -@dynamic documentDelete; -@dynamic documentRemove; -@dynamic filter; - -typedef struct GCFSListenResponse__storage_ { - uint32_t _has_storage_[2]; - GCFSTargetChange *targetChange; - GCFSDocumentChange *documentChange; - GCFSDocumentDelete *documentDelete; - GCFSExistenceFilter *filter; - GCFSDocumentRemove *documentRemove; -} GCFSListenResponse__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "targetChange", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSTargetChange), - .number = GCFSListenResponse_FieldNumber_TargetChange, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSListenResponse__storage_, targetChange), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "documentChange", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocumentChange), - .number = GCFSListenResponse_FieldNumber_DocumentChange, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSListenResponse__storage_, documentChange), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "documentDelete", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocumentDelete), - .number = GCFSListenResponse_FieldNumber_DocumentDelete, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSListenResponse__storage_, documentDelete), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "filter", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSExistenceFilter), - .number = GCFSListenResponse_FieldNumber_Filter, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSListenResponse__storage_, filter), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "documentRemove", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocumentRemove), - .number = GCFSListenResponse_FieldNumber_DocumentRemove, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSListenResponse__storage_, documentRemove), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSListenResponse class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSListenResponse__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "responseType", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GCFSListenResponse_ClearResponseTypeOneOfCase(GCFSListenResponse *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - GCFSTarget - -@implementation GCFSTarget - -@dynamic targetTypeOneOfCase; -@dynamic resumeTypeOneOfCase; -@dynamic query; -@dynamic documents; -@dynamic resumeToken; -@dynamic readTime; -@dynamic targetId; -@dynamic once; - -typedef struct GCFSTarget__storage_ { - uint32_t _has_storage_[3]; - int32_t targetId; - GCFSTarget_QueryTarget *query; - GCFSTarget_DocumentsTarget *documents; - NSData *resumeToken; - GPBTimestamp *readTime; -} GCFSTarget__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "query", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSTarget_QueryTarget), - .number = GCFSTarget_FieldNumber_Query, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSTarget__storage_, query), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "documents", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSTarget_DocumentsTarget), - .number = GCFSTarget_FieldNumber_Documents, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSTarget__storage_, documents), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "resumeToken", - .dataTypeSpecific.className = NULL, - .number = GCFSTarget_FieldNumber_ResumeToken, - .hasIndex = -2, - .offset = (uint32_t)offsetof(GCFSTarget__storage_, resumeToken), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - { - .name = "targetId", - .dataTypeSpecific.className = NULL, - .number = GCFSTarget_FieldNumber_TargetId, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSTarget__storage_, targetId), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - { - .name = "once", - .dataTypeSpecific.className = NULL, - .number = GCFSTarget_FieldNumber_Once, - .hasIndex = 1, - .offset = 2, // Stored in _has_storage_ to save space. - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - }, - { - .name = "readTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSTarget_FieldNumber_ReadTime, - .hasIndex = -2, - .offset = (uint32_t)offsetof(GCFSTarget__storage_, readTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSTarget class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSTarget__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "targetType", - "resumeType", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GCFSTarget_ClearTargetTypeOneOfCase(GCFSTarget *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -void GCFSTarget_ClearResumeTypeOneOfCase(GCFSTarget *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:1]; - GPBMaybeClearOneof(message, oneof, -2, 0); -} -#pragma mark - GCFSTarget_DocumentsTarget - -@implementation GCFSTarget_DocumentsTarget - -@dynamic documentsArray, documentsArray_Count; - -typedef struct GCFSTarget_DocumentsTarget__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *documentsArray; -} GCFSTarget_DocumentsTarget__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "documentsArray", - .dataTypeSpecific.className = NULL, - .number = GCFSTarget_DocumentsTarget_FieldNumber_DocumentsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSTarget_DocumentsTarget__storage_, documentsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeString, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSTarget_DocumentsTarget class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSTarget_DocumentsTarget__storage_) - flags:GPBDescriptorInitializationFlag_None]; - [localDescriptor setupContainingMessageClassName:GPBStringifySymbol(GCFSTarget)]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSTarget_QueryTarget - -@implementation GCFSTarget_QueryTarget - -@dynamic queryTypeOneOfCase; -@dynamic parent; -@dynamic structuredQuery; - -typedef struct GCFSTarget_QueryTarget__storage_ { - uint32_t _has_storage_[2]; - NSString *parent; - GCFSStructuredQuery *structuredQuery; -} GCFSTarget_QueryTarget__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "parent", - .dataTypeSpecific.className = NULL, - .number = GCFSTarget_QueryTarget_FieldNumber_Parent, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSTarget_QueryTarget__storage_, parent), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "structuredQuery", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSStructuredQuery), - .number = GCFSTarget_QueryTarget_FieldNumber_StructuredQuery, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSTarget_QueryTarget__storage_, structuredQuery), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSTarget_QueryTarget class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSTarget_QueryTarget__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "queryType", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - [localDescriptor setupContainingMessageClassName:GPBStringifySymbol(GCFSTarget)]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GCFSTarget_QueryTarget_ClearQueryTypeOneOfCase(GCFSTarget_QueryTarget *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - GCFSTargetChange - -@implementation GCFSTargetChange - -@dynamic targetChangeType; -@dynamic targetIdsArray, targetIdsArray_Count; -@dynamic hasCause, cause; -@dynamic resumeToken; -@dynamic hasReadTime, readTime; - -typedef struct GCFSTargetChange__storage_ { - uint32_t _has_storage_[1]; - GCFSTargetChange_TargetChangeType targetChangeType; - GPBInt32Array *targetIdsArray; - RPCStatus *cause; - NSData *resumeToken; - GPBTimestamp *readTime; -} GCFSTargetChange__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "targetChangeType", - .dataTypeSpecific.enumDescFunc = GCFSTargetChange_TargetChangeType_EnumDescriptor, - .number = GCFSTargetChange_FieldNumber_TargetChangeType, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSTargetChange__storage_, targetChangeType), - .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor), - .dataType = GPBDataTypeEnum, - }, - { - .name = "targetIdsArray", - .dataTypeSpecific.className = NULL, - .number = GCFSTargetChange_FieldNumber_TargetIdsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSTargetChange__storage_, targetIdsArray), - .flags = (GPBFieldFlags)(GPBFieldRepeated | GPBFieldPacked), - .dataType = GPBDataTypeInt32, - }, - { - .name = "cause", - .dataTypeSpecific.className = GPBStringifySymbol(RPCStatus), - .number = GCFSTargetChange_FieldNumber_Cause, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSTargetChange__storage_, cause), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "resumeToken", - .dataTypeSpecific.className = NULL, - .number = GCFSTargetChange_FieldNumber_ResumeToken, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GCFSTargetChange__storage_, resumeToken), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - { - .name = "readTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSTargetChange_FieldNumber_ReadTime, - .hasIndex = 3, - .offset = (uint32_t)offsetof(GCFSTargetChange__storage_, readTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSTargetChange class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSTargetChange__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -int32_t GCFSTargetChange_TargetChangeType_RawValue(GCFSTargetChange *message) { - GPBDescriptor *descriptor = [GCFSTargetChange descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GCFSTargetChange_FieldNumber_TargetChangeType]; - return GPBGetMessageInt32Field(message, field); -} - -void SetGCFSTargetChange_TargetChangeType_RawValue(GCFSTargetChange *message, int32_t value) { - GPBDescriptor *descriptor = [GCFSTargetChange descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GCFSTargetChange_FieldNumber_TargetChangeType]; - GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); -} - -#pragma mark - Enum GCFSTargetChange_TargetChangeType - -GPBEnumDescriptor *GCFSTargetChange_TargetChangeType_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static const char *valueNames = - "NoChange\000Add\000Remove\000Current\000Reset\000"; - static const int32_t values[] = { - GCFSTargetChange_TargetChangeType_NoChange, - GCFSTargetChange_TargetChangeType_Add, - GCFSTargetChange_TargetChangeType_Remove, - GCFSTargetChange_TargetChangeType_Current, - GCFSTargetChange_TargetChangeType_Reset, - }; - GPBEnumDescriptor *worker = - [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GCFSTargetChange_TargetChangeType) - valueNames:valueNames - values:values - count:(uint32_t)(sizeof(values) / sizeof(int32_t)) - enumVerifier:GCFSTargetChange_TargetChangeType_IsValidValue]; - if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { - [worker release]; - } - } - return descriptor; -} - -BOOL GCFSTargetChange_TargetChangeType_IsValidValue(int32_t value__) { - switch (value__) { - case GCFSTargetChange_TargetChangeType_NoChange: - case GCFSTargetChange_TargetChangeType_Add: - case GCFSTargetChange_TargetChangeType_Remove: - case GCFSTargetChange_TargetChangeType_Current: - case GCFSTargetChange_TargetChangeType_Reset: - return YES; - default: - return NO; - } -} - -#pragma mark - GCFSListCollectionIdsRequest - -@implementation GCFSListCollectionIdsRequest - -@dynamic parent; -@dynamic pageSize; -@dynamic pageToken; - -typedef struct GCFSListCollectionIdsRequest__storage_ { - uint32_t _has_storage_[1]; - int32_t pageSize; - NSString *parent; - NSString *pageToken; -} GCFSListCollectionIdsRequest__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "parent", - .dataTypeSpecific.className = NULL, - .number = GCFSListCollectionIdsRequest_FieldNumber_Parent, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSListCollectionIdsRequest__storage_, parent), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "pageSize", - .dataTypeSpecific.className = NULL, - .number = GCFSListCollectionIdsRequest_FieldNumber_PageSize, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSListCollectionIdsRequest__storage_, pageSize), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - { - .name = "pageToken", - .dataTypeSpecific.className = NULL, - .number = GCFSListCollectionIdsRequest_FieldNumber_PageToken, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GCFSListCollectionIdsRequest__storage_, pageToken), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSListCollectionIdsRequest class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSListCollectionIdsRequest__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSListCollectionIdsResponse - -@implementation GCFSListCollectionIdsResponse - -@dynamic collectionIdsArray, collectionIdsArray_Count; -@dynamic nextPageToken; - -typedef struct GCFSListCollectionIdsResponse__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *collectionIdsArray; - NSString *nextPageToken; -} GCFSListCollectionIdsResponse__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "collectionIdsArray", - .dataTypeSpecific.className = NULL, - .number = GCFSListCollectionIdsResponse_FieldNumber_CollectionIdsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSListCollectionIdsResponse__storage_, collectionIdsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeString, - }, - { - .name = "nextPageToken", - .dataTypeSpecific.className = NULL, - .number = GCFSListCollectionIdsResponse_FieldNumber_NextPageToken, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSListCollectionIdsResponse__storage_, nextPageToken), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSListCollectionIdsResponse class] - rootClass:[GCFSFirestoreRoot class] - file:GCFSFirestoreRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSListCollectionIdsResponse__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Query.pbobjc.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Query.pbobjc.h deleted file mode 100644 index e4ff487..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Query.pbobjc.h +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/firestore/v1/query.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers.h" -#endif - -#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002 -#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources. -#endif -#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION -#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -@class GCFSCursor; -@class GCFSStructuredQuery_CollectionSelector; -@class GCFSStructuredQuery_CompositeFilter; -@class GCFSStructuredQuery_FieldFilter; -@class GCFSStructuredQuery_FieldReference; -@class GCFSStructuredQuery_Filter; -@class GCFSStructuredQuery_Order; -@class GCFSStructuredQuery_Projection; -@class GCFSStructuredQuery_UnaryFilter; -@class GCFSValue; -@class GPBInt32Value; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - Enum GCFSStructuredQuery_Direction - -/** A sort direction. */ -typedef GPB_ENUM(GCFSStructuredQuery_Direction) { - /** - * Value used if any message's field encounters a value that is not defined - * by this enum. The message will also have C functions to get/set the rawValue - * of the field. - **/ - GCFSStructuredQuery_Direction_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, - /** Unspecified. */ - GCFSStructuredQuery_Direction_DirectionUnspecified = 0, - - /** Ascending. */ - GCFSStructuredQuery_Direction_Ascending = 1, - - /** Descending. */ - GCFSStructuredQuery_Direction_Descending = 2, -}; - -GPBEnumDescriptor *GCFSStructuredQuery_Direction_EnumDescriptor(void); - -/** - * Checks to see if the given value is defined by the enum or was not known at - * the time this source was generated. - **/ -BOOL GCFSStructuredQuery_Direction_IsValidValue(int32_t value); - -#pragma mark - Enum GCFSStructuredQuery_CompositeFilter_Operator - -/** A composite filter operator. */ -typedef GPB_ENUM(GCFSStructuredQuery_CompositeFilter_Operator) { - /** - * Value used if any message's field encounters a value that is not defined - * by this enum. The message will also have C functions to get/set the rawValue - * of the field. - **/ - GCFSStructuredQuery_CompositeFilter_Operator_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, - /** Unspecified. This value must not be used. */ - GCFSStructuredQuery_CompositeFilter_Operator_OperatorUnspecified = 0, - - /** The results are required to satisfy each of the combined filters. */ - GCFSStructuredQuery_CompositeFilter_Operator_And = 1, -}; - -GPBEnumDescriptor *GCFSStructuredQuery_CompositeFilter_Operator_EnumDescriptor(void); - -/** - * Checks to see if the given value is defined by the enum or was not known at - * the time this source was generated. - **/ -BOOL GCFSStructuredQuery_CompositeFilter_Operator_IsValidValue(int32_t value); - -#pragma mark - Enum GCFSStructuredQuery_FieldFilter_Operator - -/** A field filter operator. */ -typedef GPB_ENUM(GCFSStructuredQuery_FieldFilter_Operator) { - /** - * Value used if any message's field encounters a value that is not defined - * by this enum. The message will also have C functions to get/set the rawValue - * of the field. - **/ - GCFSStructuredQuery_FieldFilter_Operator_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, - /** Unspecified. This value must not be used. */ - GCFSStructuredQuery_FieldFilter_Operator_OperatorUnspecified = 0, - - /** Less than. Requires that the field come first in `order_by`. */ - GCFSStructuredQuery_FieldFilter_Operator_LessThan = 1, - - /** Less than or equal. Requires that the field come first in `order_by`. */ - GCFSStructuredQuery_FieldFilter_Operator_LessThanOrEqual = 2, - - /** Greater than. Requires that the field come first in `order_by`. */ - GCFSStructuredQuery_FieldFilter_Operator_GreaterThan = 3, - - /** - * Greater than or equal. Requires that the field come first in - * `order_by`. - **/ - GCFSStructuredQuery_FieldFilter_Operator_GreaterThanOrEqual = 4, - - /** Equal. */ - GCFSStructuredQuery_FieldFilter_Operator_Equal = 5, - - /** Contains. Requires that the field is an array. */ - GCFSStructuredQuery_FieldFilter_Operator_ArrayContains = 7, -}; - -GPBEnumDescriptor *GCFSStructuredQuery_FieldFilter_Operator_EnumDescriptor(void); - -/** - * Checks to see if the given value is defined by the enum or was not known at - * the time this source was generated. - **/ -BOOL GCFSStructuredQuery_FieldFilter_Operator_IsValidValue(int32_t value); - -#pragma mark - Enum GCFSStructuredQuery_UnaryFilter_Operator - -/** A unary operator. */ -typedef GPB_ENUM(GCFSStructuredQuery_UnaryFilter_Operator) { - /** - * Value used if any message's field encounters a value that is not defined - * by this enum. The message will also have C functions to get/set the rawValue - * of the field. - **/ - GCFSStructuredQuery_UnaryFilter_Operator_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, - /** Unspecified. This value must not be used. */ - GCFSStructuredQuery_UnaryFilter_Operator_OperatorUnspecified = 0, - - /** Test if a field is equal to NaN. */ - GCFSStructuredQuery_UnaryFilter_Operator_IsNan = 2, - - /** Test if an exprestion evaluates to Null. */ - GCFSStructuredQuery_UnaryFilter_Operator_IsNull = 3, -}; - -GPBEnumDescriptor *GCFSStructuredQuery_UnaryFilter_Operator_EnumDescriptor(void); - -/** - * Checks to see if the given value is defined by the enum or was not known at - * the time this source was generated. - **/ -BOOL GCFSStructuredQuery_UnaryFilter_Operator_IsValidValue(int32_t value); - -#pragma mark - GCFSQueryRoot - -/** - * Exposes the extension registry for this file. - * - * The base class provides: - * @code - * + (GPBExtensionRegistry *)extensionRegistry; - * @endcode - * which is a @c GPBExtensionRegistry that includes all the extensions defined by - * this file and all files that it depends on. - **/ -@interface GCFSQueryRoot : GPBRootObject -@end - -#pragma mark - GCFSStructuredQuery - -typedef GPB_ENUM(GCFSStructuredQuery_FieldNumber) { - GCFSStructuredQuery_FieldNumber_Select = 1, - GCFSStructuredQuery_FieldNumber_FromArray = 2, - GCFSStructuredQuery_FieldNumber_Where = 3, - GCFSStructuredQuery_FieldNumber_OrderByArray = 4, - GCFSStructuredQuery_FieldNumber_Limit = 5, - GCFSStructuredQuery_FieldNumber_Offset = 6, - GCFSStructuredQuery_FieldNumber_StartAt = 7, - GCFSStructuredQuery_FieldNumber_EndAt = 8, -}; - -/** - * A Firestore query. - **/ -@interface GCFSStructuredQuery : GPBMessage - -/** The projection to return. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSStructuredQuery_Projection *select; -/** Test to see if @c select has been set. */ -@property(nonatomic, readwrite) BOOL hasSelect; - -/** The collections to query. */ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *fromArray; -/** The number of items in @c fromArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger fromArray_Count; - -/** The filter to apply. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSStructuredQuery_Filter *where; -/** Test to see if @c where has been set. */ -@property(nonatomic, readwrite) BOOL hasWhere; - -/** - * The order to apply to the query results. - * - * Firestore guarantees a stable ordering through the following rules: - * - * * Any field required to appear in `order_by`, that is not already - * specified in `order_by`, is appended to the order in field name order - * by default. - * * If an order on `__name__` is not specified, it is appended by default. - * - * Fields are appended with the same sort direction as the last order - * specified, or 'ASCENDING' if no order was specified. For example: - * - * * `SELECT * FROM Foo ORDER BY A` becomes - * `SELECT * FROM Foo ORDER BY A, __name__` - * * `SELECT * FROM Foo ORDER BY A DESC` becomes - * `SELECT * FROM Foo ORDER BY A DESC, __name__ DESC` - * * `SELECT * FROM Foo WHERE A > 1` becomes - * `SELECT * FROM Foo WHERE A > 1 ORDER BY A, __name__` - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *orderByArray; -/** The number of items in @c orderByArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger orderByArray_Count; - -/** A starting point for the query results. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSCursor *startAt; -/** Test to see if @c startAt has been set. */ -@property(nonatomic, readwrite) BOOL hasStartAt; - -/** A end point for the query results. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSCursor *endAt; -/** Test to see if @c endAt has been set. */ -@property(nonatomic, readwrite) BOOL hasEndAt; - -/** - * The number of results to skip. - * - * Applies before limit, but after all other constraints. Must be >= 0 if - * specified. - **/ -@property(nonatomic, readwrite) int32_t offset; - -/** - * The maximum number of results to return. - * - * Applies after all other constraints. - * Must be >= 0 if specified. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Value *limit; -/** Test to see if @c limit has been set. */ -@property(nonatomic, readwrite) BOOL hasLimit; - -@end - -#pragma mark - GCFSStructuredQuery_CollectionSelector - -typedef GPB_ENUM(GCFSStructuredQuery_CollectionSelector_FieldNumber) { - GCFSStructuredQuery_CollectionSelector_FieldNumber_CollectionId = 2, - GCFSStructuredQuery_CollectionSelector_FieldNumber_AllDescendants = 3, -}; - -/** - * A selection of a collection, such as `messages as m1`. - **/ -@interface GCFSStructuredQuery_CollectionSelector : GPBMessage - -/** - * The collection ID. - * When set, selects only collections with this ID. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *collectionId; - -/** - * When false, selects only collections that are immediate children of - * the `parent` specified in the containing `RunQueryRequest`. - * When true, selects all descendant collections. - **/ -@property(nonatomic, readwrite) BOOL allDescendants; - -@end - -#pragma mark - GCFSStructuredQuery_Filter - -typedef GPB_ENUM(GCFSStructuredQuery_Filter_FieldNumber) { - GCFSStructuredQuery_Filter_FieldNumber_CompositeFilter = 1, - GCFSStructuredQuery_Filter_FieldNumber_FieldFilter = 2, - GCFSStructuredQuery_Filter_FieldNumber_UnaryFilter = 3, -}; - -typedef GPB_ENUM(GCFSStructuredQuery_Filter_FilterType_OneOfCase) { - GCFSStructuredQuery_Filter_FilterType_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSStructuredQuery_Filter_FilterType_OneOfCase_CompositeFilter = 1, - GCFSStructuredQuery_Filter_FilterType_OneOfCase_FieldFilter = 2, - GCFSStructuredQuery_Filter_FilterType_OneOfCase_UnaryFilter = 3, -}; - -/** - * A filter. - **/ -@interface GCFSStructuredQuery_Filter : GPBMessage - -/** The type of filter. */ -@property(nonatomic, readonly) GCFSStructuredQuery_Filter_FilterType_OneOfCase filterTypeOneOfCase; - -/** A composite filter. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSStructuredQuery_CompositeFilter *compositeFilter; - -/** A filter on a document field. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSStructuredQuery_FieldFilter *fieldFilter; - -/** A filter that takes exactly one argument. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSStructuredQuery_UnaryFilter *unaryFilter; - -@end - -/** - * Clears whatever value was set for the oneof 'filterType'. - **/ -void GCFSStructuredQuery_Filter_ClearFilterTypeOneOfCase(GCFSStructuredQuery_Filter *message); - -#pragma mark - GCFSStructuredQuery_CompositeFilter - -typedef GPB_ENUM(GCFSStructuredQuery_CompositeFilter_FieldNumber) { - GCFSStructuredQuery_CompositeFilter_FieldNumber_Op = 1, - GCFSStructuredQuery_CompositeFilter_FieldNumber_FiltersArray = 2, -}; - -/** - * A filter that merges multiple other filters using the given operator. - **/ -@interface GCFSStructuredQuery_CompositeFilter : GPBMessage - -/** The operator for combining multiple filters. */ -@property(nonatomic, readwrite) GCFSStructuredQuery_CompositeFilter_Operator op; - -/** - * The list of filters to combine. - * Must contain at least one filter. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *filtersArray; -/** The number of items in @c filtersArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger filtersArray_Count; - -@end - -/** - * Fetches the raw value of a @c GCFSStructuredQuery_CompositeFilter's @c op property, even - * if the value was not defined by the enum at the time the code was generated. - **/ -int32_t GCFSStructuredQuery_CompositeFilter_Op_RawValue(GCFSStructuredQuery_CompositeFilter *message); -/** - * Sets the raw value of an @c GCFSStructuredQuery_CompositeFilter's @c op property, allowing - * it to be set to a value that was not defined by the enum at the time the code - * was generated. - **/ -void SetGCFSStructuredQuery_CompositeFilter_Op_RawValue(GCFSStructuredQuery_CompositeFilter *message, int32_t value); - -#pragma mark - GCFSStructuredQuery_FieldFilter - -typedef GPB_ENUM(GCFSStructuredQuery_FieldFilter_FieldNumber) { - GCFSStructuredQuery_FieldFilter_FieldNumber_Field = 1, - GCFSStructuredQuery_FieldFilter_FieldNumber_Op = 2, - GCFSStructuredQuery_FieldFilter_FieldNumber_Value = 3, -}; - -/** - * A filter on a specific field. - **/ -@interface GCFSStructuredQuery_FieldFilter : GPBMessage - -/** The field to filter by. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSStructuredQuery_FieldReference *field; -/** Test to see if @c field has been set. */ -@property(nonatomic, readwrite) BOOL hasField; - -/** The operator to filter by. */ -@property(nonatomic, readwrite) GCFSStructuredQuery_FieldFilter_Operator op; - -/** The value to compare to. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSValue *value; -/** Test to see if @c value has been set. */ -@property(nonatomic, readwrite) BOOL hasValue; - -@end - -/** - * Fetches the raw value of a @c GCFSStructuredQuery_FieldFilter's @c op property, even - * if the value was not defined by the enum at the time the code was generated. - **/ -int32_t GCFSStructuredQuery_FieldFilter_Op_RawValue(GCFSStructuredQuery_FieldFilter *message); -/** - * Sets the raw value of an @c GCFSStructuredQuery_FieldFilter's @c op property, allowing - * it to be set to a value that was not defined by the enum at the time the code - * was generated. - **/ -void SetGCFSStructuredQuery_FieldFilter_Op_RawValue(GCFSStructuredQuery_FieldFilter *message, int32_t value); - -#pragma mark - GCFSStructuredQuery_UnaryFilter - -typedef GPB_ENUM(GCFSStructuredQuery_UnaryFilter_FieldNumber) { - GCFSStructuredQuery_UnaryFilter_FieldNumber_Op = 1, - GCFSStructuredQuery_UnaryFilter_FieldNumber_Field = 2, -}; - -typedef GPB_ENUM(GCFSStructuredQuery_UnaryFilter_OperandType_OneOfCase) { - GCFSStructuredQuery_UnaryFilter_OperandType_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSStructuredQuery_UnaryFilter_OperandType_OneOfCase_Field = 2, -}; - -/** - * A filter with a single operand. - **/ -@interface GCFSStructuredQuery_UnaryFilter : GPBMessage - -/** The unary operator to apply. */ -@property(nonatomic, readwrite) GCFSStructuredQuery_UnaryFilter_Operator op; - -/** The argument to the filter. */ -@property(nonatomic, readonly) GCFSStructuredQuery_UnaryFilter_OperandType_OneOfCase operandTypeOneOfCase; - -/** The field to which to apply the operator. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSStructuredQuery_FieldReference *field; - -@end - -/** - * Fetches the raw value of a @c GCFSStructuredQuery_UnaryFilter's @c op property, even - * if the value was not defined by the enum at the time the code was generated. - **/ -int32_t GCFSStructuredQuery_UnaryFilter_Op_RawValue(GCFSStructuredQuery_UnaryFilter *message); -/** - * Sets the raw value of an @c GCFSStructuredQuery_UnaryFilter's @c op property, allowing - * it to be set to a value that was not defined by the enum at the time the code - * was generated. - **/ -void SetGCFSStructuredQuery_UnaryFilter_Op_RawValue(GCFSStructuredQuery_UnaryFilter *message, int32_t value); - -/** - * Clears whatever value was set for the oneof 'operandType'. - **/ -void GCFSStructuredQuery_UnaryFilter_ClearOperandTypeOneOfCase(GCFSStructuredQuery_UnaryFilter *message); - -#pragma mark - GCFSStructuredQuery_Order - -typedef GPB_ENUM(GCFSStructuredQuery_Order_FieldNumber) { - GCFSStructuredQuery_Order_FieldNumber_Field = 1, - GCFSStructuredQuery_Order_FieldNumber_Direction = 2, -}; - -/** - * An order on a field. - **/ -@interface GCFSStructuredQuery_Order : GPBMessage - -/** The field to order by. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSStructuredQuery_FieldReference *field; -/** Test to see if @c field has been set. */ -@property(nonatomic, readwrite) BOOL hasField; - -/** The direction to order by. Defaults to `ASCENDING`. */ -@property(nonatomic, readwrite) GCFSStructuredQuery_Direction direction; - -@end - -/** - * Fetches the raw value of a @c GCFSStructuredQuery_Order's @c direction property, even - * if the value was not defined by the enum at the time the code was generated. - **/ -int32_t GCFSStructuredQuery_Order_Direction_RawValue(GCFSStructuredQuery_Order *message); -/** - * Sets the raw value of an @c GCFSStructuredQuery_Order's @c direction property, allowing - * it to be set to a value that was not defined by the enum at the time the code - * was generated. - **/ -void SetGCFSStructuredQuery_Order_Direction_RawValue(GCFSStructuredQuery_Order *message, int32_t value); - -#pragma mark - GCFSStructuredQuery_FieldReference - -typedef GPB_ENUM(GCFSStructuredQuery_FieldReference_FieldNumber) { - GCFSStructuredQuery_FieldReference_FieldNumber_FieldPath = 2, -}; - -/** - * A reference to a field, such as `max(messages.time) as max_time`. - **/ -@interface GCFSStructuredQuery_FieldReference : GPBMessage - -@property(nonatomic, readwrite, copy, null_resettable) NSString *fieldPath; - -@end - -#pragma mark - GCFSStructuredQuery_Projection - -typedef GPB_ENUM(GCFSStructuredQuery_Projection_FieldNumber) { - GCFSStructuredQuery_Projection_FieldNumber_FieldsArray = 2, -}; - -/** - * The projection of document's fields to return. - **/ -@interface GCFSStructuredQuery_Projection : GPBMessage - -/** - * The fields to return. - * - * If empty, all fields are returned. To only return the name - * of the document, use `['__name__']`. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *fieldsArray; -/** The number of items in @c fieldsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger fieldsArray_Count; - -@end - -#pragma mark - GCFSCursor - -typedef GPB_ENUM(GCFSCursor_FieldNumber) { - GCFSCursor_FieldNumber_ValuesArray = 1, - GCFSCursor_FieldNumber_Before = 2, -}; - -/** - * A position in a query result set. - **/ -@interface GCFSCursor : GPBMessage - -/** - * The values that represent a position, in the order they appear in - * the order by clause of a query. - * - * Can contain fewer values than specified in the order by clause. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *valuesArray; -/** The number of items in @c valuesArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger valuesArray_Count; - -/** - * If the position is just before or just after the given values, relative - * to the sort order defined by the query. - **/ -@property(nonatomic, readwrite) BOOL before; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Query.pbobjc.m b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Query.pbobjc.m deleted file mode 100644 index ef716bb..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Query.pbobjc.m +++ /dev/null @@ -1,909 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/firestore/v1/query.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers_RuntimeSupport.h" -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "Wrappers.pbobjc.h" -#endif - - #import "Query.pbobjc.h" - #import "Annotations.pbobjc.h" - #import "Document.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#pragma clang diagnostic ignored "-Wdirect-ivar-access" - -#pragma mark - GCFSQueryRoot - -@implementation GCFSQueryRoot - - -@end - -#pragma mark - GCFSQueryRoot_FileDescriptor - -static GPBFileDescriptor *GCFSQueryRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPB_DEBUG_CHECK_RUNTIME_VERSIONS(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.firestore.v1" - objcPrefix:@"GCFS" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GCFSStructuredQuery - -@implementation GCFSStructuredQuery - -@dynamic hasSelect, select; -@dynamic fromArray, fromArray_Count; -@dynamic hasWhere, where; -@dynamic orderByArray, orderByArray_Count; -@dynamic hasStartAt, startAt; -@dynamic hasEndAt, endAt; -@dynamic offset; -@dynamic hasLimit, limit; - -typedef struct GCFSStructuredQuery__storage_ { - uint32_t _has_storage_[1]; - int32_t offset; - GCFSStructuredQuery_Projection *select; - NSMutableArray *fromArray; - GCFSStructuredQuery_Filter *where; - NSMutableArray *orderByArray; - GPBInt32Value *limit; - GCFSCursor *startAt; - GCFSCursor *endAt; -} GCFSStructuredQuery__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "select", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSStructuredQuery_Projection), - .number = GCFSStructuredQuery_FieldNumber_Select, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSStructuredQuery__storage_, select), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "fromArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSStructuredQuery_CollectionSelector), - .number = GCFSStructuredQuery_FieldNumber_FromArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSStructuredQuery__storage_, fromArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "where", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSStructuredQuery_Filter), - .number = GCFSStructuredQuery_FieldNumber_Where, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSStructuredQuery__storage_, where), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "orderByArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSStructuredQuery_Order), - .number = GCFSStructuredQuery_FieldNumber_OrderByArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSStructuredQuery__storage_, orderByArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "limit", - .dataTypeSpecific.className = GPBStringifySymbol(GPBInt32Value), - .number = GCFSStructuredQuery_FieldNumber_Limit, - .hasIndex = 5, - .offset = (uint32_t)offsetof(GCFSStructuredQuery__storage_, limit), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "offset", - .dataTypeSpecific.className = NULL, - .number = GCFSStructuredQuery_FieldNumber_Offset, - .hasIndex = 4, - .offset = (uint32_t)offsetof(GCFSStructuredQuery__storage_, offset), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - { - .name = "startAt", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSCursor), - .number = GCFSStructuredQuery_FieldNumber_StartAt, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GCFSStructuredQuery__storage_, startAt), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "endAt", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSCursor), - .number = GCFSStructuredQuery_FieldNumber_EndAt, - .hasIndex = 3, - .offset = (uint32_t)offsetof(GCFSStructuredQuery__storage_, endAt), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSStructuredQuery class] - rootClass:[GCFSQueryRoot class] - file:GCFSQueryRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSStructuredQuery__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - Enum GCFSStructuredQuery_Direction - -GPBEnumDescriptor *GCFSStructuredQuery_Direction_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static const char *valueNames = - "DirectionUnspecified\000Ascending\000Descendin" - "g\000"; - static const int32_t values[] = { - GCFSStructuredQuery_Direction_DirectionUnspecified, - GCFSStructuredQuery_Direction_Ascending, - GCFSStructuredQuery_Direction_Descending, - }; - GPBEnumDescriptor *worker = - [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GCFSStructuredQuery_Direction) - valueNames:valueNames - values:values - count:(uint32_t)(sizeof(values) / sizeof(int32_t)) - enumVerifier:GCFSStructuredQuery_Direction_IsValidValue]; - if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { - [worker release]; - } - } - return descriptor; -} - -BOOL GCFSStructuredQuery_Direction_IsValidValue(int32_t value__) { - switch (value__) { - case GCFSStructuredQuery_Direction_DirectionUnspecified: - case GCFSStructuredQuery_Direction_Ascending: - case GCFSStructuredQuery_Direction_Descending: - return YES; - default: - return NO; - } -} - -#pragma mark - GCFSStructuredQuery_CollectionSelector - -@implementation GCFSStructuredQuery_CollectionSelector - -@dynamic collectionId; -@dynamic allDescendants; - -typedef struct GCFSStructuredQuery_CollectionSelector__storage_ { - uint32_t _has_storage_[1]; - NSString *collectionId; -} GCFSStructuredQuery_CollectionSelector__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "collectionId", - .dataTypeSpecific.className = NULL, - .number = GCFSStructuredQuery_CollectionSelector_FieldNumber_CollectionId, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_CollectionSelector__storage_, collectionId), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "allDescendants", - .dataTypeSpecific.className = NULL, - .number = GCFSStructuredQuery_CollectionSelector_FieldNumber_AllDescendants, - .hasIndex = 1, - .offset = 2, // Stored in _has_storage_ to save space. - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSStructuredQuery_CollectionSelector class] - rootClass:[GCFSQueryRoot class] - file:GCFSQueryRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSStructuredQuery_CollectionSelector__storage_) - flags:GPBDescriptorInitializationFlag_None]; - [localDescriptor setupContainingMessageClassName:GPBStringifySymbol(GCFSStructuredQuery)]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSStructuredQuery_Filter - -@implementation GCFSStructuredQuery_Filter - -@dynamic filterTypeOneOfCase; -@dynamic compositeFilter; -@dynamic fieldFilter; -@dynamic unaryFilter; - -typedef struct GCFSStructuredQuery_Filter__storage_ { - uint32_t _has_storage_[2]; - GCFSStructuredQuery_CompositeFilter *compositeFilter; - GCFSStructuredQuery_FieldFilter *fieldFilter; - GCFSStructuredQuery_UnaryFilter *unaryFilter; -} GCFSStructuredQuery_Filter__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "compositeFilter", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSStructuredQuery_CompositeFilter), - .number = GCFSStructuredQuery_Filter_FieldNumber_CompositeFilter, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_Filter__storage_, compositeFilter), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "fieldFilter", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSStructuredQuery_FieldFilter), - .number = GCFSStructuredQuery_Filter_FieldNumber_FieldFilter, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_Filter__storage_, fieldFilter), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "unaryFilter", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSStructuredQuery_UnaryFilter), - .number = GCFSStructuredQuery_Filter_FieldNumber_UnaryFilter, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_Filter__storage_, unaryFilter), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSStructuredQuery_Filter class] - rootClass:[GCFSQueryRoot class] - file:GCFSQueryRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSStructuredQuery_Filter__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "filterType", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - [localDescriptor setupContainingMessageClassName:GPBStringifySymbol(GCFSStructuredQuery)]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GCFSStructuredQuery_Filter_ClearFilterTypeOneOfCase(GCFSStructuredQuery_Filter *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - GCFSStructuredQuery_CompositeFilter - -@implementation GCFSStructuredQuery_CompositeFilter - -@dynamic op; -@dynamic filtersArray, filtersArray_Count; - -typedef struct GCFSStructuredQuery_CompositeFilter__storage_ { - uint32_t _has_storage_[1]; - GCFSStructuredQuery_CompositeFilter_Operator op; - NSMutableArray *filtersArray; -} GCFSStructuredQuery_CompositeFilter__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "op", - .dataTypeSpecific.enumDescFunc = GCFSStructuredQuery_CompositeFilter_Operator_EnumDescriptor, - .number = GCFSStructuredQuery_CompositeFilter_FieldNumber_Op, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_CompositeFilter__storage_, op), - .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor), - .dataType = GPBDataTypeEnum, - }, - { - .name = "filtersArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSStructuredQuery_Filter), - .number = GCFSStructuredQuery_CompositeFilter_FieldNumber_FiltersArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_CompositeFilter__storage_, filtersArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSStructuredQuery_CompositeFilter class] - rootClass:[GCFSQueryRoot class] - file:GCFSQueryRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSStructuredQuery_CompositeFilter__storage_) - flags:GPBDescriptorInitializationFlag_None]; - [localDescriptor setupContainingMessageClassName:GPBStringifySymbol(GCFSStructuredQuery)]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -int32_t GCFSStructuredQuery_CompositeFilter_Op_RawValue(GCFSStructuredQuery_CompositeFilter *message) { - GPBDescriptor *descriptor = [GCFSStructuredQuery_CompositeFilter descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GCFSStructuredQuery_CompositeFilter_FieldNumber_Op]; - return GPBGetMessageInt32Field(message, field); -} - -void SetGCFSStructuredQuery_CompositeFilter_Op_RawValue(GCFSStructuredQuery_CompositeFilter *message, int32_t value) { - GPBDescriptor *descriptor = [GCFSStructuredQuery_CompositeFilter descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GCFSStructuredQuery_CompositeFilter_FieldNumber_Op]; - GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); -} - -#pragma mark - Enum GCFSStructuredQuery_CompositeFilter_Operator - -GPBEnumDescriptor *GCFSStructuredQuery_CompositeFilter_Operator_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static const char *valueNames = - "OperatorUnspecified\000And\000"; - static const int32_t values[] = { - GCFSStructuredQuery_CompositeFilter_Operator_OperatorUnspecified, - GCFSStructuredQuery_CompositeFilter_Operator_And, - }; - GPBEnumDescriptor *worker = - [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GCFSStructuredQuery_CompositeFilter_Operator) - valueNames:valueNames - values:values - count:(uint32_t)(sizeof(values) / sizeof(int32_t)) - enumVerifier:GCFSStructuredQuery_CompositeFilter_Operator_IsValidValue]; - if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { - [worker release]; - } - } - return descriptor; -} - -BOOL GCFSStructuredQuery_CompositeFilter_Operator_IsValidValue(int32_t value__) { - switch (value__) { - case GCFSStructuredQuery_CompositeFilter_Operator_OperatorUnspecified: - case GCFSStructuredQuery_CompositeFilter_Operator_And: - return YES; - default: - return NO; - } -} - -#pragma mark - GCFSStructuredQuery_FieldFilter - -@implementation GCFSStructuredQuery_FieldFilter - -@dynamic hasField, field; -@dynamic op; -@dynamic hasValue, value; - -typedef struct GCFSStructuredQuery_FieldFilter__storage_ { - uint32_t _has_storage_[1]; - GCFSStructuredQuery_FieldFilter_Operator op; - GCFSStructuredQuery_FieldReference *field; - GCFSValue *value; -} GCFSStructuredQuery_FieldFilter__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "field", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSStructuredQuery_FieldReference), - .number = GCFSStructuredQuery_FieldFilter_FieldNumber_Field, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_FieldFilter__storage_, field), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "op", - .dataTypeSpecific.enumDescFunc = GCFSStructuredQuery_FieldFilter_Operator_EnumDescriptor, - .number = GCFSStructuredQuery_FieldFilter_FieldNumber_Op, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_FieldFilter__storage_, op), - .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor), - .dataType = GPBDataTypeEnum, - }, - { - .name = "value", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSValue), - .number = GCFSStructuredQuery_FieldFilter_FieldNumber_Value, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_FieldFilter__storage_, value), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSStructuredQuery_FieldFilter class] - rootClass:[GCFSQueryRoot class] - file:GCFSQueryRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSStructuredQuery_FieldFilter__storage_) - flags:GPBDescriptorInitializationFlag_None]; - [localDescriptor setupContainingMessageClassName:GPBStringifySymbol(GCFSStructuredQuery)]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -int32_t GCFSStructuredQuery_FieldFilter_Op_RawValue(GCFSStructuredQuery_FieldFilter *message) { - GPBDescriptor *descriptor = [GCFSStructuredQuery_FieldFilter descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GCFSStructuredQuery_FieldFilter_FieldNumber_Op]; - return GPBGetMessageInt32Field(message, field); -} - -void SetGCFSStructuredQuery_FieldFilter_Op_RawValue(GCFSStructuredQuery_FieldFilter *message, int32_t value) { - GPBDescriptor *descriptor = [GCFSStructuredQuery_FieldFilter descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GCFSStructuredQuery_FieldFilter_FieldNumber_Op]; - GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); -} - -#pragma mark - Enum GCFSStructuredQuery_FieldFilter_Operator - -GPBEnumDescriptor *GCFSStructuredQuery_FieldFilter_Operator_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static const char *valueNames = - "OperatorUnspecified\000LessThan\000LessThanOrE" - "qual\000GreaterThan\000GreaterThanOrEqual\000Equa" - "l\000ArrayContains\000"; - static const int32_t values[] = { - GCFSStructuredQuery_FieldFilter_Operator_OperatorUnspecified, - GCFSStructuredQuery_FieldFilter_Operator_LessThan, - GCFSStructuredQuery_FieldFilter_Operator_LessThanOrEqual, - GCFSStructuredQuery_FieldFilter_Operator_GreaterThan, - GCFSStructuredQuery_FieldFilter_Operator_GreaterThanOrEqual, - GCFSStructuredQuery_FieldFilter_Operator_Equal, - GCFSStructuredQuery_FieldFilter_Operator_ArrayContains, - }; - GPBEnumDescriptor *worker = - [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GCFSStructuredQuery_FieldFilter_Operator) - valueNames:valueNames - values:values - count:(uint32_t)(sizeof(values) / sizeof(int32_t)) - enumVerifier:GCFSStructuredQuery_FieldFilter_Operator_IsValidValue]; - if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { - [worker release]; - } - } - return descriptor; -} - -BOOL GCFSStructuredQuery_FieldFilter_Operator_IsValidValue(int32_t value__) { - switch (value__) { - case GCFSStructuredQuery_FieldFilter_Operator_OperatorUnspecified: - case GCFSStructuredQuery_FieldFilter_Operator_LessThan: - case GCFSStructuredQuery_FieldFilter_Operator_LessThanOrEqual: - case GCFSStructuredQuery_FieldFilter_Operator_GreaterThan: - case GCFSStructuredQuery_FieldFilter_Operator_GreaterThanOrEqual: - case GCFSStructuredQuery_FieldFilter_Operator_Equal: - case GCFSStructuredQuery_FieldFilter_Operator_ArrayContains: - return YES; - default: - return NO; - } -} - -#pragma mark - GCFSStructuredQuery_UnaryFilter - -@implementation GCFSStructuredQuery_UnaryFilter - -@dynamic operandTypeOneOfCase; -@dynamic op; -@dynamic field; - -typedef struct GCFSStructuredQuery_UnaryFilter__storage_ { - uint32_t _has_storage_[2]; - GCFSStructuredQuery_UnaryFilter_Operator op; - GCFSStructuredQuery_FieldReference *field; -} GCFSStructuredQuery_UnaryFilter__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "op", - .dataTypeSpecific.enumDescFunc = GCFSStructuredQuery_UnaryFilter_Operator_EnumDescriptor, - .number = GCFSStructuredQuery_UnaryFilter_FieldNumber_Op, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_UnaryFilter__storage_, op), - .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor), - .dataType = GPBDataTypeEnum, - }, - { - .name = "field", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSStructuredQuery_FieldReference), - .number = GCFSStructuredQuery_UnaryFilter_FieldNumber_Field, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_UnaryFilter__storage_, field), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSStructuredQuery_UnaryFilter class] - rootClass:[GCFSQueryRoot class] - file:GCFSQueryRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSStructuredQuery_UnaryFilter__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "operandType", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - [localDescriptor setupContainingMessageClassName:GPBStringifySymbol(GCFSStructuredQuery)]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -int32_t GCFSStructuredQuery_UnaryFilter_Op_RawValue(GCFSStructuredQuery_UnaryFilter *message) { - GPBDescriptor *descriptor = [GCFSStructuredQuery_UnaryFilter descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GCFSStructuredQuery_UnaryFilter_FieldNumber_Op]; - return GPBGetMessageInt32Field(message, field); -} - -void SetGCFSStructuredQuery_UnaryFilter_Op_RawValue(GCFSStructuredQuery_UnaryFilter *message, int32_t value) { - GPBDescriptor *descriptor = [GCFSStructuredQuery_UnaryFilter descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GCFSStructuredQuery_UnaryFilter_FieldNumber_Op]; - GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); -} - -void GCFSStructuredQuery_UnaryFilter_ClearOperandTypeOneOfCase(GCFSStructuredQuery_UnaryFilter *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - Enum GCFSStructuredQuery_UnaryFilter_Operator - -GPBEnumDescriptor *GCFSStructuredQuery_UnaryFilter_Operator_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static const char *valueNames = - "OperatorUnspecified\000IsNan\000IsNull\000"; - static const int32_t values[] = { - GCFSStructuredQuery_UnaryFilter_Operator_OperatorUnspecified, - GCFSStructuredQuery_UnaryFilter_Operator_IsNan, - GCFSStructuredQuery_UnaryFilter_Operator_IsNull, - }; - GPBEnumDescriptor *worker = - [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GCFSStructuredQuery_UnaryFilter_Operator) - valueNames:valueNames - values:values - count:(uint32_t)(sizeof(values) / sizeof(int32_t)) - enumVerifier:GCFSStructuredQuery_UnaryFilter_Operator_IsValidValue]; - if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { - [worker release]; - } - } - return descriptor; -} - -BOOL GCFSStructuredQuery_UnaryFilter_Operator_IsValidValue(int32_t value__) { - switch (value__) { - case GCFSStructuredQuery_UnaryFilter_Operator_OperatorUnspecified: - case GCFSStructuredQuery_UnaryFilter_Operator_IsNan: - case GCFSStructuredQuery_UnaryFilter_Operator_IsNull: - return YES; - default: - return NO; - } -} - -#pragma mark - GCFSStructuredQuery_Order - -@implementation GCFSStructuredQuery_Order - -@dynamic hasField, field; -@dynamic direction; - -typedef struct GCFSStructuredQuery_Order__storage_ { - uint32_t _has_storage_[1]; - GCFSStructuredQuery_Direction direction; - GCFSStructuredQuery_FieldReference *field; -} GCFSStructuredQuery_Order__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "field", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSStructuredQuery_FieldReference), - .number = GCFSStructuredQuery_Order_FieldNumber_Field, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_Order__storage_, field), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "direction", - .dataTypeSpecific.enumDescFunc = GCFSStructuredQuery_Direction_EnumDescriptor, - .number = GCFSStructuredQuery_Order_FieldNumber_Direction, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_Order__storage_, direction), - .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor), - .dataType = GPBDataTypeEnum, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSStructuredQuery_Order class] - rootClass:[GCFSQueryRoot class] - file:GCFSQueryRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSStructuredQuery_Order__storage_) - flags:GPBDescriptorInitializationFlag_None]; - [localDescriptor setupContainingMessageClassName:GPBStringifySymbol(GCFSStructuredQuery)]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -int32_t GCFSStructuredQuery_Order_Direction_RawValue(GCFSStructuredQuery_Order *message) { - GPBDescriptor *descriptor = [GCFSStructuredQuery_Order descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GCFSStructuredQuery_Order_FieldNumber_Direction]; - return GPBGetMessageInt32Field(message, field); -} - -void SetGCFSStructuredQuery_Order_Direction_RawValue(GCFSStructuredQuery_Order *message, int32_t value) { - GPBDescriptor *descriptor = [GCFSStructuredQuery_Order descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GCFSStructuredQuery_Order_FieldNumber_Direction]; - GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); -} - -#pragma mark - GCFSStructuredQuery_FieldReference - -@implementation GCFSStructuredQuery_FieldReference - -@dynamic fieldPath; - -typedef struct GCFSStructuredQuery_FieldReference__storage_ { - uint32_t _has_storage_[1]; - NSString *fieldPath; -} GCFSStructuredQuery_FieldReference__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "fieldPath", - .dataTypeSpecific.className = NULL, - .number = GCFSStructuredQuery_FieldReference_FieldNumber_FieldPath, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_FieldReference__storage_, fieldPath), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSStructuredQuery_FieldReference class] - rootClass:[GCFSQueryRoot class] - file:GCFSQueryRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSStructuredQuery_FieldReference__storage_) - flags:GPBDescriptorInitializationFlag_None]; - [localDescriptor setupContainingMessageClassName:GPBStringifySymbol(GCFSStructuredQuery)]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSStructuredQuery_Projection - -@implementation GCFSStructuredQuery_Projection - -@dynamic fieldsArray, fieldsArray_Count; - -typedef struct GCFSStructuredQuery_Projection__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *fieldsArray; -} GCFSStructuredQuery_Projection__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "fieldsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSStructuredQuery_FieldReference), - .number = GCFSStructuredQuery_Projection_FieldNumber_FieldsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSStructuredQuery_Projection__storage_, fieldsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSStructuredQuery_Projection class] - rootClass:[GCFSQueryRoot class] - file:GCFSQueryRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSStructuredQuery_Projection__storage_) - flags:GPBDescriptorInitializationFlag_None]; - [localDescriptor setupContainingMessageClassName:GPBStringifySymbol(GCFSStructuredQuery)]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSCursor - -@implementation GCFSCursor - -@dynamic valuesArray, valuesArray_Count; -@dynamic before; - -typedef struct GCFSCursor__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *valuesArray; -} GCFSCursor__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "valuesArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSValue), - .number = GCFSCursor_FieldNumber_ValuesArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSCursor__storage_, valuesArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "before", - .dataTypeSpecific.className = NULL, - .number = GCFSCursor_FieldNumber_Before, - .hasIndex = 0, - .offset = 1, // Stored in _has_storage_ to save space. - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSCursor class] - rootClass:[GCFSQueryRoot class] - file:GCFSQueryRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSCursor__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Write.pbobjc.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Write.pbobjc.h deleted file mode 100644 index 8d1b546..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Write.pbobjc.h +++ /dev/null @@ -1,515 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/firestore/v1/write.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers.h" -#endif - -#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002 -#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources. -#endif -#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION -#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -@class GCFSArrayValue; -@class GCFSDocument; -@class GCFSDocumentMask; -@class GCFSDocumentTransform; -@class GCFSDocumentTransform_FieldTransform; -@class GCFSPrecondition; -@class GCFSValue; -@class GPBTimestamp; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - Enum GCFSDocumentTransform_FieldTransform_ServerValue - -/** A value that is calculated by the server. */ -typedef GPB_ENUM(GCFSDocumentTransform_FieldTransform_ServerValue) { - /** - * Value used if any message's field encounters a value that is not defined - * by this enum. The message will also have C functions to get/set the rawValue - * of the field. - **/ - GCFSDocumentTransform_FieldTransform_ServerValue_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, - /** Unspecified. This value must not be used. */ - GCFSDocumentTransform_FieldTransform_ServerValue_ServerValueUnspecified = 0, - - /** - * The time at which the server processed the request, with millisecond - * precision. - **/ - GCFSDocumentTransform_FieldTransform_ServerValue_RequestTime = 1, -}; - -GPBEnumDescriptor *GCFSDocumentTransform_FieldTransform_ServerValue_EnumDescriptor(void); - -/** - * Checks to see if the given value is defined by the enum or was not known at - * the time this source was generated. - **/ -BOOL GCFSDocumentTransform_FieldTransform_ServerValue_IsValidValue(int32_t value); - -#pragma mark - GCFSWriteRoot - -/** - * Exposes the extension registry for this file. - * - * The base class provides: - * @code - * + (GPBExtensionRegistry *)extensionRegistry; - * @endcode - * which is a @c GPBExtensionRegistry that includes all the extensions defined by - * this file and all files that it depends on. - **/ -@interface GCFSWriteRoot : GPBRootObject -@end - -#pragma mark - GCFSWrite - -typedef GPB_ENUM(GCFSWrite_FieldNumber) { - GCFSWrite_FieldNumber_Update = 1, - GCFSWrite_FieldNumber_Delete_p = 2, - GCFSWrite_FieldNumber_UpdateMask = 3, - GCFSWrite_FieldNumber_CurrentDocument = 4, - GCFSWrite_FieldNumber_Transform = 6, -}; - -typedef GPB_ENUM(GCFSWrite_Operation_OneOfCase) { - GCFSWrite_Operation_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSWrite_Operation_OneOfCase_Update = 1, - GCFSWrite_Operation_OneOfCase_Delete_p = 2, - GCFSWrite_Operation_OneOfCase_Transform = 6, -}; - -/** - * A write on a document. - **/ -@interface GCFSWrite : GPBMessage - -/** The operation to execute. */ -@property(nonatomic, readonly) GCFSWrite_Operation_OneOfCase operationOneOfCase; - -/** A document to write. */ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocument *update; - -/** - * A document name to delete. In the format: - * `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *delete_p; - -/** - * Applies a tranformation to a document. - * At most one `transform` per document is allowed in a given request. - * An `update` cannot follow a `transform` on the same document in a given - * request. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocumentTransform *transform; - -/** - * The fields to update in this write. - * - * This field can be set only when the operation is `update`. - * If the mask is not set for an `update` and the document exists, any - * existing data will be overwritten. - * If the mask is set and the document on the server has fields not covered by - * the mask, they are left unchanged. - * Fields referenced in the mask, but not present in the input document, are - * deleted from the document on the server. - * The field paths in this mask must not contain a reserved field name. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocumentMask *updateMask; -/** Test to see if @c updateMask has been set. */ -@property(nonatomic, readwrite) BOOL hasUpdateMask; - -/** - * An optional precondition on the document. - * - * The write will fail if this is set and not met by the target document. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSPrecondition *currentDocument; -/** Test to see if @c currentDocument has been set. */ -@property(nonatomic, readwrite) BOOL hasCurrentDocument; - -@end - -/** - * Clears whatever value was set for the oneof 'operation'. - **/ -void GCFSWrite_ClearOperationOneOfCase(GCFSWrite *message); - -#pragma mark - GCFSDocumentTransform - -typedef GPB_ENUM(GCFSDocumentTransform_FieldNumber) { - GCFSDocumentTransform_FieldNumber_Document = 1, - GCFSDocumentTransform_FieldNumber_FieldTransformsArray = 2, -}; - -/** - * A transformation of a document. - **/ -@interface GCFSDocumentTransform : GPBMessage - -/** The name of the document to transform. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *document; - -/** - * The list of transformations to apply to the fields of the document, in - * order. - * This must not be empty. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *fieldTransformsArray; -/** The number of items in @c fieldTransformsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger fieldTransformsArray_Count; - -@end - -#pragma mark - GCFSDocumentTransform_FieldTransform - -typedef GPB_ENUM(GCFSDocumentTransform_FieldTransform_FieldNumber) { - GCFSDocumentTransform_FieldTransform_FieldNumber_FieldPath = 1, - GCFSDocumentTransform_FieldTransform_FieldNumber_SetToServerValue = 2, - GCFSDocumentTransform_FieldTransform_FieldNumber_Increment = 3, - GCFSDocumentTransform_FieldTransform_FieldNumber_Maximum = 4, - GCFSDocumentTransform_FieldTransform_FieldNumber_Minimum = 5, - GCFSDocumentTransform_FieldTransform_FieldNumber_AppendMissingElements = 6, - GCFSDocumentTransform_FieldTransform_FieldNumber_RemoveAllFromArray_p = 7, -}; - -typedef GPB_ENUM(GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase) { - GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_GPBUnsetOneOfCase = 0, - GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_SetToServerValue = 2, - GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_Increment = 3, - GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_Maximum = 4, - GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_Minimum = 5, - GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_AppendMissingElements = 6, - GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_RemoveAllFromArray_p = 7, -}; - -/** - * A transformation of a field of the document. - **/ -@interface GCFSDocumentTransform_FieldTransform : GPBMessage - -/** - * The path of the field. See [Document.fields][google.firestore.v1.Document.fields] for the field path syntax - * reference. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *fieldPath; - -/** The transformation to apply on the field. */ -@property(nonatomic, readonly) GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase transformTypeOneOfCase; - -/** Sets the field to the given server value. */ -@property(nonatomic, readwrite) GCFSDocumentTransform_FieldTransform_ServerValue setToServerValue; - -/** - * Adds the given value to the field's current value. - * - * This must be an integer or a double value. - * If the field is not an integer or double, or if the field does not yet - * exist, the transformation will set the field to the given value. - * If either of the given value or the current field value are doubles, - * both values will be interpreted as doubles. Double arithmetic and - * representation of double values follow IEEE 754 semantics. - * If there is positive/negative integer overflow, the field is resolved - * to the largest magnitude positive/negative integer. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSValue *increment; - -/** - * Sets the field to the maximum of its current value and the given value. - * - * This must be an integer or a double value. - * If the field is not an integer or double, or if the field does not yet - * exist, the transformation will set the field to the given value. - * If a maximum operation is applied where the field and the input value - * are of mixed types (that is - one is an integer and one is a double) - * the field takes on the type of the larger operand. If the operands are - * equivalent (e.g. 3 and 3.0), the field does not change. - * 0, 0.0, and -0.0 are all zero. The maximum of a zero stored value and - * zero input value is always the stored value. - * The maximum of any numeric value x and NaN is NaN. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSValue *maximum; - -/** - * Sets the field to the minimum of its current value and the given value. - * - * This must be an integer or a double value. - * If the field is not an integer or double, or if the field does not yet - * exist, the transformation will set the field to the input value. - * If a minimum operation is applied where the field and the input value - * are of mixed types (that is - one is an integer and one is a double) - * the field takes on the type of the smaller operand. If the operands are - * equivalent (e.g. 3 and 3.0), the field does not change. - * 0, 0.0, and -0.0 are all zero. The minimum of a zero stored value and - * zero input value is always the stored value. - * The minimum of any numeric value x and NaN is NaN. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSValue *minimum; - -/** - * Append the given elements in order if they are not already present in - * the current field value. - * If the field is not an array, or if the field does not yet exist, it is - * first set to the empty array. - * - * Equivalent numbers of different types (e.g. 3L and 3.0) are - * considered equal when checking if a value is missing. - * NaN is equal to NaN, and Null is equal to Null. - * If the input contains multiple equivalent values, only the first will - * be considered. - * - * The corresponding transform_result will be the null value. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSArrayValue *appendMissingElements; - -/** - * Remove all of the given elements from the array in the field. - * If the field is not an array, or if the field does not yet exist, it is - * set to the empty array. - * - * Equivalent numbers of the different types (e.g. 3L and 3.0) are - * considered equal when deciding whether an element should be removed. - * NaN is equal to NaN, and Null is equal to Null. - * This will remove all equivalent values if there are duplicates. - * - * The corresponding transform_result will be the null value. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSArrayValue *removeAllFromArray_p; - -@end - -/** - * Fetches the raw value of a @c GCFSDocumentTransform_FieldTransform's @c setToServerValue property, even - * if the value was not defined by the enum at the time the code was generated. - **/ -int32_t GCFSDocumentTransform_FieldTransform_SetToServerValue_RawValue(GCFSDocumentTransform_FieldTransform *message); -/** - * Sets the raw value of an @c GCFSDocumentTransform_FieldTransform's @c setToServerValue property, allowing - * it to be set to a value that was not defined by the enum at the time the code - * was generated. - **/ -void SetGCFSDocumentTransform_FieldTransform_SetToServerValue_RawValue(GCFSDocumentTransform_FieldTransform *message, int32_t value); - -/** - * Clears whatever value was set for the oneof 'transformType'. - **/ -void GCFSDocumentTransform_FieldTransform_ClearTransformTypeOneOfCase(GCFSDocumentTransform_FieldTransform *message); - -#pragma mark - GCFSWriteResult - -typedef GPB_ENUM(GCFSWriteResult_FieldNumber) { - GCFSWriteResult_FieldNumber_UpdateTime = 1, - GCFSWriteResult_FieldNumber_TransformResultsArray = 2, -}; - -/** - * The result of applying a write. - **/ -@interface GCFSWriteResult : GPBMessage - -/** - * The last update time of the document after applying the write. Not set - * after a `delete`. - * - * If the write did not actually change the document, this will be the - * previous update_time. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *updateTime; -/** Test to see if @c updateTime has been set. */ -@property(nonatomic, readwrite) BOOL hasUpdateTime; - -/** - * The results of applying each [DocumentTransform.FieldTransform][google.firestore.v1.DocumentTransform.FieldTransform], in the - * same order. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *transformResultsArray; -/** The number of items in @c transformResultsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger transformResultsArray_Count; - -@end - -#pragma mark - GCFSDocumentChange - -typedef GPB_ENUM(GCFSDocumentChange_FieldNumber) { - GCFSDocumentChange_FieldNumber_Document = 1, - GCFSDocumentChange_FieldNumber_TargetIdsArray = 5, - GCFSDocumentChange_FieldNumber_RemovedTargetIdsArray = 6, -}; - -/** - * A [Document][google.firestore.v1.Document] has changed. - * - * May be the result of multiple [writes][google.firestore.v1.Write], including deletes, that - * ultimately resulted in a new value for the [Document][google.firestore.v1.Document]. - * - * Multiple [DocumentChange][google.firestore.v1.DocumentChange] messages may be returned for the same logical - * change, if multiple targets are affected. - **/ -@interface GCFSDocumentChange : GPBMessage - -/** - * The new state of the [Document][google.firestore.v1.Document]. - * - * If `mask` is set, contains only fields that were updated or added. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GCFSDocument *document; -/** Test to see if @c document has been set. */ -@property(nonatomic, readwrite) BOOL hasDocument; - -/** A set of target IDs of targets that match this document. */ -@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *targetIdsArray; -/** The number of items in @c targetIdsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger targetIdsArray_Count; - -/** A set of target IDs for targets that no longer match this document. */ -@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *removedTargetIdsArray; -/** The number of items in @c removedTargetIdsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger removedTargetIdsArray_Count; - -@end - -#pragma mark - GCFSDocumentDelete - -typedef GPB_ENUM(GCFSDocumentDelete_FieldNumber) { - GCFSDocumentDelete_FieldNumber_Document = 1, - GCFSDocumentDelete_FieldNumber_ReadTime = 4, - GCFSDocumentDelete_FieldNumber_RemovedTargetIdsArray = 6, -}; - -/** - * A [Document][google.firestore.v1.Document] has been deleted. - * - * May be the result of multiple [writes][google.firestore.v1.Write], including updates, the - * last of which deleted the [Document][google.firestore.v1.Document]. - * - * Multiple [DocumentDelete][google.firestore.v1.DocumentDelete] messages may be returned for the same logical - * delete, if multiple targets are affected. - **/ -@interface GCFSDocumentDelete : GPBMessage - -/** The resource name of the [Document][google.firestore.v1.Document] that was deleted. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *document; - -/** A set of target IDs for targets that previously matched this entity. */ -@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *removedTargetIdsArray; -/** The number of items in @c removedTargetIdsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger removedTargetIdsArray_Count; - -/** - * The read timestamp at which the delete was observed. - * - * Greater or equal to the `commit_time` of the delete. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *readTime; -/** Test to see if @c readTime has been set. */ -@property(nonatomic, readwrite) BOOL hasReadTime; - -@end - -#pragma mark - GCFSDocumentRemove - -typedef GPB_ENUM(GCFSDocumentRemove_FieldNumber) { - GCFSDocumentRemove_FieldNumber_Document = 1, - GCFSDocumentRemove_FieldNumber_RemovedTargetIdsArray = 2, - GCFSDocumentRemove_FieldNumber_ReadTime = 4, -}; - -/** - * A [Document][google.firestore.v1.Document] has been removed from the view of the targets. - * - * Sent if the document is no longer relevant to a target and is out of view. - * Can be sent instead of a DocumentDelete or a DocumentChange if the server - * can not send the new value of the document. - * - * Multiple [DocumentRemove][google.firestore.v1.DocumentRemove] messages may be returned for the same logical - * write or delete, if multiple targets are affected. - **/ -@interface GCFSDocumentRemove : GPBMessage - -/** The resource name of the [Document][google.firestore.v1.Document] that has gone out of view. */ -@property(nonatomic, readwrite, copy, null_resettable) NSString *document; - -/** A set of target IDs for targets that previously matched this document. */ -@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *removedTargetIdsArray; -/** The number of items in @c removedTargetIdsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger removedTargetIdsArray_Count; - -/** - * The read timestamp at which the remove was observed. - * - * Greater or equal to the `commit_time` of the change/delete/remove. - **/ -@property(nonatomic, readwrite, strong, null_resettable) GPBTimestamp *readTime; -/** Test to see if @c readTime has been set. */ -@property(nonatomic, readwrite) BOOL hasReadTime; - -@end - -#pragma mark - GCFSExistenceFilter - -typedef GPB_ENUM(GCFSExistenceFilter_FieldNumber) { - GCFSExistenceFilter_FieldNumber_TargetId = 1, - GCFSExistenceFilter_FieldNumber_Count = 2, -}; - -/** - * A digest of all the documents that match a given target. - **/ -@interface GCFSExistenceFilter : GPBMessage - -/** The target ID to which this filter applies. */ -@property(nonatomic, readwrite) int32_t targetId; - -/** - * The total count of documents that match [target_id][google.firestore.v1.ExistenceFilter.target_id]. - * - * If different from the count of documents in the client that match, the - * client must manually determine which documents no longer match the target. - **/ -@property(nonatomic, readwrite) int32_t count; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Write.pbobjc.m b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Write.pbobjc.m deleted file mode 100644 index 1114421..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/firestore/v1/Write.pbobjc.m +++ /dev/null @@ -1,697 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/firestore/v1/write.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers_RuntimeSupport.h" -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "Timestamp.pbobjc.h" -#endif - - #import "Write.pbobjc.h" - #import "Annotations.pbobjc.h" - #import "Common.pbobjc.h" - #import "Document.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#pragma clang diagnostic ignored "-Wdirect-ivar-access" - -#pragma mark - GCFSWriteRoot - -@implementation GCFSWriteRoot - - -@end - -#pragma mark - GCFSWriteRoot_FileDescriptor - -static GPBFileDescriptor *GCFSWriteRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPB_DEBUG_CHECK_RUNTIME_VERSIONS(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.firestore.v1" - objcPrefix:@"GCFS" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GCFSWrite - -@implementation GCFSWrite - -@dynamic operationOneOfCase; -@dynamic update; -@dynamic delete_p; -@dynamic transform; -@dynamic hasUpdateMask, updateMask; -@dynamic hasCurrentDocument, currentDocument; - -typedef struct GCFSWrite__storage_ { - uint32_t _has_storage_[2]; - GCFSDocument *update; - NSString *delete_p; - GCFSDocumentMask *updateMask; - GCFSPrecondition *currentDocument; - GCFSDocumentTransform *transform; -} GCFSWrite__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "update", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocument), - .number = GCFSWrite_FieldNumber_Update, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSWrite__storage_, update), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "delete_p", - .dataTypeSpecific.className = NULL, - .number = GCFSWrite_FieldNumber_Delete_p, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSWrite__storage_, delete_p), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "updateMask", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocumentMask), - .number = GCFSWrite_FieldNumber_UpdateMask, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSWrite__storage_, updateMask), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "currentDocument", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSPrecondition), - .number = GCFSWrite_FieldNumber_CurrentDocument, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSWrite__storage_, currentDocument), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "transform", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocumentTransform), - .number = GCFSWrite_FieldNumber_Transform, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSWrite__storage_, transform), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSWrite class] - rootClass:[GCFSWriteRoot class] - file:GCFSWriteRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSWrite__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "operation", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -void GCFSWrite_ClearOperationOneOfCase(GCFSWrite *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - GCFSDocumentTransform - -@implementation GCFSDocumentTransform - -@dynamic document; -@dynamic fieldTransformsArray, fieldTransformsArray_Count; - -typedef struct GCFSDocumentTransform__storage_ { - uint32_t _has_storage_[1]; - NSString *document; - NSMutableArray *fieldTransformsArray; -} GCFSDocumentTransform__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "document", - .dataTypeSpecific.className = NULL, - .number = GCFSDocumentTransform_FieldNumber_Document, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSDocumentTransform__storage_, document), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "fieldTransformsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocumentTransform_FieldTransform), - .number = GCFSDocumentTransform_FieldNumber_FieldTransformsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSDocumentTransform__storage_, fieldTransformsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSDocumentTransform class] - rootClass:[GCFSWriteRoot class] - file:GCFSWriteRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSDocumentTransform__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSDocumentTransform_FieldTransform - -@implementation GCFSDocumentTransform_FieldTransform - -@dynamic transformTypeOneOfCase; -@dynamic fieldPath; -@dynamic setToServerValue; -@dynamic increment; -@dynamic maximum; -@dynamic minimum; -@dynamic appendMissingElements; -@dynamic removeAllFromArray_p; - -typedef struct GCFSDocumentTransform_FieldTransform__storage_ { - uint32_t _has_storage_[2]; - GCFSDocumentTransform_FieldTransform_ServerValue setToServerValue; - NSString *fieldPath; - GCFSValue *increment; - GCFSValue *maximum; - GCFSValue *minimum; - GCFSArrayValue *appendMissingElements; - GCFSArrayValue *removeAllFromArray_p; -} GCFSDocumentTransform_FieldTransform__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "fieldPath", - .dataTypeSpecific.className = NULL, - .number = GCFSDocumentTransform_FieldTransform_FieldNumber_FieldPath, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSDocumentTransform_FieldTransform__storage_, fieldPath), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "setToServerValue", - .dataTypeSpecific.enumDescFunc = GCFSDocumentTransform_FieldTransform_ServerValue_EnumDescriptor, - .number = GCFSDocumentTransform_FieldTransform_FieldNumber_SetToServerValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSDocumentTransform_FieldTransform__storage_, setToServerValue), - .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor), - .dataType = GPBDataTypeEnum, - }, - { - .name = "increment", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSValue), - .number = GCFSDocumentTransform_FieldTransform_FieldNumber_Increment, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSDocumentTransform_FieldTransform__storage_, increment), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "maximum", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSValue), - .number = GCFSDocumentTransform_FieldTransform_FieldNumber_Maximum, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSDocumentTransform_FieldTransform__storage_, maximum), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "minimum", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSValue), - .number = GCFSDocumentTransform_FieldTransform_FieldNumber_Minimum, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSDocumentTransform_FieldTransform__storage_, minimum), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "appendMissingElements", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSArrayValue), - .number = GCFSDocumentTransform_FieldTransform_FieldNumber_AppendMissingElements, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSDocumentTransform_FieldTransform__storage_, appendMissingElements), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "removeAllFromArray_p", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSArrayValue), - .number = GCFSDocumentTransform_FieldTransform_FieldNumber_RemoveAllFromArray_p, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GCFSDocumentTransform_FieldTransform__storage_, removeAllFromArray_p), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSDocumentTransform_FieldTransform class] - rootClass:[GCFSWriteRoot class] - file:GCFSWriteRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSDocumentTransform_FieldTransform__storage_) - flags:GPBDescriptorInitializationFlag_None]; - static const char *oneofs[] = { - "transformType", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - [localDescriptor setupContainingMessageClassName:GPBStringifySymbol(GCFSDocumentTransform)]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -int32_t GCFSDocumentTransform_FieldTransform_SetToServerValue_RawValue(GCFSDocumentTransform_FieldTransform *message) { - GPBDescriptor *descriptor = [GCFSDocumentTransform_FieldTransform descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GCFSDocumentTransform_FieldTransform_FieldNumber_SetToServerValue]; - return GPBGetMessageInt32Field(message, field); -} - -void SetGCFSDocumentTransform_FieldTransform_SetToServerValue_RawValue(GCFSDocumentTransform_FieldTransform *message, int32_t value) { - GPBDescriptor *descriptor = [GCFSDocumentTransform_FieldTransform descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GCFSDocumentTransform_FieldTransform_FieldNumber_SetToServerValue]; - GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); -} - -void GCFSDocumentTransform_FieldTransform_ClearTransformTypeOneOfCase(GCFSDocumentTransform_FieldTransform *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - Enum GCFSDocumentTransform_FieldTransform_ServerValue - -GPBEnumDescriptor *GCFSDocumentTransform_FieldTransform_ServerValue_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static const char *valueNames = - "ServerValueUnspecified\000RequestTime\000"; - static const int32_t values[] = { - GCFSDocumentTransform_FieldTransform_ServerValue_ServerValueUnspecified, - GCFSDocumentTransform_FieldTransform_ServerValue_RequestTime, - }; - GPBEnumDescriptor *worker = - [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GCFSDocumentTransform_FieldTransform_ServerValue) - valueNames:valueNames - values:values - count:(uint32_t)(sizeof(values) / sizeof(int32_t)) - enumVerifier:GCFSDocumentTransform_FieldTransform_ServerValue_IsValidValue]; - if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { - [worker release]; - } - } - return descriptor; -} - -BOOL GCFSDocumentTransform_FieldTransform_ServerValue_IsValidValue(int32_t value__) { - switch (value__) { - case GCFSDocumentTransform_FieldTransform_ServerValue_ServerValueUnspecified: - case GCFSDocumentTransform_FieldTransform_ServerValue_RequestTime: - return YES; - default: - return NO; - } -} - -#pragma mark - GCFSWriteResult - -@implementation GCFSWriteResult - -@dynamic hasUpdateTime, updateTime; -@dynamic transformResultsArray, transformResultsArray_Count; - -typedef struct GCFSWriteResult__storage_ { - uint32_t _has_storage_[1]; - GPBTimestamp *updateTime; - NSMutableArray *transformResultsArray; -} GCFSWriteResult__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "updateTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSWriteResult_FieldNumber_UpdateTime, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSWriteResult__storage_, updateTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "transformResultsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSValue), - .number = GCFSWriteResult_FieldNumber_TransformResultsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSWriteResult__storage_, transformResultsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSWriteResult class] - rootClass:[GCFSWriteRoot class] - file:GCFSWriteRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSWriteResult__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSDocumentChange - -@implementation GCFSDocumentChange - -@dynamic hasDocument, document; -@dynamic targetIdsArray, targetIdsArray_Count; -@dynamic removedTargetIdsArray, removedTargetIdsArray_Count; - -typedef struct GCFSDocumentChange__storage_ { - uint32_t _has_storage_[1]; - GCFSDocument *document; - GPBInt32Array *targetIdsArray; - GPBInt32Array *removedTargetIdsArray; -} GCFSDocumentChange__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "document", - .dataTypeSpecific.className = GPBStringifySymbol(GCFSDocument), - .number = GCFSDocumentChange_FieldNumber_Document, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSDocumentChange__storage_, document), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "targetIdsArray", - .dataTypeSpecific.className = NULL, - .number = GCFSDocumentChange_FieldNumber_TargetIdsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSDocumentChange__storage_, targetIdsArray), - .flags = (GPBFieldFlags)(GPBFieldRepeated | GPBFieldPacked), - .dataType = GPBDataTypeInt32, - }, - { - .name = "removedTargetIdsArray", - .dataTypeSpecific.className = NULL, - .number = GCFSDocumentChange_FieldNumber_RemovedTargetIdsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSDocumentChange__storage_, removedTargetIdsArray), - .flags = (GPBFieldFlags)(GPBFieldRepeated | GPBFieldPacked), - .dataType = GPBDataTypeInt32, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSDocumentChange class] - rootClass:[GCFSWriteRoot class] - file:GCFSWriteRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSDocumentChange__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSDocumentDelete - -@implementation GCFSDocumentDelete - -@dynamic document; -@dynamic removedTargetIdsArray, removedTargetIdsArray_Count; -@dynamic hasReadTime, readTime; - -typedef struct GCFSDocumentDelete__storage_ { - uint32_t _has_storage_[1]; - NSString *document; - GPBTimestamp *readTime; - GPBInt32Array *removedTargetIdsArray; -} GCFSDocumentDelete__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "document", - .dataTypeSpecific.className = NULL, - .number = GCFSDocumentDelete_FieldNumber_Document, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSDocumentDelete__storage_, document), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "readTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSDocumentDelete_FieldNumber_ReadTime, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSDocumentDelete__storage_, readTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "removedTargetIdsArray", - .dataTypeSpecific.className = NULL, - .number = GCFSDocumentDelete_FieldNumber_RemovedTargetIdsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSDocumentDelete__storage_, removedTargetIdsArray), - .flags = (GPBFieldFlags)(GPBFieldRepeated | GPBFieldPacked), - .dataType = GPBDataTypeInt32, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSDocumentDelete class] - rootClass:[GCFSWriteRoot class] - file:GCFSWriteRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSDocumentDelete__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSDocumentRemove - -@implementation GCFSDocumentRemove - -@dynamic document; -@dynamic removedTargetIdsArray, removedTargetIdsArray_Count; -@dynamic hasReadTime, readTime; - -typedef struct GCFSDocumentRemove__storage_ { - uint32_t _has_storage_[1]; - NSString *document; - GPBInt32Array *removedTargetIdsArray; - GPBTimestamp *readTime; -} GCFSDocumentRemove__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "document", - .dataTypeSpecific.className = NULL, - .number = GCFSDocumentRemove_FieldNumber_Document, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSDocumentRemove__storage_, document), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "removedTargetIdsArray", - .dataTypeSpecific.className = NULL, - .number = GCFSDocumentRemove_FieldNumber_RemovedTargetIdsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GCFSDocumentRemove__storage_, removedTargetIdsArray), - .flags = (GPBFieldFlags)(GPBFieldRepeated | GPBFieldPacked), - .dataType = GPBDataTypeInt32, - }, - { - .name = "readTime", - .dataTypeSpecific.className = GPBStringifySymbol(GPBTimestamp), - .number = GCFSDocumentRemove_FieldNumber_ReadTime, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSDocumentRemove__storage_, readTime), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSDocumentRemove class] - rootClass:[GCFSWriteRoot class] - file:GCFSWriteRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSDocumentRemove__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GCFSExistenceFilter - -@implementation GCFSExistenceFilter - -@dynamic targetId; -@dynamic count; - -typedef struct GCFSExistenceFilter__storage_ { - uint32_t _has_storage_[1]; - int32_t targetId; - int32_t count; -} GCFSExistenceFilter__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "targetId", - .dataTypeSpecific.className = NULL, - .number = GCFSExistenceFilter_FieldNumber_TargetId, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GCFSExistenceFilter__storage_, targetId), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - { - .name = "count", - .dataTypeSpecific.className = NULL, - .number = GCFSExistenceFilter_FieldNumber_Count, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GCFSExistenceFilter__storage_, count), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GCFSExistenceFilter class] - rootClass:[GCFSWriteRoot class] - file:GCFSWriteRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GCFSExistenceFilter__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/rpc/Status.pbobjc.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/rpc/Status.pbobjc.h deleted file mode 100644 index ad81346..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/rpc/Status.pbobjc.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/rpc/status.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers.h" -#endif - -#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002 -#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources. -#endif -#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION -#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -@class GPBAny; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - RPCStatusRoot - -/** - * Exposes the extension registry for this file. - * - * The base class provides: - * @code - * + (GPBExtensionRegistry *)extensionRegistry; - * @endcode - * which is a @c GPBExtensionRegistry that includes all the extensions defined by - * this file and all files that it depends on. - **/ -@interface RPCStatusRoot : GPBRootObject -@end - -#pragma mark - RPCStatus - -typedef GPB_ENUM(RPCStatus_FieldNumber) { - RPCStatus_FieldNumber_Code = 1, - RPCStatus_FieldNumber_Message = 2, - RPCStatus_FieldNumber_DetailsArray = 3, -}; - -/** - * The `Status` type defines a logical error model that is suitable for different - * programming environments, including REST APIs and RPC APIs. It is used by - * [gRPC](https://github.com/grpc). The error model is designed to be: - * - * - Simple to use and understand for most users - * - Flexible enough to meet unexpected needs - * - * # Overview - * - * The `Status` message contains three pieces of data: error code, error message, - * and error details. The error code should be an enum value of - * [google.rpc.Code][google.rpc.Code], but it may accept additional error codes if needed. The - * error message should be a developer-facing English message that helps - * developers *understand* and *resolve* the error. If a localized user-facing - * error message is needed, put the localized message in the error details or - * localize it in the client. The optional error details may contain arbitrary - * information about the error. There is a predefined set of error detail types - * in the package `google.rpc` that can be used for common error conditions. - * - * # Language mapping - * - * The `Status` message is the logical representation of the error model, but it - * is not necessarily the actual wire format. When the `Status` message is - * exposed in different client libraries and different wire protocols, it can be - * mapped differently. For example, it will likely be mapped to some exceptions - * in Java, but more likely mapped to some error codes in C. - * - * # Other uses - * - * The error model and the `Status` message can be used in a variety of - * environments, either with or without APIs, to provide a - * consistent developer experience across different environments. - * - * Example uses of this error model include: - * - * - Partial errors. If a service needs to return partial errors to the client, - * it may embed the `Status` in the normal response to indicate the partial - * errors. - * - * - Workflow errors. A typical workflow has multiple steps. Each step may - * have a `Status` message for error reporting. - * - * - Batch operations. If a client uses batch request and batch response, the - * `Status` message should be used directly inside batch response, one for - * each error sub-response. - * - * - Asynchronous operations. If an API call embeds asynchronous operation - * results in its response, the status of those operations should be - * represented directly using the `Status` message. - * - * - Logging. If some API errors are stored in logs, the message `Status` could - * be used directly after any stripping needed for security/privacy reasons. - **/ -@interface RPCStatus : GPBMessage - -/** The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. */ -@property(nonatomic, readwrite) int32_t code; - -/** - * A developer-facing error message, which should be in English. Any - * user-facing error message should be localized and sent in the - * [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. - **/ -@property(nonatomic, readwrite, copy, null_resettable) NSString *message; - -/** - * A list of messages that carry the error details. There is a common set of - * message types for APIs to use. - **/ -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *detailsArray; -/** The number of items in @c detailsArray without causing the array to be created. */ -@property(nonatomic, readonly) NSUInteger detailsArray_Count; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/rpc/Status.pbobjc.m b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/rpc/Status.pbobjc.m deleted file mode 100644 index 1183027..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/rpc/Status.pbobjc.m +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/rpc/status.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers_RuntimeSupport.h" -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "Any.pbobjc.h" -#endif - - #import "Status.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#pragma mark - RPCStatusRoot - -@implementation RPCStatusRoot - -// No extensions in the file and none of the imports (direct or indirect) -// defined extensions, so no need to generate +extensionRegistry. - -@end - -#pragma mark - RPCStatusRoot_FileDescriptor - -static GPBFileDescriptor *RPCStatusRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPB_DEBUG_CHECK_RUNTIME_VERSIONS(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.rpc" - objcPrefix:@"RPC" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - RPCStatus - -@implementation RPCStatus - -@dynamic code; -@dynamic message; -@dynamic detailsArray, detailsArray_Count; - -typedef struct RPCStatus__storage_ { - uint32_t _has_storage_[1]; - int32_t code; - NSString *message; - NSMutableArray *detailsArray; -} RPCStatus__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "code", - .dataTypeSpecific.className = NULL, - .number = RPCStatus_FieldNumber_Code, - .hasIndex = 0, - .offset = (uint32_t)offsetof(RPCStatus__storage_, code), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - { - .name = "message", - .dataTypeSpecific.className = NULL, - .number = RPCStatus_FieldNumber_Message, - .hasIndex = 1, - .offset = (uint32_t)offsetof(RPCStatus__storage_, message), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "detailsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBAny), - .number = RPCStatus_FieldNumber_DetailsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(RPCStatus__storage_, detailsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[RPCStatus class] - rootClass:[RPCStatusRoot class] - file:RPCStatusRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(RPCStatus__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/type/Latlng.pbobjc.h b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/type/Latlng.pbobjc.h deleted file mode 100644 index 90dec0d..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/type/Latlng.pbobjc.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/type/latlng.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers.h" -#endif - -#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002 -#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources. -#endif -#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION -#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - GTPLatlngRoot - -/** - * Exposes the extension registry for this file. - * - * The base class provides: - * @code - * + (GPBExtensionRegistry *)extensionRegistry; - * @endcode - * which is a @c GPBExtensionRegistry that includes all the extensions defined by - * this file and all files that it depends on. - **/ -@interface GTPLatlngRoot : GPBRootObject -@end - -#pragma mark - GTPLatLng - -typedef GPB_ENUM(GTPLatLng_FieldNumber) { - GTPLatLng_FieldNumber_Latitude = 1, - GTPLatLng_FieldNumber_Longitude = 2, -}; - -/** - * An object representing a latitude/longitude pair. This is expressed as a pair - * of doubles representing degrees latitude and degrees longitude. Unless - * specified otherwise, this must conform to the - * WGS84 - * standard. Values must be within normalized ranges. - * - * Example of normalization code in Python: - * - * def NormalizeLongitude(longitude): - * """Wraps decimal degrees longitude to [-180.0, 180.0].""" - * q, r = divmod(longitude, 360.0) - * if r > 180.0 or (r == 180.0 and q <= -1.0): - * return r - 360.0 - * return r - * - * def NormalizeLatLng(latitude, longitude): - * """Wraps decimal degrees latitude and longitude to - * [-90.0, 90.0] and [-180.0, 180.0], respectively.""" - * r = latitude % 360.0 - * if r <= 90.0: - * return r, NormalizeLongitude(longitude) - * elif r >= 270.0: - * return r - 360, NormalizeLongitude(longitude) - * else: - * return 180 - r, NormalizeLongitude(longitude + 180.0) - * - * assert 180.0 == NormalizeLongitude(180.0) - * assert -180.0 == NormalizeLongitude(-180.0) - * assert -179.0 == NormalizeLongitude(181.0) - * assert (0.0, 0.0) == NormalizeLatLng(360.0, 0.0) - * assert (0.0, 0.0) == NormalizeLatLng(-360.0, 0.0) - * assert (85.0, 180.0) == NormalizeLatLng(95.0, 0.0) - * assert (-85.0, -170.0) == NormalizeLatLng(-95.0, 10.0) - * assert (90.0, 10.0) == NormalizeLatLng(90.0, 10.0) - * assert (-90.0, -10.0) == NormalizeLatLng(-90.0, -10.0) - * assert (0.0, -170.0) == NormalizeLatLng(-180.0, 10.0) - * assert (0.0, -170.0) == NormalizeLatLng(180.0, 10.0) - * assert (-90.0, 10.0) == NormalizeLatLng(270.0, 10.0) - * assert (90.0, 10.0) == NormalizeLatLng(-270.0, 10.0) - **/ -@interface GTPLatLng : GPBMessage - -/** The latitude in degrees. It must be in the range [-90.0, +90.0]. */ -@property(nonatomic, readwrite) double latitude; - -/** The longitude in degrees. It must be in the range [-180.0, +180.0]. */ -@property(nonatomic, readwrite) double longitude; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/type/Latlng.pbobjc.m b/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/type/Latlng.pbobjc.m deleted file mode 100644 index 337d16f..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Protos/objc/google/type/Latlng.pbobjc.m +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/type/latlng.proto - -// This CPP symbol can be defined to use imports that match up to the framework -// imports needed when using CocoaPods. -#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS) - #define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0 -#endif - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS - #import -#else - #import "GPBProtocolBuffers_RuntimeSupport.h" -#endif - - #import "Latlng.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#pragma mark - GTPLatlngRoot - -@implementation GTPLatlngRoot - -// No extensions in the file and no imports, so no need to generate -// +extensionRegistry. - -@end - -#pragma mark - GTPLatlngRoot_FileDescriptor - -static GPBFileDescriptor *GTPLatlngRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPB_DEBUG_CHECK_RUNTIME_VERSIONS(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.type" - objcPrefix:@"GTP" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GTPLatLng - -@implementation GTPLatLng - -@dynamic latitude; -@dynamic longitude; - -typedef struct GTPLatLng__storage_ { - uint32_t _has_storage_[1]; - double latitude; - double longitude; -} GTPLatLng__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "latitude", - .dataTypeSpecific.className = NULL, - .number = GTPLatLng_FieldNumber_Latitude, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GTPLatLng__storage_, latitude), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeDouble, - }, - { - .name = "longitude", - .dataTypeSpecific.className = NULL, - .number = GTPLatLng_FieldNumber_Longitude, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GTPLatLng__storage_, longitude), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeDouble, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GTPLatLng class] - rootClass:[GTPLatlngRoot class] - file:GTPLatlngRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GTPLatLng__storage_) - flags:GPBDescriptorInitializationFlag_None]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRCollectionReference+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRCollectionReference+Internal.h index 9d36ede..db274e4 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRCollectionReference+Internal.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRCollectionReference+Internal.h @@ -16,14 +16,26 @@ #import "FIRCollectionReference.h" +#include + +#include "Firestore/core/src/firebase/firestore/api/collection_reference.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" +namespace api = firebase::firestore::api; +namespace model = firebase::firestore::model; + NS_ASSUME_NONNULL_BEGIN /** Internal FIRCollectionReference API we don't want exposed in our public header files. */ -@interface FIRCollectionReference (Internal) -+ (instancetype)referenceWithPath:(const firebase::firestore::model::ResourcePath &)path - firestore:(FIRFirestore *)firestore; +@interface FIRCollectionReference (/* Init */) + +- (instancetype)initWithReference:(api::CollectionReference &&)reference NS_DESIGNATED_INITIALIZER; + +// Mark the super class designated initializer unavailable. +- (instancetype)initWithQuery:(api::Query &&)query NS_UNAVAILABLE; + +- (instancetype)initWithPath:(model::ResourcePath)path + firestore:(std::shared_ptr)firestore; @end NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRCollectionReference.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRCollectionReference.mm index 3156ef4..77d633a 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRCollectionReference.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRCollectionReference.mm @@ -18,56 +18,40 @@ #include -#include "Firestore/core/src/firebase/firestore/util/autoid.h" - #import "Firestore/Source/API/FIRDocumentReference+Internal.h" #import "Firestore/Source/API/FIRFirestore+Internal.h" #import "Firestore/Source/API/FIRQuery+Internal.h" -#import "Firestore/Source/API/FIRQuery_Init.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" +#import "Firestore/Source/API/FSTUserDataConverter.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/api/collection_reference.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/error_apple.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; -using firebase::firestore::model::DocumentKey; +using firebase::firestore::api::CollectionReference; +using firebase::firestore::api::DocumentReference; +using firebase::firestore::core::ParsedSetData; using firebase::firestore::model::ResourcePath; -using firebase::firestore::util::CreateAutoId; +using firebase::firestore::util::ThrowInvalidArgument; NS_ASSUME_NONNULL_BEGIN -@interface FIRCollectionReference () -- (instancetype)initWithPath:(const ResourcePath &)path - firestore:(FIRFirestore *)firestore NS_DESIGNATED_INITIALIZER; - -// Mark the super class designated initializer unavailable. -- (instancetype)initWithQuery:(FSTQuery *)query - firestore:(FIRFirestore *)firestore - __attribute__((unavailable("Use the initWithPath constructor of FIRCollectionReference."))); -@end +@implementation FIRCollectionReference -@implementation FIRCollectionReference (Internal) -+ (instancetype)referenceWithPath:(const ResourcePath &)path firestore:(FIRFirestore *)firestore { - return [[FIRCollectionReference alloc] initWithPath:path firestore:firestore]; +- (instancetype)initWithReference:(CollectionReference &&)reference { + return [super initWithQuery:std::move(reference)]; } -@end -@implementation FIRCollectionReference - -- (instancetype)initWithPath:(const ResourcePath &)path firestore:(FIRFirestore *)firestore { - if (path.size() % 2 != 1) { - FSTThrowInvalidArgument(@"Invalid collection reference. Collection references must have an odd " - "number of segments, but %s has %zu", - path.CanonicalString().c_str(), path.size()); - } - self = [super initWithQuery:[FSTQuery queryWithPath:path] firestore:firestore]; - return self; +- (instancetype)initWithPath:(ResourcePath)path + firestore:(std::shared_ptr)firestore { + CollectionReference ref(std::move(path), std::move(firestore)); + return [self initWithReference:std::move(ref)]; } // Override the designated initializer from the super class. -- (instancetype)initWithQuery:(FSTQuery *)query firestore:(FIRFirestore *)firestore { +- (instancetype)initWithQuery:(api::Query &&)query { HARD_FAIL("Use FIRCollectionReference initWithPath: initializer."); } @@ -79,45 +63,47 @@ - (BOOL)isEqual:(nullable id)other { return [self isEqualToReference:other]; } -- (BOOL)isEqualToReference:(nullable FIRCollectionReference *)reference { - if (self == reference) return YES; - if (reference == nil) return NO; - return [self.firestore isEqual:reference.firestore] && [self.query isEqual:reference.query]; +- (BOOL)isEqualToReference:(nullable FIRCollectionReference *)otherReference { + if (self == otherReference) return YES; + if (otherReference == nil) return NO; + return self.reference == otherReference.reference; } - (NSUInteger)hash { - NSUInteger hash = [self.firestore hash]; - hash = hash * 31u + [self.query hash]; - return hash; + return self.reference.Hash(); +} + +- (const CollectionReference &)reference { + // TODO(wilhuff): Use some alternate method for doing this. + // + // Casting from Query& to CollectionReference& when the value is actually a + // Query violates aliasing rules and is technically undefined behavior. + // Nevertheless this works on Clang so this is good enough for now. + return static_cast(self.apiQuery); } - (NSString *)collectionID { - return util::WrapNSString(self.query.path.last_segment()); + return util::MakeNSString(self.reference.collection_id()); } - (FIRDocumentReference *_Nullable)parent { - const ResourcePath parentPath = self.query.path.PopLast(); - if (parentPath.empty()) { + absl::optional parent = self.reference.parent(); + if (!parent) { return nil; - } else { - DocumentKey key{parentPath}; - return [[FIRDocumentReference alloc] initWithKey:std::move(key) - firestore:self.firestore.wrapped]; } + return [[FIRDocumentReference alloc] initWithReference:std::move(*parent)]; } - (NSString *)path { - return util::WrapNSString(self.query.path.CanonicalString()); + return util::MakeNSString(self.reference.path()); } - (FIRDocumentReference *)documentWithPath:(NSString *)documentPath { if (!documentPath) { - FSTThrowInvalidArgument(@"Document path cannot be nil."); + ThrowInvalidArgument("Document path cannot be nil."); } - const ResourcePath subPath = ResourcePath::FromString(util::MakeString(documentPath)); - ResourcePath path = self.query.path.Append(subPath); - return [[FIRDocumentReference alloc] initWithPath:std::move(path) - firestore:self.firestore.wrapped]; + DocumentReference child = self.reference.Document(util::MakeString(documentPath)); + return [[FIRDocumentReference alloc] initWithReference:std::move(child)]; } - (FIRDocumentReference *)addDocumentWithData:(NSDictionary *)data { @@ -127,14 +113,14 @@ - (FIRDocumentReference *)addDocumentWithData:(NSDictionary *)da - (FIRDocumentReference *)addDocumentWithData:(NSDictionary *)data completion: (nullable void (^)(NSError *_Nullable error))completion { - FIRDocumentReference *docRef = [self documentWithAutoID]; - [docRef setData:data completion:completion]; - return docRef; + ParsedSetData parsed = [self.firestore.dataConverter parsedSetData:data]; + DocumentReference docRef = + self.reference.AddDocument(std::move(parsed), util::MakeCallback(completion)); + return [[FIRDocumentReference alloc] initWithReference:std::move(docRef)]; } - (FIRDocumentReference *)documentWithAutoID { - DocumentKey key{self.query.path.Append(CreateAutoId())}; - return [[FIRDocumentReference alloc] initWithKey:std::move(key) firestore:self.firestore.wrapped]; + return [[FIRDocumentReference alloc] initWithReference:self.reference.Document()]; } @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentChange+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentChange+Internal.h index c1c2690..58f13d2 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentChange+Internal.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentChange+Internal.h @@ -16,21 +16,18 @@ #import "FIRDocumentChange.h" -#include "Firestore/core/src/firebase/firestore/api/firestore.h" -#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" +#import -@class FIRFirestore; +#include "Firestore/core/src/firebase/firestore/api/document_change.h" + +namespace api = firebase::firestore::api; NS_ASSUME_NONNULL_BEGIN -/** Internal FIRDocumentChange API we don't want exposed in our public header files. */ -@interface FIRDocumentChange (Internal) +@interface FIRDocumentChange (/* Init */) -/** Calculates the array of FIRDocumentChange's based on the given FSTViewSnapshot. */ -+ (NSArray *) - documentChangesForSnapshot:(const firebase::firestore::core::ViewSnapshot &)snapshot - includeMetadataChanges:(bool)includeMetadataChanges - firestore:(firebase::firestore::api::Firestore *)firestore; +- (instancetype)initWithDocumentChange:(api::DocumentChange &&)documentChange + NS_DESIGNATED_INITIALIZER; @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentChange.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentChange.mm index 1a5bccd..eec863a 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentChange.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentChange.mm @@ -14,128 +14,36 @@ * limitations under the License. */ -#import "FIRDocumentChange.h" +#import "Firestore/Source/API/FIRDocumentChange+Internal.h" #import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h" -#import "Firestore/Source/API/FIRFirestore+Internal.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Model/FSTDocument.h" -#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" -#include "Firestore/core/src/firebase/firestore/model/document_set.h" +#include "Firestore/core/src/firebase/firestore/api/document_change.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -using firebase::firestore::api::Firestore; -using firebase::firestore::core::DocumentViewChange; -using firebase::firestore::core::ViewSnapshot; -using firebase::firestore::model::DocumentSet; +using firebase::firestore::api::DocumentChange; NS_ASSUME_NONNULL_BEGIN -@interface FIRDocumentChange () +namespace { -- (instancetype)initWithType:(FIRDocumentChangeType)type - document:(FIRDocumentSnapshot *)document - oldIndex:(NSUInteger)oldIndex - newIndex:(NSUInteger)newIndex NS_DESIGNATED_INITIALIZER; - -@end - -@implementation FIRDocumentChange (Internal) - -+ (FIRDocumentChangeType)documentChangeTypeForChange:(const DocumentViewChange &)change { - switch (change.type()) { - case DocumentViewChange::Type::kAdded: - return FIRDocumentChangeTypeAdded; - case DocumentViewChange::Type::kModified: - case DocumentViewChange::Type::kMetadata: - return FIRDocumentChangeTypeModified; - case DocumentViewChange::Type::kRemoved: - return FIRDocumentChangeTypeRemoved; - } - - HARD_FAIL("Unknown DocumentViewChange::Type: %s", change.type()); -} - -+ (NSArray *)documentChangesForSnapshot:(const ViewSnapshot &)snapshot - includeMetadataChanges:(bool)includeMetadataChanges - firestore:(Firestore *)firestore { - if (snapshot.old_documents().empty()) { - // Special case the first snapshot because index calculation is easy and fast. Also all changes - // on the first snapshot are adds so there are also no metadata-only changes to filter out. - FSTDocument *_Nullable lastDocument = nil; - NSUInteger index = 0; - NSMutableArray *changes = [NSMutableArray array]; - for (const DocumentViewChange &change : snapshot.document_changes()) { - FIRQueryDocumentSnapshot *document = [[FIRQueryDocumentSnapshot alloc] - initWithFirestore:firestore - documentKey:change.document().key - document:change.document() - fromCache:snapshot.from_cache() - hasPendingWrites:snapshot.mutated_keys().contains(change.document().key)]; - HARD_ASSERT(change.type() == DocumentViewChange::Type::kAdded, - "Invalid event type for first snapshot"); - HARD_ASSERT(!lastDocument || snapshot.query().comparator(lastDocument, change.document()) == - NSOrderedAscending, - "Got added events in wrong order"); - [changes addObject:[[FIRDocumentChange alloc] initWithType:FIRDocumentChangeTypeAdded - document:document - oldIndex:NSNotFound - newIndex:index++]]; - } - return changes; - } else { - // A DocumentSet that is updated incrementally as changes are applied to use to lookup the index - // of a document. - DocumentSet indexTracker = snapshot.old_documents(); - NSMutableArray *changes = [NSMutableArray array]; - for (const DocumentViewChange &change : snapshot.document_changes()) { - if (!includeMetadataChanges && change.type() == DocumentViewChange::Type::kMetadata) { - continue; - } - - FIRQueryDocumentSnapshot *document = [[FIRQueryDocumentSnapshot alloc] - initWithFirestore:firestore - documentKey:change.document().key - document:change.document() - fromCache:snapshot.from_cache() - hasPendingWrites:snapshot.mutated_keys().contains(change.document().key)]; - - size_t oldIndex = DocumentSet::npos; - size_t newIndex = DocumentSet::npos; - if (change.type() != DocumentViewChange::Type::kAdded) { - oldIndex = indexTracker.IndexOf(change.document().key); - HARD_ASSERT(oldIndex != DocumentSet::npos, "Index for document not found"); - indexTracker = indexTracker.erase(change.document().key); - } - if (change.type() != DocumentViewChange::Type::kRemoved) { - indexTracker = indexTracker.insert(change.document()); - newIndex = indexTracker.IndexOf(change.document().key); - } - [FIRDocumentChange documentChangeTypeForChange:change]; - FIRDocumentChangeType type = [FIRDocumentChange documentChangeTypeForChange:change]; - [changes addObject:[[FIRDocumentChange alloc] initWithType:type - document:document - oldIndex:oldIndex - newIndex:newIndex]]; - } - return changes; - } +/** + * Converts from C++ document change indexes to Objective-C document change + * indexes. Objective-C's NSNotFound is signed NSIntegerMax, not unsigned -1. + */ +constexpr NSUInteger MakeIndex(size_t index) { + return index == DocumentChange::npos ? NSNotFound : index; } -@end +} // namespace -@implementation FIRDocumentChange +@implementation FIRDocumentChange { + DocumentChange _documentChange; +} -- (instancetype)initWithType:(FIRDocumentChangeType)type - document:(FIRQueryDocumentSnapshot *)document - oldIndex:(NSUInteger)oldIndex - newIndex:(NSUInteger)newIndex { +- (instancetype)initWithDocumentChange:(DocumentChange &&)documentChange { if (self = [super init]) { - _type = type; - _document = document; - _oldIndex = oldIndex; - _newIndex = newIndex; + _documentChange = std::move(documentChange); } return self; } @@ -145,16 +53,36 @@ - (BOOL)isEqual:(nullable id)other { if (![other isKindOfClass:[FIRDocumentChange class]]) return NO; FIRDocumentChange *change = (FIRDocumentChange *)other; - return self.type == change.type && [self.document isEqual:change.document] && - self.oldIndex == change.oldIndex && self.newIndex == change.newIndex; + return _documentChange == change->_documentChange; } - (NSUInteger)hash { - NSUInteger result = (NSUInteger)self.type; - result = result * 31u + [self.document hash]; - result = result * 31u + (NSUInteger)self.oldIndex; - result = result * 31u + (NSUInteger)self.newIndex; - return result; + return _documentChange.Hash(); +} + +- (FIRDocumentChangeType)type { + switch (_documentChange.type()) { + case DocumentChange::Type::Added: + return FIRDocumentChangeTypeAdded; + case DocumentChange::Type::Modified: + return FIRDocumentChangeTypeModified; + case DocumentChange::Type::Removed: + return FIRDocumentChangeTypeRemoved; + } + + HARD_FAIL("Unknown DocumentChange::Type: %s", _documentChange.type()); +} + +- (FIRQueryDocumentSnapshot *)document { + return [[FIRQueryDocumentSnapshot alloc] initWithSnapshot:_documentChange.document()]; +} + +- (NSUInteger)oldIndex { + return MakeIndex(_documentChange.old_index()); +} + +- (NSUInteger)newIndex { + return MakeIndex(_documentChange.new_index()); } @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentReference+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentReference+Internal.h index aa12e97..9e357c5 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentReference+Internal.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentReference+Internal.h @@ -16,29 +16,34 @@ #import "FIRDocumentReference.h" +#include + #include "Firestore/core/src/firebase/firestore/api/document_reference.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" +namespace api = firebase::firestore::api; +namespace model = firebase::firestore::model; + NS_ASSUME_NONNULL_BEGIN @interface FIRDocumentReference (/* Init */) -- (instancetype)initWithReference:(firebase::firestore::api::DocumentReference &&)reference - NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithReference:(api::DocumentReference &&)reference NS_DESIGNATED_INITIALIZER; -- (instancetype)initWithPath:(firebase::firestore::model::ResourcePath)path - firestore:(firebase::firestore::api::Firestore *)firestore; +- (instancetype)initWithPath:(model::ResourcePath)path + firestore:(std::shared_ptr)firestore; -- (instancetype)initWithKey:(firebase::firestore::model::DocumentKey)key - firestore:(firebase::firestore::api::Firestore *)firestore; +- (instancetype)initWithKey:(model::DocumentKey)key + firestore:(std::shared_ptr)firestore; @end /** Internal FIRDocumentReference API we don't want exposed in our public header files. */ @interface FIRDocumentReference (Internal) -- (const firebase::firestore::model::DocumentKey &)key; +- (const api::DocumentReference &)internalReference; +- (const model::DocumentKey &)key; @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentReference.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentReference.mm index c1e838f..942ca37 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentReference.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentReference.mm @@ -14,51 +14,51 @@ * limitations under the License. */ -#import "FIRDocumentReference.h" +#import "FIRDocumentReference+Internal.h" #include #include #import "FIRFirestoreErrors.h" -#import "FIRFirestoreSource.h" #import "Firestore/Source/API/FIRCollectionReference+Internal.h" #import "Firestore/Source/API/FIRDocumentReference+Internal.h" #import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h" #import "Firestore/Source/API/FIRFirestore+Internal.h" +#import "Firestore/Source/API/FIRFirestoreSource+Internal.h" #import "Firestore/Source/API/FIRListenerRegistration+Internal.h" #import "Firestore/Source/API/FSTUserDataConverter.h" -#import "Firestore/Source/Core/FSTEventManager.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" #include "Firestore/core/src/firebase/firestore/api/document_reference.h" #include "Firestore/core/src/firebase/firestore/api/document_snapshot.h" +#include "Firestore/core/src/firebase/firestore/api/source.h" #include "Firestore/core/src/firebase/firestore/core/event_listener.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_set.h" -#include "Firestore/core/src/firebase/firestore/model/precondition.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/util/error_apple.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" #include "Firestore/core/src/firebase/firestore/util/status.h" #include "Firestore/core/src/firebase/firestore/util/statusor.h" -#include "Firestore/core/src/firebase/firestore/util/statusor_callback.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; +using firebase::firestore::api::CollectionReference; using firebase::firestore::api::DocumentReference; using firebase::firestore::api::DocumentSnapshot; using firebase::firestore::api::Firestore; +using firebase::firestore::api::ListenerRegistration; +using firebase::firestore::api::Source; +using firebase::firestore::api::MakeSource; using firebase::firestore::core::EventListener; using firebase::firestore::core::ListenOptions; using firebase::firestore::core::ParsedSetData; using firebase::firestore::core::ParsedUpdateData; using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::Precondition; using firebase::firestore::model::ResourcePath; using firebase::firestore::util::Status; using firebase::firestore::util::StatusOr; using firebase::firestore::util::StatusOrCallback; +using firebase::firestore::util::ThrowInvalidArgument; NS_ASSUME_NONNULL_BEGIN @@ -75,16 +75,16 @@ - (instancetype)initWithReference:(DocumentReference &&)reference { return self; } -- (instancetype)initWithPath:(ResourcePath)path firestore:(Firestore *)firestore { +- (instancetype)initWithPath:(ResourcePath)path firestore:(std::shared_ptr)firestore { if (path.size() % 2 != 0) { - FSTThrowInvalidArgument(@"Invalid document reference. Document references must have an even " - "number of segments, but %s has %zu", - path.CanonicalString().c_str(), path.size()); + ThrowInvalidArgument("Invalid document reference. Document references must have an even " + "number of segments, but %s has %s", + path.CanonicalString(), path.size()); } return [self initWithKey:DocumentKey{std::move(path)} firestore:firestore]; } -- (instancetype)initWithKey:(DocumentKey)key firestore:(Firestore *)firestore { +- (instancetype)initWithKey:(DocumentKey)key firestore:(std::shared_ptr)firestore { DocumentReference delegate{std::move(key), firestore}; return [self initWithReference:std::move(delegate)]; } @@ -111,26 +111,25 @@ - (FIRFirestore *)firestore { } - (NSString *)documentID { - return util::WrapNSString(_documentReference.document_id()); + return util::MakeNSString(_documentReference.document_id()); } - (FIRCollectionReference *)parent { - return [FIRCollectionReference referenceWithPath:_documentReference.key().path().PopLast() - firestore:self.firestore]; + return [[FIRCollectionReference alloc] initWithReference:_documentReference.Parent()]; } - (NSString *)path { - return util::WrapNSString(_documentReference.Path()); + return util::MakeNSString(_documentReference.Path()); } - (FIRCollectionReference *)collectionWithPath:(NSString *)collectionPath { if (!collectionPath) { - FSTThrowInvalidArgument(@"Collection path cannot be nil."); + ThrowInvalidArgument("Collection path cannot be nil."); } - ResourcePath subPath = ResourcePath::FromString(util::MakeString(collectionPath)); - ResourcePath path = _documentReference.key().path().Append(subPath); - return [FIRCollectionReference referenceWithPath:path firestore:self.firestore]; + CollectionReference child = + _documentReference.GetCollectionReference(util::MakeString(collectionPath)); + return [[FIRCollectionReference alloc] initWithReference:std::move(child)]; } - (void)setData:(NSDictionary *)documentData { @@ -157,8 +156,7 @@ - (void)setData:(NSDictionary *)documentData auto dataConverter = self.firestore.dataConverter; ParsedSetData parsed = merge ? [dataConverter parsedMergeData:documentData fieldMask:nil] : [dataConverter parsedSetData:documentData]; - _documentReference.SetData( - std::move(parsed).ToMutations(_documentReference.key(), Precondition::None()), completion); + _documentReference.SetData(std::move(parsed), util::MakeCallback(completion)); } - (void)setData:(NSDictionary *)documentData @@ -166,8 +164,7 @@ - (void)setData:(NSDictionary *)documentData completion:(nullable void (^)(NSError *_Nullable error))completion { ParsedSetData parsed = [self.firestore.dataConverter parsedMergeData:documentData fieldMask:mergeFields]; - _documentReference.SetData( - std::move(parsed).ToMutations(_documentReference.key(), Precondition::None()), completion); + _documentReference.SetData(std::move(parsed), util::MakeCallback(completion)); } - (void)updateData:(NSDictionary *)fields { @@ -177,9 +174,7 @@ - (void)updateData:(NSDictionary *)fields { - (void)updateData:(NSDictionary *)fields completion:(nullable void (^)(NSError *_Nullable error))completion { ParsedUpdateData parsed = [self.firestore.dataConverter parsedUpdateData:fields]; - _documentReference.UpdateData( - std::move(parsed).ToMutations(_documentReference.key(), Precondition::Exists(true)), - completion); + _documentReference.UpdateData(std::move(parsed), util::MakeCallback(completion)); } - (void)deleteDocument { @@ -187,17 +182,16 @@ - (void)deleteDocument { } - (void)deleteDocumentWithCompletion:(nullable void (^)(NSError *_Nullable error))completion { - _documentReference.DeleteDocument(completion); + _documentReference.DeleteDocument(util::MakeCallback(completion)); } - (void)getDocumentWithCompletion:(FIRDocumentSnapshotBlock)completion { - _documentReference.GetDocument(FIRFirestoreSourceDefault, - [self wrapDocumentSnapshotBlock:completion]); + _documentReference.GetDocument(Source::Default, [self wrapDocumentSnapshotBlock:completion]); } - (void)getDocumentWithSource:(FIRFirestoreSource)source completion:(FIRDocumentSnapshotBlock)completion { - _documentReference.GetDocument(source, [self wrapDocumentSnapshotBlock:completion]); + _documentReference.GetDocument(MakeSource(source), [self wrapDocumentSnapshotBlock:completion]); } - (id)addSnapshotListener:(FIRDocumentSnapshotBlock)listener { @@ -214,7 +208,7 @@ - (void)getDocumentWithSource:(FIRFirestoreSource)source - (id)addSnapshotListenerInternalWithOptions:(ListenOptions)internalOptions listener:(FIRDocumentSnapshotBlock) listener { - ListenerRegistration result = _documentReference.AddSnapshotListener( + std::unique_ptr result = _documentReference.AddSnapshotListener( std::move(internalOptions), [self wrapDocumentSnapshotBlock:listener]); return [[FSTListenerRegistration alloc] initWithRegistration:std::move(result)]; } @@ -247,6 +241,10 @@ void OnEvent(StatusOr maybe_snapshot) override { @implementation FIRDocumentReference (Internal) +- (const api::DocumentReference &)internalReference { + return _documentReference; +} + - (const DocumentKey &)key { return _documentReference.key(); } diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentSnapshot+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentSnapshot+Internal.h index b371b6a..499df4e 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentSnapshot+Internal.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentSnapshot+Internal.h @@ -16,32 +16,30 @@ #import "FIRDocumentSnapshot.h" +#include + #include "Firestore/core/src/firebase/firestore/api/document_snapshot.h" #include "Firestore/core/src/firebase/firestore/api/snapshot_metadata.h" +#include "Firestore/core/src/firebase/firestore/model/document.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" -@class FIRFirestore; -@class FSTDocument; - -using firebase::firestore::api::DocumentSnapshot; -using firebase::firestore::api::Firestore; -using firebase::firestore::api::SnapshotMetadata; -using firebase::firestore::model::DocumentKey; +namespace api = firebase::firestore::api; +namespace model = firebase::firestore::model; NS_ASSUME_NONNULL_BEGIN @interface FIRDocumentSnapshot (/* Init */) -- (instancetype)initWithSnapshot:(DocumentSnapshot &&)snapshot NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithSnapshot:(api::DocumentSnapshot &&)snapshot NS_DESIGNATED_INITIALIZER; -- (instancetype)initWithFirestore:(Firestore *)firestore - documentKey:(DocumentKey)documentKey - document:(nullable FSTDocument *)document - metadata:(SnapshotMetadata)metadata; +- (instancetype)initWithFirestore:(std::shared_ptr)firestore + documentKey:(model::DocumentKey)documentKey + document:(const absl::optional &)document + metadata:(api::SnapshotMetadata)metadata; -- (instancetype)initWithFirestore:(Firestore *)firestore - documentKey:(DocumentKey)documentKey - document:(nullable FSTDocument *)document +- (instancetype)initWithFirestore:(std::shared_ptr)firestore + documentKey:(model::DocumentKey)documentKey + document:(const absl::optional &)document fromCache:(bool)fromCache hasPendingWrites:(bool)hasPendingWrites; @@ -50,7 +48,7 @@ NS_ASSUME_NONNULL_BEGIN /** Internal FIRDocumentSnapshot API we don't want exposed in our public header files. */ @interface FIRDocumentSnapshot (Internal) -@property(nonatomic, strong, readonly, nullable) FSTDocument *internalDocument; +- (const absl::optional &)internalDocument; @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentSnapshot.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentSnapshot.mm index eb210d9..e00a048 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentSnapshot.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRDocumentSnapshot.mm @@ -14,35 +14,53 @@ * limitations under the License. */ -#import "FIRDocumentSnapshot.h" +#import "FIRDocumentSnapshot+Internal.h" #include +#include #include "Firestore/core/src/firebase/firestore/util/warnings.h" -#import "FIRFirestoreSettings.h" - #import "Firestore/Source/API/FIRDocumentReference+Internal.h" #import "Firestore/Source/API/FIRFieldPath+Internal.h" #import "Firestore/Source/API/FIRFirestore+Internal.h" +#import "Firestore/Source/API/FIRGeoPoint+Internal.h" #import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h" -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" +#import "Firestore/Source/API/FIRTimestamp+Internal.h" +#import "Firestore/Source/API/converters.h" #include "Firestore/core/src/firebase/firestore/api/document_snapshot.h" #include "Firestore/core/src/firebase/firestore/api/firestore.h" +#include "Firestore/core/src/firebase/firestore/api/settings.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/model/field_value_options.h" +#include "Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; +using firebase::Timestamp; +using firebase::firestore::GeoPoint; using firebase::firestore::api::DocumentSnapshot; using firebase::firestore::api::Firestore; +using firebase::firestore::api::MakeFIRGeoPoint; +using firebase::firestore::api::MakeFIRTimestamp; +using firebase::firestore::api::SnapshotMetadata; using firebase::firestore::model::DatabaseId; +using firebase::firestore::model::Document; using firebase::firestore::model::DocumentKey; -using firebase::firestore::util::WrapNSString; +using firebase::firestore::model::FieldPath; +using firebase::firestore::model::FieldValue; +using firebase::firestore::model::FieldValueOptions; +using firebase::firestore::model::ObjectValue; +using firebase::firestore::model::ServerTimestampBehavior; +using firebase::firestore::nanopb::MakeNSData; +using firebase::firestore::util::MakeString; +using firebase::firestore::util::ThrowInvalidArgument; NS_ASSUME_NONNULL_BEGIN @@ -54,11 +72,11 @@ ServerTimestampBehavior InternalServerTimestampBehavior(FIRServerTimestampBehavior behavior) { switch (behavior) { case FIRServerTimestampBehaviorNone: - return ServerTimestampBehavior::None; + return ServerTimestampBehavior::kNone; case FIRServerTimestampBehaviorEstimate: - return ServerTimestampBehavior::Estimate; + return ServerTimestampBehavior::kEstimate; case FIRServerTimestampBehaviorPrevious: - return ServerTimestampBehavior::Previous; + return ServerTimestampBehavior::kPrevious; default: HARD_FAIL("Unexpected server timestamp option: %s", behavior); } @@ -79,17 +97,24 @@ - (instancetype)initWithSnapshot:(DocumentSnapshot &&)snapshot { return self; } -- (instancetype)initWithFirestore:(Firestore *)firestore +- (instancetype)initWithFirestore:(std::shared_ptr)firestore documentKey:(DocumentKey)documentKey - document:(nullable FSTDocument *)document + document:(const absl::optional &)document metadata:(SnapshotMetadata)metadata { - DocumentSnapshot wrapped{firestore, std::move(documentKey), document, std::move(metadata)}; + DocumentSnapshot wrapped; + if (document.has_value()) { + wrapped = + DocumentSnapshot::FromDocument(std::move(firestore), document.value(), std::move(metadata)); + } else { + wrapped = DocumentSnapshot::FromNoDocument(std::move(firestore), std::move(documentKey), + std::move(metadata)); + } return [self initWithSnapshot:std::move(wrapped)]; } -- (instancetype)initWithFirestore:(Firestore *)firestore +- (instancetype)initWithFirestore:(std::shared_ptr)firestore documentKey:(DocumentKey)documentKey - document:(nullable FSTDocument *)document + document:(const absl::optional &)document fromCache:(bool)fromCache hasPendingWrites:(bool)hasPendingWrites { return [self initWithFirestore:firestore @@ -117,7 +142,7 @@ - (BOOL)exists { return _snapshot.exists(); } -- (FSTDocument *)internalDocument { +- (const absl::optional &)internalDocument { return _snapshot.internal_document(); } @@ -126,7 +151,7 @@ - (FIRDocumentReference *)reference { } - (NSString *)documentID { - return WrapNSString(_snapshot.document_id()); + return util::MakeNSString(_snapshot.document_id()); } @dynamic metadata; @@ -144,9 +169,11 @@ - (FIRSnapshotMetadata *)metadata { - (nullable NSDictionary *)dataWithServerTimestampBehavior: (FIRServerTimestampBehavior)serverTimestampBehavior { - FSTFieldValueOptions *options = [self optionsForServerTimestampBehavior:serverTimestampBehavior]; - FSTObjectValue *data = _snapshot.GetData(); - return data == nil ? nil : [self convertedObject:data options:options]; + FieldValueOptions options = [self optionsForServerTimestampBehavior:serverTimestampBehavior]; + absl::optional data = _snapshot.GetData(); + if (!data) return nil; + + return [self convertedObject:data->GetInternalValue() options:options]; } - (nullable id)valueForField:(id)field { @@ -155,77 +182,123 @@ - (nullable id)valueForField:(id)field { - (nullable id)valueForField:(id)field serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior { - FIRFieldPath *fieldPath; + FieldPath fieldPath; if ([field isKindOfClass:[NSString class]]) { - fieldPath = [FIRFieldPath pathWithDotSeparatedString:field]; + fieldPath = FieldPath::FromDotSeparatedString(MakeString(field)); } else if ([field isKindOfClass:[FIRFieldPath class]]) { - fieldPath = field; + fieldPath = ((FIRFieldPath *)field).internalValue; } else { - FSTThrowInvalidArgument(@"Subscript key must be an NSString or FIRFieldPath."); + ThrowInvalidArgument("Subscript key must be an NSString or FIRFieldPath."); } - FSTFieldValue *fieldValue = _snapshot.GetValue(fieldPath.internalValue); - FSTFieldValueOptions *options = [self optionsForServerTimestampBehavior:serverTimestampBehavior]; - return fieldValue == nil ? nil : [self convertedValue:fieldValue options:options]; + absl::optional fieldValue = _snapshot.GetValue(fieldPath); + FieldValueOptions options = [self optionsForServerTimestampBehavior:serverTimestampBehavior]; + return !fieldValue ? nil : [self convertedValue:*fieldValue options:options]; } - (nullable id)objectForKeyedSubscript:(id)key { return [self valueForField:key]; } -- (FSTFieldValueOptions *)optionsForServerTimestampBehavior: +- (FieldValueOptions)optionsForServerTimestampBehavior: (FIRServerTimestampBehavior)serverTimestampBehavior { SUPPRESS_DEPRECATED_DECLARATIONS_BEGIN() - return [[FSTFieldValueOptions alloc] - initWithServerTimestampBehavior:InternalServerTimestampBehavior(serverTimestampBehavior) - timestampsInSnapshotsEnabled:_snapshot.firestore() - ->settings() - .timestampsInSnapshotsEnabled]; + return FieldValueOptions(InternalServerTimestampBehavior(serverTimestampBehavior), + _snapshot.firestore()->settings().timestamps_in_snapshots_enabled()); SUPPRESS_END() } -- (id)convertedValue:(FSTFieldValue *)value options:(FSTFieldValueOptions *)options { - if ([value isKindOfClass:[FSTObjectValue class]]) { - return [self convertedObject:(FSTObjectValue *)value options:options]; - } else if ([value isKindOfClass:[FSTArrayValue class]]) { - return [self convertedArray:(FSTArrayValue *)value options:options]; - } else if ([value isKindOfClass:[FSTReferenceValue class]]) { - FSTReferenceValue *ref = (FSTReferenceValue *)value; - const DatabaseId *refDatabase = ref.databaseID; - const DatabaseId *database = &_snapshot.firestore()->database_id(); - if (*refDatabase != *database) { - // TODO(b/32073923): Log this as a proper warning. - NSLog(@"WARNING: Document %@ contains a document reference within a different database " - "(%s/%s) which is not supported. It will be treated as a reference within the " - "current database (%s/%s) instead.", - self.reference.path, refDatabase->project_id().c_str(), - refDatabase->database_id().c_str(), database->project_id().c_str(), - database->database_id().c_str()); - } - DocumentKey key = [[ref valueWithOptions:options] key]; - return [[FIRDocumentReference alloc] initWithKey:key firestore:_snapshot.firestore()]; +- (id)convertedValue:(FieldValue)value options:(const FieldValueOptions &)options { + switch (value.type()) { + case FieldValue::Type::Null: + return [NSNull null]; + case FieldValue::Type::Boolean: + return value.boolean_value() ? @YES : @NO; + case FieldValue::Type::Integer: + return @(value.integer_value()); + case FieldValue::Type::Double: + return @(value.double_value()); + case FieldValue::Type::Timestamp: + return [self convertedTimestamp:value options:options]; + case FieldValue::Type::ServerTimestamp: + return [self convertedServerTimestamp:value options:options]; + case FieldValue::Type::String: + return util::MakeNSString(value.string_value()); + case FieldValue::Type::Blob: + return MakeNSData(value.blob_value()); + case FieldValue::Type::Reference: + return [self convertedReference:value]; + case FieldValue::Type::GeoPoint: + return MakeFIRGeoPoint(value.geo_point_value()); + case FieldValue::Type::Array: + return [self convertedArray:value.array_value() options:options]; + case FieldValue::Type::Object: + return [self convertedObject:value.object_value() options:options]; + } + + UNREACHABLE(); +} + +- (id)convertedTimestamp:(const FieldValue &)value options:(const FieldValueOptions &)options { + FIRTimestamp *wrapped = MakeFIRTimestamp(value.timestamp_value()); + if (options.timestamps_in_snapshots_enabled()) { + return wrapped; } else { - return [value valueWithOptions:options]; + return [wrapped dateValue]; } } -- (NSDictionary *)convertedObject:(FSTObjectValue *)objectValue - options:(FSTFieldValueOptions *)options { - NSMutableDictionary *result = [NSMutableDictionary dictionary]; - [objectValue.internalValue - enumerateKeysAndObjectsUsingBlock:^(NSString *key, FSTFieldValue *value, BOOL *stop) { - result[key] = [self convertedValue:value options:options]; - }]; - return result; +- (id)convertedServerTimestamp:(const FieldValue &)value + options:(const FieldValueOptions &)options { + const auto &sts = value.server_timestamp_value(); + switch (options.server_timestamp_behavior()) { + case ServerTimestampBehavior::kNone: + return [NSNull null]; + case ServerTimestampBehavior::kEstimate: { + FieldValue local_write_time = FieldValue::FromTimestamp(sts.local_write_time()); + return [self convertedTimestamp:local_write_time options:options]; + } + case ServerTimestampBehavior::kPrevious: + return sts.previous_value() ? [self convertedValue:*sts.previous_value() options:options] + : [NSNull null]; + } + + UNREACHABLE(); +} + +- (id)convertedReference:(const FieldValue &)value { + const auto &ref = value.reference_value(); + const DatabaseId &refDatabase = ref.database_id(); + const DatabaseId &database = _snapshot.firestore()->database_id(); + if (refDatabase != database) { + LOG_WARN("Document %s contains a document reference within a different database (%s/%s) which " + "is not supported. It will be treated as a reference within the current database " + "(%s/%s) instead.", + _snapshot.CreateReference().Path(), refDatabase.project_id(), + refDatabase.database_id(), database.project_id(), database.database_id()); + } + const DocumentKey &key = ref.key(); + return [[FIRDocumentReference alloc] initWithKey:key firestore:_snapshot.firestore()]; } -- (NSArray *)convertedArray:(FSTArrayValue *)arrayValue - options:(FSTFieldValueOptions *)options { - NSArray *internalValue = arrayValue.internalValue; - NSMutableArray *result = [NSMutableArray arrayWithCapacity:internalValue.count]; - [internalValue enumerateObjectsUsingBlock:^(id value, NSUInteger idx, BOOL *stop) { +- (NSArray *)convertedArray:(const FieldValue::Array &)arrayContents + options:(const FieldValueOptions &)options { + NSMutableArray *result = [NSMutableArray arrayWithCapacity:arrayContents.size()]; + for (const FieldValue &value : arrayContents) { [result addObject:[self convertedValue:value options:options]]; - }]; + } + return result; +} + +- (NSDictionary *)convertedObject:(const FieldValue::Map &)objectValue + options:(const FieldValueOptions &)options { + NSMutableDictionary *result = [NSMutableDictionary dictionary]; + for (const auto &kv : objectValue) { + const std::string &key = kv.first; + const FieldValue &value = kv.second; + + result[util::MakeNSString(key)] = [self convertedValue:value options:options]; + } return result; } diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFieldPath+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFieldPath+Internal.h index 6fb6add..be8079a 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFieldPath+Internal.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFieldPath+Internal.h @@ -18,14 +18,16 @@ #include "Firestore/core/src/firebase/firestore/model/field_path.h" +namespace model = firebase::firestore::model; + NS_ASSUME_NONNULL_BEGIN @interface FIRFieldPath () /** Internal field path representation */ -- (const firebase::firestore::model::FieldPath &)internalValue; +- (const model::FieldPath &)internalValue; -- (instancetype)initPrivate:(firebase::firestore::model::FieldPath)path NS_DESIGNATED_INITIALIZER; +- (instancetype)initPrivate:(model::FieldPath)path NS_DESIGNATED_INITIALIZER; @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFieldPath.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFieldPath.mm index 68f3de1..d983f68 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFieldPath.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFieldPath.mm @@ -22,14 +22,15 @@ #include #import "Firestore/Source/API/FIRFieldPath+Internal.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" #include "Firestore/core/src/firebase/firestore/util/hashing.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; using firebase::firestore::model::FieldPath; +using firebase::firestore::util::ThrowInvalidArgument; NS_ASSUME_NONNULL_BEGIN @@ -44,19 +45,16 @@ @implementation FIRFieldPath - (instancetype)initWithFields:(NSArray *)fieldNames { if (fieldNames.count == 0) { - FSTThrowInvalidArgument(@"Invalid field path. Provided names must not be empty."); + ThrowInvalidArgument("Invalid field path. Provided names must not be empty."); } - std::vector field_names; - field_names.reserve(fieldNames.count); - for (int i = 0; i < fieldNames.count; ++i) { - if (fieldNames[i].length == 0) { - FSTThrowInvalidArgument(@"Invalid field name at index %d. Field names must not be empty.", i); - } - field_names.emplace_back(util::MakeString(fieldNames[i])); + std::vector converted; + converted.reserve(fieldNames.count); + for (NSString *fieldName in fieldNames) { + converted.emplace_back(util::MakeString(fieldName)); } - return [self initPrivate:FieldPath(std::move(field_names))]; + return [self initPrivate:FieldPath::FromSegments(std::move(converted))]; } + (instancetype)documentID { @@ -71,31 +69,8 @@ - (instancetype)initPrivate:(FieldPath)fieldPath { } + (instancetype)pathWithDotSeparatedString:(NSString *)path { - if ([[FIRFieldPath reservedCharactersRegex] - numberOfMatchesInString:path - options:0 - range:NSMakeRange(0, path.length)] > 0) { - FSTThrowInvalidArgument( - @"Invalid field path (%@). Paths must not contain '~', '*', '/', '[', or ']'", path); - } - @try { - return [[FIRFieldPath alloc] initWithFields:[path componentsSeparatedByString:@"."]]; - } @catch (NSException *exception) { - FSTThrowInvalidArgument( - @"Invalid field path (%@). Paths must not be empty, begin with '.', end with '.', or " - @"contain '..'", - path); - } -} - -/** Matches any characters in a field path string that are reserved. */ -+ (NSRegularExpression *)reservedCharactersRegex { - static NSRegularExpression *regex = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - regex = [NSRegularExpression regularExpressionWithPattern:@"[~*/\\[\\]]" options:0 error:nil]; - }); - return regex; + return + [[FIRFieldPath alloc] initPrivate:FieldPath::FromDotSeparatedString(util::MakeString(path))]; } - (id)copyWithZone:(NSZone *__nullable)zone { diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFieldValue.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFieldValue.mm index 884b187..dccf735 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFieldValue.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFieldValue.mm @@ -130,8 +130,7 @@ - (instancetype)initWithOperand:(NSNumber *)operand; @end @implementation FSTNumericIncrementFieldValue -- (instancetype)initWithOperand:(NSNumber *)operand; -{ +- (instancetype)initWithOperand:(NSNumber *)operand { if (self = [super initPrivate]) { _operand = operand; } diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestore+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestore+Internal.h index 06d5b7d..78c53f3 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestore+Internal.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestore+Internal.h @@ -23,65 +23,51 @@ #include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" -NS_ASSUME_NONNULL_BEGIN - @class FIRApp; @class FSTFirestoreClient; @class FSTUserDataConverter; +namespace api = firebase::firestore::api; +namespace auth = firebase::firestore::auth; +namespace model = firebase::firestore::model; +namespace util = firebase::firestore::util; + +NS_ASSUME_NONNULL_BEGIN + +/** Provides a registry management interface for FIRFirestore instances. */ +@protocol FSTFirestoreInstanceRegistry + +/** Removes the FIRFirestore instance with given database name from registry. */ +- (void)removeInstanceWithDatabase:(NSString *)database; + +@end + @interface FIRFirestore (/* Init */) /** * Initializes a Firestore object with all the required parameters directly. This exists so that * tests can create FIRFirestore objects without needing FIRApp. */ -- (instancetype) - initWithProjectID:(std::string)projectID - database:(std::string)database - persistenceKey:(std::string)persistenceKey - credentialsProvider: - (std::unique_ptr)credentialsProvider - workerQueue:(std::unique_ptr)workerQueue - firebaseApp:(FIRApp *)app; +- (instancetype)initWithDatabaseID:(model::DatabaseId)databaseID + persistenceKey:(std::string)persistenceKey + credentialsProvider:(std::shared_ptr)credentialsProvider + workerQueue:(std::shared_ptr)workerQueue + firebaseApp:(FIRApp *)app + instanceRegistry:(nullable id)registry; @end /** Internal FIRFirestore API we don't want exposed in our public header files. */ @interface FIRFirestore (Internal) -// TODO(b/116617988): Move this to FIRFirestore.h and update CHANGELOG.md once backend support is -// ready. -#pragma mark - Collection Group Queries -/** - * Creates and returns a new `Query` that includes all documents in the database that are contained - * in a collection or subcollection with the given collectionID. - * - * @param collectionID Identifies the collections to query over. Every collection or subcollection - * with this ID as the last segment of its path will be included. Cannot contain a slash. - * @return The created `Query`. - */ -- (FIRQuery *)collectionGroupWithID:(NSString *)collectionID NS_SWIFT_NAME(collectionGroup(_:)); - -/** Checks to see if logging is is globally enabled for the Firestore client. */ -+ (BOOL)isLoggingEnabled; ++ (FIRFirestore *)recoverFromFirestore:(std::shared_ptr)firestore; -+ (FIRFirestore *)recoverFromFirestore:(firebase::firestore::api::Firestore *)firestore; - -/** - * Shutdown this `FIRFirestore`, releasing all resources (abandoning any outstanding writes, - * removing all listens, closing all network connections, etc.). - * - * @param completion A block to execute once everything has shut down. - */ -- (void)shutdownWithCompletion:(nullable void (^)(NSError *_Nullable error))completion - NS_SWIFT_NAME(shutdown(completion:)); +- (void)terminateInternalWithCompletion:(nullable void (^)(NSError *_Nullable error))completion; -@property(nonatomic, assign, readonly) firebase::firestore::api::Firestore *wrapped; +- (const std::shared_ptr &)workerQueue; -@property(nonatomic, assign, readonly) firebase::firestore::util::AsyncQueue *workerQueue; +@property(nonatomic, assign, readonly) std::shared_ptr wrapped; -// FIRFirestore ownes the DatabaseId instance. -@property(nonatomic, assign, readonly) const firebase::firestore::model::DatabaseId *databaseID; -@property(nonatomic, strong, readonly) FSTFirestoreClient *client; +@property(nonatomic, assign, readonly) const model::DatabaseId &databaseID; @property(nonatomic, strong, readonly) FSTUserDataConverter *dataConverter; @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestore.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestore.mm index e4761b1..f4722f6 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestore.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestore.mm @@ -14,47 +14,71 @@ * limitations under the License. */ -#import "FIRFirestore.h" +#import "FIRFirestore+Internal.h" #import #import #import -#import -#import #include #include #include -#import "FIRFirestore.h" +#import "FIRFirestoreSettings+Internal.h" +#import "Firestore/Source/API/FIRCollectionReference+Internal.h" #import "Firestore/Source/API/FIRDocumentReference+Internal.h" -#import "Firestore/Source/API/FIRFirestore+Internal.h" +#import "Firestore/Source/API/FIRListenerRegistration+Internal.h" +#import "Firestore/Source/API/FIRQuery+Internal.h" +#import "Firestore/Source/API/FIRTransaction+Internal.h" +#import "Firestore/Source/API/FIRWriteBatch+Internal.h" #import "Firestore/Source/API/FSTFirestoreComponent.h" #import "Firestore/Source/API/FSTUserDataConverter.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" +#include "Firestore/core/src/firebase/firestore/api/collection_reference.h" #include "Firestore/core/src/firebase/firestore/api/firestore.h" +#include "Firestore/core/src/firebase/firestore/api/write_batch.h" #include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" +#include "Firestore/core/src/firebase/firestore/core/transaction.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" -#include "Firestore/core/src/firebase/firestore/util/delayed_constructor.h" +#include "Firestore/core/src/firebase/firestore/util/empty.h" +#include "Firestore/core/src/firebase/firestore/util/error_apple.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" +#include "Firestore/core/src/firebase/firestore/util/exception_apple.h" +#include "Firestore/core/src/firebase/firestore/util/executor_libdispatch.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/statusor.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; using firebase::firestore::api::DocumentReference; using firebase::firestore::api::Firestore; +using firebase::firestore::api::ListenerRegistration; using firebase::firestore::auth::CredentialsProvider; +using firebase::firestore::core::EventListener; using firebase::firestore::model::DatabaseId; using firebase::firestore::util::AsyncQueue; -using firebase::firestore::util::DelayedConstructor; +using firebase::firestore::util::Empty; +using firebase::firestore::util::MakeCallback; +using firebase::firestore::util::MakeNSError; +using firebase::firestore::util::MakeNSString; +using firebase::firestore::util::MakeString; +using firebase::firestore::util::ObjcThrowHandler; +using firebase::firestore::util::SetThrowHandler; +using firebase::firestore::util::Status; +using firebase::firestore::util::StatusOr; +using firebase::firestore::util::ThrowIllegalState; +using firebase::firestore::util::ThrowInvalidArgument; + +using UserUpdateBlock = id _Nullable (^)(FIRTransaction *, NSError **); +using UserTransactionCompletion = void (^)(id _Nullable, NSError *_Nullable); NS_ASSUME_NONNULL_BEGIN -extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; - #pragma mark - FIRFirestore @interface FIRFirestore () @@ -64,72 +88,40 @@ @interface FIRFirestore () @end @implementation FIRFirestore { - DelayedConstructor _firestore; -} - -+ (NSMutableDictionary *)instances { - static dispatch_once_t token = 0; - static NSMutableDictionary *instances; - dispatch_once(&token, ^{ - instances = [NSMutableDictionary dictionary]; - }); - return instances; + std::shared_ptr _firestore; + FIRFirestoreSettings *_settings; + __weak id _registry; } + (void)initialize { - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - [center addObserverForName:kFIRAppDeleteNotification - object:nil - queue:nil - usingBlock:^(NSNotification *_Nonnull note) { - NSString *appName = note.userInfo[kFIRAppNameKey]; - if (appName == nil) return; - - NSMutableDictionary *instances = [self instances]; - @synchronized(instances) { - // Since the key for instances isn't just the app name, iterate over all the - // keys to get the one(s) we have to delete. There could be multiple in case - // the user calls firestoreForApp:database:. - NSMutableArray *keysToDelete = [[NSMutableArray alloc] init]; - NSString *keyPrefix = [NSString stringWithFormat:@"%@|", appName]; - for (NSString *key in instances.allKeys) { - if ([key hasPrefix:keyPrefix]) { - [keysToDelete addObject:key]; - } - } - - // Loop through the keys found and delete them from the stored instances. - for (NSString *key in keysToDelete) { - [instances removeObjectForKey:key]; - } - } - }]; + if (self == [FIRFirestore class]) { + SetThrowHandler(ObjcThrowHandler); + } } + (instancetype)firestore { FIRApp *app = [FIRApp defaultApp]; if (!app) { - FSTThrowInvalidUsage(@"FIRAppNotConfiguredException", - @"Failed to get FirebaseApp instance. Please call FirebaseApp.configure() " - @"before using Firestore"); + ThrowIllegalState("Failed to get FirebaseApp instance. Please call FirebaseApp.configure() " + "before using Firestore"); } - return [self firestoreForApp:app database:util::WrapNSString(DatabaseId::kDefault)]; + return [self firestoreForApp:app database:MakeNSString(DatabaseId::kDefault)]; } + (instancetype)firestoreForApp:(FIRApp *)app { - return [self firestoreForApp:app database:util::WrapNSString(DatabaseId::kDefault)]; + return [self firestoreForApp:app database:MakeNSString(DatabaseId::kDefault)]; } // TODO(b/62410906): make this public + (instancetype)firestoreForApp:(FIRApp *)app database:(NSString *)database { if (!app) { - FSTThrowInvalidArgument(@"FirebaseApp instance may not be nil. Use FirebaseApp.app() if you'd " - "like to use the default FirebaseApp instance."); + ThrowInvalidArgument("FirebaseApp instance may not be nil. Use FirebaseApp.app() if you'd like " + "to use the default FirebaseApp instance."); } if (!database) { - FSTThrowInvalidArgument(@"database identifier may not be nil. Use '%s' if you want the default " - "database", - DatabaseId::kDefault); + ThrowInvalidArgument("Database identifier may not be nil. Use '%s' if you want the default " + "database", + DatabaseId::kDefault); } id provider = @@ -137,21 +129,23 @@ + (instancetype)firestoreForApp:(FIRApp *)app database:(NSString *)database { return [provider firestoreForDatabase:database]; } -- (instancetype)initWithProjectID:(std::string)projectID - database:(std::string)database - persistenceKey:(std::string)persistenceKey - credentialsProvider:(std::unique_ptr)credentialsProvider - workerQueue:(std::unique_ptr)workerQueue - firebaseApp:(FIRApp *)app { +- (instancetype)initWithDatabaseID:(model::DatabaseId)databaseID + persistenceKey:(std::string)persistenceKey + credentialsProvider:(std::shared_ptr)credentialsProvider + workerQueue:(std::shared_ptr)workerQueue + firebaseApp:(FIRApp *)app + instanceRegistry:(nullable id)registry { if (self = [super init]) { - _firestore.Init(std::move(projectID), std::move(database), std::move(persistenceKey), - std::move(credentialsProvider), std::move(workerQueue), (__bridge void *)self); + _firestore = std::make_shared(std::move(databaseID), std::move(persistenceKey), + std::move(credentialsProvider), std::move(workerQueue), + (__bridge void *)self); _app = app; + _registry = registry; FSTPreConverterBlock block = ^id _Nullable(id _Nullable input) { if ([input isKindOfClass:[FIRDocumentReference class]]) { - FIRDocumentReference *documentReference = (FIRDocumentReference *)input; + auto documentReference = (FIRDocumentReference *)input; return [[FSTDocumentKeyReference alloc] initWithKey:documentReference.key databaseID:documentReference.firestore.databaseID]; } else { @@ -159,68 +153,154 @@ - (instancetype)initWithProjectID:(std::string)projectID } }; - _dataConverter = [[FSTUserDataConverter alloc] initWithDatabaseID:&_firestore->database_id() + _dataConverter = [[FSTUserDataConverter alloc] initWithDatabaseID:_firestore->database_id() preConverter:block]; + // Use the property setter so the default settings get plumbed into _firestoreClient. + self.settings = [[FIRFirestoreSettings alloc] init]; } return self; } - (FIRFirestoreSettings *)settings { - return _firestore->settings(); + // Disallow mutation of our internal settings + return [_settings copy]; } - (void)setSettings:(FIRFirestoreSettings *)settings { - _firestore->set_settings(settings); -} + if (![settings isEqual:_settings]) { + _settings = settings; + _firestore->set_settings([settings internalSettings]); -/** - * Ensures that the FirestoreClient is configured and returns it. - */ -- (FSTFirestoreClient *)client { - return _firestore->client(); + std::unique_ptr user_executor = + absl::make_unique(settings.dispatchQueue); + _firestore->set_user_executor(std::move(user_executor)); + } } - (FIRCollectionReference *)collectionWithPath:(NSString *)collectionPath { if (!collectionPath) { - FSTThrowInvalidArgument(@"Collection path cannot be nil."); + ThrowInvalidArgument("Collection path cannot be nil."); } if ([collectionPath containsString:@"//"]) { - FSTThrowInvalidArgument(@"Invalid path (%@). Paths must not contain // in them.", - collectionPath); + ThrowInvalidArgument("Invalid path (%s). Paths must not contain // in them.", collectionPath); } - return _firestore->GetCollection(util::MakeString(collectionPath)); + return [[FIRCollectionReference alloc] + initWithReference:_firestore->GetCollection(MakeString(collectionPath))]; } - (FIRDocumentReference *)documentWithPath:(NSString *)documentPath { if (!documentPath) { - FSTThrowInvalidArgument(@"Document path cannot be nil."); + ThrowInvalidArgument("Document path cannot be nil."); } if ([documentPath containsString:@"//"]) { - FSTThrowInvalidArgument(@"Invalid path (%@). Paths must not contain // in them.", documentPath); + ThrowInvalidArgument("Invalid path (%s). Paths must not contain // in them.", documentPath); } - DocumentReference documentReference = _firestore->GetDocument(util::MakeString(documentPath)); + DocumentReference documentReference = _firestore->GetDocument(MakeString(documentPath)); return [[FIRDocumentReference alloc] initWithReference:std::move(documentReference)]; } +- (FIRQuery *)collectionGroupWithID:(NSString *)collectionID { + if (!collectionID) { + ThrowInvalidArgument("Collection ID cannot be nil."); + } + if ([collectionID containsString:@"/"]) { + ThrowInvalidArgument("Invalid collection ID (%s). Collection IDs must not contain / in them.", + collectionID); + } + + auto query = _firestore->GetCollectionGroup(MakeString(collectionID)); + return [[FIRQuery alloc] initWithQuery:std::move(query) firestore:_firestore]; +} + - (FIRWriteBatch *)batch { - return _firestore->GetBatch(); + return [FIRWriteBatch writeBatchWithDataConverter:self.dataConverter + writeBatch:_firestore->GetBatch()]; } -- (void)runTransactionWithBlock:(id _Nullable (^)(FIRTransaction *, NSError **))updateBlock +- (void)runTransactionWithBlock:(UserUpdateBlock)updateBlock dispatchQueue:(dispatch_queue_t)queue - completion: - (void (^)(id _Nullable result, NSError *_Nullable error))completion { - // We wrap the function they provide in order to use internal implementation classes for - // transaction, and to run the user callback block on the proper queue. + completion:(UserTransactionCompletion)completion { if (!updateBlock) { - FSTThrowInvalidArgument(@"Transaction block cannot be nil."); - } else if (!completion) { - FSTThrowInvalidArgument(@"Transaction completion block cannot be nil."); + ThrowInvalidArgument("Transaction block cannot be nil."); } + if (!completion) { + ThrowInvalidArgument("Transaction completion block cannot be nil."); + } + + class TransactionResult { + public: + TransactionResult(FIRFirestore *firestore, + UserUpdateBlock update_block, + dispatch_queue_t queue, + UserTransactionCompletion completion) + : firestore_(firestore), + user_update_block_(update_block), + queue_(queue), + user_completion_(completion) { + } + + void RunUpdateBlock(std::shared_ptr internalTransaction, + core::TransactionResultCallback internalCallback) { + dispatch_async(queue_, ^{ + auto transaction = [FIRTransaction transactionWithInternalTransaction:internalTransaction + firestore:firestore_]; + + NSError *_Nullable error = nil; + user_result_ = user_update_block_(transaction, &error); + + // If the user set an error, disregard the result. + if (error) { + // If the error is a user error, set flag to not retry the transaction. + if (error.domain != FIRFirestoreErrorDomain) { + internalTransaction->MarkPermanentlyFailed(); + } + internalCallback(Status::FromNSError(error)); + } else { + internalCallback(Status::OK()); + } + }); + } + + void HandleFinalStatus(const Status &status) { + if (!status.ok()) { + user_completion_(nil, MakeNSError(status)); + return; + } - _firestore->RunTransaction(updateBlock, queue, completion); + user_completion_(user_result_, nil); + } + + private: + FIRFirestore *firestore_; + UserUpdateBlock user_update_block_; + dispatch_queue_t queue_; + UserTransactionCompletion user_completion_; + + id _Nullable user_result_; + }; + + auto result_capture = std::make_shared(self, updateBlock, queue, completion); + + // Wrap the user-supplied updateBlock in a core C++ compatible callback. Wrap the result of the + // updateBlock invocation up in a TransactionResult for tunneling through the internals of the + // system. + auto internalUpdateBlock = [result_capture]( + std::shared_ptr internalTransaction, + core::TransactionResultCallback internalCallback) { + result_capture->RunUpdateBlock(internalTransaction, internalCallback); + }; + + // Unpacks the TransactionResult value and calls the user completion handler. + // + // PORTING NOTE: Other platforms where the user return value is internally representable don't + // need this wrapper. + auto objcTranslator = [result_capture](const Status &status) { + result_capture->HandleFinalStatus(status); + }; + + _firestore->RunTransaction(std::move(internalUpdateBlock), std::move(objcTranslator)); } - (void)runTransactionWithBlock:(id _Nullable (^)(FIRTransaction *, NSError **error))updateBlock @@ -238,55 +318,64 @@ - (void)runTransactionWithBlock:(id _Nullable (^)(FIRTransaction *, NSError **er } + (void)enableLogging:(BOOL)logging { - FIRSetLoggerLevel(logging ? FIRLoggerLevelDebug : FIRLoggerLevelNotice); + util::LogSetLevel(logging ? util::kLogLevelDebug : util::kLogLevelNotice); } - (void)enableNetworkWithCompletion:(nullable void (^)(NSError *_Nullable error))completion { - _firestore->EnableNetwork(completion); + _firestore->EnableNetwork(MakeCallback(completion)); } - (void)disableNetworkWithCompletion:(nullable void (^)(NSError *_Nullable))completion { - _firestore->DisableNetwork(completion); + _firestore->DisableNetwork(MakeCallback(completion)); } -@end - -@implementation FIRFirestore (Internal) +- (void)clearPersistenceWithCompletion:(nullable void (^)(NSError *_Nullable error))completion { + _firestore->ClearPersistence(MakeCallback(completion)); +} -- (Firestore *)wrapped { - return _firestore.get(); +- (void)waitForPendingWritesWithCompletion:(void (^)(NSError *_Nullable error))completion { + _firestore->WaitForPendingWrites(MakeCallback(completion)); } -- (AsyncQueue *)workerQueue { - return _firestore->worker_queue(); +- (void)terminateWithCompletion:(nullable void (^)(NSError *_Nullable error))completion { + id strongRegistry = _registry; + if (strongRegistry) { + [strongRegistry + removeInstanceWithDatabase:MakeNSString(_firestore->database_id().database_id())]; + } + [self terminateInternalWithCompletion:completion]; } -- (const DatabaseId *)databaseID { - return &_firestore->database_id(); +- (id)addSnapshotsInSyncListener:(void (^)(void))listener { + std::unique_ptr> eventListener = + core::EventListener::Create([listener](const StatusOr &v) { listener(); }); + std::unique_ptr result = + _firestore->AddSnapshotsInSyncListener(std::move(eventListener)); + return [[FSTListenerRegistration alloc] initWithRegistration:std::move(result)]; } -+ (BOOL)isLoggingEnabled { - return FIRIsLoggableLevel(FIRLoggerLevelDebug, NO); +@end + +@implementation FIRFirestore (Internal) + +- (std::shared_ptr)wrapped { + return _firestore; } -+ (FIRFirestore *)recoverFromFirestore:(Firestore *)firestore { - return (__bridge FIRFirestore *)firestore->extension(); +- (const std::shared_ptr &)workerQueue { + return _firestore->worker_queue(); } -- (FIRQuery *)collectionGroupWithID:(NSString *)collectionID { - if (!collectionID) { - FSTThrowInvalidArgument(@"Collection ID cannot be nil."); - } - if ([collectionID containsString:@"/"]) { - FSTThrowInvalidArgument( - @"Invalid collection ID (%@). Collection IDs must not contain / in them.", collectionID); - } +- (const DatabaseId &)databaseID { + return _firestore->database_id(); +} - return _firestore->GetCollectionGroup(collectionID); ++ (FIRFirestore *)recoverFromFirestore:(std::shared_ptr)firestore { + return (__bridge FIRFirestore *)firestore->extension(); } -- (void)shutdownWithCompletion:(nullable void (^)(NSError *_Nullable error))completion { - _firestore->Shutdown(completion); +- (void)terminateInternalWithCompletion:(nullable void (^)(NSError *_Nullable error))completion { + _firestore->Terminate(MakeCallback(completion)); } @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestoreSettings+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestoreSettings+Internal.h new file mode 100644 index 0000000..44d4226 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestoreSettings+Internal.h @@ -0,0 +1,32 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import "FIRFirestoreSettings.h" + +#import + +#include "Firestore/core/src/firebase/firestore/api/settings.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFirestoreSettings (Internal) + +/** Converts this FIRFirestoreSettings instance into an api::Settings object. */ +- (firebase::firestore::api::Settings)internalSettings; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestoreSettings.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestoreSettings.mm index 3dd7dbd..278f75a 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestoreSettings.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestoreSettings.mm @@ -14,31 +14,36 @@ * limitations under the License. */ -#include "Firestore/core/src/firebase/firestore/util/warnings.h" - #import "FIRFirestoreSettings.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" +#include "Firestore/core/src/firebase/firestore/api/settings.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" +#include "Firestore/core/src/firebase/firestore/util/warnings.h" +#include "absl/base/attributes.h" +#include "absl/memory/memory.h" NS_ASSUME_NONNULL_BEGIN -static NSString *const kDefaultHost = @"firestore.googleapis.com"; -static const BOOL kDefaultSSLEnabled = YES; -static const BOOL kDefaultPersistenceEnabled = YES; -static const int64_t kDefaultCacheSizeBytes = 100 * 1024 * 1024; -static const int64_t kMinimumCacheSizeBytes = 1 * 1024 * 1024; -static const BOOL kDefaultTimestampsInSnapshotsEnabled = YES; +namespace api = firebase::firestore::api; +namespace util = firebase::firestore::util; +using api::Settings; +using util::ThrowInvalidArgument; + +// Public constant +ABSL_CONST_INIT extern "C" const int64_t kFIRFirestoreCacheSizeUnlimited = + api::Settings::CacheSizeUnlimited; @implementation FIRFirestoreSettings - (instancetype)init { if (self = [super init]) { - _host = kDefaultHost; - _sslEnabled = kDefaultSSLEnabled; + _host = [NSString stringWithUTF8String:Settings::DefaultHost]; + _sslEnabled = Settings::DefaultSslEnabled; _dispatchQueue = dispatch_get_main_queue(); - _persistenceEnabled = kDefaultPersistenceEnabled; - _timestampsInSnapshotsEnabled = kDefaultTimestampsInSnapshotsEnabled; - _cacheSizeBytes = kDefaultCacheSizeBytes; + _persistenceEnabled = Settings::DefaultPersistenceEnabled; + _timestampsInSnapshotsEnabled = Settings::DefaultTimestampsInSnapshotsEnabled; + _cacheSizeBytes = Settings::DefaultCacheSizeBytes; } return self; } @@ -88,32 +93,42 @@ - (id)copyWithZone:(nullable NSZone *)zone { - (void)setHost:(NSString *)host { if (!host) { - FSTThrowInvalidArgument( - @"host setting may not be nil. You should generally just use the default value " - "(which is %@)", - kDefaultHost); + ThrowInvalidArgument("Host setting may not be nil. You should generally just use the default " + "value (which is %s)", + Settings::DefaultHost); } _host = [host mutableCopy]; } - (void)setDispatchQueue:(dispatch_queue_t)dispatchQueue { if (!dispatchQueue) { - FSTThrowInvalidArgument( - @"dispatch queue setting may not be nil. Create a new dispatch queue with " - "dispatch_queue_create(\"com.example.MyQueue\", NULL) or just use the default " - "(which is the main queue, returned from dispatch_get_main_queue())"); + ThrowInvalidArgument( + "Dispatch queue setting may not be nil. Create a new dispatch queue with " + "dispatch_queue_create(\"com.example.MyQueue\", NULL) or just use the default (which is " + "the main queue, returned from dispatch_get_main_queue())"); } _dispatchQueue = dispatchQueue; } - (void)setCacheSizeBytes:(int64_t)cacheSizeBytes { if (cacheSizeBytes != kFIRFirestoreCacheSizeUnlimited && - cacheSizeBytes < kMinimumCacheSizeBytes) { - FSTThrowInvalidArgument(@"Cache size must be set to at least %i bytes", kMinimumCacheSizeBytes); + cacheSizeBytes < Settings::MinimumCacheSizeBytes) { + ThrowInvalidArgument("Cache size must be set to at least %s bytes", + Settings::MinimumCacheSizeBytes); } _cacheSizeBytes = cacheSizeBytes; } +- (api::Settings)internalSettings { + api::Settings settings; + settings.set_host(util::MakeString(_host)); + settings.set_ssl_enabled(_sslEnabled); + settings.set_persistence_enabled(_persistenceEnabled); + settings.set_timestamps_in_snapshots_enabled(_timestampsInSnapshotsEnabled); + settings.set_cache_size_bytes(_cacheSizeBytes); + return settings; +} + @end NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestoreSource+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestoreSource+Internal.h new file mode 100644 index 0000000..694a7de --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestoreSource+Internal.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import "FIRFirestoreSource.h" + +#include "Firestore/core/src/firebase/firestore/api/source.h" + +namespace firebase { +namespace firestore { +namespace api { + +Source MakeSource(FIRFirestoreSource source); + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestoreSource.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestoreSource.mm new file mode 100644 index 0000000..9d3444a --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestoreSource.mm @@ -0,0 +1,41 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import "Firestore/Source/API/FIRFirestoreSource+Internal.h" + +#include "Firestore/core/src/firebase/firestore/api/source.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" + +namespace firebase { +namespace firestore { +namespace api { + +Source MakeSource(FIRFirestoreSource source) { + switch (source) { + case FIRFirestoreSourceDefault: + return Source::Default; + case FIRFirestoreSourceServer: + return Source::Server; + case FIRFirestoreSourceCache: + return Source::Cache; + } + + UNREACHABLE(); +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRGeoPoint+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRGeoPoint+Internal.h index 6eb8548..4fe0f57 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRGeoPoint+Internal.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRGeoPoint+Internal.h @@ -20,7 +20,9 @@ NS_ASSUME_NONNULL_BEGIN /** Internal FIRGeoPoint API we don't want exposed in our public header files. */ @interface FIRGeoPoint (Internal) + - (NSComparisonResult)compare:(FIRGeoPoint *)other; + @end NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRGeoPoint.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRGeoPoint.mm index cfd70fb..2e6c442 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRGeoPoint.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRGeoPoint.mm @@ -16,10 +16,11 @@ #import "Firestore/Source/API/FIRGeoPoint+Internal.h" -#import "Firestore/core/src/firebase/firestore/util/comparison.h" - -#import "Firestore/Source/Util/FSTUsageValidation.h" +#include "Firestore/core/include/firebase/firestore/geo_point.h" +#include "Firestore/core/src/firebase/firestore/util/comparison.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" +using firebase::firestore::util::ThrowInvalidArgument; using firebase::firestore::util::DoubleBitwiseEquals; using firebase::firestore::util::DoubleBitwiseHash; using firebase::firestore::util::WrapCompare; @@ -31,14 +32,14 @@ @implementation FIRGeoPoint - (instancetype)initWithLatitude:(double)latitude longitude:(double)longitude { if (self = [super init]) { if (latitude < -90 || latitude > 90 || !isfinite(latitude)) { - FSTThrowInvalidArgument(@"GeoPoint requires a latitude value in the range of [-90, 90], " - "but was %f", - latitude); + ThrowInvalidArgument("GeoPoint requires a latitude value in the range of [-90, 90], " + "but was %s", + latitude); } if (longitude < -180 || longitude > 180 || !isfinite(longitude)) { - FSTThrowInvalidArgument(@"GeoPoint requires a longitude value in the range of [-180, 180], " - "but was %f", - longitude); + ThrowInvalidArgument("GeoPoint requires a longitude value in the range of [-180, 180], " + "but was %s", + longitude); } _latitude = latitude; @@ -47,15 +48,6 @@ - (instancetype)initWithLatitude:(double)latitude longitude:(double)longitude { return self; } -- (NSComparisonResult)compare:(FIRGeoPoint *)other { - NSComparisonResult result = WrapCompare(self.latitude, other.latitude); - if (result != NSOrderedSame) { - return result; - } else { - return WrapCompare(self.longitude, other.longitude); - } -} - #pragma mark - NSObject methods - (NSString *)description { @@ -85,4 +77,17 @@ - (id)copyWithZone:(NSZone *_Nullable)zone { @end +@implementation FIRGeoPoint (Internal) + +- (NSComparisonResult)compare:(FIRGeoPoint *)other { + NSComparisonResult result = WrapCompare(self.latitude, other.latitude); + if (result != NSOrderedSame) { + return result; + } else { + return WrapCompare(self.longitude, other.longitude); + } +} + +@end + NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRListenerRegistration+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRListenerRegistration+Internal.h index e3f1cd5..9630da8 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRListenerRegistration+Internal.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRListenerRegistration+Internal.h @@ -14,18 +14,20 @@ * limitations under the License. */ +#include + #import "FIRListenerRegistration.h" #include "Firestore/core/src/firebase/firestore/api/listener_registration.h" -NS_ASSUME_NONNULL_BEGIN +namespace api = firebase::firestore::api; -using firebase::firestore::api::ListenerRegistration; +NS_ASSUME_NONNULL_BEGIN /** Private implementation of the FIRListenerRegistration protocol. */ @interface FSTListenerRegistration : NSObject -- (instancetype)initWithRegistration:(ListenerRegistration &&)registration; +- (instancetype)initWithRegistration:(std::unique_ptr)registration; @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRListenerRegistration.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRListenerRegistration.mm index b69b9fb..82b09d2 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRListenerRegistration.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRListenerRegistration.mm @@ -14,23 +14,17 @@ * limitations under the License. */ -#include - #import "Firestore/Source/API/FIRListenerRegistration+Internal.h" -#include "Firestore/core/src/firebase/firestore/util/delayed_constructor.h" - NS_ASSUME_NONNULL_BEGIN -using firebase::firestore::util::DelayedConstructor; - @implementation FSTListenerRegistration { - DelayedConstructor _registration; + std::unique_ptr _registration; } -- (instancetype)initWithRegistration:(ListenerRegistration &&)registration { +- (instancetype)initWithRegistration:(std::unique_ptr)registration { if (self = [super init]) { - _registration.Init(std::move(registration)); + _registration = std::move(registration); } return self; } diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuery+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuery+Internal.h index fa6c415..c0a74c4 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuery+Internal.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuery+Internal.h @@ -16,15 +16,31 @@ #import "FIRQuery.h" -@class FSTQuery; +#include + +#include "Firestore/core/src/firebase/firestore/api/query_core.h" +#include "Firestore/core/src/firebase/firestore/core/query.h" + +namespace api = firebase::firestore::api; +namespace core = firebase::firestore::core; NS_ASSUME_NONNULL_BEGIN +@interface FIRQuery (/* Init */) + +- (instancetype)initWithQuery:(api::Query &&)query NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithQuery:(core::Query)query + firestore:(std::shared_ptr)firestore; + +@end + /** Internal FIRQuery API we don't want exposed in our public header files. */ @interface FIRQuery (Internal) -+ (FIRQuery *)referenceWithQuery:(FSTQuery *)query firestore:(FIRFirestore *)firestore; -@property(nonatomic, strong, readonly) FSTQuery *query; +- (const core::Query &)query; + +- (const api::Query &)apiQuery; @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuery.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuery.mm index 507e1f3..5be6369 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuery.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuery.mm @@ -18,144 +18,141 @@ #include #include +#include #import "FIRDocumentReference.h" #import "FIRFirestoreErrors.h" -#import "FIRFirestoreSource.h" #import "Firestore/Source/API/FIRDocumentReference+Internal.h" #import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h" #import "Firestore/Source/API/FIRFieldPath+Internal.h" #import "Firestore/Source/API/FIRFieldValue+Internal.h" #import "Firestore/Source/API/FIRFirestore+Internal.h" +#import "Firestore/Source/API/FIRFirestoreSource+Internal.h" #import "Firestore/Source/API/FIRListenerRegistration+Internal.h" #import "Firestore/Source/API/FIRQuery+Internal.h" #import "Firestore/Source/API/FIRQuerySnapshot+Internal.h" -#import "Firestore/Source/API/FIRQuery_Init.h" #import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h" #import "Firestore/Source/API/FSTUserDataConverter.h" -#import "Firestore/Source/Core/FSTEventManager.h" -#import "Firestore/Source/Core/FSTFirestoreClient.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" +#include "Firestore/core/src/firebase/firestore/api/query_core.h" +#include "Firestore/core/src/firebase/firestore/api/query_listener_registration.h" +#include "Firestore/core/src/firebase/firestore/core/bound.h" +#include "Firestore/core/src/firebase/firestore/core/direction.h" +#include "Firestore/core/src/firebase/firestore/core/filter.h" +#include "Firestore/core/src/firebase/firestore/core/firestore_client.h" +#include "Firestore/core/src/firebase/firestore/core/order_by.h" +#include "Firestore/core/src/firebase/firestore/core/query.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/util/error_apple.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/statusor.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" +#include "absl/memory/memory.h" namespace util = firebase::firestore::util; +using firebase::firestore::api::Firestore; +using firebase::firestore::api::ListenerRegistration; +using firebase::firestore::api::Query; +using firebase::firestore::api::QueryListenerRegistration; +using firebase::firestore::api::QuerySnapshot; +using firebase::firestore::api::SnapshotMetadata; +using firebase::firestore::api::Source; using firebase::firestore::core::AsyncEventListener; +using firebase::firestore::core::Bound; +using firebase::firestore::core::Direction; using firebase::firestore::core::EventListener; +using firebase::firestore::core::Filter; +using firebase::firestore::core::ListenOptions; +using firebase::firestore::core::OrderBy; +using firebase::firestore::core::OrderByList; +using firebase::firestore::core::QueryListener; using firebase::firestore::core::ViewSnapshot; +using firebase::firestore::model::DatabaseId; +using firebase::firestore::model::Document; using firebase::firestore::model::DocumentKey; using firebase::firestore::model::FieldPath; +using firebase::firestore::model::FieldValue; using firebase::firestore::model::ResourcePath; using firebase::firestore::util::MakeNSError; +using firebase::firestore::util::MakeString; using firebase::firestore::util::StatusOr; +using firebase::firestore::util::ThrowInvalidArgument; NS_ASSUME_NONNULL_BEGIN -@interface FIRQuery () -@property(nonatomic, strong, readonly) FSTQuery *query; -@end +namespace { -@implementation FIRQuery (Internal) -+ (instancetype)referenceWithQuery:(FSTQuery *)query firestore:(FIRFirestore *)firestore { - return [[FIRQuery alloc] initWithQuery:query firestore:firestore]; +FieldPath MakeFieldPath(NSString *field) { + return FieldPath::FromDotSeparatedString(MakeString(field)); } -@end -@implementation FIRQuery +FIRQuery *Wrap(Query &&query) { + return [[FIRQuery alloc] initWithQuery:std::move(query)]; +} + +int32_t SaturatedLimitValue(NSInteger limit) { + int32_t internal_limit; + if (limit == NSNotFound || limit >= core::Target::kNoLimit) { + internal_limit = core::Target::kNoLimit; + } else { + internal_limit = static_cast(limit); + } + return internal_limit; +} + +} // namespace + +@implementation FIRQuery { + Query _query; +} #pragma mark - Constructor Methods -- (instancetype)initWithQuery:(FSTQuery *)query firestore:(FIRFirestore *)firestore { +- (instancetype)initWithQuery:(Query &&)query { if (self = [super init]) { - _query = query; - _firestore = firestore; + _query = std::move(query); } return self; } +- (instancetype)initWithQuery:(core::Query)query firestore:(std::shared_ptr)firestore { + return [self initWithQuery:Query{std::move(query), std::move(firestore)}]; +} + #pragma mark - NSObject Methods - (BOOL)isEqual:(nullable id)other { if (other == self) return YES; if (![[other class] isEqual:[self class]]) return NO; - return [self isEqualToQuery:other]; -} - -- (BOOL)isEqualToQuery:(nullable FIRQuery *)query { - if (self == query) return YES; - if (query == nil) return NO; - - return [self.firestore isEqual:query.firestore] && [self.query isEqual:query.query]; + auto otherQuery = static_cast(other); + return _query == otherQuery->_query; } - (NSUInteger)hash { - NSUInteger hash = [self.firestore hash]; - hash = hash * 31u + [self.query hash]; - return hash; + return _query.Hash(); } #pragma mark - Public Methods +- (FIRFirestore *)firestore { + return [FIRFirestore recoverFromFirestore:_query.firestore()]; +} + - (void)getDocumentsWithCompletion:(void (^)(FIRQuerySnapshot *_Nullable snapshot, NSError *_Nullable error))completion { - [self getDocumentsWithSource:FIRFirestoreSourceDefault completion:completion]; + _query.GetDocuments(Source::Default, [self wrapQuerySnapshotBlock:completion]); } -- (void)getDocumentsWithSource:(FIRFirestoreSource)source +- (void)getDocumentsWithSource:(FIRFirestoreSource)publicSource completion:(void (^)(FIRQuerySnapshot *_Nullable snapshot, NSError *_Nullable error))completion { - if (source == FIRFirestoreSourceCache) { - [self.firestore.client getDocumentsFromLocalCache:self completion:completion]; - return; - } - - ListenOptions listenOptions( - /*include_query_metadata_changes=*/true, - /*include_document_metadata_changes=*/true, - /*wait_for_sync_when_online=*/true); - - dispatch_semaphore_t registered = dispatch_semaphore_create(0); - __block id listenerRegistration; - FIRQuerySnapshotBlock listener = ^(FIRQuerySnapshot *snapshot, NSError *error) { - if (error) { - completion(nil, error); - return; - } - - // Remove query first before passing event to user to avoid user actions affecting the - // now stale query. - dispatch_semaphore_wait(registered, DISPATCH_TIME_FOREVER); - [listenerRegistration remove]; - - if (snapshot.metadata.fromCache && source == FIRFirestoreSourceServer) { - completion(nil, - [NSError errorWithDomain:FIRFirestoreErrorDomain - code:FIRFirestoreErrorCodeUnavailable - userInfo:@{ - NSLocalizedDescriptionKey : - @"Failed to get documents from server. (However, these " - @"documents may exist in the local cache. Run again " - @"without setting source to FIRFirestoreSourceServer to " - @"retrieve the cached documents.)" - }]); - } else { - completion(snapshot, nil); - } - }; - - listenerRegistration = [self addSnapshotListenerInternalWithOptions:listenOptions - listener:listener]; - dispatch_semaphore_signal(registered); + Source source = api::MakeSource(publicSource); + _query.GetDocuments(source, [self wrapQuerySnapshotBlock:completion]); } - (id)addSnapshotListener:(FIRQuerySnapshotBlock)listener { @@ -172,8 +169,8 @@ ListenOptions listenOptions( - (id)addSnapshotListenerInternalWithOptions:(ListenOptions)internalOptions listener: (FIRQuerySnapshotBlock)listener { - Firestore *firestore = self.firestore.wrapped; - FSTQuery *query = self.query; + std::shared_ptr firestore = self.firestore.wrapped; + const core::Query &query = self.query; // Convert from ViewSnapshots to QuerySnapshots. auto view_listener = EventListener::Create( @@ -194,89 +191,100 @@ ListenOptions listenOptions( }); // Call the view_listener on the user Executor. - auto async_listener = AsyncEventListener::Create(firestore->client().userExecutor, - std::move(view_listener)); + auto async_listener = AsyncEventListener::Create( + firestore->client()->user_executor(), std::move(view_listener)); std::shared_ptr query_listener = - [firestore->client() listenToQuery:query options:internalOptions listener:async_listener]; + firestore->client()->ListenToQuery(query, internalOptions, async_listener); return [[FSTListenerRegistration alloc] - initWithRegistration:ListenerRegistration(firestore->client(), std::move(async_listener), - std::move(query_listener))]; + initWithRegistration:absl::make_unique(firestore->client(), + std::move(async_listener), + std::move(query_listener))]; } - (FIRQuery *)queryWhereField:(NSString *)field isEqualTo:(id)value { - return [self queryWithFilterOperator:FSTRelationFilterOperatorEqual field:field value:value]; + return [self queryWithFilterOperator:Filter::Operator::Equal field:field value:value]; } - (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path isEqualTo:(id)value { - return [self queryWithFilterOperator:FSTRelationFilterOperatorEqual - path:path.internalValue - value:value]; + return [self queryWithFilterOperator:Filter::Operator::Equal path:path.internalValue value:value]; } - (FIRQuery *)queryWhereField:(NSString *)field isLessThan:(id)value { - return [self queryWithFilterOperator:FSTRelationFilterOperatorLessThan field:field value:value]; + return [self queryWithFilterOperator:Filter::Operator::LessThan field:field value:value]; } - (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path isLessThan:(id)value { - return [self queryWithFilterOperator:FSTRelationFilterOperatorLessThan + return [self queryWithFilterOperator:Filter::Operator::LessThan path:path.internalValue value:value]; } - (FIRQuery *)queryWhereField:(NSString *)field isLessThanOrEqualTo:(id)value { - return [self queryWithFilterOperator:FSTRelationFilterOperatorLessThanOrEqual - field:field - value:value]; + return [self queryWithFilterOperator:Filter::Operator::LessThanOrEqual field:field value:value]; } - (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path isLessThanOrEqualTo:(id)value { - return [self queryWithFilterOperator:FSTRelationFilterOperatorLessThanOrEqual + return [self queryWithFilterOperator:Filter::Operator::LessThanOrEqual path:path.internalValue value:value]; } - (FIRQuery *)queryWhereField:(NSString *)field isGreaterThan:(id)value { - return [self queryWithFilterOperator:FSTRelationFilterOperatorGreaterThan - field:field - value:value]; + return [self queryWithFilterOperator:Filter::Operator::GreaterThan field:field value:value]; } - (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path isGreaterThan:(id)value { - return [self queryWithFilterOperator:FSTRelationFilterOperatorGreaterThan + return [self queryWithFilterOperator:Filter::Operator::GreaterThan path:path.internalValue value:value]; } - (FIRQuery *)queryWhereField:(NSString *)field arrayContains:(id)value { - return [self queryWithFilterOperator:FSTRelationFilterOperatorArrayContains - field:field - value:value]; + return [self queryWithFilterOperator:Filter::Operator::ArrayContains field:field value:value]; } - (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path arrayContains:(id)value { - return [self queryWithFilterOperator:FSTRelationFilterOperatorArrayContains + return [self queryWithFilterOperator:Filter::Operator::ArrayContains path:path.internalValue value:value]; } - (FIRQuery *)queryWhereField:(NSString *)field isGreaterThanOrEqualTo:(id)value { - return [self queryWithFilterOperator:FSTRelationFilterOperatorGreaterThanOrEqual + return [self queryWithFilterOperator:Filter::Operator::GreaterThanOrEqual field:field value:value]; } - (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path isGreaterThanOrEqualTo:(id)value { - return [self queryWithFilterOperator:FSTRelationFilterOperatorGreaterThanOrEqual + return [self queryWithFilterOperator:Filter::Operator::GreaterThanOrEqual path:path.internalValue value:value]; } +- (FIRQuery *)queryWhereField:(NSString *)field arrayContainsAny:(NSArray *)values { + return [self queryWithFilterOperator:Filter::Operator::ArrayContainsAny field:field value:values]; +} + +- (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path arrayContainsAny:(NSArray *)values { + return [self queryWithFilterOperator:Filter::Operator::ArrayContainsAny + path:path.internalValue + value:values]; +} + +- (FIRQuery *)queryWhereField:(NSString *)field in:(NSArray *)values { + return [self queryWithFilterOperator:Filter::Operator::In field:field value:values]; +} + +- (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path in:(NSArray *)values { + return [self queryWithFilterOperator:Filter::Operator::In path:path.internalValue value:values]; +} + - (FIRQuery *)queryFilteredUsingComparisonPredicate:(NSPredicate *)predicate { NSComparisonPredicate *comparison = (NSComparisonPredicate *)predicate; if (comparison.comparisonPredicateModifier != NSDirectPredicateModifier) { - FSTThrowInvalidArgument(@"Invalid query. Predicate cannot have an aggregate modifier."); + ThrowInvalidArgument("Invalid query. Predicate cannot have an aggregate modifier."); } NSString *path; id value = nil; @@ -315,24 +323,24 @@ - (FIRQuery *)queryFilteredUsingComparisonPredicate:(NSPredicate *)predicate { default:; // Fallback below to throw assertion. } } else { - FSTThrowInvalidArgument( - @"Invalid query. Predicate comparisons must include a key path and a constant."); + ThrowInvalidArgument( + "Invalid query. Predicate comparisons must include a key path and a constant."); } // Fallback cases of unsupported comparison operator. switch (comparison.predicateOperatorType) { case NSCustomSelectorPredicateOperatorType: - FSTThrowInvalidArgument(@"Invalid query. Custom predicate filters are not supported."); + ThrowInvalidArgument("Invalid query. Custom predicate filters are not supported."); break; default: - FSTThrowInvalidArgument(@"Invalid query. Operator type %lu is not supported.", - (unsigned long)comparison.predicateOperatorType); + ThrowInvalidArgument("Invalid query. Operator type %s is not supported.", + comparison.predicateOperatorType); } } - (FIRQuery *)queryFilteredUsingCompoundPredicate:(NSPredicate *)predicate { NSCompoundPredicate *compound = (NSCompoundPredicate *)predicate; if (compound.compoundPredicateType != NSAndPredicateType || compound.subpredicates.count == 0) { - FSTThrowInvalidArgument(@"Invalid query. Only compound queries using AND are supported."); + ThrowInvalidArgument("Invalid query. Only compound queries using AND are supported."); } FIRQuery *query = self; for (NSPredicate *pred in compound.subpredicates) { @@ -350,19 +358,16 @@ - (FIRQuery *)queryFilteredUsingPredicate:(NSPredicate *)predicate { predicateWithBlock:^BOOL(id obj, NSDictionary *bindings) { return true; }] class]]) { - FSTThrowInvalidArgument(@"Invalid query. Block-based predicates are not " - "supported. Please use predicateWithFormat to " - "create predicates instead."); + ThrowInvalidArgument("Invalid query. Block-based predicates are not supported. Please use " + "predicateWithFormat to create predicates instead."); } else { - FSTThrowInvalidArgument(@"Invalid query. Expect comparison or compound of " - "comparison predicate. Please use " - "predicateWithFormat to create predicates."); + ThrowInvalidArgument("Invalid query. Expect comparison or compound of comparison predicate. " + "Please use predicateWithFormat to create predicates."); } } - (FIRQuery *)queryOrderedByField:(NSString *)field { - return [self queryOrderedByFieldPath:[FIRFieldPath pathWithDotSeparatedString:field] - descending:NO]; + return [self queryOrderedByField:field descending:NO]; } - (FIRQuery *)queryOrderedByFieldPath:(FIRFieldPath *)fieldPath { @@ -370,301 +375,219 @@ - (FIRQuery *)queryOrderedByFieldPath:(FIRFieldPath *)fieldPath { } - (FIRQuery *)queryOrderedByField:(NSString *)field descending:(BOOL)descending { - return [self queryOrderedByFieldPath:[FIRFieldPath pathWithDotSeparatedString:field] - descending:descending]; + return [self queryOrderedByFieldPath:MakeFieldPath(field) + direction:Direction::FromDescending(descending)]; } - (FIRQuery *)queryOrderedByFieldPath:(FIRFieldPath *)fieldPath descending:(BOOL)descending { - [self validateNewOrderByPath:fieldPath.internalValue]; - if (self.query.startAt) { - FSTThrowInvalidUsage( - @"InvalidQueryException", - @"Invalid query. You must not specify a starting point before specifying the order by."); - } - if (self.query.endAt) { - FSTThrowInvalidUsage( - @"InvalidQueryException", - @"Invalid query. You must not specify an ending point before specifying the order by."); - } - FSTSortOrder *sortOrder = [FSTSortOrder sortOrderWithFieldPath:fieldPath.internalValue - ascending:!descending]; - return [FIRQuery referenceWithQuery:[self.query queryByAddingSortOrder:sortOrder] - firestore:self.firestore]; + return [self queryOrderedByFieldPath:fieldPath.internalValue + direction:Direction::FromDescending(descending)]; +} + +- (FIRQuery *)queryOrderedByFieldPath:(model::FieldPath)fieldPath direction:(Direction)direction { + return Wrap(_query.OrderBy(std::move(fieldPath), direction)); } - (FIRQuery *)queryLimitedTo:(NSInteger)limit { - if (limit <= 0) { - FSTThrowInvalidArgument(@"Invalid Query. Query limit (%ld) is invalid. Limit must be positive.", - (long)limit); - } - return [FIRQuery referenceWithQuery:[self.query queryBySettingLimit:limit] firestore:_firestore]; + return Wrap(_query.LimitToFirst(SaturatedLimitValue(limit))); +} + +- (FIRQuery *)queryLimitedToLast:(NSInteger)limit { + return Wrap(_query.LimitToLast(SaturatedLimitValue(limit))); } - (FIRQuery *)queryStartingAtDocument:(FIRDocumentSnapshot *)snapshot { - FSTBound *bound = [self boundFromSnapshot:snapshot isBefore:YES]; - return [FIRQuery referenceWithQuery:[self.query queryByAddingStartAt:bound] - firestore:self.firestore]; + Bound bound = [self boundFromSnapshot:snapshot isBefore:YES]; + return Wrap(_query.StartAt(std::move(bound))); } - (FIRQuery *)queryStartingAtValues:(NSArray *)fieldValues { - FSTBound *bound = [self boundFromFieldValues:fieldValues isBefore:YES]; - return [FIRQuery referenceWithQuery:[self.query queryByAddingStartAt:bound] - firestore:self.firestore]; + Bound bound = [self boundFromFieldValues:fieldValues isBefore:YES]; + return Wrap(_query.StartAt(std::move(bound))); } - (FIRQuery *)queryStartingAfterDocument:(FIRDocumentSnapshot *)snapshot { - FSTBound *bound = [self boundFromSnapshot:snapshot isBefore:NO]; - return [FIRQuery referenceWithQuery:[self.query queryByAddingStartAt:bound] - firestore:self.firestore]; + Bound bound = [self boundFromSnapshot:snapshot isBefore:NO]; + return Wrap(_query.StartAt(std::move(bound))); } - (FIRQuery *)queryStartingAfterValues:(NSArray *)fieldValues { - FSTBound *bound = [self boundFromFieldValues:fieldValues isBefore:NO]; - return [FIRQuery referenceWithQuery:[self.query queryByAddingStartAt:bound] - firestore:self.firestore]; + Bound bound = [self boundFromFieldValues:fieldValues isBefore:NO]; + return Wrap(_query.StartAt(std::move(bound))); } - (FIRQuery *)queryEndingBeforeDocument:(FIRDocumentSnapshot *)snapshot { - FSTBound *bound = [self boundFromSnapshot:snapshot isBefore:YES]; - return [FIRQuery referenceWithQuery:[self.query queryByAddingEndAt:bound] - firestore:self.firestore]; + Bound bound = [self boundFromSnapshot:snapshot isBefore:YES]; + return Wrap(_query.EndAt(std::move(bound))); } - (FIRQuery *)queryEndingBeforeValues:(NSArray *)fieldValues { - FSTBound *bound = [self boundFromFieldValues:fieldValues isBefore:YES]; - return [FIRQuery referenceWithQuery:[self.query queryByAddingEndAt:bound] - firestore:self.firestore]; + Bound bound = [self boundFromFieldValues:fieldValues isBefore:YES]; + return Wrap(_query.EndAt(std::move(bound))); } - (FIRQuery *)queryEndingAtDocument:(FIRDocumentSnapshot *)snapshot { - FSTBound *bound = [self boundFromSnapshot:snapshot isBefore:NO]; - return [FIRQuery referenceWithQuery:[self.query queryByAddingEndAt:bound] - firestore:self.firestore]; + Bound bound = [self boundFromSnapshot:snapshot isBefore:NO]; + return Wrap(_query.EndAt(std::move(bound))); } - (FIRQuery *)queryEndingAtValues:(NSArray *)fieldValues { - FSTBound *bound = [self boundFromFieldValues:fieldValues isBefore:NO]; - return [FIRQuery referenceWithQuery:[self.query queryByAddingEndAt:bound] - firestore:self.firestore]; + Bound bound = [self boundFromFieldValues:fieldValues isBefore:NO]; + return Wrap(_query.EndAt(std::move(bound))); } #pragma mark - Private Methods -/** Private helper for all of the queryWhereField: methods. */ -- (FIRQuery *)queryWithFilterOperator:(FSTRelationFilterOperator)filterOperator - field:(NSString *)field - value:(id)value { - return [self queryWithFilterOperator:filterOperator - path:[FIRFieldPath pathWithDotSeparatedString:field].internalValue - value:value]; +- (FieldValue)parsedQueryValue:(id)value { + return [self.firestore.dataConverter parsedQueryValue:value]; } -- (FIRQuery *)queryWithFilterOperator:(FSTRelationFilterOperator)filterOperator - path:(const FieldPath &)fieldPath - value:(id)value { - FSTFieldValue *fieldValue; - if (fieldPath.IsKeyFieldPath()) { - if (filterOperator == FSTRelationFilterOperatorArrayContains) { - FSTThrowInvalidArgument( - @"Invalid query. You can't perform arrayContains queries on document ID since document " - "IDs are not arrays."); - } - if ([value isKindOfClass:[NSString class]]) { - NSString *documentKey = (NSString *)value; - if (documentKey.length == 0) { - FSTThrowInvalidArgument(@"Invalid query. When querying by document ID you must provide " - "a valid document ID, but it was an empty string."); - } - if (![self.query isCollectionGroupQuery] && [documentKey containsString:@"/"]) { - FSTThrowInvalidArgument( - @"Invalid query. When querying a collection by document ID you must provide " - "a plain document ID, but '%@' contains a '/' character.", - documentKey); - } - ResourcePath path = - self.query.path.Append(ResourcePath::FromString([documentKey UTF8String])); - if (!DocumentKey::IsDocumentKey(path)) { - FSTThrowInvalidArgument( - @"Invalid query. When querying a collection group by document ID, " - "the value provided must result in a valid document path, but '%s' is not because it " - "has an odd number of segments.", - path.CanonicalString().c_str()); - } - fieldValue = - [FSTReferenceValue referenceValue:[FSTDocumentKey keyWithDocumentKey:DocumentKey{path}] - databaseID:self.firestore.databaseID]; - } else if ([value isKindOfClass:[FIRDocumentReference class]]) { - FIRDocumentReference *ref = (FIRDocumentReference *)value; - fieldValue = [FSTReferenceValue referenceValue:[FSTDocumentKey keyWithDocumentKey:ref.key] - databaseID:self.firestore.databaseID]; - } else { - FSTThrowInvalidArgument(@"Invalid query. When querying by document ID you must provide a " - "valid string or DocumentReference, but it was of type: %@", - NSStringFromClass([value class])); - } - } else { - fieldValue = [self.firestore.dataConverter parsedQueryValue:value]; - } - - FSTFilter *filter = [FSTFilter filterWithField:fieldPath - filterOperator:filterOperator - value:fieldValue]; - - if ([filter isKindOfClass:[FSTRelationFilter class]]) { - [self validateNewRelationFilter:(FSTRelationFilter *)filter]; - } - - return [FIRQuery referenceWithQuery:[self.query queryByAddingFilter:filter] - firestore:self.firestore]; +- (FieldValue)parsedQueryValue:(id)value allowArrays:(bool)allowArrays { + return [self.firestore.dataConverter parsedQueryValue:value allowArrays:allowArrays]; } -- (void)validateNewRelationFilter:(FSTRelationFilter *)filter { - if ([filter isInequality]) { - const FieldPath *existingField = [self.query inequalityFilterField]; - if (existingField && *existingField != filter.field) { - FSTThrowInvalidUsage( - @"InvalidQueryException", - @"Invalid Query. All where filters with an inequality " - "(lessThan, lessThanOrEqual, greaterThan, or greaterThanOrEqual) must be on the same " - "field. But you have inequality filters on '%s' and '%s'", - existingField->CanonicalString().c_str(), filter.field.CanonicalString().c_str()); +- (QuerySnapshot::Listener)wrapQuerySnapshotBlock:(FIRQuerySnapshotBlock)block { + class Converter : public EventListener { + public: + explicit Converter(FIRQuerySnapshotBlock block) : block_(block) { } - const FieldPath *firstOrderByField = [self.query firstSortOrderField]; - if (firstOrderByField) { - [self validateOrderByField:*firstOrderByField matchesInequalityField:filter.field]; - } - } else if (filter.filterOperator == FSTRelationFilterOperatorArrayContains) { - if ([self.query hasArrayContainsFilter]) { - FSTThrowInvalidUsage(@"InvalidQueryException", - @"Invalid Query. Queries only support a single arrayContains filter."); + void OnEvent(StatusOr maybe_snapshot) override { + if (maybe_snapshot.ok()) { + FIRQuerySnapshot *result = + [[FIRQuerySnapshot alloc] initWithSnapshot:std::move(maybe_snapshot).ValueOrDie()]; + block_(result, nil); + } else { + block_(nil, util::MakeNSError(maybe_snapshot.status())); + } } - } + + private: + FIRQuerySnapshotBlock block_; + }; + + return absl::make_unique(block); } -- (void)validateNewOrderByPath:(const FieldPath &)fieldPath { - if (![self.query firstSortOrderField]) { - // This is the first order by. It must match any inequality. - const FieldPath *inequalityField = [self.query inequalityFilterField]; - if (inequalityField) { - [self validateOrderByField:fieldPath matchesInequalityField:*inequalityField]; - } - } +/** Private helper for all of the queryWhereField: methods. */ +- (FIRQuery *)queryWithFilterOperator:(Filter::Operator)filterOperator + field:(NSString *)field + value:(id)value { + return [self queryWithFilterOperator:filterOperator path:MakeFieldPath(field) value:value]; } -- (void)validateOrderByField:(const FieldPath &)orderByField - matchesInequalityField:(const FieldPath &)inequalityField { - if (orderByField != inequalityField) { - FSTThrowInvalidUsage( - @"InvalidQueryException", - @"Invalid query. You have a where filter with an " - "inequality (lessThan, lessThanOrEqual, greaterThan, or greaterThanOrEqual) on field '%s' " - "and so you must also use '%s' as your first queryOrderedBy field, but your first " - "queryOrderedBy is currently on field '%s' instead.", - inequalityField.CanonicalString().c_str(), inequalityField.CanonicalString().c_str(), - orderByField.CanonicalString().c_str()); - } +- (FIRQuery *)queryWithFilterOperator:(Filter::Operator)filterOperator + path:(const FieldPath &)fieldPath + value:(id)value { + FieldValue fieldValue = [self parsedQueryValue:value + allowArrays:filterOperator == Filter::Operator::In]; + auto describer = [value] { return MakeString(NSStringFromClass([value class])); }; + return Wrap(_query.Filter(fieldPath, filterOperator, std::move(fieldValue), describer)); } /** - * Create a FSTBound from a query given the document. + * Create a Bound from a query given the document. * - * Note that the FSTBound will always include the key of the document and the position will be + * Note that the Bound will always include the key of the document and the position will be * unambiguous. * * Will throw if the document does not contain all fields of the order by of * the query or if any of the fields in the order by are an uncommitted server * timestamp. */ -- (FSTBound *)boundFromSnapshot:(FIRDocumentSnapshot *)snapshot isBefore:(BOOL)isBefore { +- (Bound)boundFromSnapshot:(FIRDocumentSnapshot *)snapshot isBefore:(BOOL)isBefore { if (![snapshot exists]) { - FSTThrowInvalidUsage(@"InvalidQueryException", - @"Invalid query. You are trying to start or end a query using a document " - @"that doesn't exist."); + ThrowInvalidArgument("Invalid query. You are trying to start or end a query using a document " + "that doesn't exist."); } - FSTDocument *document = snapshot.internalDocument; - NSMutableArray *components = [NSMutableArray array]; + const Document &document = *snapshot.internalDocument; + const DatabaseId &databaseID = self.firestore.databaseID; + std::vector components; // Because people expect to continue/end a query at the exact document provided, we need to // use the implicit sort order rather than the explicit sort order, because it's guaranteed to // contain the document key. That way the position becomes unambiguous and the query // continues/ends exactly at the provided document. Without the key (by using the explicit sort // orders), multiple documents could match the position, yielding duplicate results. - for (FSTSortOrder *sortOrder in self.query.sortOrders) { - if (sortOrder.field == FieldPath::KeyFieldPath()) { - [components addObject:[FSTReferenceValue - referenceValue:[FSTDocumentKey keyWithDocumentKey:document.key] - databaseID:self.firestore.databaseID]]; + for (const OrderBy &orderBy : self.query.order_bys()) { + if (orderBy.field() == FieldPath::KeyFieldPath()) { + components.push_back(FieldValue::FromReference(databaseID, document.key())); } else { - FSTFieldValue *value = [document fieldForPath:sortOrder.field]; - - if ([value isKindOfClass:[FSTServerTimestampValue class]]) { - FSTThrowInvalidUsage(@"InvalidQueryException", - @"Invalid query. You are trying to start or end a query using a " - "document for which the field '%s' is an uncommitted server " - "timestamp. (Since the value of this field is unknown, you cannot " - "start/end a query with it.)", - sortOrder.field.CanonicalString().c_str()); - } else if (value != nil) { - [components addObject:value]; + absl::optional value = document.field(orderBy.field()); + + if (value) { + if (value->type() == FieldValue::Type::ServerTimestamp) { + ThrowInvalidArgument( + "Invalid query. You are trying to start or end a query using a document for which " + "the field '%s' is an uncommitted server timestamp. (Since the value of this field " + "is unknown, you cannot start/end a query with it.)", + orderBy.field().CanonicalString()); + } else { + components.push_back(*value); + } } else { - FSTThrowInvalidUsage(@"InvalidQueryException", - @"Invalid query. You are trying to start or end a query using a " - "document for which the field '%s' (used as the order by) " - "does not exist.", - sortOrder.field.CanonicalString().c_str()); + ThrowInvalidArgument( + "Invalid query. You are trying to start or end a query using a document for which the " + "field '%s' (used as the order by) does not exist.", + orderBy.field().CanonicalString()); } } } - return [FSTBound boundWithPosition:components isBefore:isBefore]; + return Bound(std::move(components), isBefore); } -/** Converts a list of field values to an FSTBound. */ -- (FSTBound *)boundFromFieldValues:(NSArray *)fieldValues isBefore:(BOOL)isBefore { +/** Converts a list of field values to an Bound. */ +- (Bound)boundFromFieldValues:(NSArray *)fieldValues isBefore:(BOOL)isBefore { // Use explicit sort order because it has to match the query the user made - NSArray *explicitSortOrders = self.query.explicitSortOrders; - if (fieldValues.count > explicitSortOrders.count) { - FSTThrowInvalidUsage(@"InvalidQueryException", - @"Invalid query. You are trying to start or end a query using more values " - @"than were specified in the order by."); + const OrderByList &explicitSortOrders = self.query.explicit_order_bys(); + if (fieldValues.count > explicitSortOrders.size()) { + ThrowInvalidArgument("Invalid query. You are trying to start or end a query using more values " + "than were specified in the order by."); } - NSMutableArray *components = [NSMutableArray array]; - [fieldValues enumerateObjectsUsingBlock:^(id rawValue, NSUInteger idx, BOOL *stop) { - FSTSortOrder *sortOrder = explicitSortOrders[idx]; - if (sortOrder.field == FieldPath::KeyFieldPath()) { - if (![rawValue isKindOfClass:[NSString class]]) { - FSTThrowInvalidUsage(@"InvalidQueryException", - @"Invalid query. Expected a string for the document ID."); + std::vector components; + for (NSUInteger idx = 0, max = fieldValues.count; idx < max; ++idx) { + id rawValue = fieldValues[idx]; + const OrderBy &sortOrder = explicitSortOrders[idx]; + + FieldValue fieldValue = [self parsedQueryValue:rawValue]; + if (sortOrder.field().IsKeyFieldPath()) { + if (fieldValue.type() != FieldValue::Type::String) { + ThrowInvalidArgument("Invalid query. Expected a string for the document ID."); } - NSString *documentID = (NSString *)rawValue; - if (![self.query isCollectionGroupQuery] && [documentID containsString:@"/"]) { - FSTThrowInvalidUsage( - @"InvalidQueryException", - @"Invalid query. When querying a collection and ordering by document ID, " - "you must pass a plain document ID, but '%@' contains a slash.", - documentID); + const std::string &documentID = fieldValue.string_value(); + if (!self.query.IsCollectionGroupQuery() && documentID.find('/') != std::string::npos) { + ThrowInvalidArgument("Invalid query. When querying a collection and ordering by document " + "ID, you must pass a plain document ID, but '%s' contains a slash.", + documentID); } - ResourcePath path = self.query.path.Append(ResourcePath::FromString([documentID UTF8String])); + ResourcePath path = self.query.path().Append(ResourcePath::FromString(documentID)); if (!DocumentKey::IsDocumentKey(path)) { - FSTThrowInvalidUsage( - @"InvalidQueryException", - @"Invalid query. When querying a collection group and ordering by document ID, " - "you must pass a value that results in a valid document path, but '%s' " - "is not because it contains an odd number of segments.", - path.CanonicalString().c_str()); + ThrowInvalidArgument("Invalid query. When querying a collection group and ordering by " + "document ID, you must pass a value that results in a valid document " + "path, but '%s' is not because it contains an odd number of segments.", + path.CanonicalString()); } DocumentKey key{path}; - [components - addObject:[FSTReferenceValue referenceValue:[FSTDocumentKey keyWithDocumentKey:key] - databaseID:self.firestore.databaseID]]; - } else { - FSTFieldValue *fieldValue = [self.firestore.dataConverter parsedQueryValue:rawValue]; - [components addObject:fieldValue]; + fieldValue = FieldValue::FromReference(self.firestore.databaseID, key); } - }]; - return [FSTBound boundWithPosition:components isBefore:isBefore]; + components.push_back(fieldValue); + } + + return Bound(std::move(components), isBefore); +} + +@end + +@implementation FIRQuery (Internal) + +- (const core::Query &)query { + return _query.query(); +} + +- (const api::Query &)apiQuery { + return _query; } @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuerySnapshot+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuerySnapshot+Internal.h index 96589d1..622bf68 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuerySnapshot+Internal.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuerySnapshot+Internal.h @@ -16,6 +16,8 @@ #import "FIRQuerySnapshot.h" +#include + #include "Firestore/core/src/firebase/firestore/api/firestore.h" #include "Firestore/core/src/firebase/firestore/api/query_snapshot.h" #include "Firestore/core/src/firebase/firestore/api/snapshot_metadata.h" @@ -23,24 +25,21 @@ @class FIRFirestore; @class FIRSnapshotMetadata; -@class FSTQuery; -using firebase::firestore::api::Firestore; -using firebase::firestore::api::QuerySnapshot; -using firebase::firestore::api::SnapshotMetadata; -using firebase::firestore::core::ViewSnapshot; +namespace api = firebase::firestore::api; +namespace core = firebase::firestore::core; NS_ASSUME_NONNULL_BEGIN /** Internal FIRQuerySnapshot API we don't want exposed in our public header files. */ @interface FIRQuerySnapshot (/* Init */) -- (instancetype)initWithSnapshot:(QuerySnapshot &&)snapshot NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithSnapshot:(api::QuerySnapshot &&)snapshot NS_DESIGNATED_INITIALIZER; -- (instancetype)initWithFirestore:(Firestore *)firestore - originalQuery:(FSTQuery *)query - snapshot:(ViewSnapshot &&)snapshot - metadata:(SnapshotMetadata)metadata; +- (instancetype)initWithFirestore:(std::shared_ptr)firestore + originalQuery:(core::Query)query + snapshot:(core::ViewSnapshot &&)snapshot + metadata:(api::SnapshotMetadata)metadata; @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuerySnapshot.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuerySnapshot.mm index 52a4810..43c97ac 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuerySnapshot.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuerySnapshot.mm @@ -24,18 +24,20 @@ #import "Firestore/Source/API/FIRFirestore+Internal.h" #import "Firestore/Source/API/FIRQuery+Internal.h" #import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" #include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" #include "Firestore/core/src/firebase/firestore/model/document_set.h" #include "Firestore/core/src/firebase/firestore/util/delayed_constructor.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" +using firebase::firestore::api::DocumentChange; +using firebase::firestore::api::DocumentSnapshot; using firebase::firestore::api::Firestore; using firebase::firestore::api::QuerySnapshot; +using firebase::firestore::api::SnapshotMetadata; using firebase::firestore::core::ViewSnapshot; using firebase::firestore::util::DelayedConstructor; +using firebase::firestore::util::ThrowInvalidArgument; NS_ASSUME_NONNULL_BEGIN @@ -59,11 +61,11 @@ - (instancetype)initWithSnapshot:(QuerySnapshot &&)snapshot { return self; } -- (instancetype)initWithFirestore:(Firestore *)firestore - originalQuery:(FSTQuery *)query +- (instancetype)initWithFirestore:(std::shared_ptr)firestore + originalQuery:(core::Query)query snapshot:(ViewSnapshot &&)snapshot metadata:(SnapshotMetadata)metadata { - QuerySnapshot wrapped(firestore, query, std::move(snapshot), std::move(metadata)); + QuerySnapshot wrapped(firestore, std::move(query), std::move(snapshot), std::move(metadata)); return [self initWithSnapshot:std::move(wrapped)]; } @@ -80,8 +82,7 @@ - (NSUInteger)hash { } - (FIRQuery *)query { - FIRFirestore *firestore = [FIRFirestore recoverFromFirestore:_snapshot->firestore()]; - return [FIRQuery referenceWithQuery:_snapshot->internal_query() firestore:firestore]; + return [[FIRQuery alloc] initWithQuery:_snapshot->query()]; } - (FIRSnapshotMetadata *)metadata { @@ -122,16 +123,15 @@ - (NSInteger)count { - (NSArray *)documentChangesWithIncludeMetadataChanges: (BOOL)includeMetadataChanges { - if (includeMetadataChanges && _snapshot->view_snapshot().excludes_metadata_changes()) { - FSTThrowInvalidArgument( - @"To include metadata changes with your document changes, you must call " - @"addSnapshotListener(includeMetadataChanges: true)."); - } - if (!_documentChanges || _documentChangesIncludeMetadataChanges != includeMetadataChanges) { - _documentChanges = [FIRDocumentChange documentChangesForSnapshot:_snapshot->view_snapshot() - includeMetadataChanges:includeMetadataChanges - firestore:_snapshot->firestore()]; + NSMutableArray *documentChanges = [NSMutableArray array]; + _snapshot->ForEachChange( + static_cast(includeMetadataChanges), [&documentChanges](DocumentChange change) { + [documentChanges + addObject:[[FIRDocumentChange alloc] initWithDocumentChange:std::move(change)]]; + }); + + _documentChanges = documentChanges; _documentChangesIncludeMetadataChanges = includeMetadataChanges; } return _documentChanges; diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuery_Init.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuery_Init.h deleted file mode 100644 index d6b0f37..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRQuery_Init.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "FIRQuery.h" - -@class FSTQuery; - -NS_ASSUME_NONNULL_BEGIN - -/** - * An Internal class extension for `FIRQuery` that exposes the init method to classes - * that need to derive from it. - */ -@interface FIRQuery (/*Init*/) -- (instancetype)initWithQuery:(FSTQuery *)query - firestore:(FIRFirestore *)firestore NS_DESIGNATED_INITIALIZER; -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRSnapshotMetadata+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRSnapshotMetadata+Internal.h index 6c5c699..6c533bb 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRSnapshotMetadata+Internal.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRSnapshotMetadata+Internal.h @@ -20,13 +20,13 @@ #include "Firestore/core/src/firebase/firestore/api/snapshot_metadata.h" -using firebase::firestore::api::SnapshotMetadata; +namespace api = firebase::firestore::api; NS_ASSUME_NONNULL_BEGIN @interface FIRSnapshotMetadata (/* Init */) -- (instancetype)initWithMetadata:(SnapshotMetadata)metadata NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithMetadata:(api::SnapshotMetadata)metadata NS_DESIGNATED_INITIALIZER; - (instancetype)initWithPendingWrites:(bool)pendingWrites fromCache:(bool)fromCache; diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRSnapshotMetadata.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRSnapshotMetadata.mm index 87fa45e..92b7db1 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRSnapshotMetadata.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRSnapshotMetadata.mm @@ -25,10 +25,10 @@ NS_ASSUME_NONNULL_BEGIN @implementation FIRSnapshotMetadata { - SnapshotMetadata _metadata; + api::SnapshotMetadata _metadata; } -- (instancetype)initWithMetadata:(SnapshotMetadata)metadata { +- (instancetype)initWithMetadata:(api::SnapshotMetadata)metadata { if (self = [super init]) { _metadata = std::move(metadata); } @@ -36,7 +36,7 @@ - (instancetype)initWithMetadata:(SnapshotMetadata)metadata { } - (instancetype)initWithPendingWrites:(bool)pendingWrites fromCache:(bool)fromCache { - SnapshotMetadata wrapped(pendingWrites, fromCache); + api::SnapshotMetadata wrapped(pendingWrites, fromCache); return [self initWithMetadata:std::move(wrapped)]; } diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRTimestamp.m b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRTimestamp.m index e5a2cd3..ca130b3 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRTimestamp.m +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRTimestamp.m @@ -110,7 +110,7 @@ - (NSUInteger)hash { } - (NSString *)description { - return [NSString stringWithFormat:@"FIRTimestamp: seconds=%lld nanoseconds=%d>", self.seconds, + return [NSString stringWithFormat:@"", self.seconds, self.nanoseconds]; } diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRTransaction+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRTransaction+Internal.h index 32abd3f..25d64ed 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRTransaction+Internal.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRTransaction+Internal.h @@ -22,10 +22,15 @@ @class FIRFirestore; +namespace core = firebase::firestore::core; + +NS_ASSUME_NONNULL_BEGIN + @interface FIRTransaction (Internal) -+ (instancetype)transactionWithInternalTransaction: - (std::shared_ptr)transaction ++ (instancetype)transactionWithInternalTransaction:(std::shared_ptr)transaction firestore:(FIRFirestore *)firestore; @end + +NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRTransaction.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRTransaction.mm index b0d0f9f..0c7cf31 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRTransaction.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRTransaction.mm @@ -25,19 +25,23 @@ #import "Firestore/Source/API/FIRFirestore+Internal.h" #import "Firestore/Source/API/FIRTransaction+Internal.h" #import "Firestore/Source/API/FSTUserDataConverter.h" -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" #include "Firestore/core/src/firebase/firestore/core/transaction.h" #include "Firestore/core/src/firebase/firestore/util/error_apple.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/statusor.h" using firebase::firestore::core::ParsedSetData; using firebase::firestore::core::ParsedUpdateData; using firebase::firestore::core::Transaction; +using firebase::firestore::model::Document; +using firebase::firestore::model::MaybeDocument; using firebase::firestore::util::MakeNSError; using firebase::firestore::util::Status; +using firebase::firestore::util::StatusOr; +using firebase::firestore::util::ThrowInvalidArgument; NS_ASSUME_NONNULL_BEGIN @@ -117,34 +121,35 @@ - (void)getDocument:(FIRDocumentReference *)document NSError *_Nullable error))completion { [self validateReference:document]; _internalTransaction->Lookup( - {document.key}, [self, document, completion](const std::vector &documents, - const Status &status) { - if (!status.ok()) { - completion(nil, MakeNSError(status)); + {document.key}, + [self, document, completion](const StatusOr> &maybe_documents) { + if (!maybe_documents.ok()) { + completion(nil, MakeNSError(maybe_documents.status())); return; } + const auto &documents = maybe_documents.ValueOrDie(); HARD_ASSERT(documents.size() == 1, "Mismatch in docs returned from document lookup."); - FSTMaybeDocument *internalDoc = documents.front(); - if ([internalDoc isKindOfClass:[FSTDeletedDocument class]]) { + const MaybeDocument &internalDoc = documents.front(); + if (internalDoc.is_no_document()) { FIRDocumentSnapshot *doc = [[FIRDocumentSnapshot alloc] initWithFirestore:self.firestore.wrapped documentKey:document.key - document:nil + document:absl::nullopt fromCache:false hasPendingWrites:false]; completion(doc, nil); - } else if ([internalDoc isKindOfClass:[FSTDocument class]]) { + } else if (internalDoc.is_document()) { FIRDocumentSnapshot *doc = [[FIRDocumentSnapshot alloc] initWithFirestore:self.firestore.wrapped - documentKey:internalDoc.key - document:(FSTDocument *)internalDoc + documentKey:internalDoc.key() + document:Document(internalDoc) fromCache:false hasPendingWrites:false]; completion(doc, nil); } else { HARD_FAIL("BatchGetDocumentsRequest returned unexpected document type: %s", - NSStringFromClass([internalDoc class])); + internalDoc.type()); } }); } @@ -171,7 +176,7 @@ - (FIRDocumentSnapshot *_Nullable)getDocument:(FIRDocumentReference *)document - (void)validateReference:(FIRDocumentReference *)reference { if (reference.firestore != self.firestore) { - FSTThrowInvalidArgument(@"Provided document reference is from a different Firestore instance."); + ThrowInvalidArgument("Provided document reference is from a different Firestore instance."); } } diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRWriteBatch+Internal.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRWriteBatch+Internal.h index a434e02..3d70848 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRWriteBatch+Internal.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRWriteBatch+Internal.h @@ -16,10 +16,21 @@ #import "FIRWriteBatch.h" -@class FIRFirestore; +#import + +#include "Firestore/core/src/firebase/firestore/api/write_batch.h" + +@class FSTUserDataConverter; + +namespace api = firebase::firestore::api; + +NS_ASSUME_NONNULL_BEGIN @interface FIRWriteBatch (Internal) -+ (instancetype)writeBatchWithFirestore:(FIRFirestore *)firestore; ++ (instancetype)writeBatchWithDataConverter:(FSTUserDataConverter *)dataConverter + writeBatch:(api::WriteBatch &&)writeBatch; @end + +NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRWriteBatch.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRWriteBatch.mm index 484b8b0..c92cbb8 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRWriteBatch.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FIRWriteBatch.mm @@ -14,22 +14,16 @@ * limitations under the License. */ -#import "FIRWriteBatch.h" - -#include -#include -#include +#import "Firestore/Source/API/FIRWriteBatch+Internal.h" #import "Firestore/Source/API/FIRDocumentReference+Internal.h" -#import "Firestore/Source/API/FIRFirestore+Internal.h" -#import "Firestore/Source/API/FIRWriteBatch+Internal.h" #import "Firestore/Source/API/FSTUserDataConverter.h" -#import "Firestore/Source/Core/FSTFirestoreClient.h" -#import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" -#include "Firestore/core/src/firebase/firestore/model/precondition.h" +#include "Firestore/core/src/firebase/firestore/api/write_batch.h" +#include "Firestore/core/src/firebase/firestore/util/delayed_constructor.h" +#include "Firestore/core/src/firebase/firestore/util/error_apple.h" +namespace util = firebase::firestore::util; using firebase::firestore::core::ParsedSetData; using firebase::firestore::core::ParsedUpdateData; using firebase::firestore::model::Precondition; @@ -40,29 +34,33 @@ @interface FIRWriteBatch () -- (instancetype)initWithFirestore:(FIRFirestore *)firestore NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDataConverter:(FSTUserDataConverter *)dataConverter + writeBatch:(api::WriteBatch &&)writeBatch NS_DESIGNATED_INITIALIZER; -@property(nonatomic, strong, readonly) FIRFirestore *firestore; -@property(nonatomic, assign) BOOL committed; +@property(nonatomic, strong, readonly) FSTUserDataConverter *dataConverter; @end @implementation FIRWriteBatch (Internal) -+ (instancetype)writeBatchWithFirestore:(FIRFirestore *)firestore { - return [[FIRWriteBatch alloc] initWithFirestore:firestore]; ++ (instancetype)writeBatchWithDataConverter:(FSTUserDataConverter *)dataConverter + writeBatch:(api::WriteBatch &&)writeBatch { + return [[FIRWriteBatch alloc] initWithDataConverter:dataConverter + writeBatch:std::move(writeBatch)]; } @end @implementation FIRWriteBatch { - std::vector _mutations; + util::DelayedConstructor _writeBatch; } -- (instancetype)initWithFirestore:(FIRFirestore *)firestore { +- (instancetype)initWithDataConverter:(FSTUserDataConverter *)dataConverter + writeBatch:(api::WriteBatch &&)writeBatch { self = [super init]; if (self) { - _firestore = firestore; + _dataConverter = dataConverter; + _writeBatch.Init(std::move(writeBatch)); } return self; } @@ -75,14 +73,9 @@ - (FIRWriteBatch *)setData:(NSDictionary *)data - (FIRWriteBatch *)setData:(NSDictionary *)data forDocument:(FIRDocumentReference *)document merge:(BOOL)merge { - [self verifyNotCommitted]; - [self validateReference:document]; - - ParsedSetData parsed = merge ? [self.firestore.dataConverter parsedMergeData:data fieldMask:nil] - : [self.firestore.dataConverter parsedSetData:data]; - std::vector append_mutations = - std::move(parsed).ToMutations(document.key, Precondition::None()); - std::move(append_mutations.begin(), append_mutations.end(), std::back_inserter(_mutations)); + ParsedSetData parsed = merge ? [self.dataConverter parsedMergeData:data fieldMask:nil] + : [self.dataConverter parsedSetData:data]; + _writeBatch->SetData(document.internalReference, std::move(parsed)); return self; } @@ -90,37 +83,23 @@ - (FIRWriteBatch *)setData:(NSDictionary *)data - (FIRWriteBatch *)setData:(NSDictionary *)data forDocument:(FIRDocumentReference *)document mergeFields:(NSArray *)mergeFields { - [self verifyNotCommitted]; - [self validateReference:document]; - - ParsedSetData parsed = [self.firestore.dataConverter parsedMergeData:data fieldMask:mergeFields]; - std::vector append_mutations = - std::move(parsed).ToMutations(document.key, Precondition::None()); - std::move(append_mutations.begin(), append_mutations.end(), std::back_inserter(_mutations)); + ParsedSetData parsed = [self.dataConverter parsedMergeData:data fieldMask:mergeFields]; + _writeBatch->SetData(document.internalReference, std::move(parsed)); return self; } - (FIRWriteBatch *)updateData:(NSDictionary *)fields forDocument:(FIRDocumentReference *)document { - [self verifyNotCommitted]; - [self validateReference:document]; - - ParsedUpdateData parsed = [self.firestore.dataConverter parsedUpdateData:fields]; - std::vector append_mutations = - std::move(parsed).ToMutations(document.key, Precondition::Exists(true)); - std::move(append_mutations.begin(), append_mutations.end(), std::back_inserter(_mutations)); + ParsedUpdateData parsed = [self.dataConverter parsedUpdateData:fields]; + _writeBatch->UpdateData(document.internalReference, std::move(parsed)); return self; } - (FIRWriteBatch *)deleteDocument:(FIRDocumentReference *)document { - [self verifyNotCommitted]; - [self validateReference:document]; + _writeBatch->DeleteData(document.internalReference); - _mutations.push_back([[FSTDeleteMutation alloc] initWithKey:document.key - precondition:Precondition::None()]); - ; return self; } @@ -129,22 +108,7 @@ - (void)commit { } - (void)commitWithCompletion:(nullable void (^)(NSError *_Nullable error))completion { - [self verifyNotCommitted]; - self.committed = TRUE; - [self.firestore.client writeMutations:std::move(_mutations) completion:completion]; -} - -- (void)verifyNotCommitted { - if (self.committed) { - FSTThrowInvalidUsage(@"FIRIllegalStateException", - @"A write batch can no longer be used after commit has been called."); - } -} - -- (void)validateReference:(FIRDocumentReference *)reference { - if (reference.firestore != self.firestore) { - FSTThrowInvalidArgument(@"Provided document reference is from a different Firestore instance."); - } + _writeBatch->Commit(util::MakeCallback(completion)); } @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTFirestoreComponent.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTFirestoreComponent.h index 62446f0..74504ca 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTFirestoreComponent.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTFirestoreComponent.h @@ -16,6 +16,8 @@ #import +#import "Firestore/Source/API/FIRFirestore+Internal.h" + @class FIRApp; @class FIRFirestore; @@ -35,7 +37,8 @@ NS_ASSUME_NONNULL_BEGIN /// A concrete implementation for FSTInstanceProvider to create Firestore instances and register /// with Core's component system. -@interface FSTFirestoreComponent : NSObject +@interface FSTFirestoreComponent + : NSObject /// The FIRApp that instances will be set up with. @property(nonatomic, weak, readonly) FIRApp *app; @@ -46,6 +49,8 @@ NS_ASSUME_NONNULL_BEGIN /// Default method for retrieving a Firestore instance, or creating one if it doesn't exist. - (FIRFirestore *)firestoreForDatabase:(NSString *)database; +- (void)removeInstanceWithDatabase:(NSString *)database; + /// Default initializer. - (instancetype)initWithApp:(FIRApp *)app NS_DESIGNATED_INITIALIZER; diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTFirestoreComponent.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTFirestoreComponent.mm index 2d676d9..c9dedf6 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTFirestoreComponent.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTFirestoreComponent.mm @@ -29,13 +29,14 @@ #include #import "Firestore/Source/API/FIRFirestore+Internal.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" + #include "Firestore/core/include/firebase/firestore/firestore_version.h" #include "Firestore/core/src/firebase/firestore/api/firestore.h" #include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" #include "Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" -#include "Firestore/core/src/firebase/firestore/util/executor_libdispatch.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" +#include "Firestore/core/src/firebase/firestore/util/executor.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "absl/memory/memory.h" @@ -43,8 +44,9 @@ using firebase::firestore::api::Firestore; using firebase::firestore::auth::CredentialsProvider; using firebase::firestore::auth::FirebaseCredentialsProvider; -using util::AsyncQueue; -using util::ExecutorLibdispatch; +using firebase::firestore::util::AsyncQueue; +using firebase::firestore::util::Executor; +using firebase::firestore::util::ThrowInvalidArgument; NS_ASSUME_NONNULL_BEGIN @@ -69,14 +71,23 @@ - (instancetype)initWithApp:(FIRApp *)app { return self; } +- (NSString *)keyForDatabase:(NSString *)database { + return [NSString stringWithFormat:@"%@|%@", self.app.name, database]; +} + #pragma mark - FSTInstanceProvider Conformance - (FIRFirestore *)firestoreForDatabase:(NSString *)database { if (!database) { - FSTThrowInvalidArgument(@"database identifier may not be nil."); + ThrowInvalidArgument("Database identifier may not be nil."); } - NSString *key = [NSString stringWithFormat:@"%@|%@", self.app.name, database]; + NSString *projectID = self.app.options.projectID; + if (!projectID) { + ThrowInvalidArgument("FIROptions.projectID must be set to a valid project ID."); + } + + NSString *key = [self keyForDatabase:database]; // Get the component from the container. @synchronized(self.instances) { @@ -87,33 +98,44 @@ - (FIRFirestore *)firestoreForDatabase:(NSString *)database { absl::StrAppend(&queue_name, ".", util::MakeString(self.app.name)); } - auto executor = absl::make_unique( - dispatch_queue_create(queue_name.c_str(), DISPATCH_QUEUE_SERIAL)); - auto workerQueue = absl::make_unique(std::move(executor)); + auto executor = Executor::CreateSerial(queue_name.c_str()); + auto workerQueue = AsyncQueue::Create(std::move(executor)); id auth = FIR_COMPONENT(FIRAuthInterop, self.app.container); - auto credentialsProvider = absl::make_unique(self.app, auth); + auto credentialsProvider = std::make_shared(self.app, auth); - std::string projectID = util::MakeString(self.app.options.projectID); + model::DatabaseId databaseID{util::MakeString(projectID), util::MakeString(database)}; std::string persistenceKey = util::MakeString(self.app.name); - firestore = [[FIRFirestore alloc] initWithProjectID:std::move(projectID) - database:util::MakeString(database) - persistenceKey:std::move(persistenceKey) - credentialsProvider:std::move(credentialsProvider) - workerQueue:std::move(workerQueue) - firebaseApp:self.app]; + firestore = [[FIRFirestore alloc] initWithDatabaseID:std::move(databaseID) + persistenceKey:std::move(persistenceKey) + credentialsProvider:std::move(credentialsProvider) + workerQueue:std::move(workerQueue) + firebaseApp:self.app + instanceRegistry:self]; _instances[key] = firestore; } - return firestore; } } +- (void)removeInstanceWithDatabase:(NSString *)database { + @synchronized(_instances) { + NSString *key = [self keyForDatabase:database]; + [_instances removeObjectForKey:key]; + } +} + #pragma mark - FIRComponentLifecycleMaintainer - (void)appWillBeDeleted:(FIRApp *)app { - // Stop any actions and clean up resources since instances of Firestore associated with this app - // will be removed. Currently does not do anything. + NSDictionary *instances; + @synchronized(_instances) { + instances = [_instances copy]; + [_instances removeAllObjects]; + } + for (NSString *key in instances) { + [instances[key] terminateInternalWithCompletion:nil]; + } } #pragma mark - Object Lifecycle diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTUserDataConverter.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTUserDataConverter.h index d5cf3ca..fbf0b21 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTUserDataConverter.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTUserDataConverter.h @@ -18,16 +18,19 @@ #include +#include "Firestore/core/include/firebase/firestore/timestamp.h" #include "Firestore/core/src/firebase/firestore/core/user_data.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/field_mask.h" #include "Firestore/core/src/firebase/firestore/model/field_transform.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" #include "Firestore/core/src/firebase/firestore/model/precondition.h" -@class FSTObjectValue; -@class FSTFieldValue; -@class FSTMutation; +@class FIRTimestamp; + +namespace core = firebase::firestore::core; +namespace model = firebase::firestore::model; NS_ASSUME_NONNULL_BEGIN @@ -42,14 +45,12 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithKey:(firebase::firestore::model::DocumentKey)key - databaseID:(const firebase::firestore::model::DatabaseId *)databaseID - NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithKey:(model::DocumentKey)key + databaseID:(model::DatabaseId)databaseID NS_DESIGNATED_INITIALIZER; -- (const firebase::firestore::model::DocumentKey &)key; +- (const model::DocumentKey &)key; -// Does not own the DatabaseId instance. -@property(nonatomic, assign, readonly) const firebase::firestore::model::DatabaseId *databaseID; +@property(nonatomic, assign, readonly) const model::DatabaseId &databaseID; @end @@ -66,21 +67,28 @@ typedef id _Nullable (^FSTPreConverterBlock)(id _Nullable); @interface FSTUserDataConverter : NSObject - (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithDatabaseID:(const firebase::firestore::model::DatabaseId *)databaseID +- (instancetype)initWithDatabaseID:(model::DatabaseId)databaseID preConverter:(FSTPreConverterBlock)preConverter NS_DESIGNATED_INITIALIZER; /** Parse document data from a non-merge setData call.*/ -- (firebase::firestore::core::ParsedSetData)parsedSetData:(id)input; +- (core::ParsedSetData)parsedSetData:(id)input; /** Parse document data from a setData call with `merge:YES`. */ -- (firebase::firestore::core::ParsedSetData)parsedMergeData:(id)input - fieldMask:(nullable NSArray *)fieldMask; +- (core::ParsedSetData)parsedMergeData:(id)input fieldMask:(nullable NSArray *)fieldMask; /** Parse update data from an updateData call. */ -- (firebase::firestore::core::ParsedUpdateData)parsedUpdateData:(id)input; +- (core::ParsedUpdateData)parsedUpdateData:(id)input; /** Parse a "query value" (e.g. value in a where filter or a value in a cursor bound). */ -- (FSTFieldValue *)parsedQueryValue:(id)input; +- (model::FieldValue)parsedQueryValue:(id)input; + +/** + * Parse a "query value" (e.g. value in a where filter or a value in a cursor bound). + * + * @param allowArrays Whether the query value is an array that may directly contain additional + * arrays (e.g.) the operand of an `in` query). + */ +- (model::FieldValue)parsedQueryValue:(id)input allowArrays:(bool)allowArrays; @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTUserDataConverter.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTUserDataConverter.mm index 0f0abd8..9a0e0cb 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTUserDataConverter.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/FSTUserDataConverter.mm @@ -29,9 +29,8 @@ #import "Firestore/Source/API/FIRFieldPath+Internal.h" #import "Firestore/Source/API/FIRFieldValue+Internal.h" #import "Firestore/Source/API/FIRFirestore+Internal.h" -#import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" +#import "Firestore/Source/API/FIRGeoPoint+Internal.h" +#import "Firestore/Source/API/converters.h" #include "Firestore/core/src/firebase/firestore/core/user_data.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" @@ -39,18 +38,26 @@ #include "Firestore/core/src/firebase/firestore/model/field_mask.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" #include "Firestore/core/src/firebase/firestore/model/field_transform.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" #include "Firestore/core/src/firebase/firestore/model/precondition.h" -#include "Firestore/core/src/firebase/firestore/model/transform_operations.h" +#include "Firestore/core/src/firebase/firestore/model/transform_operation.h" +#include "Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h" +#include "Firestore/core/src/firebase/firestore/timestamp_internal.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "absl/memory/memory.h" #include "absl/strings/match.h" +#include "absl/types/optional.h" namespace util = firebase::firestore::util; -using firebase::firestore::core::ParsedSetData; -using firebase::firestore::core::ParsedUpdateData; +using firebase::Timestamp; +using firebase::TimestampInternal; +using firebase::firestore::GeoPoint; using firebase::firestore::core::ParseAccumulator; using firebase::firestore::core::ParseContext; +using firebase::firestore::core::ParsedSetData; +using firebase::firestore::core::ParsedUpdateData; using firebase::firestore::core::UserDataSource; using firebase::firestore::model::ArrayTransform; using firebase::firestore::model::DatabaseId; @@ -58,10 +65,14 @@ using firebase::firestore::model::FieldMask; using firebase::firestore::model::FieldPath; using firebase::firestore::model::FieldTransform; +using firebase::firestore::model::FieldValue; using firebase::firestore::model::NumericIncrementTransform; +using firebase::firestore::model::ObjectValue; using firebase::firestore::model::Precondition; using firebase::firestore::model::ServerTimestampTransform; using firebase::firestore::model::TransformOperation; +using firebase::firestore::nanopb::MakeByteString; +using firebase::firestore::util::ThrowInvalidArgument; NS_ASSUME_NONNULL_BEGIN @@ -69,38 +80,45 @@ @implementation FSTDocumentKeyReference { DocumentKey _key; + DatabaseId _databaseID; } -- (instancetype)initWithKey:(DocumentKey)key databaseID:(const DatabaseId *)databaseID { +- (instancetype)initWithKey:(DocumentKey)key databaseID:(DatabaseId)databaseID { self = [super init]; if (self) { _key = std::move(key); - _databaseID = databaseID; + _databaseID = std::move(databaseID); } return self; } -- (const firebase::firestore::model::DocumentKey &)key { +- (const model::DocumentKey &)key { return _key; } +- (const model::DatabaseId &)databaseID { + return _databaseID; +} + @end +#pragma mark - Conversion helpers + #pragma mark - FSTUserDataConverter @interface FSTUserDataConverter () -// Does not own the DatabaseId instance. -@property(assign, nonatomic, readonly) const DatabaseId *databaseID; @property(strong, nonatomic, readonly) FSTPreConverterBlock preConverter; @end -@implementation FSTUserDataConverter +@implementation FSTUserDataConverter { + DatabaseId _databaseID; +} -- (instancetype)initWithDatabaseID:(const DatabaseId *)databaseID +- (instancetype)initWithDatabaseID:(DatabaseId)databaseID preConverter:(FSTPreConverterBlock)preConverter { self = [super init]; if (self) { - _databaseID = databaseID; + _databaseID = std::move(databaseID); _preConverter = preConverter; } return self; @@ -110,26 +128,29 @@ - (ParsedSetData)parsedSetData:(id)input { // NOTE: The public API is typed as NSDictionary but we type 'input' as 'id' since we can't trust // Obj-C to verify the type for us. if (![input isKindOfClass:[NSDictionary class]]) { - FSTThrowInvalidArgument(@"Data to be written must be an NSDictionary."); + ThrowInvalidArgument("Data to be written must be an NSDictionary."); } ParseAccumulator accumulator{UserDataSource::Set}; - FSTFieldValue *updateData = [self parseData:input context:accumulator.RootContext()]; + absl::optional updateData = [self parseData:input context:accumulator.RootContext()]; + HARD_ASSERT(updateData.has_value(), "Parsed data should not be nil."); - return std::move(accumulator).SetData((FSTObjectValue *)updateData); + return std::move(accumulator).SetData(ObjectValue(std::move(*updateData))); } - (ParsedSetData)parsedMergeData:(id)input fieldMask:(nullable NSArray *)fieldMask { // NOTE: The public API is typed as NSDictionary but we type 'input' as 'id' since we can't trust // Obj-C to verify the type for us. if (![input isKindOfClass:[NSDictionary class]]) { - FSTThrowInvalidArgument(@"Data to be written must be an NSDictionary."); + ThrowInvalidArgument("Data to be written must be an NSDictionary."); } ParseAccumulator accumulator{UserDataSource::MergeSet}; - FSTObjectValue *updateData = (FSTObjectValue *)[self parseData:input - context:accumulator.RootContext()]; + absl::optional updateData = [self parseData:input context:accumulator.RootContext()]; + HARD_ASSERT(updateData.has_value(), "Parsed data should not be nil."); + + ObjectValue updateObject = ObjectValue(std::move(*updateData)); if (fieldMask) { std::set validatedFieldPaths; @@ -137,28 +158,28 @@ - (ParsedSetData)parsedMergeData:(id)input fieldMask:(nullable NSArray *)fie FieldPath path; if ([fieldPath isKindOfClass:[NSString class]]) { - path = [FIRFieldPath pathWithDotSeparatedString:fieldPath].internalValue; + path = FieldPath::FromDotSeparatedString(util::MakeString(fieldPath)); } else if ([fieldPath isKindOfClass:[FIRFieldPath class]]) { - path = ((FIRFieldPath *)fieldPath).internalValue; + path = static_cast(fieldPath).internalValue; } else { - FSTThrowInvalidArgument( - @"All elements in mergeFields: must be NSStrings or FIRFieldPaths."); + ThrowInvalidArgument("All elements in mergeFields: must be NSStrings or FIRFieldPaths."); } // Verify that all elements specified in the field mask are part of the parsed context. if (!accumulator.Contains(path)) { - FSTThrowInvalidArgument( - @"Field '%s' is specified in your field mask but missing from your input data.", - path.CanonicalString().c_str()); + ThrowInvalidArgument( + "Field '%s' is specified in your field mask but missing from your input data.", + path.CanonicalString()); } validatedFieldPaths.insert(path); } - return std::move(accumulator).MergeData(updateData, FieldMask{std::move(validatedFieldPaths)}); + return std::move(accumulator) + .MergeData(updateObject, FieldMask{std::move(validatedFieldPaths)}); } else { - return std::move(accumulator).MergeData(updateData); + return std::move(accumulator).MergeData(updateObject); } } @@ -166,25 +187,24 @@ - (ParsedUpdateData)parsedUpdateData:(id)input { // NOTE: The public API is typed as NSDictionary but we type 'input' as 'id' since we can't trust // Obj-C to verify the type for us. if (![input isKindOfClass:[NSDictionary class]]) { - FSTThrowInvalidArgument(@"Data to be written must be an NSDictionary."); + ThrowInvalidArgument("Data to be written must be an NSDictionary."); } NSDictionary *dict = input; ParseAccumulator accumulator{UserDataSource::Update}; __block ParseContext context = accumulator.RootContext(); - __block FSTObjectValue *updateData = [FSTObjectValue objectValue]; + __block ObjectValue updateData = ObjectValue::Empty(); [dict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { FieldPath path; if ([key isKindOfClass:[NSString class]]) { - path = [FIRFieldPath pathWithDotSeparatedString:key].internalValue; + path = FieldPath::FromDotSeparatedString(util::MakeString(key)); } else if ([key isKindOfClass:[FIRFieldPath class]]) { path = ((FIRFieldPath *)key).internalValue; } else { - FSTThrowInvalidArgument( - @"Dictionary keys in updateData: must be NSStrings or FIRFieldPaths."); + ThrowInvalidArgument("Dictionary keys in updateData: must be NSStrings or FIRFieldPaths."); } value = self.preConverter(value); @@ -192,11 +212,11 @@ - (ParsedUpdateData)parsedUpdateData:(id)input { // Add it to the field mask, but don't add anything to updateData. context.AddToFieldMask(std::move(path)); } else { - FSTFieldValue *_Nullable parsedValue = [self parseData:value - context:context.ChildContext(path)]; + absl::optional parsedValue = [self parseData:value + context:context.ChildContext(path)]; if (parsedValue) { context.AddToFieldMask(path); - updateData = [updateData objectBySettingValue:parsedValue forPath:path]; + updateData = updateData.Set(path, *parsedValue); } } }]; @@ -204,14 +224,19 @@ - (ParsedUpdateData)parsedUpdateData:(id)input { return std::move(accumulator).UpdateData(updateData); } -- (FSTFieldValue *)parsedQueryValue:(id)input { - ParseAccumulator accumulator{UserDataSource::Argument}; +- (FieldValue)parsedQueryValue:(id)input { + return [self parsedQueryValue:input allowArrays:false]; +} + +- (FieldValue)parsedQueryValue:(id)input allowArrays:(bool)allowArrays { + ParseAccumulator accumulator{allowArrays ? UserDataSource::ArrayArgument + : UserDataSource::Argument}; - FSTFieldValue *_Nullable parsed = [self parseData:input context:accumulator.RootContext()]; + absl::optional parsed = [self parseData:input context:accumulator.RootContext()]; HARD_ASSERT(parsed, "Parsed data should not be nil."); HARD_ASSERT(accumulator.field_transforms().empty(), "Field transforms should have been disallowed."); - return parsed; + return *parsed; } /** @@ -224,7 +249,7 @@ - (FSTFieldValue *)parsedQueryValue:(id)input { * @return The parsed value, or nil if the value was a FieldValue sentinel that should not be * included in the resulting parsed data. */ -- (nullable FSTFieldValue *)parseData:(id)input context:(ParseContext &&)context { +- (absl::optional)parseData:(id)input context:(ParseContext &&)context { input = self.preConverter(input); if ([input isKindOfClass:[NSDictionary class]]) { return [self parseDictionary:(NSDictionary *)input context:std::move(context)]; @@ -235,7 +260,7 @@ - (nullable FSTFieldValue *)parseData:(id)input context:(ParseContext &&)context // directly prior to the transform trying to transform it). So we don't call appendToFieldMask // and we return nil as our parsing result. [self parseSentinelFieldValue:(FIRFieldValue *)input context:std::move(context)]; - return nil; + return absl::nullopt; } else { // If context path is unset we are already inside an array and we don't support field mask paths @@ -246,8 +271,11 @@ - (nullable FSTFieldValue *)parseData:(id)input context:(ParseContext &&)context if ([input isKindOfClass:[NSArray class]]) { // TODO(b/34871131): Include the path containing the array in the error message. - if (context.array_element()) { - FSTThrowInvalidArgument(@"Nested arrays are not supported"); + // In the case of IN queries, the parsed data is an array (representing the set of values to + // be included for the IN query) that may directly contain additional arrays (each + // representing an individual field value), so we disable this validation. + if (context.array_element() && context.data_source() != UserDataSource::ArrayArgument) { + ThrowInvalidArgument("Nested arrays are not supported"); } return [self parseArray:(NSArray *)input context:std::move(context)]; } else { @@ -256,39 +284,44 @@ - (nullable FSTFieldValue *)parseData:(id)input context:(ParseContext &&)context } } -- (FSTFieldValue *)parseDictionary:(NSDictionary *)dict context:(ParseContext &&)context { - NSMutableDictionary *result = - [NSMutableDictionary dictionaryWithCapacity:dict.count]; - - if ([dict count] == 0) { +- (FieldValue)parseDictionary:(NSDictionary *)dict + context:(ParseContext &&)context { + if (dict.count == 0) { const FieldPath *path = context.path(); if (path && !path->empty()) { context.AddToFieldMask(*path); } - return [FSTObjectValue objectValue]; + return ObjectValue::Empty().AsFieldValue(); } else { + __block ObjectValue result = ObjectValue::Empty(); + [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) { - FSTFieldValue *_Nullable parsedValue = + absl::optional parsedValue = [self parseData:value context:context.ChildContext(util::MakeString(key))]; if (parsedValue) { - result[key] = parsedValue; + FieldPath path = FieldPath{util::MakeString(key)}; + result = result.Set(path, *parsedValue); } }]; + + return result; } - return [[FSTObjectValue alloc] initWithDictionary:result]; } -- (FSTFieldValue *)parseArray:(NSArray *)array context:(ParseContext &&)context { - NSMutableArray *result = [NSMutableArray arrayWithCapacity:array.count]; +- (FieldValue)parseArray:(NSArray *)array context:(ParseContext &&)context { + __block FieldValue::Array result; + result.reserve(array.count); + [array enumerateObjectsUsingBlock:^(id entry, NSUInteger idx, BOOL *stop) { - FSTFieldValue *_Nullable parsedEntry = [self parseData:entry context:context.ChildContext(idx)]; + absl::optional parsedEntry = [self parseData:entry + context:context.ChildContext(idx)]; if (!parsedEntry) { // Just include nulls in the array for fields being replaced with a sentinel. - parsedEntry = [FSTNullValue nullValue]; + parsedEntry = FieldValue::Null(); } - [result addObject:parsedEntry]; + result.push_back(*parsedEntry); }]; - return [[FSTArrayValue alloc] initWithValueNoCopy:result]; + return FieldValue::FromArray(std::move(result)); } /** @@ -298,11 +331,11 @@ - (FSTFieldValue *)parseArray:(NSArray *)array context:(ParseContext &&)context - (void)parseSentinelFieldValue:(FIRFieldValue *)fieldValue context:(ParseContext &&)context { // Sentinels are only supported with writes, and not within arrays. if (!context.write()) { - FSTThrowInvalidArgument(@"%@ can only be used with updateData() and setData()%s", - fieldValue.methodName, context.FieldDescription().c_str()); + ThrowInvalidArgument("%s can only be used with updateData() and setData()%s", + fieldValue.methodName, context.FieldDescription()); } if (!context.path()) { - FSTThrowInvalidArgument(@"%@ is not currently supported inside arrays", fieldValue.methodName); + ThrowInvalidArgument("%s is not currently supported inside arrays", fieldValue.methodName); } if ([fieldValue isKindOfClass:[FSTDeleteFieldValue class]]) { @@ -314,41 +347,36 @@ - (void)parseSentinelFieldValue:(FIRFieldValue *)fieldValue context:(ParseContex } else if (context.data_source() == UserDataSource::Update) { HARD_ASSERT(context.path()->size() > 0, "FieldValue.delete() at the top level should have already been handled."); - FSTThrowInvalidArgument(@"FieldValue.delete() can only appear at the top level of your " - "update data%s", - context.FieldDescription().c_str()); + ThrowInvalidArgument("FieldValue.delete() can only appear at the top level of your " + "update data%s", + context.FieldDescription()); } else { // We shouldn't encounter delete sentinels for queries or non-merge setData calls. - FSTThrowInvalidArgument( - @"FieldValue.delete() can only be used with updateData() and setData() with " - @"merge:true%s", - context.FieldDescription().c_str()); + ThrowInvalidArgument( + "FieldValue.delete() can only be used with updateData() and setData() with merge:true%s", + context.FieldDescription()); } } else if ([fieldValue isKindOfClass:[FSTServerTimestampFieldValue class]]) { - context.AddToFieldTransforms(*context.path(), absl::make_unique( - ServerTimestampTransform::Get())); + context.AddToFieldTransforms(*context.path(), ServerTimestampTransform()); } else if ([fieldValue isKindOfClass:[FSTArrayUnionFieldValue class]]) { - std::vector parsedElements = + std::vector parsedElements = [self parseArrayTransformElements:((FSTArrayUnionFieldValue *)fieldValue).elements]; - auto array_union = absl::make_unique(TransformOperation::Type::ArrayUnion, - std::move(parsedElements)); + ArrayTransform array_union(TransformOperation::Type::ArrayUnion, std::move(parsedElements)); context.AddToFieldTransforms(*context.path(), std::move(array_union)); } else if ([fieldValue isKindOfClass:[FSTArrayRemoveFieldValue class]]) { - std::vector parsedElements = + std::vector parsedElements = [self parseArrayTransformElements:((FSTArrayRemoveFieldValue *)fieldValue).elements]; - auto array_remove = absl::make_unique(TransformOperation::Type::ArrayRemove, - std::move(parsedElements)); + ArrayTransform array_remove(TransformOperation::Type::ArrayRemove, std::move(parsedElements)); context.AddToFieldTransforms(*context.path(), std::move(array_remove)); } else if ([fieldValue isKindOfClass:[FSTNumericIncrementFieldValue class]]) { FSTNumericIncrementFieldValue *numericIncrementFieldValue = (FSTNumericIncrementFieldValue *)fieldValue; - FSTNumberValue *operand = - (FSTNumberValue *)[self parsedQueryValue:numericIncrementFieldValue.operand]; - auto numeric_increment = absl::make_unique(operand); + FieldValue operand = [self parsedQueryValue:numericIncrementFieldValue.operand]; + NumericIncrementTransform numeric_increment(std::move(operand)); context.AddToFieldTransforms(*context.path(), std::move(numeric_increment)); @@ -367,9 +395,9 @@ - (void)parseSentinelFieldValue:(FIRFieldValue *)fieldValue context:(ParseContex * * @return The parsed value. */ -- (nullable FSTFieldValue *)parseScalarValue:(nullable id)input context:(ParseContext &&)context { +- (absl::optional)parseScalarValue:(nullable id)input context:(ParseContext &&)context { if (!input || [input isMemberOfClass:[NSNull class]]) { - return [FSTNullValue nullValue]; + return FieldValue::Null(); } else if ([input isKindOfClass:[NSNumber class]]) { // Recover the underlying type of the number, using the method described here: @@ -381,7 +409,7 @@ - (nullable FSTFieldValue *)parseScalarValue:(nullable id)input context:(ParseCo // Articles/ocrtTypeEncodings.html switch (cType[0]) { case 'q': - return [FSTIntegerValue integerValue:[input longLongValue]]; + return FieldValue::FromInteger([input longLongValue]); case 'i': // Falls through. case 's': // Falls through. @@ -390,7 +418,7 @@ - (nullable FSTFieldValue *)parseScalarValue:(nullable id)input context:(ParseCo case 'S': // Coerce integer values that aren't long long. Allow unsigned integer types that are // guaranteed small enough to skip a length check. - return [FSTIntegerValue integerValue:[input longLongValue]]; + return FieldValue::FromInteger([input longLongValue]); case 'L': // Falls through. case 'Q': @@ -400,24 +428,23 @@ - (nullable FSTFieldValue *)parseScalarValue:(nullable id)input context:(ParseCo unsigned long long extended = [input unsignedLongLongValue]; if (extended > LLONG_MAX) { - FSTThrowInvalidArgument(@"NSNumber (%llu) is too large%s", - [input unsignedLongLongValue], - context.FieldDescription().c_str()); + ThrowInvalidArgument("NSNumber (%s) is too large%s", [input unsignedLongLongValue], + context.FieldDescription()); } else { - return [FSTIntegerValue integerValue:(int64_t)extended]; + return FieldValue::FromInteger(static_cast(extended)); } } case 'f': - return [FSTDoubleValue doubleValue:[input doubleValue]]; + return FieldValue::FromDouble([input doubleValue]); case 'd': // Double values are already the right type, so just reuse the existing boxed double. // // Note that NSNumber already performs NaN normalization to a single shared instance // so there's no need to treat NaN specially here. - return [FSTDoubleValue doubleValue:[input doubleValue]]; + return FieldValue::FromDouble([input doubleValue]); case 'B': // Falls through. case 'c': // Falls through. @@ -429,7 +456,7 @@ - (nullable FSTFieldValue *)parseScalarValue:(nullable id)input context:(ParseCo // legitimate usage of signed chars is impossible, but this should be rare. // // Additionally, for consistency, map unsigned chars to bools in the same way. - return [FSTBooleanValue booleanValue:[input boolValue]]; + return FieldValue::FromBoolean([input boolValue]); default: // All documented codes should be handled above, so this shouldn't happen. @@ -437,57 +464,56 @@ - (nullable FSTFieldValue *)parseScalarValue:(nullable id)input context:(ParseCo } } else if ([input isKindOfClass:[NSString class]]) { - return [FSTStringValue stringValue:input]; + return FieldValue::FromString(util::MakeString(input)); } else if ([input isKindOfClass:[NSDate class]]) { - return [FSTTimestampValue timestampValue:[FIRTimestamp timestampWithDate:input]]; + NSDate *inputDate = input; + return FieldValue::FromTimestamp(api::MakeTimestamp(inputDate)); } else if ([input isKindOfClass:[FIRTimestamp class]]) { - FIRTimestamp *originalTimestamp = (FIRTimestamp *)input; - FIRTimestamp *truncatedTimestamp = - [FIRTimestamp timestampWithSeconds:originalTimestamp.seconds - nanoseconds:originalTimestamp.nanoseconds / 1000 * 1000]; - return [FSTTimestampValue timestampValue:truncatedTimestamp]; + FIRTimestamp *inputTimestamp = input; + Timestamp timestamp = TimestampInternal::Truncate(api::MakeTimestamp(inputTimestamp)); + return FieldValue::FromTimestamp(timestamp); } else if ([input isKindOfClass:[FIRGeoPoint class]]) { - return [FSTGeoPointValue geoPointValue:input]; + return FieldValue::FromGeoPoint(api::MakeGeoPoint(input)); } else if ([input isKindOfClass:[NSData class]]) { - return [FSTBlobValue blobValue:input]; + NSData *inputData = input; + return FieldValue::FromBlob(MakeByteString(inputData)); } else if ([input isKindOfClass:[FSTDocumentKeyReference class]]) { FSTDocumentKeyReference *reference = input; - if (*reference.databaseID != *self.databaseID) { - const DatabaseId *other = reference.databaseID; - FSTThrowInvalidArgument( - @"Document Reference is for database %s/%s but should be for database %s/%s%s", - other->project_id().c_str(), other->database_id().c_str(), - self.databaseID->project_id().c_str(), self.databaseID->database_id().c_str(), - context.FieldDescription().c_str()); + if (reference.databaseID != _databaseID) { + const DatabaseId &other = reference.databaseID; + ThrowInvalidArgument( + "Document Reference is for database %s/%s but should be for database %s/%s%s", + other.project_id(), other.database_id(), _databaseID.project_id(), + _databaseID.database_id(), context.FieldDescription()); } - return [FSTReferenceValue referenceValue:[FSTDocumentKey keyWithDocumentKey:reference.key] - databaseID:self.databaseID]; + return FieldValue::FromReference(_databaseID, reference.key); } else { - FSTThrowInvalidArgument(@"Unsupported type: %@%s", NSStringFromClass([input class]), - context.FieldDescription().c_str()); + ThrowInvalidArgument("Unsupported type: %s%s", NSStringFromClass([input class]), + context.FieldDescription()); } } -- (std::vector)parseArrayTransformElements:(NSArray *)elements { +- (std::vector)parseArrayTransformElements:(NSArray *)elements { ParseAccumulator accumulator{UserDataSource::Argument}; - std::vector values; + std::vector values; for (NSUInteger i = 0; i < elements.count; i++) { id element = elements[i]; // Although array transforms are used with writes, the actual elements being unioned or removed // are not considered writes since they cannot contain any FieldValue sentinels, etc. ParseContext context = accumulator.RootContext(); - FSTFieldValue *parsedElement = [self parseData:element context:context.ChildContext(i)]; + absl::optional parsedElement = [self parseData:element + context:context.ChildContext(i)]; HARD_ASSERT(parsedElement && accumulator.field_transforms().size() == 0, "Failed to properly parse array transform element: %s", element); - values.push_back(parsedElement); + values.push_back(*parsedElement); } return values; } diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/converters.h b/Example/Pods/FirebaseFirestore/Firestore/Source/API/converters.h new file mode 100644 index 0000000..199df59 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/converters.h @@ -0,0 +1,59 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_SOURCE_API_CONVERTERS_H_ +#define FIRESTORE_SOURCE_API_CONVERTERS_H_ + +#if !defined(__OBJC__) +#error "This header only supports Objective-C++" +#endif // !defined(__OBJC__) + +#import + +@class FIRGeoPoint; +@class FIRTimestamp; + +NS_ASSUME_NONNULL_BEGIN + +namespace firebase { + +class Timestamp; + +namespace firestore { + +class GeoPoint; + +namespace api { + +/** Converts a user-supplied FIRGeoPoint to the equivalent C++ GeoPoint. */ +GeoPoint MakeGeoPoint(FIRGeoPoint* geo_point); + +/** Converts a C++ GeoPoint to the equivalent Objective-C FIRGeoPoint. */ +FIRGeoPoint* MakeFIRGeoPoint(const GeoPoint& geo_point); + +/** Converts a user-supplied FIRTimestamp to the equivalent C++ Timestamp. */ +Timestamp MakeTimestamp(FIRTimestamp* timestamp); +Timestamp MakeTimestamp(NSDate* date); + +FIRTimestamp* MakeFIRTimestamp(const Timestamp& timestamp); + +} // namespace api +} // namespace firestore +} // namespace firebase + +NS_ASSUME_NONNULL_END + +#endif // FIRESTORE_SOURCE_API_CONVERTERS_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/API/converters.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/API/converters.mm new file mode 100644 index 0000000..bc96fb1 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/API/converters.mm @@ -0,0 +1,58 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/Source/API/converters.h" + +#import "FIRGeoPoint.h" +#import "FIRTimestamp.h" + +#include "Firestore/core/include/firebase/firestore/geo_point.h" +#include "Firestore/core/include/firebase/firestore/timestamp.h" + +NS_ASSUME_NONNULL_BEGIN + +namespace firebase { +namespace firestore { +namespace api { + +GeoPoint MakeGeoPoint(FIRGeoPoint* geo_point) { + return GeoPoint(geo_point.latitude, geo_point.longitude); +} + +FIRGeoPoint* MakeFIRGeoPoint(const GeoPoint& geo_point) { + return [[FIRGeoPoint alloc] initWithLatitude:geo_point.latitude() + longitude:geo_point.longitude()]; +} + +Timestamp MakeTimestamp(FIRTimestamp* timestamp) { + return Timestamp(timestamp.seconds, timestamp.nanoseconds); +} + +Timestamp MakeTimestamp(NSDate* date) { + FIRTimestamp* timestamp = [FIRTimestamp timestampWithDate:date]; + return MakeTimestamp(timestamp); +} + +FIRTimestamp* MakeFIRTimestamp(const Timestamp& timestamp) { + return [[FIRTimestamp alloc] initWithSeconds:timestamp.seconds() + nanoseconds:timestamp.nanoseconds()]; +} + +} // namespace api +} // namespace firestore +} // namespace firebase + +NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTEventManager.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTEventManager.h deleted file mode 100644 index c3d9639..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTEventManager.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include - -#include "Firestore/core/src/firebase/firestore/core/query_listener.h" -#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" - -@class FSTQuery; -@class FSTSyncEngine; - -NS_ASSUME_NONNULL_BEGIN - -using firebase::firestore::core::QueryListener; - -#pragma mark - FSTEventManager - -/** - * EventManager is responsible for mapping queries to query event emitters. It handles "fan-out." - * (Identical queries will re-use the same watch on the backend.) - */ -@interface FSTEventManager : NSObject - -+ (instancetype)eventManagerWithSyncEngine:(FSTSyncEngine *)syncEngine; - -- (instancetype)init __attribute__((unavailable("Use static constructor method."))); - -- (firebase::firestore::model::TargetId)addListener:(std::shared_ptr)listener; -- (void)removeListener:(const std::shared_ptr &)listener; - -- (void)applyChangedOnlineState:(firebase::firestore::model::OnlineState)onlineState; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTEventManager.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTEventManager.mm deleted file mode 100644 index 93f5999..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTEventManager.mm +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Core/FSTEventManager.h" - -#include -#include -#include - -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Core/FSTSyncEngine.h" - -#include "Firestore/core/src/firebase/firestore/model/document_set.h" -#include "Firestore/core/src/firebase/firestore/util/error_apple.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/objc_compatibility.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" -#include "absl/algorithm/container.h" -#include "absl/types/optional.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace objc = firebase::firestore::util::objc; -using firebase::firestore::core::DocumentViewChange; -using firebase::firestore::core::ViewSnapshot; -using firebase::firestore::model::OnlineState; -using firebase::firestore::model::TargetId; -using firebase::firestore::util::MakeStatus; -using firebase::firestore::util::Status; - -#pragma mark - FSTQueryListenersInfo - -namespace { - -/** - * Holds the listeners and the last received ViewSnapshot for a query being tracked by - * EventManager. - */ -struct QueryListenersInfo { - TargetId target_id; - std::vector> listeners; - - void Erase(const std::shared_ptr &listener) { - auto found = absl::c_find(listeners, listener); - if (found != listeners.end()) { - listeners.erase(found); - } - } - - const absl::optional &view_snapshot() const { - return snapshot_; - } - - void set_view_snapshot(const absl::optional &snapshot) { - snapshot_ = snapshot; - } - - private: - // Other members are public in this struct, ensure that any reads are - // copies by requiring reads to go through a const getter. - absl::optional snapshot_; -}; - -} // namespace - -#pragma mark - FSTEventManager - -@interface FSTEventManager () - -- (instancetype)initWithSyncEngine:(FSTSyncEngine *)syncEngine NS_DESIGNATED_INITIALIZER; - -@property(nonatomic, strong, readonly) FSTSyncEngine *syncEngine; -@property(nonatomic, assign) OnlineState onlineState; - -@end - -@implementation FSTEventManager { - objc::unordered_map _queries; -} - -+ (instancetype)eventManagerWithSyncEngine:(FSTSyncEngine *)syncEngine { - return [[FSTEventManager alloc] initWithSyncEngine:syncEngine]; -} - -- (instancetype)initWithSyncEngine:(FSTSyncEngine *)syncEngine { - if (self = [super init]) { - _syncEngine = syncEngine; - _syncEngine.syncEngineDelegate = self; - } - return self; -} - -- (TargetId)addListener:(std::shared_ptr)listener { - FSTQuery *query = listener->query(); - - auto inserted = _queries.emplace(query, QueryListenersInfo{}); - bool first_listen = inserted.second; - QueryListenersInfo &query_info = inserted.first->second; - - query_info.listeners.push_back(listener); - - listener->OnOnlineStateChanged(self.onlineState); - - if (query_info.view_snapshot().has_value()) { - listener->OnViewSnapshot(query_info.view_snapshot().value()); - } - - if (first_listen) { - query_info.target_id = [self.syncEngine listenToQuery:query]; - } - return query_info.target_id; -} - -- (void)removeListener:(const std::shared_ptr &)listener { - FSTQuery *query = listener->query(); - bool last_listen = false; - - auto found_iter = _queries.find(query); - if (found_iter != _queries.end()) { - QueryListenersInfo &query_info = found_iter->second; - query_info.Erase(listener); - last_listen = query_info.listeners.empty(); - } - - if (last_listen) { - _queries.erase(found_iter); - [self.syncEngine stopListeningToQuery:query]; - } -} - -- (void)handleViewSnapshots:(std::vector &&)viewSnapshots { - for (ViewSnapshot &viewSnapshot : viewSnapshots) { - FSTQuery *query = viewSnapshot.query(); - auto found_iter = _queries.find(query); - if (found_iter != _queries.end()) { - QueryListenersInfo &query_info = found_iter->second; - for (const auto &listener : query_info.listeners) { - listener->OnViewSnapshot(viewSnapshot); - } - query_info.set_view_snapshot(std::move(viewSnapshot)); - } - } -} - -- (void)handleError:(NSError *)error forQuery:(FSTQuery *)query { - auto found_iter = _queries.find(query); - if (found_iter != _queries.end()) { - QueryListenersInfo &query_info = found_iter->second; - for (const auto &listener : query_info.listeners) { - listener->OnError(MakeStatus(error)); - } - - // Remove all listeners. NOTE: We don't need to call [FSTSyncEngine stopListening] after an - // error. - _queries.erase(found_iter); - } -} - -- (void)applyChangedOnlineState:(OnlineState)onlineState { - self.onlineState = onlineState; - - for (auto &&kv : _queries) { - QueryListenersInfo &info = kv.second; - for (auto &&listener : info.listeners) { - listener->OnOnlineStateChanged(onlineState); - } - } -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTFirestoreClient.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTFirestoreClient.h deleted file mode 100644 index 8d4c4cf..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTFirestoreClient.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include -#include - -#import "Firestore/Source/Core/FSTTypes.h" - -#include "Firestore/core/src/firebase/firestore/api/document_reference.h" -#include "Firestore/core/src/firebase/firestore/api/document_snapshot.h" -#include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" -#include "Firestore/core/src/firebase/firestore/core/database_info.h" -#include "Firestore/core/src/firebase/firestore/core/listen_options.h" -#include "Firestore/core/src/firebase/firestore/core/query_listener.h" -#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" -#include "Firestore/core/src/firebase/firestore/model/database_id.h" -#include "Firestore/core/src/firebase/firestore/util/async_queue.h" -#include "Firestore/core/src/firebase/firestore/util/executor.h" -#include "Firestore/core/src/firebase/firestore/util/statusor_callback.h" - -@class FIRDocumentReference; -@class FIRDocumentSnapshot; -@class FIRFirestoreSettings; -@class FIRQuery; -@class FIRQuerySnapshot; -@class FSTDatabaseID; -@class FSTDatabaseInfo; -@class FSTDocument; -@class FSTMutation; -@class FSTQuery; -@class FSTTransaction; - -NS_ASSUME_NONNULL_BEGIN - -using firebase::firestore::api::DocumentSnapshot; -using firebase::firestore::core::ListenOptions; -using firebase::firestore::core::QueryListener; -using firebase::firestore::core::ViewSnapshot; - -/** - * FirestoreClient is a top-level class that constructs and owns all of the pieces of the client - * SDK architecture. It is responsible for creating the worker queue that is shared by all of the - * other components in the system. - */ -@interface FSTFirestoreClient : NSObject - -/** - * Creates and returns a FSTFirestoreClient with the given parameters. - * - * All callbacks and events will be triggered on the provided userExecutor. - */ -+ (instancetype) - clientWithDatabaseInfo:(const firebase::firestore::core::DatabaseInfo &)databaseInfo - settings:(FIRFirestoreSettings *)settings - credentialsProvider:(firebase::firestore::auth::CredentialsProvider *) - credentialsProvider // no passing ownership - userExecutor:(std::unique_ptr)userExecutor - workerQueue:(std::unique_ptr)workerQueue; - -- (instancetype)init __attribute__((unavailable("Use static constructor method."))); - -/** Shuts down this client, cancels all writes / listeners, and releases all resources. */ -- (void)shutdownWithCompletion:(nullable FSTVoidErrorBlock)completion; - -/** Disables the network connection. Pending operations will not complete. */ -- (void)disableNetworkWithCompletion:(nullable FSTVoidErrorBlock)completion; - -/** Enables the network connection and requeues all pending operations. */ -- (void)enableNetworkWithCompletion:(nullable FSTVoidErrorBlock)completion; - -/** Starts listening to a query. */ -- (std::shared_ptr)listenToQuery:(FSTQuery *)query - options:(ListenOptions)options - listener:(ViewSnapshot::SharedListener &&)listener; - -/** Stops listening to a query previously listened to. */ -- (void)removeListener:(const std::shared_ptr &)listener; - -/** - * Retrieves a document from the cache via the indicated completion. If the doc - * doesn't exist, an error will be sent to the completion. - */ -- (void)getDocumentFromLocalCache:(const firebase::firestore::api::DocumentReference &)doc - completion:(DocumentSnapshot::Listener &&)completion; - -/** - * Retrieves a (possibly empty) set of documents from the cache via the - * indicated completion. - */ -- (void)getDocumentsFromLocalCache:(FIRQuery *)query - completion:(void (^)(FIRQuerySnapshot *_Nullable query, - NSError *_Nullable error))completion; - -/** Write mutations. completion will be notified when it's written to the backend. */ -- (void)writeMutations:(std::vector &&)mutations - completion:(nullable FSTVoidErrorBlock)completion; - -/** Tries to execute the transaction in updateBlock up to retries times. */ -- (void)transactionWithRetries:(int)retries - updateBlock:(FSTTransactionBlock)updateBlock - completion:(FSTVoidIDErrorBlock)completion; - -/** The database ID of the databaseInfo this client was initialized with. */ -// Ownes a DatabaseInfo instance, which contains the id here. -@property(nonatomic, assign, readonly) const firebase::firestore::model::DatabaseId *databaseID; - -/** - * Dispatch queue for user callbacks / events. This will often be the "Main Dispatch Queue" of the - * app but the developer can configure it to a different queue if they so choose. - */ -- (firebase::firestore::util::Executor *)userExecutor; - -/** For testing only. */ -- (firebase::firestore::util::AsyncQueue *)workerQueue; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTFirestoreClient.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTFirestoreClient.mm deleted file mode 100644 index de03ebe..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTFirestoreClient.mm +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Core/FSTFirestoreClient.h" - -#include // NOLINT(build/c++11) -#include // NOLINT(build/c++11) -#include -#include - -#import "FIRFirestoreErrors.h" -#import "FIRFirestoreSettings.h" -#import "Firestore/Source/API/FIRDocumentReference+Internal.h" -#import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h" -#import "Firestore/Source/API/FIRFirestore+Internal.h" -#import "Firestore/Source/API/FIRQuery+Internal.h" -#import "Firestore/Source/API/FIRQuerySnapshot+Internal.h" -#import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h" -#import "Firestore/Source/Core/FSTEventManager.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Core/FSTSyncEngine.h" -#import "Firestore/Source/Core/FSTView.h" -#import "Firestore/Source/Local/FSTLRUGarbageCollector.h" -#import "Firestore/Source/Local/FSTLevelDB.h" -#import "Firestore/Source/Local/FSTLocalSerializer.h" -#import "Firestore/Source/Local/FSTLocalStore.h" -#import "Firestore/Source/Local/FSTMemoryPersistence.h" -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Remote/FSTSerializerBeta.h" -#import "Firestore/Source/Util/FSTClasses.h" - -#include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" -#include "Firestore/core/src/firebase/firestore/core/database_info.h" -#include "Firestore/core/src/firebase/firestore/model/database_id.h" -#include "Firestore/core/src/firebase/firestore/model/document_set.h" -#include "Firestore/core/src/firebase/firestore/remote/datastore.h" -#include "Firestore/core/src/firebase/firestore/remote/remote_store.h" -#include "Firestore/core/src/firebase/firestore/util/async_queue.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/log.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" -#include "Firestore/core/src/firebase/firestore/util/statusor.h" -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" -#include "absl/memory/memory.h" - -namespace util = firebase::firestore::util; -using firebase::firestore::FirestoreErrorCode; -using firebase::firestore::api::DocumentReference; -using firebase::firestore::api::DocumentSnapshot; -using firebase::firestore::auth::CredentialsProvider; -using firebase::firestore::auth::User; -using firebase::firestore::core::DatabaseInfo; -using firebase::firestore::core::ViewSnapshot; -using firebase::firestore::local::LruParams; -using firebase::firestore::model::DatabaseId; -using firebase::firestore::model::DocumentKeySet; -using firebase::firestore::model::DocumentMap; -using firebase::firestore::model::MaybeDocumentMap; -using firebase::firestore::model::OnlineState; -using firebase::firestore::remote::Datastore; -using firebase::firestore::remote::RemoteStore; -using firebase::firestore::util::Path; -using firebase::firestore::util::Status; -using firebase::firestore::util::AsyncQueue; -using firebase::firestore::util::DelayedOperation; -using firebase::firestore::util::Executor; -using firebase::firestore::util::Status; -using firebase::firestore::util::StatusOr; -using firebase::firestore::util::StatusOrCallback; -using firebase::firestore::util::TimerId; - -NS_ASSUME_NONNULL_BEGIN - -/** How long we wait to try running LRU GC after SDK initialization. */ -static const std::chrono::milliseconds FSTLruGcInitialDelay = std::chrono::minutes(1); -/** Minimum amount of time between GC checks, after the first one. */ -static const std::chrono::milliseconds FSTLruGcRegularDelay = std::chrono::minutes(5); - -@interface FSTFirestoreClient () { - DatabaseInfo _databaseInfo; -} - -- (instancetype)initWithDatabaseInfo:(const DatabaseInfo &)databaseInfo - settings:(FIRFirestoreSettings *)settings - credentialsProvider: - (CredentialsProvider *)credentialsProvider // no passing ownership - userExecutor:(std::unique_ptr)userExecutor - workerQueue:(std::unique_ptr)queue NS_DESIGNATED_INITIALIZER; - -@property(nonatomic, assign, readonly) const DatabaseInfo *databaseInfo; -@property(nonatomic, strong, readonly) FSTEventManager *eventManager; -@property(nonatomic, strong, readonly) id persistence; -@property(nonatomic, strong, readonly) FSTSyncEngine *syncEngine; -@property(nonatomic, strong, readonly) FSTLocalStore *localStore; - -// Does not own the CredentialsProvider instance. -@property(nonatomic, assign, readonly) CredentialsProvider *credentialsProvider; - -@end - -@implementation FSTFirestoreClient { - /** - * Async queue responsible for all of our internal processing. When we get incoming work from - * the user (via public API) or the network (incoming gRPC messages), we should always dispatch - * onto this queue. This ensures our internal data structures are never accessed from multiple - * threads simultaneously. - */ - std::unique_ptr _workerQueue; - - std::unique_ptr _remoteStore; - - std::unique_ptr _userExecutor; - std::chrono::milliseconds _initialGcDelay; - std::chrono::milliseconds _regularGcDelay; - BOOL _gcHasRun; - _Nullable id _lruDelegate; - DelayedOperation _lruCallback; -} - -- (Executor *)userExecutor { - return _userExecutor.get(); -} - -- (AsyncQueue *)workerQueue { - return _workerQueue.get(); -} - -+ (instancetype)clientWithDatabaseInfo:(const DatabaseInfo &)databaseInfo - settings:(FIRFirestoreSettings *)settings - credentialsProvider: - (CredentialsProvider *)credentialsProvider // no passing ownership - userExecutor:(std::unique_ptr)userExecutor - workerQueue:(std::unique_ptr)workerQueue { - return [[FSTFirestoreClient alloc] initWithDatabaseInfo:databaseInfo - settings:settings - credentialsProvider:credentialsProvider - userExecutor:std::move(userExecutor) - workerQueue:std::move(workerQueue)]; -} - -- (instancetype)initWithDatabaseInfo:(const DatabaseInfo &)databaseInfo - settings:(FIRFirestoreSettings *)settings - credentialsProvider: - (CredentialsProvider *)credentialsProvider // no passing ownership - userExecutor:(std::unique_ptr)userExecutor - workerQueue:(std::unique_ptr)workerQueue { - if (self = [super init]) { - _databaseInfo = databaseInfo; - _credentialsProvider = credentialsProvider; - _userExecutor = std::move(userExecutor); - _workerQueue = std::move(workerQueue); - _gcHasRun = NO; - _initialGcDelay = FSTLruGcInitialDelay; - _regularGcDelay = FSTLruGcRegularDelay; - - auto userPromise = std::make_shared>(); - bool initialized = false; - - __weak __typeof__(self) weakSelf = self; - auto credentialChangeListener = [initialized, userPromise, weakSelf](User user) mutable { - __typeof__(self) strongSelf = weakSelf; - if (!strongSelf) return; - - if (!initialized) { - initialized = true; - userPromise->set_value(user); - } else { - strongSelf->_workerQueue->Enqueue( - [strongSelf, user] { [strongSelf credentialDidChangeWithUser:user]; }); - } - }; - - _credentialsProvider->SetCredentialChangeListener(credentialChangeListener); - - // Defer initialization until we get the current user from the credentialChangeListener. This is - // guaranteed to be synchronously dispatched onto our worker queue, so we will be initialized - // before any subsequently queued work runs. - _workerQueue->Enqueue([self, userPromise, settings] { - User user = userPromise->get_future().get(); - [self initializeWithUser:user settings:settings]; - }); - } - return self; -} - -- (void)initializeWithUser:(const User &)user settings:(FIRFirestoreSettings *)settings { - // Do all of our initialization on our own dispatch queue. - _workerQueue->VerifyIsCurrentQueue(); - LOG_DEBUG("Initializing. Current user: %s", user.uid()); - - // Note: The initialization work must all be synchronous (we can't dispatch more work) since - // external write/listen operations could get queued to run before that subsequent work - // completes. - if (settings.isPersistenceEnabled) { - Path dir = [FSTLevelDB storageDirectoryForDatabaseInfo:*self.databaseInfo - documentsDirectory:[FSTLevelDB documentsDirectory]]; - - FSTSerializerBeta *remoteSerializer = - [[FSTSerializerBeta alloc] initWithDatabaseID:&self.databaseInfo->database_id()]; - FSTLocalSerializer *serializer = - [[FSTLocalSerializer alloc] initWithRemoteSerializer:remoteSerializer]; - FSTLevelDB *ldb; - Status levelDbStatus = - [FSTLevelDB dbWithDirectory:std::move(dir) - serializer:serializer - lruParams:LruParams::WithCacheSize(settings.cacheSizeBytes) - ptr:&ldb]; - if (!levelDbStatus.ok()) { - // If leveldb fails to start then just throw up our hands: the error is unrecoverable. - // There's nothing an end-user can do and nearly all failures indicate the developer is doing - // something grossly wrong so we should stop them cold in their tracks with a failure they - // can't ignore. - [NSException raise:NSInternalInconsistencyException - format:@"Failed to open DB: %s", levelDbStatus.ToString().c_str()]; - } - _lruDelegate = ldb.referenceDelegate; - _persistence = ldb; - [self scheduleLruGarbageCollection]; - } else { - _persistence = [FSTMemoryPersistence persistenceWithEagerGC]; - } - - _localStore = [[FSTLocalStore alloc] initWithPersistence:_persistence initialUser:user]; - - auto datastore = - std::make_shared(*self.databaseInfo, _workerQueue.get(), _credentialsProvider); - - _remoteStore = absl::make_unique( - _localStore, std::move(datastore), _workerQueue.get(), - [self](OnlineState onlineState) { [self.syncEngine applyChangedOnlineState:onlineState]; }); - - _syncEngine = [[FSTSyncEngine alloc] initWithLocalStore:_localStore - remoteStore:_remoteStore.get() - initialUser:user]; - - _eventManager = [FSTEventManager eventManagerWithSyncEngine:_syncEngine]; - - // Setup wiring for remote store. - _remoteStore->set_sync_engine(_syncEngine); - - // NOTE: RemoteStore depends on LocalStore (for persisting stream tokens, refilling mutation - // queue, etc.) so must be started after LocalStore. - [_localStore start]; - _remoteStore->Start(); -} - -/** - * Schedules a callback to try running LRU garbage collection. Reschedules itself after the GC has - * run. - */ -- (void)scheduleLruGarbageCollection { - std::chrono::milliseconds delay = _gcHasRun ? _regularGcDelay : _initialGcDelay; - _lruCallback = _workerQueue->EnqueueAfterDelay(delay, TimerId::GarbageCollectionDelay, [self]() { - [self->_localStore collectGarbage:self->_lruDelegate.gc]; - self->_gcHasRun = YES; - [self scheduleLruGarbageCollection]; - }); -} - -- (void)credentialDidChangeWithUser:(const User &)user { - _workerQueue->VerifyIsCurrentQueue(); - - LOG_DEBUG("Credential Changed. Current user: %s", user.uid()); - [self.syncEngine credentialDidChangeWithUser:user]; -} - -- (void)disableNetworkWithCompletion:(nullable FSTVoidErrorBlock)completion { - _workerQueue->Enqueue([self, completion] { - _remoteStore->DisableNetwork(); - if (completion) { - self->_userExecutor->Execute([=] { completion(nil); }); - } - }); -} - -- (void)enableNetworkWithCompletion:(nullable FSTVoidErrorBlock)completion { - _workerQueue->Enqueue([self, completion] { - _remoteStore->EnableNetwork(); - if (completion) { - self->_userExecutor->Execute([=] { completion(nil); }); - } - }); -} - -- (void)shutdownWithCompletion:(nullable FSTVoidErrorBlock)completion { - _workerQueue->Enqueue([self, completion] { - self->_credentialsProvider->SetCredentialChangeListener(nullptr); - - // If we've scheduled LRU garbage collection, cancel it. - if (self->_lruCallback) { - self->_lruCallback.Cancel(); - } - _remoteStore->Shutdown(); - [self.persistence shutdown]; - if (completion) { - self->_userExecutor->Execute([=] { completion(nil); }); - } - }); -} - -- (std::shared_ptr)listenToQuery:(FSTQuery *)query - options:(ListenOptions)options - listener:(ViewSnapshot::SharedListener &&)listener { - auto query_listener = QueryListener::Create(query, std::move(options), std::move(listener)); - - _workerQueue->Enqueue([self, query_listener] { [self.eventManager addListener:query_listener]; }); - - return query_listener; -} - -- (void)removeListener:(const std::shared_ptr &)listener { - _workerQueue->Enqueue([self, listener] { [self.eventManager removeListener:listener]; }); -} - -- (void)getDocumentFromLocalCache:(const DocumentReference &)doc - completion:(DocumentSnapshot::Listener &&)completion { - auto shared_completion = absl::ShareUniquePtr(std::move(completion)); - _workerQueue->Enqueue([self, doc, shared_completion] { - FSTMaybeDocument *maybeDoc = [self.localStore readDocument:doc.key()]; - StatusOr maybe_snapshot; - - if ([maybeDoc isKindOfClass:[FSTDocument class]]) { - FSTDocument *document = (FSTDocument *)maybeDoc; - maybe_snapshot = DocumentSnapshot{doc.firestore(), doc.key(), document, - /*from_cache=*/true, - /*has_pending_writes=*/document.hasLocalMutations}; - } else if ([maybeDoc isKindOfClass:[FSTDeletedDocument class]]) { - maybe_snapshot = DocumentSnapshot{doc.firestore(), doc.key(), nil, - /*from_cache=*/true, - /*has_pending_writes=*/false}; - } else { - maybe_snapshot = Status{FirestoreErrorCode::Unavailable, - "Failed to get document from cache. (However, this document " - "may exist on the server. Run again without setting source to " - "FIRFirestoreSourceCache to attempt to retrieve the document "}; - } - - if (shared_completion) { - self->_userExecutor->Execute([=] { shared_completion->OnEvent(std::move(maybe_snapshot)); }); - } - }); -} - -- (void)getDocumentsFromLocalCache:(FIRQuery *)query - completion:(void (^)(FIRQuerySnapshot *_Nullable query, - NSError *_Nullable error))completion { - _workerQueue->Enqueue([self, query, completion] { - DocumentMap docs = [self.localStore executeQuery:query.query]; - - FSTView *view = [[FSTView alloc] initWithQuery:query.query remoteDocuments:DocumentKeySet{}]; - FSTViewDocumentChanges *viewDocChanges = - [view computeChangesWithDocuments:docs.underlying_map()]; - FSTViewChange *viewChange = [view applyChangesToDocuments:viewDocChanges]; - HARD_ASSERT(viewChange.limboChanges.count == 0, - "View returned limbo documents during local-only query execution."); - HARD_ASSERT(viewChange.snapshot.has_value(), "Expected a snapshot"); - - ViewSnapshot snapshot = std::move(viewChange.snapshot).value(); - SnapshotMetadata metadata(snapshot.has_pending_writes(), snapshot.from_cache()); - - FIRQuerySnapshot *result = [[FIRQuerySnapshot alloc] initWithFirestore:query.firestore.wrapped - originalQuery:query.query - snapshot:std::move(snapshot) - metadata:std::move(metadata)]; - - if (completion) { - self->_userExecutor->Execute([=] { completion(result, nil); }); - } - }); -} - -- (void)writeMutations:(std::vector &&)mutations - completion:(nullable FSTVoidErrorBlock)completion { - // TODO(c++14): move `mutations` into lambda (C++14). - _workerQueue->Enqueue([self, mutations, completion]() mutable { - if (mutations.empty()) { - if (completion) { - self->_userExecutor->Execute([=] { completion(nil); }); - } - } else { - [self.syncEngine writeMutations:std::move(mutations) - completion:^(NSError *error) { - // Dispatch the result back onto the user dispatch queue. - if (completion) { - self->_userExecutor->Execute([=] { completion(error); }); - } - }]; - } - }); -}; - -- (void)transactionWithRetries:(int)retries - updateBlock:(FSTTransactionBlock)updateBlock - completion:(FSTVoidIDErrorBlock)completion { - _workerQueue->Enqueue([self, retries, updateBlock, completion] { - [self.syncEngine - transactionWithRetries:retries - workerQueue:_workerQueue.get() - updateBlock:updateBlock - completion:^(id _Nullable result, NSError *_Nullable error) { - // Dispatch the result back onto the user dispatch queue. - if (completion) { - self->_userExecutor->Execute([=] { completion(result, error); }); - } - }]; - }); -} - -- (const DatabaseInfo *)databaseInfo { - return &_databaseInfo; -} - -- (const DatabaseId *)databaseID { - return &_databaseInfo.database_id(); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTQuery.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTQuery.h deleted file mode 100644 index 851da92..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTQuery.h +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include "Firestore/core/src/firebase/firestore/model/field_path.h" -#include "Firestore/core/src/firebase/firestore/model/resource_path.h" - -@class FSTDocument; -@class FSTFieldValue; - -NS_ASSUME_NONNULL_BEGIN - -/** - * FSTRelationFilterOperator is a value relation operator that can be used to filter documents. - * It is similar to NSPredicateOperatorType, but only has operators supported by Firestore. - */ -typedef NS_ENUM(NSInteger, FSTRelationFilterOperator) { - FSTRelationFilterOperatorLessThan = 0, - FSTRelationFilterOperatorLessThanOrEqual, - FSTRelationFilterOperatorEqual, - FSTRelationFilterOperatorGreaterThanOrEqual, - FSTRelationFilterOperatorGreaterThan, - FSTRelationFilterOperatorArrayContains, -}; - -/** Interface used for all query filters. */ -@interface FSTFilter : NSObject - -/** - * Creates a filter for the provided path, operator, and value. - * - * Note that if the relational operator is FSTRelationFilterOperatorEqual and - * the value is [FSTNullValue nullValue] or [FSTDoubleValue nanValue], this - * will return the appropriate FSTNullFilter or FSTNanFilter class instead of a - * FSTRelationFilter. - */ -+ (instancetype)filterWithField:(const firebase::firestore::model::FieldPath &)field - filterOperator:(FSTRelationFilterOperator)op - value:(FSTFieldValue *)value; - -/** Returns the field the Filter operates over. Abstract method. */ -- (const firebase::firestore::model::FieldPath &)field; - -/** Returns true if a document matches the filter. Abstract method. */ -- (BOOL)matchesDocument:(FSTDocument *)document; - -/** A unique ID identifying the filter; used when serializing queries. Abstract method. */ -- (NSString *)canonicalID; - -@end - -/** - * FSTRelationFilter is a document filter constraint on a query with a single relation operator. - * It is similar to NSComparisonPredicate, except customized for Firestore semantics. - */ -@interface FSTRelationFilter : FSTFilter - -/** - * Creates a new constraint for filtering documents. - * - * @param field A path to a field in the document to filter on. The LHS of the expression. - * @param filterOperator The binary operator to apply. - * @param value A constant value to compare @a field to. The RHS of the expression. - * @return A new instance of FSTRelationFilter. - */ -- (instancetype)initWithField:(firebase::firestore::model::FieldPath)field - filterOperator:(FSTRelationFilterOperator)filterOperator - value:(FSTFieldValue *)value; - -- (instancetype)init NS_UNAVAILABLE; - -/** Returns YES if the receiver is not an equality relation. */ -- (BOOL)isInequality; - -/** The left hand side of the relation. A path into a document field. */ -- (const firebase::firestore::model::FieldPath &)field; - -/** The type of equality/inequality operator to use in the relation. */ -@property(nonatomic, assign, readonly) FSTRelationFilterOperator filterOperator; - -/** The right hand side of the relation. A constant value to compare to. */ -@property(nonatomic, strong, readonly) FSTFieldValue *value; - -@end - -/** Filter that matches NULL values. */ -@interface FSTNullFilter : FSTFilter -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithField:(firebase::firestore::model::FieldPath)field - NS_DESIGNATED_INITIALIZER; -@end - -/** Filter that matches NAN values. */ -@interface FSTNanFilter : FSTFilter -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithField:(firebase::firestore::model::FieldPath)field - NS_DESIGNATED_INITIALIZER; -@end - -/** FSTSortOrder is a field and direction to order query results by. */ -@interface FSTSortOrder : NSObject - -/** Creates a new sort order with the given field and direction. */ -+ (instancetype)sortOrderWithFieldPath:(firebase::firestore::model::FieldPath)fieldPath - ascending:(BOOL)ascending; - -- (instancetype)init NS_UNAVAILABLE; - -/** Compares two documents based on the field and direction of this sort order. */ -- (NSComparisonResult)compareDocument:(FSTDocument *)document1 toDocument:(FSTDocument *)document2; - -/** The field to sort by. */ -- (const firebase::firestore::model::FieldPath &)field; - -/** The direction of the sort. */ -@property(nonatomic, assign, readonly, getter=isAscending) BOOL ascending; - -@end - -/** - * FSTBound represents a bound of a query. - * - * The bound is specified with the given components representing a position and whether it's just - * before or just after the position (relative to whatever the query order is). - * - * The position represents a logical index position for a query. It's a prefix of values for - * the (potentially implicit) order by clauses of a query. - * - * FSTBound provides a function to determine whether a document comes before or after a bound. - * This is influenced by whether the position is just before or just after the provided values. - */ -@interface FSTBound : NSObject - -/** - * Creates a new bound. - * - * @param position The position relative to the sort order. - * @param isBefore Whether this bound is just before or just after the position. - */ -+ (instancetype)boundWithPosition:(NSArray *)position isBefore:(BOOL)isBefore; - -/** Whether this bound is just before or just after the provided position */ -@property(nonatomic, assign, readonly, getter=isBefore) BOOL before; - -/** The index position of this bound represented as an array of field values. */ -@property(nonatomic, strong, readonly) NSArray *position; - -/** Returns YES if a document comes before a bound using the provided sort order. */ -- (BOOL)sortsBeforeDocument:(FSTDocument *)document - usingSortOrder:(NSArray *)sortOrder; - -@end - -/** FSTQuery represents the internal structure of a Firestore query. */ -@interface FSTQuery : NSObject - -- (id)init NS_UNAVAILABLE; - -/** - * Initializes a query with all of its components directly. - */ -- (instancetype)initWithPath:(firebase::firestore::model::ResourcePath)path - collectionGroup:(nullable NSString *)collectionGroup - filterBy:(NSArray *)filters - orderBy:(NSArray *)sortOrders - limit:(NSInteger)limit - startAt:(nullable FSTBound *)startAtBound - endAt:(nullable FSTBound *)endAtBound NS_DESIGNATED_INITIALIZER; - -/** - * Creates and returns a new FSTQuery. - * - * @param path The path to the collection to be queried over. - * @return A new instance of FSTQuery. - */ -+ (instancetype)queryWithPath:(firebase::firestore::model::ResourcePath)path; - -/** - * Creates and returns a new FSTQuery. - * - * @param path The path to the location to be queried over. Must currently be - * empty in the case of a collection group query. - * @param collectionGroup The collection group to be queried over. nil if this - * is not a collection group query. - * @return A new instance of FSTQuery. - */ -+ (instancetype)queryWithPath:(firebase::firestore::model::ResourcePath)path - collectionGroup:(nullable NSString *)collectionGroup; - -/** - * Returns the list of ordering constraints that were explicitly requested on the query by the - * user. - * - * Note that the actual query performed might add additional sort orders to match the behavior - * of the backend. - */ -- (NSArray *)explicitSortOrders; - -/** - * Returns the full list of ordering constraints on the query. - * - * This might include additional sort orders added implicitly to match the backend behavior. - */ -- (NSArray *)sortOrders; - -/** - * Creates a new FSTQuery with an additional filter. - * - * @param filter The predicate to filter by. - * @return the new FSTQuery. - */ -- (instancetype)queryByAddingFilter:(FSTFilter *)filter; - -/** - * Creates a new FSTQuery with an additional ordering constraint. - * - * @param sortOrder The key and direction to order by. - * @return the new FSTQuery. - */ -- (instancetype)queryByAddingSortOrder:(FSTSortOrder *)sortOrder; - -/** - * Returns a new FSTQuery with the given limit on how many results can be returned. - * - * @param limit The maximum number of results to return. If @a limit <= 0, behavior is unspecified. - * If @a limit == NSNotFound, then no limit is applied. - */ -- (instancetype)queryBySettingLimit:(NSInteger)limit; - -/** - * Creates a new FSTQuery starting at the provided bound. - * - * @param bound The bound to start this query at. - * @return the new FSTQuery. - */ -- (instancetype)queryByAddingStartAt:(FSTBound *)bound; - -/** - * Creates a new FSTQuery ending at the provided bound. - * - * @param bound The bound to end this query at. - * @return the new FSTQuery. - */ -- (instancetype)queryByAddingEndAt:(FSTBound *)bound; - -/** - * Helper to convert a collection group query into a collection query at a specific path. This is - * used when executing collection group queries, since we have to split the query into a set of - * collection queries at multiple paths. - */ -- (instancetype)collectionQueryAtPath:(firebase::firestore::model::ResourcePath)path; - -/** Returns YES if the receiver is query for a specific document. */ -- (BOOL)isDocumentQuery; - -/** Returns YES if the receiver is a collection group query. */ -- (BOOL)isCollectionGroupQuery; - -/** Returns YES if the @a document matches the constraints of the receiver. */ -- (BOOL)matchesDocument:(FSTDocument *)document; - -/** Returns a comparator that will sort documents according to the receiver's sort order. */ -- (NSComparator)comparator; - -/** Returns the field of the first filter on the receiver that's an inequality, or nullptr if none. - */ -- (nullable const firebase::firestore::model::FieldPath *)inequalityFilterField; - -/** Returns YES if the query has an arrayContains filter already. */ -- (BOOL)hasArrayContainsFilter; - -/** Returns the first field in an order-by constraint, or nullptr if none. */ -- (nullable const firebase::firestore::model::FieldPath *)firstSortOrderField; - -/** The base path of the query. */ -- (const firebase::firestore::model::ResourcePath &)path; - -/** The collection group of the query. */ -@property(nonatomic, nullable, strong, readonly) NSString *collectionGroup; - -/** The filters on the documents returned by the query. */ -@property(nonatomic, strong, readonly) NSArray *filters; - -/** The maximum number of results to return, or NSNotFound if no limit. */ -@property(nonatomic, assign, readonly) NSInteger limit; - -/** - * A canonical string identifying the query. Two different instances of equivalent queries will - * return the same canonicalID. - */ -@property(nonatomic, strong, readonly) NSString *canonicalID; - -/** An optional bound to start the query at. */ -@property(nonatomic, nullable, strong, readonly) FSTBound *startAt; - -/** An optional bound to end the query at. */ -@property(nonatomic, nullable, strong, readonly) FSTBound *endAt; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTQuery.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTQuery.mm deleted file mode 100644 index d057c87..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTQuery.mm +++ /dev/null @@ -1,901 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Core/FSTQuery.h" - -#include -#include -#include - -#import "Firestore/Source/API/FIRFirestore+Internal.h" -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Util/FSTClasses.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" - -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/field_path.h" -#include "Firestore/core/src/firebase/firestore/model/resource_path.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/hashing.h" -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" - -namespace util = firebase::firestore::util; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::FieldPath; -using firebase::firestore::model::ResourcePath; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - FSTRelationFilterOperator functions - -/** - * Returns the reverse order (i.e. Ascending => Descending) etc. - */ -static constexpr NSComparisonResult ReverseOrder(NSComparisonResult result) { - return static_cast(-static_cast(result)); -} - -NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOperator) { - switch (filterOperator) { - case FSTRelationFilterOperatorLessThan: - return @"<"; - case FSTRelationFilterOperatorLessThanOrEqual: - return @"<="; - case FSTRelationFilterOperatorEqual: - return @"=="; - case FSTRelationFilterOperatorGreaterThanOrEqual: - return @">="; - case FSTRelationFilterOperatorGreaterThan: - return @">"; - case FSTRelationFilterOperatorArrayContains: - return @"array_contains"; - default: - HARD_FAIL("Unknown FSTRelationFilterOperator %s", filterOperator); - } -} - -@implementation FSTFilter - -+ (instancetype)filterWithField:(const FieldPath &)field - filterOperator:(FSTRelationFilterOperator)op - value:(FSTFieldValue *)value { - if ([value isEqual:[FSTNullValue nullValue]]) { - if (op != FSTRelationFilterOperatorEqual) { - FSTThrowInvalidUsage(@"InvalidQueryException", - @"Invalid Query. You can only perform equality comparisons on nil / " - "NSNull."); - } - return [[FSTNullFilter alloc] initWithField:field]; - } else if ([value isEqual:[FSTDoubleValue nanValue]]) { - if (op != FSTRelationFilterOperatorEqual) { - FSTThrowInvalidUsage(@"InvalidQueryException", - @"Invalid Query. You can only perform equality comparisons on NaN."); - } - return [[FSTNanFilter alloc] initWithField:field]; - } else { - return [[FSTRelationFilter alloc] initWithField:field filterOperator:op value:value]; - } -} - -- (const FieldPath &)field { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (BOOL)matchesDocument:(FSTDocument *)document { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (NSString *)canonicalID { - @throw FSTAbstractMethodException(); // NOLINT -} - -@end - -#pragma mark - FSTRelationFilter - -@interface FSTRelationFilter () { - /** The left hand side of the relation. A path into a document field. */ - firebase::firestore::model::FieldPath _field; -} - -/** - * Initializes the receiver relation filter. - * - * @param field A path to a field in the document to filter on. The LHS of the expression. - * @param filterOperator The binary operator to apply. - * @param value A constant value to compare @a field to. The RHS of the expression. - */ -- (instancetype)initWithField:(FieldPath)field - filterOperator:(FSTRelationFilterOperator)filterOperator - value:(FSTFieldValue *)value NS_DESIGNATED_INITIALIZER; - -/** Returns YES if @a document matches the receiver's constraint. */ -- (BOOL)matchesDocument:(FSTDocument *)document; - -/** - * A canonical string identifying the filter. Two different instances of equivalent filters will - * return the same canonicalID. - */ -- (NSString *)canonicalID; - -@end - -@implementation FSTRelationFilter - -#pragma mark - Constructor methods - -- (instancetype)initWithField:(FieldPath)field - filterOperator:(FSTRelationFilterOperator)filterOperator - value:(FSTFieldValue *)value { - self = [super init]; - if (self) { - _field = std::move(field); - _filterOperator = filterOperator; - _value = value; - } - return self; -} - -#pragma mark - Public Methods - -- (BOOL)isInequality { - return self.filterOperator != FSTRelationFilterOperatorEqual && - self.filterOperator != FSTRelationFilterOperatorArrayContains; -} - -- (const firebase::firestore::model::FieldPath &)field { - return _field; -} - -#pragma mark - NSObject methods - -- (NSString *)description { - return [NSString stringWithFormat:@"%s %@ %@", _field.CanonicalString().c_str(), - FSTStringFromQueryRelationOperator(self.filterOperator), - self.value]; -} - -- (BOOL)isEqual:(id)other { - if (self == other) { - return YES; - } - if (![other isKindOfClass:[FSTRelationFilter class]]) { - return NO; - } - return [self isEqualToFilter:(FSTRelationFilter *)other]; -} - -#pragma mark - Private methods - -- (BOOL)matchesDocument:(FSTDocument *)document { - if (_field.IsKeyFieldPath()) { - HARD_ASSERT([self.value isKindOfClass:[FSTReferenceValue class]], - "Comparing on key, but filter value not a FSTReferenceValue."); - HARD_ASSERT(self.filterOperator != FSTRelationFilterOperatorArrayContains, - "arrayContains queries don't make sense on document keys."); - FSTReferenceValue *refValue = (FSTReferenceValue *)self.value; - NSComparisonResult comparison = CompareKeys(document.key, refValue.value.key); - return [self matchesComparison:comparison]; - } else { - return [self matchesValue:[document fieldForPath:self.field]]; - } -} - -- (NSString *)canonicalID { - // TODO(b/37283291): This should be collision robust and avoid relying on |description| methods. - return [NSString stringWithFormat:@"%s%@%@", _field.CanonicalString().c_str(), - FSTStringFromQueryRelationOperator(self.filterOperator), - [self.value value]]; -} - -- (BOOL)isEqualToFilter:(FSTRelationFilter *)other { - if (self.filterOperator != other.filterOperator) { - return NO; - } - if (_field != other.field) { - return NO; - } - if (![self.value isEqual:other.value]) { - return NO; - } - return YES; -} - -/** Returns YES if receiver is true with the given value as its LHS. */ -- (BOOL)matchesValue:(FSTFieldValue *)other { - if (self.filterOperator == FSTRelationFilterOperatorArrayContains) { - if ([other isMemberOfClass:[FSTArrayValue class]]) { - FSTArrayValue *arrayValue = (FSTArrayValue *)other; - return [arrayValue.internalValue containsObject:self.value]; - } else { - return false; - } - } else { - // Only perform comparison queries on types with matching backend order (such as double and - // int). - return self.value.typeOrder == other.typeOrder && - [self matchesComparison:[other compare:self.value]]; - } -} - -- (BOOL)matchesComparison:(NSComparisonResult)comparison { - switch (self.filterOperator) { - case FSTRelationFilterOperatorLessThan: - return comparison == NSOrderedAscending; - case FSTRelationFilterOperatorLessThanOrEqual: - return comparison == NSOrderedAscending || comparison == NSOrderedSame; - case FSTRelationFilterOperatorEqual: - return comparison == NSOrderedSame; - case FSTRelationFilterOperatorGreaterThanOrEqual: - return comparison == NSOrderedDescending || comparison == NSOrderedSame; - case FSTRelationFilterOperatorGreaterThan: - return comparison == NSOrderedDescending; - default: - HARD_FAIL("Unknown operator: %s", self.filterOperator); - } -} - -@end - -#pragma mark - FSTNullFilter - -@interface FSTNullFilter () { - FieldPath _field; -} -@end - -@implementation FSTNullFilter -- (instancetype)initWithField:(FieldPath)field { - if (self = [super init]) { - _field = std::move(field); - } - return self; -} - -- (BOOL)matchesDocument:(FSTDocument *)document { - FSTFieldValue *fieldValue = [document fieldForPath:self.field]; - return fieldValue != nil && [fieldValue isEqual:[FSTNullValue nullValue]]; -} - -- (NSString *)canonicalID { - return [NSString stringWithFormat:@"%s IS NULL", _field.CanonicalString().c_str()]; -} - -- (const firebase::firestore::model::FieldPath &)field { - return _field; -} - -- (NSString *)description { - return [self canonicalID]; -} - -- (BOOL)isEqual:(id)other { - if (other == self) return YES; - if (![[other class] isEqual:[self class]]) return NO; - - return _field == ((FSTNullFilter *)other)->_field; -} - -- (NSUInteger)hash { - return util::Hash(_field); -} - -@end - -#pragma mark - FSTNanFilter - -@interface FSTNanFilter () { - FieldPath _field; -} -@end - -@implementation FSTNanFilter - -- (instancetype)initWithField:(FieldPath)field { - if (self = [super init]) { - _field = std::move(field); - } - return self; -} - -- (BOOL)matchesDocument:(FSTDocument *)document { - FSTFieldValue *fieldValue = [document fieldForPath:self.field]; - return fieldValue != nil && [fieldValue isEqual:[FSTDoubleValue nanValue]]; -} - -- (NSString *)canonicalID { - return [NSString stringWithFormat:@"%s IS NaN", _field.CanonicalString().c_str()]; -} - -- (const firebase::firestore::model::FieldPath &)field { - return _field; -} - -- (NSString *)description { - return [self canonicalID]; -} - -- (BOOL)isEqual:(id)other { - if (other == self) return YES; - if (![[other class] isEqual:[self class]]) return NO; - - return _field == ((FSTNanFilter *)other)->_field; -} - -- (NSUInteger)hash { - return util::Hash(_field); -} -@end - -#pragma mark - FSTSortOrder - -@interface FSTSortOrder () { - /** The field to sort by. */ - firebase::firestore::model::FieldPath _field; -} - -/** Creates a new sort order with the given field and direction. */ -- (instancetype)initWithFieldPath:(FieldPath)fieldPath ascending:(BOOL)ascending; - -- (NSString *)canonicalID; - -@end - -@implementation FSTSortOrder - -#pragma mark - Constructor methods - -+ (instancetype)sortOrderWithFieldPath:(FieldPath)fieldPath ascending:(BOOL)ascending { - return [[FSTSortOrder alloc] initWithFieldPath:std::move(fieldPath) ascending:ascending]; -} - -- (instancetype)initWithFieldPath:(FieldPath)fieldPath ascending:(BOOL)ascending { - self = [super init]; - if (self) { - _field = std::move(fieldPath); - _ascending = ascending; - } - return self; -} - -- (const firebase::firestore::model::FieldPath &)field { - return _field; -} - -#pragma mark - Public methods - -- (NSComparisonResult)compareDocument:(FSTDocument *)document1 toDocument:(FSTDocument *)document2 { - NSComparisonResult result; - if (_field == FieldPath::KeyFieldPath()) { - result = CompareKeys(document1.key, document2.key); - } else { - FSTFieldValue *value1 = [document1 fieldForPath:self.field]; - FSTFieldValue *value2 = [document2 fieldForPath:self.field]; - HARD_ASSERT(value1 != nil && value2 != nil, - "Trying to compare documents on fields that don't exist."); - result = [value1 compare:value2]; - } - if (!self.isAscending) { - result = ReverseOrder(result); - } - return result; -} - -- (NSString *)canonicalID { - return [NSString stringWithFormat:@"%s%@", _field.CanonicalString().c_str(), - self.isAscending ? @"asc" : @"desc"]; -} - -- (BOOL)isEqualToSortOrder:(FSTSortOrder *)other { - return _field == other->_field && self.isAscending == other.isAscending; -} - -#pragma mark - NSObject methods - -- (NSString *)description { - return [NSString stringWithFormat:@"", - _field.CanonicalString().c_str(), - self.ascending ? @"asc" : @"desc"]; -} - -- (BOOL)isEqual:(NSObject *)other { - if (self == other) { - return YES; - } - if (![other isKindOfClass:[FSTSortOrder class]]) { - return NO; - } - return [self isEqualToSortOrder:(FSTSortOrder *)other]; -} - -- (NSUInteger)hash { - return [self.canonicalID hash]; -} - -- (instancetype)copyWithZone:(nullable NSZone *)zone { - return self; -} - -@end - -#pragma mark - FSTBound - -@implementation FSTBound - -- (instancetype)initWithPosition:(NSArray *)position isBefore:(BOOL)isBefore { - if (self = [super init]) { - _position = position; - _before = isBefore; - } - return self; -} - -+ (instancetype)boundWithPosition:(NSArray *)position isBefore:(BOOL)isBefore { - return [[FSTBound alloc] initWithPosition:position isBefore:isBefore]; -} - -- (NSString *)canonicalString { - // TODO(b/29183165): Make this collision robust. - NSMutableString *string = [NSMutableString string]; - if (self.isBefore) { - [string appendString:@"b:"]; - } else { - [string appendString:@"a:"]; - } - for (FSTFieldValue *component in self.position) { - [string appendFormat:@"%@", component]; - } - return string; -} - -- (BOOL)sortsBeforeDocument:(FSTDocument *)document - usingSortOrder:(NSArray *)sortOrder { - HARD_ASSERT(self.position.count <= sortOrder.count, - "FSTIndexPosition has more components than provided sort order."); - __block NSComparisonResult result = NSOrderedSame; - [self.position enumerateObjectsUsingBlock:^(FSTFieldValue *fieldValue, NSUInteger idx, - BOOL *stop) { - FSTSortOrder *sortOrderComponent = sortOrder[idx]; - NSComparisonResult comparison; - if (sortOrderComponent.field == FieldPath::KeyFieldPath()) { - HARD_ASSERT([fieldValue isKindOfClass:[FSTReferenceValue class]], - "FSTBound has a non-key value where the key path is being used %s", fieldValue); - FSTReferenceValue *refValue = (FSTReferenceValue *)fieldValue; - comparison = CompareKeys(refValue.value.key, document.key); - } else { - FSTFieldValue *docValue = [document fieldForPath:sortOrderComponent.field]; - HARD_ASSERT(docValue != nil, - "Field should exist since document matched the orderBy already."); - comparison = [fieldValue compare:docValue]; - } - - if (!sortOrderComponent.isAscending) { - comparison = ReverseOrder(comparison); - } - - if (comparison != 0) { - result = comparison; - *stop = YES; - } - }]; - - return self.isBefore ? result <= NSOrderedSame : result < NSOrderedSame; -} - -#pragma mark - NSObject methods - -- (NSString *)description { - return [NSString stringWithFormat:@"", self.position, - self.isBefore ? @"YES" : @"NO"]; -} - -- (BOOL)isEqual:(NSObject *)other { - if (self == other) { - return YES; - } - if (![other isKindOfClass:[FSTBound class]]) { - return NO; - } - - FSTBound *otherBound = (FSTBound *)other; - - return [self.position isEqualToArray:otherBound.position] && self.isBefore == otherBound.isBefore; -} - -- (NSUInteger)hash { - return 31 * self.position.hash + (self.isBefore ? 0 : 1); -} - -- (instancetype)copyWithZone:(nullable NSZone *)zone { - return self; -} - -@end - -#pragma mark - FSTQuery - -@interface FSTQuery () { - // Cached value of the canonicalID property. - NSString *_canonicalID; - /** The base path of the query. */ - ResourcePath _path; -} - -/** A list of fields given to sort by. This does not include the implicit key sort at the end. */ -@property(nonatomic, strong, readonly) NSArray *explicitSortOrders; - -/** The memoized list of sort orders */ -@property(nonatomic, nullable, strong, readwrite) NSArray *memoizedSortOrders; - -@end - -@implementation FSTQuery - -#pragma mark - Constructors - -+ (instancetype)queryWithPath:(ResourcePath)path { - return [FSTQuery queryWithPath:std::move(path) collectionGroup:nil]; -} - -+ (instancetype)queryWithPath:(ResourcePath)path - collectionGroup:(nullable NSString *)collectionGroup { - return [[FSTQuery alloc] initWithPath:std::move(path) - collectionGroup:collectionGroup - filterBy:@[] - orderBy:@[] - limit:NSNotFound - startAt:nil - endAt:nil]; -} - -- (instancetype)initWithPath:(ResourcePath)path - collectionGroup:(nullable NSString *)collectionGroup - filterBy:(NSArray *)filters - orderBy:(NSArray *)sortOrders - limit:(NSInteger)limit - startAt:(nullable FSTBound *)startAtBound - endAt:(nullable FSTBound *)endAtBound { - if (self = [super init]) { - _path = std::move(path); - _collectionGroup = collectionGroup; - _filters = filters; - _explicitSortOrders = sortOrders; - _limit = limit; - _startAt = startAtBound; - _endAt = endAtBound; - } - return self; -} - -#pragma mark - NSObject methods - -- (NSString *)description { - return [NSString stringWithFormat:@"", self.canonicalID]; -} - -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[FSTQuery class]]) { - return NO; - } - return [self isEqualToQuery:(FSTQuery *)object]; -} - -- (NSUInteger)hash { - return [self.canonicalID hash]; -} - -- (instancetype)copyWithZone:(nullable NSZone *)zone { - return self; -} - -#pragma mark - Public methods - -- (NSArray *)sortOrders { - if (self.memoizedSortOrders == nil) { - const FieldPath *inequalityField = [self inequalityFilterField]; - const FieldPath *firstSortOrderField = [self firstSortOrderField]; - if (inequalityField && !firstSortOrderField) { - // In order to implicitly add key ordering, we must also add the inequality filter field for - // it to be a valid query. Note that the default inequality field and key ordering is - // ascending. - if (inequalityField->IsKeyFieldPath()) { - self.memoizedSortOrders = @[ [FSTSortOrder sortOrderWithFieldPath:FieldPath::KeyFieldPath() - ascending:YES] ]; - } else { - self.memoizedSortOrders = @[ - [FSTSortOrder sortOrderWithFieldPath:*inequalityField ascending:YES], - [FSTSortOrder sortOrderWithFieldPath:FieldPath::KeyFieldPath() ascending:YES] - ]; - } - } else { - HARD_ASSERT(!inequalityField || *inequalityField == *firstSortOrderField, - "First orderBy %s should match inequality field %s.", - firstSortOrderField->CanonicalString(), inequalityField->CanonicalString()); - - __block BOOL foundKeyOrder = NO; - - NSMutableArray *result = [NSMutableArray array]; - for (FSTSortOrder *sortOrder in self.explicitSortOrders) { - [result addObject:sortOrder]; - if (sortOrder.field == FieldPath::KeyFieldPath()) { - foundKeyOrder = YES; - } - } - - if (!foundKeyOrder) { - // The direction of the implicit key ordering always matches the direction of the last - // explicit sort order - BOOL lastIsAscending = - self.explicitSortOrders.count > 0 ? self.explicitSortOrders.lastObject.ascending : YES; - [result addObject:[FSTSortOrder sortOrderWithFieldPath:FieldPath::KeyFieldPath() - ascending:lastIsAscending]]; - } - - self.memoizedSortOrders = result; - } - } - return self.memoizedSortOrders; -} - -- (instancetype)queryByAddingFilter:(FSTFilter *)filter { - HARD_ASSERT(![self isDocumentQuery], "No filtering allowed for document query"); - - const FieldPath *newInequalityField = nullptr; - if ([filter isKindOfClass:[FSTRelationFilter class]] && - [((FSTRelationFilter *)filter) isInequality]) { - newInequalityField = &filter.field; - } - const FieldPath *queryInequalityField = [self inequalityFilterField]; - HARD_ASSERT( - !queryInequalityField || !newInequalityField || *queryInequalityField == *newInequalityField, - "Query must only have one inequality field."); - - return [[FSTQuery alloc] initWithPath:self.path - collectionGroup:self.collectionGroup - filterBy:[self.filters arrayByAddingObject:filter] - orderBy:self.explicitSortOrders - limit:self.limit - startAt:self.startAt - endAt:self.endAt]; -} - -- (instancetype)queryByAddingSortOrder:(FSTSortOrder *)sortOrder { - HARD_ASSERT(![self isDocumentQuery], "No ordering is allowed for a document query."); - - // TODO(klimt): Validate that the same key isn't added twice. - return [[FSTQuery alloc] initWithPath:self.path - collectionGroup:self.collectionGroup - filterBy:self.filters - orderBy:[self.explicitSortOrders arrayByAddingObject:sortOrder] - limit:self.limit - startAt:self.startAt - endAt:self.endAt]; -} - -- (instancetype)queryBySettingLimit:(NSInteger)limit { - return [[FSTQuery alloc] initWithPath:self.path - collectionGroup:self.collectionGroup - filterBy:self.filters - orderBy:self.explicitSortOrders - limit:limit - startAt:self.startAt - endAt:self.endAt]; -} - -- (instancetype)queryByAddingStartAt:(FSTBound *)bound { - return [[FSTQuery alloc] initWithPath:self.path - collectionGroup:self.collectionGroup - filterBy:self.filters - orderBy:self.explicitSortOrders - limit:self.limit - startAt:bound - endAt:self.endAt]; -} - -- (instancetype)queryByAddingEndAt:(FSTBound *)bound { - return [[FSTQuery alloc] initWithPath:self.path - collectionGroup:self.collectionGroup - filterBy:self.filters - orderBy:self.explicitSortOrders - limit:self.limit - startAt:self.startAt - endAt:bound]; -} - -- (instancetype)collectionQueryAtPath:(firebase::firestore::model::ResourcePath)path { - return [[FSTQuery alloc] initWithPath:path - collectionGroup:nil - filterBy:self.filters - orderBy:self.explicitSortOrders - limit:self.limit - startAt:self.startAt - endAt:self.endAt]; -} - -- (BOOL)isDocumentQuery { - return DocumentKey::IsDocumentKey(_path) && !self.collectionGroup && self.filters.count == 0; -} - -- (BOOL)isCollectionGroupQuery { - return self.collectionGroup != nil; -} - -- (BOOL)matchesDocument:(FSTDocument *)document { - return [self pathAndCollectionGroupMatchDocument:document] && - [self orderByMatchesDocument:document] && [self filtersMatchDocument:document] && - [self boundsMatchDocument:document]; -} - -- (NSComparator)comparator { - return ^NSComparisonResult(id document1, id document2) { - BOOL didCompareOnKeyField = NO; - for (FSTSortOrder *orderBy in self.sortOrders) { - NSComparisonResult comp = [orderBy compareDocument:document1 toDocument:document2]; - if (comp != NSOrderedSame) { - return comp; - } - didCompareOnKeyField = didCompareOnKeyField || orderBy.field == FieldPath::KeyFieldPath(); - } - HARD_ASSERT(didCompareOnKeyField, "sortOrder of query did not include key ordering"); - return NSOrderedSame; - }; -} - -- (nullable const FieldPath *)inequalityFilterField { - for (FSTFilter *filter in self.filters) { - if ([filter isKindOfClass:[FSTRelationFilter class]] && - ((FSTRelationFilter *)filter).isInequality) { - return &filter.field; - } - } - return nullptr; -} - -- (BOOL)hasArrayContainsFilter { - for (FSTFilter *filter in self.filters) { - if ([filter isKindOfClass:[FSTRelationFilter class]] && - ((FSTRelationFilter *)filter).filterOperator == FSTRelationFilterOperatorArrayContains) { - return YES; - } - } - return NO; -} - -- (nullable const FieldPath *)firstSortOrderField { - if (self.explicitSortOrders.count > 0) { - return &self.explicitSortOrders.firstObject.field; - } - return nullptr; -} - -/** The base path of the query. */ -- (const firebase::firestore::model::ResourcePath &)path { - return _path; -} - -#pragma mark - Private properties - -- (NSString *)canonicalID { - if (_canonicalID) { - return _canonicalID; - } - - NSMutableString *canonicalID = [NSMutableString string]; - [canonicalID appendFormat:@"%s", _path.CanonicalString().c_str()]; - - if (self.collectionGroup) { - [canonicalID appendFormat:@"|cg:%@", self.collectionGroup]; - } - - // Add filters. - [canonicalID appendString:@"|f:"]; - for (FSTFilter *predicate in self.filters) { - [canonicalID appendFormat:@"%@", [predicate canonicalID]]; - } - - // Add order by. - [canonicalID appendString:@"|ob:"]; - for (FSTSortOrder *orderBy in self.sortOrders) { - [canonicalID appendString:orderBy.canonicalID]; - } - - // Add limit. - if (self.limit != NSNotFound) { - [canonicalID appendFormat:@"|l:%ld", (long)self.limit]; - } - - if (self.startAt) { - [canonicalID appendFormat:@"|lb:%@", self.startAt.canonicalString]; - } - - if (self.endAt) { - [canonicalID appendFormat:@"|ub:%@", self.endAt.canonicalString]; - } - - _canonicalID = canonicalID; - return canonicalID; -} - -#pragma mark - Private methods - -- (BOOL)isEqualToQuery:(FSTQuery *)other { - return self.path == other.path && - (self.collectionGroup == other.collectionGroup || - [self.collectionGroup isEqual:other.collectionGroup]) && - self.limit == other.limit && [self.filters isEqual:other.filters] && - [self.sortOrders isEqual:other.sortOrders] && - (self.startAt == other.startAt || [self.startAt isEqual:other.startAt]) && - (self.endAt == other.endAt || [self.endAt isEqual:other.endAt]); -} - -/* Returns YES if the document matches the path and collection group for the receiver. */ -- (BOOL)pathAndCollectionGroupMatchDocument:(FSTDocument *)document { - const ResourcePath &documentPath = document.key.path(); - if (self.collectionGroup) { - // NOTE: self.path is currently always empty since we don't expose Collection Group queries - // rooted at a document path yet. - return document.key.HasCollectionId(util::MakeString(self.collectionGroup)) && - self.path.IsPrefixOf(documentPath); - } else if (DocumentKey::IsDocumentKey(_path)) { - // Exact match for document queries. - return self.path == documentPath; - } else { - // Shallow ancestor queries by default. - return self.path.IsPrefixOf(documentPath) && _path.size() == documentPath.size() - 1; - } -} - -/** - * A document must have a value for every ordering clause in order to show up in the results. - */ -- (BOOL)orderByMatchesDocument:(FSTDocument *)document { - for (FSTSortOrder *orderBy in self.explicitSortOrders) { - const FieldPath &fieldPath = orderBy.field; - // order by key always matches - if (fieldPath != FieldPath::KeyFieldPath() && [document fieldForPath:fieldPath] == nil) { - return NO; - } - } - return YES; -} - -/** Returns YES if the document matches all of the filters in the receiver. */ -- (BOOL)filtersMatchDocument:(FSTDocument *)document { - for (FSTFilter *filter in self.filters) { - if (![filter matchesDocument:document]) { - return NO; - } - } - return YES; -} - -- (BOOL)boundsMatchDocument:(FSTDocument *)document { - if (self.startAt && ![self.startAt sortsBeforeDocument:document usingSortOrder:self.sortOrders]) { - return NO; - } - if (self.endAt && [self.endAt sortsBeforeDocument:document usingSortOrder:self.sortOrders]) { - return NO; - } - return YES; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTSyncEngine.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTSyncEngine.h deleted file mode 100644 index 0409498..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTSyncEngine.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include - -#import "Firestore/Source/Core/FSTTypes.h" - -#include "Firestore/core/src/firebase/firestore/auth/user.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" -#include "Firestore/core/src/firebase/firestore/remote/remote_store.h" -#include "Firestore/core/src/firebase/firestore/util/async_queue.h" - -@class FSTLocalStore; -@class FSTMutation; -@class FSTQuery; - -using firebase::firestore::model::OnlineState; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - FSTSyncEngineDelegate - -/** - * A delegate to be notified when the client's online state changes or when the sync engine produces - * new view snapshots or errors. - */ -@protocol FSTSyncEngineDelegate -- (void)handleViewSnapshots:(std::vector &&)viewSnapshots; -- (void)handleError:(NSError *)error forQuery:(FSTQuery *)query; -- (void)applyChangedOnlineState:(OnlineState)onlineState; -@end - -/** - * SyncEngine is the central controller in the client SDK architecture. It is the glue code - * between the EventManager, LocalStore, and RemoteStore. Some of SyncEngine's responsibilities - * include: - * 1. Coordinating client requests and remote events between the EventManager and the local and - * remote data stores. - * 2. Managing a View object for each query, providing the unified view between the local and - * remote data stores. - * 3. Notifying the RemoteStore when the LocalStore has new mutations in its queue that need - * sending to the backend. - * - * The SyncEngine’s methods should only ever be called by methods running on our own worker - * queue. - */ -@interface FSTSyncEngine : NSObject - -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithLocalStore:(FSTLocalStore *)localStore - remoteStore:(firebase::firestore::remote::RemoteStore *)remoteStore - initialUser:(const firebase::firestore::auth::User &)user - NS_DESIGNATED_INITIALIZER; - -/** - * A delegate to be notified when queries being listened to produce new view snapshots or errors. - */ -@property(nonatomic, weak) id syncEngineDelegate; - -/** - * Initiates a new listen. The FSTLocalStore will be queried for initial data and the listen will - * be sent to the `RemoteStore` to get remote data. The registered FSTSyncEngineDelegate will be - * notified of resulting view snapshots and/or listen errors. - * - * @return the target ID assigned to the query. - */ -- (firebase::firestore::model::TargetId)listenToQuery:(FSTQuery *)query; - -/** Stops listening to a query previously listened to via listenToQuery:. */ -- (void)stopListeningToQuery:(FSTQuery *)query; - -/** - * Initiates the write of local mutation batch which involves adding the writes to the mutation - * queue, notifying the remote store about new mutations, and raising events for any changes this - * write caused. The provided completion block will be called once the write has been acked or - * rejected by the backend (or failed locally for any other reason). - */ -- (void)writeMutations:(std::vector &&)mutations - completion:(FSTVoidErrorBlock)completion; - -/** - * Runs the given transaction block up to retries times and then calls completion. - * - * @param retries The number of times to try before giving up. - * @param workerQueue The queue to dispatch sync engine calls to. - * @param updateBlock The block to call to execute the user's transaction. - * @param completion The block to call when the transaction is finished or failed. - */ -- (void)transactionWithRetries:(int)retries - workerQueue:(firebase::firestore::util::AsyncQueue *)workerQueue - updateBlock:(FSTTransactionBlock)updateBlock - completion:(FSTVoidIDErrorBlock)completion; - -- (void)credentialDidChangeWithUser:(const firebase::firestore::auth::User &)user; - -/** Applies an OnlineState change to the sync engine and notifies any views of the change. */ -- (void)applyChangedOnlineState:(firebase::firestore::model::OnlineState)onlineState; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTSyncEngine.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTSyncEngine.mm deleted file mode 100644 index b00982f..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTSyncEngine.mm +++ /dev/null @@ -1,646 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Core/FSTSyncEngine.h" - -#include -#include -#include -#include -#include -#include - -#import "FIRFirestoreErrors.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Core/FSTView.h" -#import "Firestore/Source/Local/FSTLocalStore.h" -#import "Firestore/Source/Local/FSTLocalViewChanges.h" -#import "Firestore/Source/Local/FSTLocalWriteResult.h" -#import "Firestore/Source/Local/FSTQueryData.h" -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Model/FSTMutationBatch.h" - -#include "Firestore/core/src/firebase/firestore/auth/user.h" -#include "Firestore/core/src/firebase/firestore/core/target_id_generator.h" -#include "Firestore/core/src/firebase/firestore/core/transaction.h" -#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" -#include "Firestore/core/src/firebase/firestore/local/reference_set.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/document_map.h" -#include "Firestore/core/src/firebase/firestore/model/document_set.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" -#include "Firestore/core/src/firebase/firestore/util/error_apple.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/log.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" -#include "absl/types/optional.h" - -using firebase::firestore::auth::HashUser; -using firebase::firestore::auth::User; -using firebase::firestore::core::TargetIdGenerator; -using firebase::firestore::core::Transaction; -using firebase::firestore::core::ViewSnapshot; -using firebase::firestore::local::ReferenceSet; -using firebase::firestore::model::BatchId; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::DocumentKeySet; -using firebase::firestore::model::DocumentMap; -using firebase::firestore::model::MaybeDocumentMap; -using firebase::firestore::model::ListenSequenceNumber; -using firebase::firestore::model::OnlineState; -using firebase::firestore::model::SnapshotVersion; -using firebase::firestore::model::TargetId; -using firebase::firestore::remote::RemoteEvent; -using firebase::firestore::remote::RemoteStore; -using firebase::firestore::remote::TargetChange; -using firebase::firestore::util::AsyncQueue; -using firebase::firestore::util::MakeNSError; -using firebase::firestore::util::Status; - -NS_ASSUME_NONNULL_BEGIN - -// Limbo documents don't use persistence, and are eagerly GC'd. So, listens for them don't need -// real sequence numbers. -static const ListenSequenceNumber kIrrelevantSequenceNumber = -1; - -#pragma mark - FSTQueryView - -/** - * FSTQueryView contains all of the info that FSTSyncEngine needs to track for a particular - * query and view. - */ -@interface FSTQueryView : NSObject - -- (instancetype)initWithQuery:(FSTQuery *)query - targetID:(TargetId)targetID - resumeToken:(NSData *)resumeToken - view:(FSTView *)view NS_DESIGNATED_INITIALIZER; - -- (instancetype)init NS_UNAVAILABLE; - -/** The query itself. */ -@property(nonatomic, strong, readonly) FSTQuery *query; - -/** The targetID created by the client that is used in the watch stream to identify this query. */ -@property(nonatomic, assign, readonly) TargetId targetID; - -/** - * An identifier from the datastore backend that indicates the last state of the results that - * was received. This can be used to indicate where to continue receiving new doc changes for the - * query. - */ -@property(nonatomic, copy, readonly) NSData *resumeToken; - -/** - * The view is responsible for computing the final merged truth of what docs are in the query. - * It gets notified of local and remote changes, and applies the query filters and limits to - * determine the most correct possible results. - */ -@property(nonatomic, strong, readonly) FSTView *view; - -@end - -@implementation FSTQueryView - -- (instancetype)initWithQuery:(FSTQuery *)query - targetID:(TargetId)targetID - resumeToken:(NSData *)resumeToken - view:(FSTView *)view { - if (self = [super init]) { - _query = query; - _targetID = targetID; - _resumeToken = resumeToken; - _view = view; - } - return self; -} - -@end - -#pragma mark - LimboResolution - -/** Tracks a limbo resolution. */ -class LimboResolution { - public: - LimboResolution() { - } - - explicit LimboResolution(const DocumentKey &key) : key{key} { - } - - DocumentKey key; - - /** - * Set to true once we've received a document. This is used in remoteKeysForTarget and - * ultimately used by `WatchChangeAggregator` to decide whether it needs to manufacture a delete - * event for the target once the target is CURRENT. - */ - bool document_received = false; -}; - -#pragma mark - FSTSyncEngine - -@interface FSTSyncEngine () - -/** The local store, used to persist mutations and cached documents. */ -@property(nonatomic, strong, readonly) FSTLocalStore *localStore; - -/** FSTQueryViews for all active queries, indexed by query. */ -@property(nonatomic, strong, readonly) - NSMutableDictionary *queryViewsByQuery; - -@end - -@implementation FSTSyncEngine { - /** The remote store for sending writes, watches, etc. to the backend. */ - RemoteStore *_remoteStore; - - /** Used for creating the TargetId for the listens used to resolve limbo documents. */ - TargetIdGenerator _targetIdGenerator; - - /** Stores user completion blocks, indexed by user and BatchId. */ - std::unordered_map *, HashUser> - _mutationCompletionBlocks; - - /** FSTQueryViews for all active queries, indexed by target ID. */ - std::unordered_map _queryViewsByTarget; - - /** - * When a document is in limbo, we create a special listen to resolve it. This maps the - * DocumentKey of each limbo document to the TargetId of the listen resolving it. - */ - std::map _limboTargetsByKey; - - /** - * Basically the inverse of limboTargetsByKey, a map of target ID to a LimboResolution (which - * includes the DocumentKey as well as whether we've received a document for the target). - */ - std::map _limboResolutionsByTarget; - - User _currentUser; - - /** Used to track any documents that are currently in limbo. */ - ReferenceSet _limboDocumentRefs; -} - -- (instancetype)initWithLocalStore:(FSTLocalStore *)localStore - remoteStore:(RemoteStore *)remoteStore - initialUser:(const User &)initialUser { - if (self = [super init]) { - _localStore = localStore; - _remoteStore = remoteStore; - - _queryViewsByQuery = [NSMutableDictionary dictionary]; - - _targetIdGenerator = TargetIdGenerator::SyncEngineTargetIdGenerator(); - _currentUser = initialUser; - } - return self; -} - -- (TargetId)listenToQuery:(FSTQuery *)query { - [self assertDelegateExistsForSelector:_cmd]; - HARD_ASSERT(self.queryViewsByQuery[query] == nil, "We already listen to query: %s", query); - - FSTQueryData *queryData = [self.localStore allocateQuery:query]; - ViewSnapshot viewSnapshot = [self initializeViewAndComputeSnapshotForQueryData:queryData]; - [self.syncEngineDelegate handleViewSnapshots:{viewSnapshot}]; - - _remoteStore->Listen(queryData); - return queryData.targetID; -} - -- (ViewSnapshot)initializeViewAndComputeSnapshotForQueryData:(FSTQueryData *)queryData { - DocumentMap docs = [self.localStore executeQuery:queryData.query]; - DocumentKeySet remoteKeys = [self.localStore remoteDocumentKeysForTarget:queryData.targetID]; - - FSTView *view = [[FSTView alloc] initWithQuery:queryData.query - remoteDocuments:std::move(remoteKeys)]; - FSTViewDocumentChanges *viewDocChanges = [view computeChangesWithDocuments:docs.underlying_map()]; - FSTViewChange *viewChange = [view applyChangesToDocuments:viewDocChanges]; - HARD_ASSERT(viewChange.limboChanges.count == 0, - "View returned limbo docs before target ack from the server."); - - FSTQueryView *queryView = [[FSTQueryView alloc] initWithQuery:queryData.query - targetID:queryData.targetID - resumeToken:queryData.resumeToken - view:view]; - self.queryViewsByQuery[queryData.query] = queryView; - _queryViewsByTarget[queryData.targetID] = queryView; - - HARD_ASSERT(viewChange.snapshot.has_value(), - "applyChangesToDocuments for new view should always return a snapshot"); - return viewChange.snapshot.value(); -} - -- (void)stopListeningToQuery:(FSTQuery *)query { - [self assertDelegateExistsForSelector:_cmd]; - - FSTQueryView *queryView = self.queryViewsByQuery[query]; - HARD_ASSERT(queryView, "Trying to stop listening to a query not found"); - - [self.localStore releaseQuery:query]; - _remoteStore->StopListening(queryView.targetID); - [self removeAndCleanupQuery:queryView]; -} - -- (void)writeMutations:(std::vector &&)mutations - completion:(FSTVoidErrorBlock)completion { - [self assertDelegateExistsForSelector:_cmd]; - - FSTLocalWriteResult *result = [self.localStore locallyWriteMutations:std::move(mutations)]; - [self addMutationCompletionBlock:completion batchID:result.batchID]; - - [self emitNewSnapshotsAndNotifyLocalStoreWithChanges:result.changes remoteEvent:absl::nullopt]; - _remoteStore->FillWritePipeline(); -} - -- (void)addMutationCompletionBlock:(FSTVoidErrorBlock)completion batchID:(BatchId)batchID { - NSMutableDictionary *completionBlocks = - _mutationCompletionBlocks[_currentUser]; - if (!completionBlocks) { - completionBlocks = [NSMutableDictionary dictionary]; - _mutationCompletionBlocks[_currentUser] = completionBlocks; - } - [completionBlocks setObject:completion forKey:@(batchID)]; -} - -/** - * Takes an updateBlock in which a set of reads and writes can be performed atomically. In the - * updateBlock, user code can read and write values using a transaction object. After the - * updateBlock, all changes will be committed. If someone else has changed any of the data - * referenced, then the updateBlock will be called again. If the updateBlock still fails after the - * given number of retries, then the transaction will be rejected. - * - * The transaction object passed to the updateBlock contains methods for accessing documents - * and collections. Unlike other firestore access, data accessed with the transaction will not - * reflect local changes that have not been committed. For this reason, it is required that all - * reads are performed before any writes. Transactions must be performed while online. - */ -- (void)transactionWithRetries:(int)retries - workerQueue:(AsyncQueue *)workerQueue - updateBlock:(FSTTransactionBlock)updateBlock - completion:(FSTVoidIDErrorBlock)completion { - workerQueue->VerifyIsCurrentQueue(); - HARD_ASSERT(retries >= 0, "Got negative number of retries for transaction"); - - std::shared_ptr transaction = _remoteStore->CreateTransaction(); - updateBlock(transaction, ^(id _Nullable result, NSError *_Nullable error) { - workerQueue->Enqueue( - [self, retries, workerQueue, updateBlock, completion, transaction, result, error] { - if (error) { - completion(nil, error); - return; - } - transaction->Commit([self, retries, workerQueue, updateBlock, completion, - result](const Status &status) { - if (status.ok()) { - completion(result, nil); - return; - } - - // TODO(b/35201829): Only retry on real transaction failures. - if (retries == 0) { - NSError *wrappedError = - [NSError errorWithDomain:FIRFirestoreErrorDomain - code:FIRFirestoreErrorCodeFailedPrecondition - userInfo:@{ - NSLocalizedDescriptionKey : @"Transaction failed all retries.", - NSUnderlyingErrorKey : MakeNSError(status) - }]; - completion(nil, wrappedError); - return; - } - workerQueue->VerifyIsCurrentQueue(); - return [self transactionWithRetries:(retries - 1) - workerQueue:workerQueue - updateBlock:updateBlock - completion:completion]; - }); - }); - }); -} - -- (void)applyRemoteEvent:(const RemoteEvent &)remoteEvent { - [self assertDelegateExistsForSelector:_cmd]; - - // Update `receivedDocument` as appropriate for any limbo targets. - for (const auto &entry : remoteEvent.target_changes()) { - TargetId targetID = entry.first; - const TargetChange &change = entry.second; - const auto iter = _limboResolutionsByTarget.find(targetID); - if (iter != _limboResolutionsByTarget.end()) { - LimboResolution &limboResolution = iter->second; - // Since this is a limbo resolution lookup, it's for a single document and it could be - // added, modified, or removed, but not a combination. - HARD_ASSERT(change.added_documents().size() + change.modified_documents().size() + - change.removed_documents().size() <= - 1, - "Limbo resolution for single document contains multiple changes."); - - if (change.added_documents().size() > 0) { - limboResolution.document_received = true; - } else if (change.modified_documents().size() > 0) { - HARD_ASSERT(limboResolution.document_received, - "Received change for limbo target document without add."); - } else if (change.removed_documents().size() > 0) { - HARD_ASSERT(limboResolution.document_received, - "Received remove for limbo target document without add."); - limboResolution.document_received = false; - } else { - // This was probably just a CURRENT targetChange or similar. - } - } - } - - MaybeDocumentMap changes = [self.localStore applyRemoteEvent:remoteEvent]; - [self emitNewSnapshotsAndNotifyLocalStoreWithChanges:changes remoteEvent:remoteEvent]; -} - -- (void)applyChangedOnlineState:(OnlineState)onlineState { - __block std::vector newViewSnapshots; - [self.queryViewsByQuery - enumerateKeysAndObjectsUsingBlock:^(FSTQuery *query, FSTQueryView *queryView, BOOL *stop) { - FSTViewChange *viewChange = [queryView.view applyChangedOnlineState:onlineState]; - HARD_ASSERT(viewChange.limboChanges.count == 0, - "OnlineState should not affect limbo documents."); - if (viewChange.snapshot.has_value()) { - newViewSnapshots.push_back(std::move(viewChange.snapshot.value())); - } - }]; - - [self.syncEngineDelegate handleViewSnapshots:std::move(newViewSnapshots)]; - [self.syncEngineDelegate applyChangedOnlineState:onlineState]; -} - -- (void)rejectListenWithTargetID:(const TargetId)targetID error:(NSError *)error { - [self assertDelegateExistsForSelector:_cmd]; - - const auto iter = _limboResolutionsByTarget.find(targetID); - if (iter != _limboResolutionsByTarget.end()) { - const DocumentKey limboKey = iter->second.key; - // Since this query failed, we won't want to manually unlisten to it. - // So go ahead and remove it from bookkeeping. - _limboTargetsByKey.erase(limboKey); - _limboResolutionsByTarget.erase(targetID); - - // TODO(dimond): Retry on transient errors? - - // It's a limbo doc. Create a synthetic event saying it was deleted. This is kind of a hack. - // Ideally, we would have a method in the local store to purge a document. However, it would - // be tricky to keep all of the local store's invariants with another method. - FSTDeletedDocument *doc = [FSTDeletedDocument documentWithKey:limboKey - version:SnapshotVersion::None() - hasCommittedMutations:NO]; - DocumentKeySet limboDocuments = DocumentKeySet{doc.key}; - RemoteEvent event{SnapshotVersion::None(), /*target_changes=*/{}, /*target_mismatches=*/{}, - /*document_updates=*/{{limboKey, doc}}, std::move(limboDocuments)}; - [self applyRemoteEvent:event]; - } else { - auto found = _queryViewsByTarget.find(targetID); - HARD_ASSERT(found != _queryViewsByTarget.end(), "Unknown targetId: %s", targetID); - FSTQueryView *queryView = found->second; - FSTQuery *query = queryView.query; - [self.localStore releaseQuery:query]; - [self removeAndCleanupQuery:queryView]; - if ([self errorIsInteresting:error]) { - LOG_WARN("Listen for query at %s failed: %s", query.path.CanonicalString(), - error.localizedDescription); - } - [self.syncEngineDelegate handleError:error forQuery:query]; - } -} - -- (void)applySuccessfulWriteWithResult:(FSTMutationBatchResult *)batchResult { - [self assertDelegateExistsForSelector:_cmd]; - - // The local store may or may not be able to apply the write result and raise events immediately - // (depending on whether the watcher is caught up), so we raise user callbacks first so that they - // consistently happen before listen events. - [self processUserCallbacksForBatchID:batchResult.batch.batchID error:nil]; - - MaybeDocumentMap changes = [self.localStore acknowledgeBatchWithResult:batchResult]; - [self emitNewSnapshotsAndNotifyLocalStoreWithChanges:changes remoteEvent:absl::nullopt]; -} - -- (void)rejectFailedWriteWithBatchID:(BatchId)batchID error:(NSError *)error { - [self assertDelegateExistsForSelector:_cmd]; - MaybeDocumentMap changes = [self.localStore rejectBatchID:batchID]; - - if (!changes.empty() && [self errorIsInteresting:error]) { - const DocumentKey &minKey = changes.min()->first; - LOG_WARN("Write at %s failed: %s", minKey.ToString(), error.localizedDescription); - } - - // The local store may or may not be able to apply the write result and raise events immediately - // (depending on whether the watcher is caught up), so we raise user callbacks first so that they - // consistently happen before listen events. - [self processUserCallbacksForBatchID:batchID error:error]; - - [self emitNewSnapshotsAndNotifyLocalStoreWithChanges:changes remoteEvent:absl::nullopt]; -} - -- (void)processUserCallbacksForBatchID:(BatchId)batchID error:(NSError *_Nullable)error { - NSMutableDictionary *completionBlocks = - _mutationCompletionBlocks[_currentUser]; - - // NOTE: Mutations restored from persistence won't have completion blocks, so it's okay for - // this (or the completion below) to be nil. - if (completionBlocks) { - NSNumber *boxedBatchID = @(batchID); - FSTVoidErrorBlock completion = completionBlocks[boxedBatchID]; - if (completion) { - completion(error); - [completionBlocks removeObjectForKey:boxedBatchID]; - } - } -} - -- (void)assertDelegateExistsForSelector:(SEL)methodSelector { - HARD_ASSERT(self.syncEngineDelegate, "Tried to call '%s' before delegate was registered.", - NSStringFromSelector(methodSelector)); -} - -- (void)removeAndCleanupQuery:(FSTQueryView *)queryView { - [self.queryViewsByQuery removeObjectForKey:queryView.query]; - _queryViewsByTarget.erase(queryView.targetID); - - DocumentKeySet limboKeys = _limboDocumentRefs.ReferencedKeys(queryView.targetID); - _limboDocumentRefs.RemoveReferences(queryView.targetID); - for (const DocumentKey &key : limboKeys) { - if (!_limboDocumentRefs.ContainsKey(key)) { - // We removed the last reference for this key. - [self removeLimboTargetForKey:key]; - } - } -} - -/** - * Computes a new snapshot from the changes and calls the registered callback with the new snapshot. - */ -- (void)emitNewSnapshotsAndNotifyLocalStoreWithChanges:(const MaybeDocumentMap &)changes - remoteEvent:(const absl::optional &) - maybeRemoteEvent { - __block std::vector newSnapshots; - NSMutableArray *documentChangesInAllViews = [NSMutableArray array]; - - [self.queryViewsByQuery - enumerateKeysAndObjectsUsingBlock:^(FSTQuery *query, FSTQueryView *queryView, BOOL *stop) { - FSTView *view = queryView.view; - FSTViewDocumentChanges *viewDocChanges = [view computeChangesWithDocuments:changes]; - if (viewDocChanges.needsRefill) { - // The query has a limit and some docs were removed/updated, so we need to re-run the - // query against the local store to make sure we didn't lose any good docs that had been - // past the limit. - DocumentMap docs = [self.localStore executeQuery:queryView.query]; - viewDocChanges = [view computeChangesWithDocuments:docs.underlying_map() - previousChanges:viewDocChanges]; - } - - absl::optional targetChange; - if (maybeRemoteEvent.has_value()) { - const RemoteEvent &remoteEvent = maybeRemoteEvent.value(); - auto it = remoteEvent.target_changes().find(queryView.targetID); - if (it != remoteEvent.target_changes().end()) { - targetChange = it->second; - } - } - FSTViewChange *viewChange = [queryView.view applyChangesToDocuments:viewDocChanges - targetChange:targetChange]; - - [self updateTrackedLimboDocumentsWithChanges:viewChange.limboChanges - targetID:queryView.targetID]; - - if (viewChange.snapshot.has_value()) { - newSnapshots.push_back(viewChange.snapshot.value()); - FSTLocalViewChanges *docChanges = - [FSTLocalViewChanges changesForViewSnapshot:viewChange.snapshot.value() - withTargetID:queryView.targetID]; - [documentChangesInAllViews addObject:docChanges]; - } - }]; - - [self.syncEngineDelegate handleViewSnapshots:std::move(newSnapshots)]; - [self.localStore notifyLocalViewChanges:documentChangesInAllViews]; -} - -/** Updates the limbo document state for the given targetID. */ -- (void)updateTrackedLimboDocumentsWithChanges:(NSArray *)limboChanges - targetID:(TargetId)targetID { - for (FSTLimboDocumentChange *limboChange in limboChanges) { - switch (limboChange.type) { - case FSTLimboDocumentChangeTypeAdded: - _limboDocumentRefs.AddReference(limboChange.key, targetID); - [self trackLimboChange:limboChange]; - break; - - case FSTLimboDocumentChangeTypeRemoved: - LOG_DEBUG("Document no longer in limbo: %s", limboChange.key.ToString()); - _limboDocumentRefs.RemoveReference(limboChange.key, targetID); - if (!_limboDocumentRefs.ContainsKey(limboChange.key)) { - // We removed the last reference for this key - [self removeLimboTargetForKey:limboChange.key]; - } - break; - - default: - HARD_FAIL("Unknown limbo change type: %s", limboChange.type); - } - } -} - -- (void)trackLimboChange:(FSTLimboDocumentChange *)limboChange { - DocumentKey key{limboChange.key}; - - if (_limboTargetsByKey.find(key) == _limboTargetsByKey.end()) { - LOG_DEBUG("New document in limbo: %s", key.ToString()); - TargetId limboTargetID = _targetIdGenerator.NextId(); - FSTQuery *query = [FSTQuery queryWithPath:key.path()]; - FSTQueryData *queryData = [[FSTQueryData alloc] initWithQuery:query - targetID:limboTargetID - listenSequenceNumber:kIrrelevantSequenceNumber - purpose:FSTQueryPurposeLimboResolution]; - _limboResolutionsByTarget.emplace(limboTargetID, LimboResolution{key}); - _remoteStore->Listen(queryData); - _limboTargetsByKey[key] = limboTargetID; - } -} - -- (void)removeLimboTargetForKey:(const DocumentKey &)key { - const auto iter = _limboTargetsByKey.find(key); - if (iter == _limboTargetsByKey.end()) { - // This target already got removed, because the query failed. - return; - } - TargetId limboTargetID = iter->second; - _remoteStore->StopListening(limboTargetID); - _limboTargetsByKey.erase(key); - _limboResolutionsByTarget.erase(limboTargetID); -} - -// Used for testing -- (std::map)currentLimboDocuments { - // Return defensive copy - return _limboTargetsByKey; -} - -- (void)credentialDidChangeWithUser:(const firebase::firestore::auth::User &)user { - BOOL userChanged = (_currentUser != user); - _currentUser = user; - - if (userChanged) { - // Notify local store and emit any resulting events from swapping out the mutation queue. - MaybeDocumentMap changes = [self.localStore userDidChange:user]; - [self emitNewSnapshotsAndNotifyLocalStoreWithChanges:changes remoteEvent:absl::nullopt]; - } - - // Notify remote store so it can restart its streams. - _remoteStore->HandleCredentialChange(); -} - -- (DocumentKeySet)remoteKeysForTarget:(TargetId)targetId { - const auto iter = _limboResolutionsByTarget.find(targetId); - if (iter != _limboResolutionsByTarget.end() && iter->second.document_received) { - return DocumentKeySet{iter->second.key}; - } else { - auto found = _queryViewsByTarget.find(targetId); - FSTQueryView *queryView = found != _queryViewsByTarget.end() ? found->second : nil; - return queryView ? queryView.view.syncedDocuments : DocumentKeySet{}; - } -} - -/** - * Decides if the error likely represents a developer mistake such as forgetting to create an index - * or permission denied. Used to decide whether an error is worth automatically logging as a - * warning. - */ -- (BOOL)errorIsInteresting:(NSError *)error { - if (error.domain == FIRFirestoreErrorDomain) { - if (error.code == FIRFirestoreErrorCodeFailedPrecondition && - [error.localizedDescription containsString:@"requires an index"]) { - return YES; - } else if (error.code == FIRFirestoreErrorCodePermissionDenied) { - return YES; - } - } - - return NO; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTTypes.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTTypes.h deleted file mode 100644 index 86c1e94..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTTypes.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include - -namespace firebase { -namespace firestore { -namespace core { - -class Transaction; - -} -} -} - -NS_ASSUME_NONNULL_BEGIN - -@class FSTMaybeDocument; - -/** - * FSTVoidBlock is a block that's called when a specific event happens but that otherwise has - * no information associated with it. - */ -typedef void (^FSTVoidBlock)(void); - -/** - * FSTVoidErrorBlock is a block that gets an error, if one occurred. - * - * @param error The error if it occurred, or nil. - */ -typedef void (^FSTVoidErrorBlock)(NSError *_Nullable error); - -/** FSTVoidIDErrorBlock is a block that takes an optional value and error. */ -typedef void (^FSTVoidIDErrorBlock)(id _Nullable, NSError *_Nullable); - -/** - * FSTVoidMaybeDocumentErrorBlock is a block that gets either a list of documents or an error. - * - * @param documents The documents, if no error occurred, or nil. - * @param error The error, if one occurred, or nil. - */ -typedef void (^FSTVoidMaybeDocumentArrayErrorBlock)( - NSArray *_Nullable documents, NSError *_Nullable error); - -/** - * FSTTransactionBlock is a block that wraps a user's transaction update block internally. - * - * @param transaction An object with methods for performing reads and writes within the - * transaction. - * @param completion To be called by the block once the user's code is finished. - */ -typedef void (^FSTTransactionBlock)( - std::shared_ptr transaction, - void (^completion)(id _Nullable, NSError *_Nullable)); - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTView.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTView.h deleted file mode 100644 index aed8732..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTView.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" -#include "Firestore/core/src/firebase/firestore/model/document_map.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" - -#include "absl/types/optional.h" - -namespace firebase { -namespace firestore { -namespace remote { - -class TargetChange; - -} // namespace remote -} // namespace firestore -} // namespace firebase - -@class FSTQuery; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - FSTViewDocumentChanges - -/** The result of applying a set of doc changes to a view. */ -@interface FSTViewDocumentChanges : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -- (const firebase::firestore::model::DocumentKeySet &)mutatedKeys; - -/** The new set of docs that should be in the view. */ -- (const firebase::firestore::model::DocumentSet &)documentSet; - -/** The diff of this these docs with the previous set of docs. */ -- (const firebase::firestore::core::DocumentViewChangeSet &)changeSet; - -/** - * Whether the set of documents passed in was not sufficient to calculate the new state of the view - * and there needs to be another pass based on the local cache. - */ -@property(nonatomic, assign, readonly) BOOL needsRefill; - -@end - -#pragma mark - FSTLimboDocumentChange - -typedef NS_ENUM(NSInteger, FSTLimboDocumentChangeType) { - FSTLimboDocumentChangeTypeAdded = 0, - FSTLimboDocumentChangeTypeRemoved, -}; - -// A change to a particular document wrt to whether it is in "limbo". -@interface FSTLimboDocumentChange : NSObject - -+ (instancetype)changeWithType:(FSTLimboDocumentChangeType)type - key:(firebase::firestore::model::DocumentKey)key; - -- (id)init __attribute__((unavailable("Use a static constructor method."))); - -- (const firebase::firestore::model::DocumentKey &)key; - -@property(nonatomic, assign, readonly) FSTLimboDocumentChangeType type; -@end - -#pragma mark - FSTViewChange - -// A set of changes to a view. -@interface FSTViewChange : NSObject - -- (id)init __attribute__((unavailable("Use a static constructor method."))); - -- (absl::optional &)snapshot; -@property(nonatomic, strong, readonly) NSArray *limboChanges; -@end - -#pragma mark - FSTView - -/** - * View is responsible for computing the final merged truth of what docs are in a query. It gets - * notified of local and remote changes to docs, and applies the query filters and limits to - * determine the most correct possible results. - */ -@interface FSTView : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithQuery:(FSTQuery *)query - remoteDocuments:(firebase::firestore::model::DocumentKeySet)remoteDocuments - NS_DESIGNATED_INITIALIZER; - -/** - * Iterates over a set of doc changes, applies the query limit, and computes what the new results - * should be, what the changes were, and whether we may need to go back to the local cache for - * more results. Does not make any changes to the view. - * - * @param docChanges The doc changes to apply to this view. - * @return a new set of docs, changes, and refill flag. - */ -- (FSTViewDocumentChanges *)computeChangesWithDocuments: - (const firebase::firestore::model::MaybeDocumentMap &)docChanges; - -/** - * Iterates over a set of doc changes, applies the query limit, and computes what the new results - * should be, what the changes were, and whether we may need to go back to the local cache for - * more results. Does not make any changes to the view. - * - * @param docChanges The doc changes to apply to this view. - * @param previousChanges If this is being called with a refill, then start with this set of docs - * and changes instead of the current view. - * @return a new set of docs, changes, and refill flag. - */ -- (FSTViewDocumentChanges *) - computeChangesWithDocuments:(const firebase::firestore::model::MaybeDocumentMap &)docChanges - previousChanges:(nullable FSTViewDocumentChanges *)previousChanges; - -/** - * Updates the view with the given ViewDocumentChanges. - * - * @param docChanges The set of changes to make to the view's docs. - * @return A new FSTViewChange with the given docs, changes, and sync state. - */ -- (FSTViewChange *)applyChangesToDocuments:(FSTViewDocumentChanges *)docChanges; - -/** - * Updates the view with the given FSTViewDocumentChanges and updates limbo docs and sync state from - * the given (optional) target change. - * - * @param docChanges The set of changes to make to the view's docs. - * @param targetChange A target change to apply for computing limbo docs and sync state. - * @return A new FSTViewChange with the given docs, changes, and sync state. - */ -- (FSTViewChange *) - applyChangesToDocuments:(FSTViewDocumentChanges *)docChanges - targetChange: - (const absl::optional &)targetChange; - -/** - * Applies an OnlineState change to the view, potentially generating an FSTViewChange if the - * view's syncState changes as a result. - */ -- (FSTViewChange *)applyChangedOnlineState:(firebase::firestore::model::OnlineState)onlineState; - -/** - * The set of remote documents that the server has told us belongs to the target associated with - * this view. - */ -- (const firebase::firestore::model::DocumentKeySet &)syncedDocuments; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTView.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTView.mm deleted file mode 100644 index 079c547..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Core/FSTView.mm +++ /dev/null @@ -1,528 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Core/FSTView.h" - -#include -#include -#include - -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Model/FSTFieldValue.h" - -#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" -#include "Firestore/core/src/firebase/firestore/model/document_set.h" -#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" -#include "Firestore/core/src/firebase/firestore/util/delayed_constructor.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" - -using firebase::firestore::core::DocumentViewChange; -using firebase::firestore::core::DocumentViewChangeSet; -using firebase::firestore::core::SyncState; -using firebase::firestore::core::ViewSnapshot; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::DocumentKeySet; -using firebase::firestore::model::DocumentSet; -using firebase::firestore::model::MaybeDocumentMap; -using firebase::firestore::model::OnlineState; -using firebase::firestore::remote::TargetChange; -using firebase::firestore::util::DelayedConstructor; - -NS_ASSUME_NONNULL_BEGIN - -namespace { - -int GetDocumentViewChangeTypePosition(DocumentViewChange::Type changeType) { - switch (changeType) { - case DocumentViewChange::Type::kRemoved: - return 0; - case DocumentViewChange::Type::kAdded: - return 1; - case DocumentViewChange::Type::kModified: - return 2; - case DocumentViewChange::Type::kMetadata: - // A metadata change is converted to a modified change at the public API layer. Since we sort - // by document key and then change type, metadata and modified changes must be sorted - // equivalently. - return 2; - } - HARD_FAIL("Unknown DocumentViewChange::Type %s", changeType); -} - -} // namespace - -#pragma mark - FSTViewDocumentChanges - -/** The result of applying a set of doc changes to a view. */ -@interface FSTViewDocumentChanges () - -- (instancetype)initWithDocumentSet:(DocumentSet)documentSet - changeSet:(DocumentViewChangeSet &&)changeSet - needsRefill:(BOOL)needsRefill - mutatedKeys:(DocumentKeySet)mutatedKeys NS_DESIGNATED_INITIALIZER; - -@end - -@implementation FSTViewDocumentChanges { - DelayedConstructor _documentSet; - DocumentKeySet _mutatedKeys; - DocumentViewChangeSet _changeSet; -} - -- (instancetype)initWithDocumentSet:(DocumentSet)documentSet - changeSet:(DocumentViewChangeSet &&)changeSet - needsRefill:(BOOL)needsRefill - mutatedKeys:(DocumentKeySet)mutatedKeys { - self = [super init]; - if (self) { - _documentSet.Init(std::move(documentSet)); - _changeSet = std::move(changeSet); - _needsRefill = needsRefill; - _mutatedKeys = std::move(mutatedKeys); - } - return self; -} - -- (const DocumentKeySet &)mutatedKeys { - return _mutatedKeys; -} - -- (const firebase::firestore::model::DocumentSet &)documentSet { - return *_documentSet; -} - -- (const firebase::firestore::core::DocumentViewChangeSet &)changeSet { - return _changeSet; -} - -@end - -#pragma mark - FSTLimboDocumentChange - -@interface FSTLimboDocumentChange () - -+ (instancetype)changeWithType:(FSTLimboDocumentChangeType)type key:(DocumentKey)key; - -- (instancetype)initWithType:(FSTLimboDocumentChangeType)type - key:(DocumentKey)key NS_DESIGNATED_INITIALIZER; - -@end - -@implementation FSTLimboDocumentChange { - DocumentKey _key; -} - -+ (instancetype)changeWithType:(FSTLimboDocumentChangeType)type key:(DocumentKey)key { - return [[FSTLimboDocumentChange alloc] initWithType:type key:std::move(key)]; -} - -- (instancetype)initWithType:(FSTLimboDocumentChangeType)type key:(DocumentKey)key { - self = [super init]; - if (self) { - _type = type; - _key = std::move(key); - } - return self; -} - -- (const DocumentKey &)key { - return _key; -} - -- (BOOL)isEqual:(id)other { - if (self == other) { - return YES; - } - if (![other isKindOfClass:[FSTLimboDocumentChange class]]) { - return NO; - } - FSTLimboDocumentChange *otherChange = (FSTLimboDocumentChange *)other; - return self.type == otherChange.type && self.key == otherChange.key; -} - -- (NSUInteger)hash { - NSUInteger hash = self.type; - hash = hash * 31u + self.key.Hash(); - return hash; -} - -@end - -#pragma mark - FSTViewChange - -@interface FSTViewChange () - -+ (FSTViewChange *)changeWithSnapshot:(absl::optional &&)snapshot - limboChanges:(NSArray *)limboChanges; - -- (instancetype)initWithSnapshot:(absl::optional &&)snapshot - limboChanges:(NSArray *)limboChanges - NS_DESIGNATED_INITIALIZER; - -@end - -@implementation FSTViewChange { - absl::optional _snapshot; -} - -+ (FSTViewChange *)changeWithSnapshot:(absl::optional &&)snapshot - limboChanges:(NSArray *)limboChanges { - return [[self alloc] initWithSnapshot:std::move(snapshot) limboChanges:limboChanges]; -} - -- (instancetype)initWithSnapshot:(absl::optional &&)snapshot - limboChanges:(NSArray *)limboChanges { - self = [super init]; - if (self) { - _snapshot = std::move(snapshot); - _limboChanges = limboChanges; - } - return self; -} - -- (absl::optional &)snapshot { - return _snapshot; -} - -@end - -#pragma mark - FSTView - -@interface FSTView () - -@property(nonatomic, strong, readonly) FSTQuery *query; - -@property(nonatomic, assign) firebase::firestore::core::SyncState syncState; - -/** - * A flag whether the view is current with the backend. A view is considered current after it - * has seen the current flag from the backend and did not lose consistency within the watch stream - * (e.g. because of an existence filter mismatch). - */ -@property(nonatomic, assign, getter=isCurrent) BOOL current; - -@end - -@implementation FSTView { - DelayedConstructor _documentSet; - - /** Documents included in the remote target. */ - DocumentKeySet _syncedDocuments; - - /** Documents in the view but not in the remote target */ - DocumentKeySet _limboDocuments; - - /** Document Keys that have local changes. */ - DocumentKeySet _mutatedKeys; -} - -- (instancetype)initWithQuery:(FSTQuery *)query remoteDocuments:(DocumentKeySet)remoteDocuments { - self = [super init]; - if (self) { - _query = query; - _documentSet.Init(query.comparator); - _syncedDocuments = std::move(remoteDocuments); - } - return self; -} - -- (const DocumentKeySet &)syncedDocuments { - return _syncedDocuments; -} - -- (FSTViewDocumentChanges *)computeChangesWithDocuments:(const MaybeDocumentMap &)docChanges { - return [self computeChangesWithDocuments:docChanges previousChanges:nil]; -} - -- (FSTViewDocumentChanges *)computeChangesWithDocuments:(const MaybeDocumentMap &)docChanges - previousChanges: - (nullable FSTViewDocumentChanges *)previousChanges { - DocumentViewChangeSet changeSet; - if (previousChanges) { - changeSet = previousChanges.changeSet; - } - DocumentSet oldDocumentSet = previousChanges ? previousChanges.documentSet : *_documentSet; - - DocumentKeySet newMutatedKeys = previousChanges ? previousChanges.mutatedKeys : _mutatedKeys; - DocumentKeySet oldMutatedKeys = _mutatedKeys; - DocumentSet newDocumentSet = oldDocumentSet; - BOOL needsRefill = NO; - - // Track the last doc in a (full) limit. This is necessary, because some update (a delete, or an - // update moving a doc past the old limit) might mean there is some other document in the local - // cache that either should come (1) between the old last limit doc and the new last document, - // in the case of updates, or (2) after the new last document, in the case of deletes. So we - // keep this doc at the old limit to compare the updates to. - // - // Note that this should never get used in a refill (when previousChanges is set), because there - // will only be adds -- no deletes or updates. - FSTDocument *_Nullable lastDocInLimit = - (self.query.limit != NSNotFound && oldDocumentSet.size() == self.query.limit) - ? oldDocumentSet.GetLastDocument() - : nil; - - for (const auto &kv : docChanges) { - const DocumentKey &key = kv.first; - FSTMaybeDocument *maybeNewDoc = kv.second; - - FSTDocument *_Nullable oldDoc = oldDocumentSet.GetDocument(key); - FSTDocument *_Nullable newDoc = nil; - if ([maybeNewDoc isKindOfClass:[FSTDocument class]]) { - newDoc = (FSTDocument *)maybeNewDoc; - } - if (newDoc) { - HARD_ASSERT(key == newDoc.key, "Mismatching key in document changes: %s != %s", - key.ToString(), newDoc.key.ToString()); - if (![self.query matchesDocument:newDoc]) { - newDoc = nil; - } - } - - BOOL oldDocHadPendingMutations = oldDoc && oldMutatedKeys.contains(oldDoc.key); - - // We only consider committed mutations for documents that were mutated during the lifetime of - // the view. - BOOL newDocHasPendingMutations = - newDoc && (newDoc.hasLocalMutations || - (oldMutatedKeys.contains(newDoc.key) && newDoc.hasCommittedMutations)); - - BOOL changeApplied = NO; - // Calculate change - if (oldDoc && newDoc) { - BOOL docsEqual = [oldDoc.data isEqual:newDoc.data]; - if (!docsEqual) { - if (![self shouldWaitForSyncedDocument:newDoc oldDocument:oldDoc]) { - changeSet.AddChange(DocumentViewChange{newDoc, DocumentViewChange::Type::kModified}); - changeApplied = YES; - - if (lastDocInLimit && self.query.comparator(newDoc, lastDocInLimit) > 0) { - // This doc moved from inside the limit to after the limit. That means there may be - // some doc in the local cache that's actually less than this one. - needsRefill = YES; - } - } - } else if (oldDocHadPendingMutations != newDocHasPendingMutations) { - changeSet.AddChange(DocumentViewChange{newDoc, DocumentViewChange::Type::kMetadata}); - changeApplied = YES; - } - - } else if (!oldDoc && newDoc) { - changeSet.AddChange(DocumentViewChange{newDoc, DocumentViewChange::Type::kAdded}); - changeApplied = YES; - } else if (oldDoc && !newDoc) { - changeSet.AddChange(DocumentViewChange{oldDoc, DocumentViewChange::Type::kRemoved}); - changeApplied = YES; - - if (lastDocInLimit) { - // A doc was removed from a full limit query. We'll need to re-query from the local cache - // to see if we know about some other doc that should be in the results. - needsRefill = YES; - } - } - - if (changeApplied) { - if (newDoc) { - newDocumentSet = newDocumentSet.insert(newDoc); - if (newDoc.hasLocalMutations) { - newMutatedKeys = newMutatedKeys.insert(key); - } else { - newMutatedKeys = newMutatedKeys.erase(key); - } - } else { - newDocumentSet = newDocumentSet.erase(key); - newMutatedKeys = newMutatedKeys.erase(key); - } - } - } - - if (self.query.limit != NSNotFound && newDocumentSet.size() > self.query.limit) { - for (size_t i = newDocumentSet.size() - self.query.limit; i > 0; --i) { - FSTDocument *oldDoc = newDocumentSet.GetLastDocument(); - newDocumentSet = newDocumentSet.erase(oldDoc.key); - newMutatedKeys = newMutatedKeys.erase(oldDoc.key); - changeSet.AddChange(DocumentViewChange{oldDoc, DocumentViewChange::Type::kRemoved}); - } - } - - HARD_ASSERT(!needsRefill || !previousChanges, - "View was refilled using docs that themselves needed refilling."); - - return [[FSTViewDocumentChanges alloc] initWithDocumentSet:std::move(newDocumentSet) - changeSet:std::move(changeSet) - needsRefill:needsRefill - mutatedKeys:newMutatedKeys]; -} - -- (BOOL)shouldWaitForSyncedDocument:(FSTDocument *)newDoc oldDocument:(FSTDocument *)oldDoc { - // We suppress the initial change event for documents that were modified as part of a write - // acknowledgment (e.g. when the value of a server transform is applied) as Watch will send us - // the same document again. By suppressing the event, we only raise two user visible events (one - // with `hasPendingWrites` and the final state of the document) instead of three (one with - // `hasPendingWrites`, the modified document with `hasPendingWrites` and the final state of the - // document). - return (oldDoc.hasLocalMutations && newDoc.hasCommittedMutations && !newDoc.hasLocalMutations); -} - -- (FSTViewChange *)applyChangesToDocuments:(FSTViewDocumentChanges *)docChanges { - return [self applyChangesToDocuments:docChanges targetChange:{}]; -} - -- (FSTViewChange *)applyChangesToDocuments:(FSTViewDocumentChanges *)docChanges - targetChange:(const absl::optional &)targetChange { - HARD_ASSERT(!docChanges.needsRefill, "Cannot apply changes that need a refill"); - - DocumentSet oldDocuments = *_documentSet; - *_documentSet = docChanges.documentSet; - _mutatedKeys = docChanges.mutatedKeys; - - // Sort changes based on type and query comparator. - std::vector changes = docChanges.changeSet.GetChanges(); - std::sort(changes.begin(), changes.end(), - [self](const DocumentViewChange &lhs, const DocumentViewChange &rhs) { - int pos1 = GetDocumentViewChangeTypePosition(lhs.type()); - int pos2 = GetDocumentViewChangeTypePosition(rhs.type()); - if (pos1 != pos2) { - return pos1 < pos2; - } - return self.query.comparator(lhs.document(), rhs.document()) == NSOrderedAscending; - }); - - [self applyTargetChange:targetChange]; - NSArray *limboChanges = [self updateLimboDocuments]; - BOOL synced = _limboDocuments.empty() && self.isCurrent; - SyncState newSyncState = synced ? SyncState::Synced : SyncState::Local; - bool syncStateChanged = newSyncState != self.syncState; - self.syncState = newSyncState; - - if (changes.empty() && !syncStateChanged) { - // No changes. - return [FSTViewChange changeWithSnapshot:absl::nullopt limboChanges:limboChanges]; - } else { - ViewSnapshot snapshot{self.query, - docChanges.documentSet, - oldDocuments, - std::move(changes), - docChanges.mutatedKeys, - /*from_cache=*/newSyncState == SyncState::Local, - syncStateChanged, - /*excludes_metadata_changes=*/false}; - - return [FSTViewChange changeWithSnapshot:std::move(snapshot) limboChanges:limboChanges]; - } -} - -- (FSTViewChange *)applyChangedOnlineState:(OnlineState)onlineState { - if (self.isCurrent && onlineState == OnlineState::Offline) { - // If we're offline, set `current` to NO and then call applyChanges to refresh our syncState - // and generate an FSTViewChange as appropriate. We are guaranteed to get a new `TargetChange` - // that sets `current` back to YES once the client is back online. - self.current = NO; - return [self applyChangesToDocuments:[[FSTViewDocumentChanges alloc] - initWithDocumentSet:*_documentSet - changeSet:DocumentViewChangeSet {} - needsRefill:NO - mutatedKeys:_mutatedKeys]]; - } else { - // No effect, just return a no-op FSTViewChange. - return [[FSTViewChange alloc] initWithSnapshot:absl::nullopt limboChanges:@[]]; - } -} - -#pragma mark - Private methods - -/** Returns whether the doc for the given key should be in limbo. */ -- (BOOL)shouldBeLimboDocumentKey:(const DocumentKey &)key { - // If the remote end says it's part of this query, it's not in limbo. - if (_syncedDocuments.contains(key)) { - return NO; - } - // The local store doesn't think it's a result, so it shouldn't be in limbo. - if (!_documentSet->ContainsKey(key)) { - return NO; - } - // If there are local changes to the doc, they might explain why the server doesn't know that it's - // part of the query. So don't put it in limbo. - // TODO(klimt): Ideally, we would only consider changes that might actually affect this specific - // query. - if (_documentSet->GetDocument(key).hasLocalMutations) { - return NO; - } - // Everything else is in limbo. - return YES; -} - -/** - * Updates syncedDocuments and current based on the given change. - */ -- (void)applyTargetChange:(const absl::optional &)maybeTargetChange { - if (maybeTargetChange.has_value()) { - const TargetChange &target_change = maybeTargetChange.value(); - - for (const DocumentKey &key : target_change.added_documents()) { - _syncedDocuments = _syncedDocuments.insert(key); - } - for (const DocumentKey &key : target_change.modified_documents()) { - HARD_ASSERT(_syncedDocuments.find(key) != _syncedDocuments.end(), - "Modified document %s not found in view.", key.ToString()); - } - for (const DocumentKey &key : target_change.removed_documents()) { - _syncedDocuments = _syncedDocuments.erase(key); - } - - self.current = target_change.current(); - } -} - -/** Updates limboDocuments and returns any changes as FSTLimboDocumentChanges. */ -- (NSArray *)updateLimboDocuments { - // We can only determine limbo documents when we're in-sync with the server. - if (!self.isCurrent) { - return @[]; - } - - // TODO(klimt): Do this incrementally so that it's not quadratic when updating many documents. - DocumentKeySet oldLimboDocuments = std::move(_limboDocuments); - _limboDocuments = DocumentKeySet{}; - for (FSTDocument *doc : *_documentSet) { - if ([self shouldBeLimboDocumentKey:doc.key]) { - _limboDocuments = _limboDocuments.insert(doc.key); - } - } - - // Diff the new limbo docs with the old limbo docs. - NSMutableArray *changes = - [NSMutableArray arrayWithCapacity:(oldLimboDocuments.size() + _limboDocuments.size())]; - for (const DocumentKey &key : oldLimboDocuments) { - if (!_limboDocuments.contains(key)) { - [changes addObject:[FSTLimboDocumentChange changeWithType:FSTLimboDocumentChangeTypeRemoved - key:key]]; - } - } - for (const DocumentKey &key : _limboDocuments) { - if (!oldLimboDocuments.contains(key)) { - [changes addObject:[FSTLimboDocumentChange changeWithType:FSTLimboDocumentChangeTypeAdded - key:key]]; - } - } - return changes; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLRUGarbageCollector.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLRUGarbageCollector.h deleted file mode 100644 index 9d59813..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLRUGarbageCollector.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#import - -#include -#include - -#import "FIRFirestoreSettings.h" -#import "Firestore/Source/Local/FSTQueryData.h" - -#include "Firestore/core/src/firebase/firestore/local/query_cache.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" - -@class FSTLRUGarbageCollector; - -extern const firebase::firestore::model::ListenSequenceNumber kFSTListenSequenceNumberInvalid; - -namespace firebase { -namespace firestore { -namespace local { - -struct LruParams { - static const int64_t CacheSizeUnlimited = -1; - - static LruParams Default() { - return LruParams{100 * 1024 * 1024, 10, 1000}; - } - - static LruParams Disabled() { - return LruParams{kFIRFirestoreCacheSizeUnlimited, 0, 0}; - } - - static LruParams WithCacheSize(int64_t cacheSize) { - LruParams params = Default(); - params.minBytesThreshold = cacheSize; - return params; - } - - int64_t minBytesThreshold; - int percentileToCollect; - int maximumSequenceNumbersToCollect; -}; - -struct LruResults { - static LruResults DidNotRun() { - return LruResults{/* didRun= */ false, 0, 0, 0}; - } - - bool didRun; - int sequenceNumbersCollected; - int targetsRemoved; - int documentsRemoved; -}; - -} // namespace local -} // namespace firestore -} // namespace firebase - -/** - * Persistence layers intending to use LRU Garbage collection should implement this protocol. This - * protocol defines the operations that the LRU garbage collector needs from the persistence layer. - */ -@protocol FSTLRUDelegate - -/** - * Enumerates all the targets that the delegate is aware of. This is typically all of the targets in - * an FSTQueryCache. - */ -- (void)enumerateTargetsUsingCallback:(const firebase::firestore::local::TargetCallback &)callback; - -/** - * Enumerates all of the outstanding mutations. - */ -- (void)enumerateMutationsUsingCallback: - (const firebase::firestore::local::OrphanedDocumentCallback &)callback; - -/** - * Removes all unreferenced documents from the cache that have a sequence number less than or equal - * to the given sequence number. Returns the number of documents removed. - */ -- (int)removeOrphanedDocumentsThroughSequenceNumber: - (firebase::firestore::model::ListenSequenceNumber)sequenceNumber; - -/** - * Removes all targets that are not currently being listened to and have a sequence number less than - * or equal to the given sequence number. Returns the number of targets removed. - */ -- (int)removeTargetsThroughSequenceNumber: - (firebase::firestore::model::ListenSequenceNumber)sequenceNumber - liveQueries: - (const std::unordered_map &)liveQueries; - -- (size_t)byteSize; - -/** Returns the number of targets and orphaned documents cached. */ -- (size_t)sequenceNumberCount; - -/** Access to the underlying LRU Garbage collector instance. */ -@property(strong, nonatomic, readonly) FSTLRUGarbageCollector *gc; - -@end - -/** - * FSTLRUGarbageCollector defines the LRU algorithm used to clean up old documents and targets. It - * is persistence-agnostic, as long as proper delegate is provided. - */ -@interface FSTLRUGarbageCollector : NSObject - -- (instancetype)initWithDelegate:(id)delegate - params:(firebase::firestore::local::LruParams)params - NS_DESIGNATED_INITIALIZER; - -- (instancetype)init NS_UNAVAILABLE; - -/** - * Given a target percentile, return the number of queries that make up that percentage of the - * queries that are cached. For instance, if 20 queries are cached, and the percentile is 40, the - * result will be 8. - */ -- (int)queryCountForPercentile:(NSUInteger)percentile; - -/** - * Given a number of queries n, return the nth sequence number in the cache. - */ -- (firebase::firestore::model::ListenSequenceNumber)sequenceNumberForQueryCount: - (NSUInteger)queryCount; - -/** - * Removes queries that are not currently live (as indicated by presence in the liveQueries map) and - * have a sequence number less than or equal to the given sequence number. - */ -- (int)removeQueriesUpThroughSequenceNumber: - (firebase::firestore::model::ListenSequenceNumber)sequenceNumber - liveQueries: - (const std::unordered_map &)liveQueries; - -/** - * Removes all unreferenced documents from the cache that have a sequence number less than or equal - * to the given sequence number. Returns the number of documents removed. - */ -- (int)removeOrphanedDocumentsThroughSequenceNumber: - (firebase::firestore::model::ListenSequenceNumber)sequenceNumber; - -- (size_t)byteSize; - -- (firebase::firestore::local::LruResults)collectWithLiveTargets: - (const std::unordered_map &)liveTargets; - -@end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLRUGarbageCollector.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLRUGarbageCollector.mm deleted file mode 100644 index 95a86fa..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLRUGarbageCollector.mm +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#import "Firestore/Source/Local/FSTLRUGarbageCollector.h" - -#include //NOLINT(build/c++11) -#include -#include - -#import "Firestore/Source/Local/FSTPersistence.h" -#include "Firestore/core/include/firebase/firestore/timestamp.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/util/log.h" - -using Millis = std::chrono::milliseconds; -using firebase::Timestamp; -using firebase::firestore::local::LruParams; -using firebase::firestore::local::LruResults; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::ListenSequenceNumber; -using firebase::firestore::model::TargetId; - -const int64_t kFIRFirestoreCacheSizeUnlimited = LruParams::CacheSizeUnlimited; -const ListenSequenceNumber kFSTListenSequenceNumberInvalid = -1; - -static Millis::rep millisecondsBetween(const Timestamp &start, const Timestamp &end) { - return std::chrono::duration_cast(end.ToTimePoint() - start.ToTimePoint()).count(); -} - -/** - * RollingSequenceNumberBuffer tracks the nth sequence number in a series. Sequence numbers may be - * added out of order. - */ -class RollingSequenceNumberBuffer { - public: - explicit RollingSequenceNumberBuffer(size_t max_elements) - : queue_(std::priority_queue()), max_elements_(max_elements) { - } - - RollingSequenceNumberBuffer(const RollingSequenceNumberBuffer &other) = delete; - - RollingSequenceNumberBuffer &operator=(const RollingSequenceNumberBuffer &other) = delete; - - void AddElement(ListenSequenceNumber sequence_number) { - if (queue_.size() < max_elements_) { - queue_.push(sequence_number); - } else { - ListenSequenceNumber highestValue = queue_.top(); - if (sequence_number < highestValue) { - queue_.pop(); - queue_.push(sequence_number); - } - } - } - - ListenSequenceNumber max_value() const { - return queue_.top(); - } - - size_t size() const { - return queue_.size(); - } - - private: - std::priority_queue queue_; - const size_t max_elements_; -}; - -@implementation FSTLRUGarbageCollector { - __weak id _delegate; - LruParams _params; -} - -- (instancetype)initWithDelegate:(id)delegate params:(LruParams)params { - self = [super init]; - if (self) { - _delegate = delegate; - _params = std::move(params); - } - return self; -} - -- (LruResults)collectWithLiveTargets: - (const std::unordered_map &)liveTargets { - if (_params.minBytesThreshold == kFIRFirestoreCacheSizeUnlimited) { - LOG_DEBUG("Garbage collection skipped; disabled"); - return LruResults::DidNotRun(); - } - - size_t currentSize = [self byteSize]; - if (currentSize < _params.minBytesThreshold) { - // Not enough on disk to warrant collection. Wait another timeout cycle. - LOG_DEBUG("Garbage collection skipped; Cache size %s is lower than threshold %s", currentSize, - _params.minBytesThreshold); - return LruResults::DidNotRun(); - } else { - LOG_DEBUG("Running garbage collection on cache of size: %s", currentSize); - return [self runGCWithLiveTargets:liveTargets]; - } -} - -- (LruResults)runGCWithLiveTargets: - (const std::unordered_map &)liveTargets { - Timestamp start = Timestamp::Now(); - int sequenceNumbers = [self queryCountForPercentile:_params.percentileToCollect]; - // Cap at the configured max - if (sequenceNumbers > _params.maximumSequenceNumbersToCollect) { - sequenceNumbers = _params.maximumSequenceNumbersToCollect; - } - Timestamp countedTargets = Timestamp::Now(); - - ListenSequenceNumber upperBound = [self sequenceNumberForQueryCount:sequenceNumbers]; - Timestamp foundUpperBound = Timestamp::Now(); - - int numTargetsRemoved = [self removeQueriesUpThroughSequenceNumber:upperBound - liveQueries:liveTargets]; - Timestamp removedTargets = Timestamp::Now(); - - int numDocumentsRemoved = [self removeOrphanedDocumentsThroughSequenceNumber:upperBound]; - Timestamp removedDocuments = Timestamp::Now(); - - std::string desc = "LRU Garbage Collection:\n"; - absl::StrAppend(&desc, "\tCounted targets in ", millisecondsBetween(start, countedTargets), - "ms\n"); - absl::StrAppend(&desc, "\tDetermined least recently used ", sequenceNumbers, - " sequence numbers in ", millisecondsBetween(countedTargets, foundUpperBound), - "ms\n"); - absl::StrAppend(&desc, "\tRemoved ", numTargetsRemoved, " targets in ", - millisecondsBetween(foundUpperBound, removedTargets), "ms\n"); - absl::StrAppend(&desc, "\tRemoved ", numDocumentsRemoved, " documents in ", - millisecondsBetween(removedTargets, removedDocuments), "ms\n"); - absl::StrAppend(&desc, "Total duration: ", millisecondsBetween(start, removedDocuments), "ms"); - LOG_DEBUG(desc.c_str()); - - return LruResults{/* didRun= */ true, sequenceNumbers, numTargetsRemoved, numDocumentsRemoved}; -} - -- (int)queryCountForPercentile:(NSUInteger)percentile { - size_t totalCount = [_delegate sequenceNumberCount]; - int setSize = (int)((percentile / 100.0f) * totalCount); - return setSize; -} - -- (ListenSequenceNumber)sequenceNumberForQueryCount:(NSUInteger)queryCount { - if (queryCount == 0) { - return kFSTListenSequenceNumberInvalid; - } - RollingSequenceNumberBuffer buffer(queryCount); - - [_delegate enumerateTargetsUsingCallback:[&buffer](FSTQueryData *queryData) { - buffer.AddElement(queryData.sequenceNumber); - }]; - [_delegate enumerateMutationsUsingCallback:[&buffer](const DocumentKey &docKey, - ListenSequenceNumber sequenceNumber) { - buffer.AddElement(sequenceNumber); - }]; - return buffer.max_value(); -} - -- (int)removeQueriesUpThroughSequenceNumber:(ListenSequenceNumber)sequenceNumber - liveQueries:(const std::unordered_map &) - liveQueries { - return [_delegate removeTargetsThroughSequenceNumber:sequenceNumber liveQueries:liveQueries]; -} - -- (int)removeOrphanedDocumentsThroughSequenceNumber:(ListenSequenceNumber)sequenceNumber { - return [_delegate removeOrphanedDocumentsThroughSequenceNumber:sequenceNumber]; -} - -- (size_t)byteSize { - return [_delegate byteSize]; -} - -@end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLevelDB.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLevelDB.h deleted file mode 100644 index 2ef3f6e..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLevelDB.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include -#include -#include - -#import "Firestore/Source/Local/FSTLRUGarbageCollector.h" -#import "Firestore/Source/Local/FSTPersistence.h" -#include "Firestore/core/src/firebase/firestore/core/database_info.h" -#include "Firestore/core/src/firebase/firestore/local/leveldb_transaction.h" -#include "Firestore/core/src/firebase/firestore/util/path.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" -#include "Firestore/core/src/firebase/firestore/util/statusor.h" -#include "leveldb/db.h" - -@class FSTLocalSerializer; - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTLevelDBLRUDelegate : NSObject -@end - -/** A LevelDB-backed instance of FSTPersistence. */ -// TODO(mikelehen): Rename to FSTLevelDBPersistence. -@interface FSTLevelDB : NSObject - -/** - * Creates a LevelDB in the given directory and sets `ptr` to point to it. Return value indicates - * success in creating the leveldb instance and must be checked before accessing `ptr`. C++ note: - * Once FSTLevelDB is ported to C++, this factory method should return StatusOr<>. It cannot - * currently do that because ObjC references are not allowed in StatusOr. - */ -+ (firebase::firestore::util::Status)dbWithDirectory:(firebase::firestore::util::Path)directory - serializer:(FSTLocalSerializer *)serializer - lruParams: - (firebase::firestore::local::LruParams)lruParams - ptr:(FSTLevelDB *_Nullable *_Nonnull)ptr; - -- (instancetype)init NS_UNAVAILABLE; - -/** Finds a suitable directory to serve as the root of all Firestore local storage. */ -+ (firebase::firestore::util::Path)documentsDirectory; - -/** - * Computes a unique storage directory for the given identifying components of local storage. - * - * @param databaseInfo The identifying information for the local storage instance. - * @param documentsDirectory The root document directory relative to which the storage directory - * will be created. Usually just +[FSTLevelDB documentsDir]. - * @return A storage directory unique to the instance identified by databaseInfo. - */ -+ (firebase::firestore::util::Path) - storageDirectoryForDatabaseInfo:(const firebase::firestore::core::DatabaseInfo &)databaseInfo - documentsDirectory:(const firebase::firestore::util::Path &)documentsDirectory; - -/** - * @return A standard set of read options - */ -+ (const leveldb::ReadOptions)standardReadOptions; - -/** The native db pointer, allocated during start. */ -@property(nonatomic, assign, readonly) leveldb::DB *ptr; - -@property(nonatomic, readonly) firebase::firestore::local::LevelDbTransaction *currentTransaction; - -@property(nonatomic, readonly) const std::set &users; - -@property(nonatomic, readonly, strong) FSTLevelDBLRUDelegate *referenceDelegate; - -@property(nonatomic, readonly, strong) FSTLocalSerializer *serializer; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLevelDB.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLevelDB.mm deleted file mode 100644 index 478e68a..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLevelDB.mm +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Local/FSTLevelDB.h" - -#include -#include -#include - -#import "FIRFirestoreErrors.h" -#import "Firestore/Source/Local/FSTLRUGarbageCollector.h" -#import "Firestore/Source/Remote/FSTSerializerBeta.h" - -#include "Firestore/core/include/firebase/firestore/firestore_errors.h" -#include "Firestore/core/src/firebase/firestore/auth/user.h" -#include "Firestore/core/src/firebase/firestore/core/database_info.h" -#include "Firestore/core/src/firebase/firestore/local/index_manager.h" -#include "Firestore/core/src/firebase/firestore/local/leveldb_index_manager.h" -#include "Firestore/core/src/firebase/firestore/local/leveldb_key.h" -#include "Firestore/core/src/firebase/firestore/local/leveldb_migrations.h" -#include "Firestore/core/src/firebase/firestore/local/leveldb_mutation_queue.h" -#include "Firestore/core/src/firebase/firestore/local/leveldb_query_cache.h" -#include "Firestore/core/src/firebase/firestore/local/leveldb_remote_document_cache.h" -#include "Firestore/core/src/firebase/firestore/local/leveldb_transaction.h" -#include "Firestore/core/src/firebase/firestore/local/leveldb_util.h" -#include "Firestore/core/src/firebase/firestore/local/listen_sequence.h" -#include "Firestore/core/src/firebase/firestore/local/reference_set.h" -#include "Firestore/core/src/firebase/firestore/local/remote_document_cache.h" -#include "Firestore/core/src/firebase/firestore/model/database_id.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/resource_path.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" -#include "Firestore/core/src/firebase/firestore/util/filesystem.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/ordered_code.h" -#include "Firestore/core/src/firebase/firestore/util/statusor.h" -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" -#include "Firestore/core/src/firebase/firestore/util/string_util.h" -#include "absl/memory/memory.h" -#include "absl/strings/match.h" -#include "absl/strings/str_cat.h" -#include "leveldb/db.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace util = firebase::firestore::util; -using firebase::firestore::FirestoreErrorCode; -using firebase::firestore::auth::User; -using firebase::firestore::core::DatabaseInfo; -using firebase::firestore::local::ConvertStatus; -using firebase::firestore::local::IndexManager; -using firebase::firestore::local::LevelDbDocumentMutationKey; -using firebase::firestore::local::LevelDbDocumentTargetKey; -using firebase::firestore::local::LevelDbIndexManager; -using firebase::firestore::local::LevelDbMigrations; -using firebase::firestore::local::LevelDbMutationKey; -using firebase::firestore::local::LevelDbMutationQueue; -using firebase::firestore::local::LevelDbQueryCache; -using firebase::firestore::local::LevelDbRemoteDocumentCache; -using firebase::firestore::local::LevelDbTransaction; -using firebase::firestore::local::ListenSequence; -using firebase::firestore::local::LruParams; -using firebase::firestore::local::OrphanedDocumentCallback; -using firebase::firestore::local::ReferenceSet; -using firebase::firestore::local::RemoteDocumentCache; -using firebase::firestore::local::TargetCallback; -using firebase::firestore::model::DatabaseId; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::ListenSequenceNumber; -using firebase::firestore::model::ResourcePath; -using firebase::firestore::model::TargetId; -using firebase::firestore::util::OrderedCode; -using firebase::firestore::util::Path; -using firebase::firestore::util::Status; -using firebase::firestore::util::StatusOr; -using firebase::firestore::util::StringFormat; -using leveldb::DB; -using leveldb::Options; -using leveldb::ReadOptions; -using leveldb::WriteOptions; - -static const char *kReservedPathComponent = "firestore"; - -@interface FSTLevelDB () - -- (size_t)byteSize; - -@property(nonatomic, assign, getter=isStarted) BOOL started; - -- (LevelDbQueryCache *)queryCache; - -- (LevelDbMutationQueue *)mutationQueueForUser:(const User &)user; - -@end - -/** - * Provides LRU functionality for leveldb persistence. - * - * Although this could implement FSTTransactional, it doesn't because it is not directly tied to - * a transaction runner, it just happens to be called from FSTLevelDB, which is FSTTransactional. - */ -@interface FSTLevelDBLRUDelegate () - -- (void)transactionWillStart; - -- (void)transactionWillCommit; - -- (void)start; - -@end - -@implementation FSTLevelDBLRUDelegate { - FSTLRUGarbageCollector *_gc; - // This delegate should have the same lifetime as the persistence layer, but mark as - // weak to avoid retain cycle. - __weak FSTLevelDB *_db; - ReferenceSet *_additionalReferences; - ListenSequenceNumber _currentSequenceNumber; - // PORTING NOTE: doesn't need to be a pointer once this class is ported to C++. - std::unique_ptr _listenSequence; -} - -- (instancetype)initWithPersistence:(FSTLevelDB *)persistence lruParams:(LruParams)lruParams { - if (self = [super init]) { - _gc = [[FSTLRUGarbageCollector alloc] initWithDelegate:self params:lruParams]; - _db = persistence; - _currentSequenceNumber = kFSTListenSequenceNumberInvalid; - } - return self; -} - -- (void)start { - ListenSequenceNumber highestSequenceNumber = _db.queryCache->highest_listen_sequence_number(); - _listenSequence = absl::make_unique(highestSequenceNumber); -} - -- (void)transactionWillStart { - HARD_ASSERT(_currentSequenceNumber == kFSTListenSequenceNumberInvalid, - "Previous sequence number is still in effect"); - _currentSequenceNumber = _listenSequence->Next(); -} - -- (void)transactionWillCommit { - _currentSequenceNumber = kFSTListenSequenceNumberInvalid; -} - -- (ListenSequenceNumber)currentSequenceNumber { - HARD_ASSERT(_currentSequenceNumber != kFSTListenSequenceNumberInvalid, - "Asking for a sequence number outside of a transaction"); - return _currentSequenceNumber; -} - -- (void)addInMemoryPins:(ReferenceSet *)set { - // We should be able to assert that _additionalReferences is nil, but due to restarts in spec - // tests it would fail. - _additionalReferences = set; -} - -- (void)removeTarget:(FSTQueryData *)queryData { - FSTQueryData *updated = - [queryData queryDataByReplacingSnapshotVersion:queryData.snapshotVersion - resumeToken:queryData.resumeToken - sequenceNumber:[self currentSequenceNumber]]; - _db.queryCache->UpdateTarget(updated); -} - -- (void)addReference:(const DocumentKey &)key { - [self writeSentinelForKey:key]; -} - -- (void)removeReference:(const DocumentKey &)key { - [self writeSentinelForKey:key]; -} - -- (BOOL)mutationQueuesContainKey:(const DocumentKey &)docKey { - const std::set &users = _db.users; - const ResourcePath &path = docKey.path(); - std::string buffer; - auto it = _db.currentTransaction->NewIterator(); - // For each user, if there is any batch that contains this document in any batch, we know it's - // pinned. - for (const std::string &user : users) { - std::string mutationKey = LevelDbDocumentMutationKey::KeyPrefix(user, path); - it->Seek(mutationKey); - if (it->Valid() && absl::StartsWith(it->key(), mutationKey)) { - return YES; - } - } - return NO; -} - -- (BOOL)isPinned:(const DocumentKey &)docKey { - if (_additionalReferences->ContainsKey(docKey)) { - return YES; - } - if ([self mutationQueuesContainKey:docKey]) { - return YES; - } - return NO; -} - -- (void)enumerateTargetsUsingCallback:(const TargetCallback &)callback { - _db.queryCache->EnumerateTargets(callback); -} - -- (void)enumerateMutationsUsingCallback:(const OrphanedDocumentCallback &)callback { - _db.queryCache->EnumerateOrphanedDocuments(callback); -} - -- (int)removeOrphanedDocumentsThroughSequenceNumber:(ListenSequenceNumber)upperBound { - int count = 0; - _db.queryCache->EnumerateOrphanedDocuments( - [&count, self, upperBound](const DocumentKey &docKey, ListenSequenceNumber sequenceNumber) { - if (sequenceNumber <= upperBound) { - if (![self isPinned:docKey]) { - count++; - self->_db.remoteDocumentCache->Remove(docKey); - [self removeSentinel:docKey]; - } - } - }); - return count; -} - -- (void)removeSentinel:(const DocumentKey &)key { - _db.currentTransaction->Delete(LevelDbDocumentTargetKey::SentinelKey(key)); -} - -- (int)removeTargetsThroughSequenceNumber:(ListenSequenceNumber)sequenceNumber - liveQueries:(const std::unordered_map &) - liveQueries { - return _db.queryCache->RemoveTargets(sequenceNumber, liveQueries); -} - -- (size_t)sequenceNumberCount { - size_t totalCount = _db.queryCache->size(); - [self enumerateMutationsUsingCallback:[&totalCount](const DocumentKey &key, - ListenSequenceNumber sequenceNumber) { - totalCount++; - }]; - return totalCount; -} - -- (FSTLRUGarbageCollector *)gc { - return _gc; -} - -- (void)writeSentinelForKey:(const DocumentKey &)key { - std::string sentinelKey = LevelDbDocumentTargetKey::SentinelKey(key); - std::string encodedSequenceNumber = - LevelDbDocumentTargetKey::EncodeSentinelValue([self currentSequenceNumber]); - _db.currentTransaction->Put(sentinelKey, encodedSequenceNumber); -} - -- (void)removeMutationReference:(const DocumentKey &)key { - [self writeSentinelForKey:key]; -} - -- (void)limboDocumentUpdated:(const DocumentKey &)key { - [self writeSentinelForKey:key]; -} - -- (size_t)byteSize { - return [_db byteSize]; -} - -@end - -@implementation FSTLevelDB { - Path _directory; - std::unique_ptr _transaction; - std::unique_ptr _ptr; - std::unique_ptr _documentCache; - std::unique_ptr _indexManager; - FSTTransactionRunner _transactionRunner; - FSTLevelDBLRUDelegate *_referenceDelegate; - std::unique_ptr _queryCache; - std::set _users; - std::unique_ptr _currentMutationQueue; -} - -/** - * For now this is paranoid, but perhaps disable that in production builds. - */ -+ (const ReadOptions)standardReadOptions { - ReadOptions options; - options.verify_checksums = true; - return options; -} - -+ (std::set)collectUserSet:(LevelDbTransaction *)transaction { - std::set users; - - std::string tablePrefix = LevelDbMutationKey::KeyPrefix(); - auto it = transaction->NewIterator(); - it->Seek(tablePrefix); - LevelDbMutationKey rowKey; - while (it->Valid() && absl::StartsWith(it->key(), tablePrefix) && rowKey.Decode(it->key())) { - users.insert(rowKey.user_id()); - - auto userEnd = LevelDbMutationKey::KeyPrefix(rowKey.user_id()); - userEnd = util::PrefixSuccessor(userEnd); - it->Seek(userEnd); - } - return users; -} - -+ (firebase::firestore::util::Status)dbWithDirectory:(firebase::firestore::util::Path)directory - serializer:(FSTLocalSerializer *)serializer - lruParams: - (firebase::firestore::local::LruParams)lruParams - ptr:(FSTLevelDB **)ptr { - Status status = [self ensureDirectory:directory]; - if (!status.ok()) return status; - - StatusOr> database = [self createDBWithDirectory:directory]; - if (!database.status().ok()) { - return database.status(); - } - - std::unique_ptr ldb = std::move(database.ValueOrDie()); - LevelDbMigrations::RunMigrations(ldb.get()); - LevelDbTransaction transaction(ldb.get(), "Start LevelDB"); - std::set users = [self collectUserSet:&transaction]; - transaction.Commit(); - FSTLevelDB *db = [[self alloc] initWithLevelDB:std::move(ldb) - users:users - directory:directory - serializer:serializer - lruParams:lruParams]; - *ptr = db; - return Status::OK(); -} - -- (instancetype)initWithLevelDB:(std::unique_ptr)db - users:(std::set)users - directory:(firebase::firestore::util::Path)directory - serializer:(FSTLocalSerializer *)serializer - lruParams:(firebase::firestore::local::LruParams)lruParams { - if (self = [super init]) { - self.started = YES; - _ptr = std::move(db); - _directory = std::move(directory); - _serializer = serializer; - _queryCache = absl::make_unique(self, _serializer); - _documentCache = absl::make_unique(self, _serializer); - _indexManager = absl::make_unique(self); - _referenceDelegate = [[FSTLevelDBLRUDelegate alloc] initWithPersistence:self - lruParams:lruParams]; - _transactionRunner.SetBackingPersistence(self); - _users = std::move(users); - // TODO(gsoltis): set up a leveldb transaction for these operations. - _queryCache->Start(); - [_referenceDelegate start]; - } - return self; -} - -- (size_t)byteSize { - int64_t count = 0; - auto iter = util::DirectoryIterator::Create(_directory); - for (; iter->Valid(); iter->Next()) { - int64_t fileSize = util::FileSize(iter->file()).ValueOrDie(); - count += fileSize; - } - HARD_ASSERT(iter->status().ok(), "Failed to iterate leveldb directory: %s", - iter->status().error_message().c_str()); - HARD_ASSERT(count >= 0 && count <= SIZE_MAX, "Overflowed counting bytes cached"); - return static_cast(count); -} - -- (const std::set &)users { - return _users; -} - -- (leveldb::DB *)ptr { - return _ptr.get(); -} - -- (const FSTTransactionRunner &)run { - return _transactionRunner; -} - -+ (Path)documentsDirectory { -#if TARGET_OS_IPHONE - NSArray *directories = - NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - return Path::FromNSString(directories[0]).AppendUtf8(kReservedPathComponent); - -#elif TARGET_OS_OSX - std::string dotPrefixed = absl::StrCat(".", kReservedPathComponent); - return Path::FromNSString(NSHomeDirectory()).AppendUtf8(dotPrefixed); - -#else -#error "local storage on tvOS" - // TODO(mcg): Writing to NSDocumentsDirectory on tvOS will fail; we need to write to Caches - // https://developer.apple.com/library/content/documentation/General/Conceptual/AppleTV_PG/ - -#endif -} - -+ (Path)storageDirectoryForDatabaseInfo:(const DatabaseInfo &)databaseInfo - documentsDirectory:(const Path &)documentsDirectory { - // Use two different path formats: - // - // * persistenceKey / projectID . databaseID / name - // * persistenceKey / projectID / name - // - // projectIDs are DNS-compatible names and cannot contain dots so there's - // no danger of collisions. - std::string project_key = databaseInfo.database_id().project_id(); - if (!databaseInfo.database_id().IsDefaultDatabase()) { - absl::StrAppend(&project_key, ".", databaseInfo.database_id().database_id()); - } - - // Reserve one additional path component to allow multiple physical databases - return Path::JoinUtf8(documentsDirectory, databaseInfo.persistence_key(), project_key, "main"); -} - -#pragma mark - Startup - -/** Creates the directory at @a directory and marks it as excluded from iCloud backup. */ -+ (Status)ensureDirectory:(const Path &)directory { - Status status = util::RecursivelyCreateDir(directory); - if (!status.ok()) { - return Status{FirestoreErrorCode::Internal, "Failed to create persistence directory"}.CausedBy( - status); - } - - NSURL *dirURL = [NSURL fileURLWithPath:directory.ToNSString()]; - NSError *localError = nil; - if (![dirURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:&localError]) { - return Status{FirestoreErrorCode::Internal, - "Failed to mark persistence directory as excluded from backups"} - .CausedBy(Status::FromNSError(localError)); - } - - return Status::OK(); -} - -/** Opens the database within the given directory. */ -+ (StatusOr>)createDBWithDirectory:(const Path &)directory { - Options options; - options.create_if_missing = true; - - DB *database = nullptr; - leveldb::Status status = DB::Open(options, directory.ToUtf8String(), &database); - if (!status.ok()) { - return Status{FirestoreErrorCode::Internal, - StringFormat("Failed to open LevelDB database at %s", directory.ToUtf8String())} - .CausedBy(ConvertStatus(status)); - } - - return std::unique_ptr(database); -} - -- (LevelDbTransaction *)currentTransaction { - HARD_ASSERT(_transaction != nullptr, "Attempting to access transaction before one has started"); - return _transaction.get(); -} - -#pragma mark - Persistence Factory methods - -- (LevelDbMutationQueue *)mutationQueueForUser:(const User &)user { - _users.insert(user.uid()); - _currentMutationQueue.reset(new LevelDbMutationQueue(user, self, self.serializer)); - return _currentMutationQueue.get(); -} - -- (LevelDbQueryCache *)queryCache { - return _queryCache.get(); -} - -- (RemoteDocumentCache *)remoteDocumentCache { - return _documentCache.get(); -} - -- (IndexManager *)indexManager { - return _indexManager.get(); -} - -- (void)startTransaction:(absl::string_view)label { - HARD_ASSERT(_transaction == nullptr, "Starting a transaction while one is already outstanding"); - _transaction = absl::make_unique(_ptr.get(), label); - [_referenceDelegate transactionWillStart]; -} - -- (void)commitTransaction { - HARD_ASSERT(_transaction != nullptr, "Committing a transaction before one is started"); - [_referenceDelegate transactionWillCommit]; - _transaction->Commit(); - _transaction.reset(); -} - -- (void)shutdown { - HARD_ASSERT(self.isStarted, "FSTLevelDB shutdown without start!"); - self.started = NO; - _ptr.reset(); -} - -- (id)referenceDelegate { - return _referenceDelegate; -} - -- (ListenSequenceNumber)currentSequenceNumber { - return [_referenceDelegate currentSequenceNumber]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalSerializer.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalSerializer.h deleted file mode 100644 index 3c57a35..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalSerializer.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" - -@class FSTMaybeDocument; -@class FSTMutationBatch; -@class FSTQueryData; -@class FSTSerializerBeta; - -@class FSTPBMaybeDocument; -@class FSTPBTarget; -@class FSTPBWriteBatch; - -@class GPBTimestamp; - -NS_ASSUME_NONNULL_BEGIN - -/** - * Serializer for values stored in the LocalStore. - * - * Note that FSTLocalSerializer currently delegates to the serializer for the Firestore v1 RPC - * protocol to save implementation time and code duplication. We'll need to revisit this when the - * RPC protocol we use diverges from local storage. - */ -@interface FSTLocalSerializer : NSObject - -- (instancetype)initWithRemoteSerializer:(FSTSerializerBeta *)remoteSerializer; - -- (instancetype)init NS_UNAVAILABLE; - -/** Encodes an FSTMaybeDocument model to the equivalent protocol buffer for local storage. */ -- (FSTPBMaybeDocument *)encodedMaybeDocument:(FSTMaybeDocument *)document; - -/** Decodes an FSTPBMaybeDocument proto to the equivalent model. */ -- (FSTMaybeDocument *)decodedMaybeDocument:(FSTPBMaybeDocument *)proto; - -/** Encodes an FSTMutationBatch model for local storage in the mutation queue. */ -- (FSTPBWriteBatch *)encodedMutationBatch:(FSTMutationBatch *)batch; - -/** Decodes an FSTPBWriteBatch proto into a MutationBatch model. */ -- (FSTMutationBatch *)decodedMutationBatch:(FSTPBWriteBatch *)batch; - -/** Encodes an FSTQueryData model for local storage in the query cache. */ -- (FSTPBTarget *)encodedQueryData:(FSTQueryData *)queryData; - -/** Decodes an FSTPBTarget proto from local storage into an FSTQueryData model. */ -- (FSTQueryData *)decodedQueryData:(FSTPBTarget *)target; - -/** Encodes a SnapshotVersion model into a GPBTimestamp proto. */ -- (GPBTimestamp *)encodedVersion:(const firebase::firestore::model::SnapshotVersion &)version; - -/** Decodes a GPBTimestamp proto into a SnapshotVersion model. */ -- (firebase::firestore::model::SnapshotVersion)decodedVersion:(GPBTimestamp *)version; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalSerializer.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalSerializer.mm deleted file mode 100644 index 97545aa..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalSerializer.mm +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Local/FSTLocalSerializer.h" - -#include -#include -#include - -#import "FIRTimestamp.h" -#import "Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h" -#import "Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h" -#import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h" -#import "Firestore/Protos/objc/google/firestore/v1/Document.pbobjc.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Local/FSTQueryData.h" -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Remote/FSTSerializerBeta.h" - -#include "Firestore/core/include/firebase/firestore/timestamp.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" - -using firebase::Timestamp; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::ListenSequenceNumber; -using firebase::firestore::model::SnapshotVersion; -using firebase::firestore::model::TargetId; - -@interface FSTLocalSerializer () - -@property(nonatomic, strong, readonly) FSTSerializerBeta *remoteSerializer; - -@end - -/** Serializer for values stored in the LocalStore. */ -@implementation FSTLocalSerializer - -- (instancetype)initWithRemoteSerializer:(FSTSerializerBeta *)remoteSerializer { - self = [super init]; - if (self) { - _remoteSerializer = remoteSerializer; - } - return self; -} - -- (FSTPBMaybeDocument *)encodedMaybeDocument:(FSTMaybeDocument *)document { - FSTPBMaybeDocument *proto = [FSTPBMaybeDocument message]; - - if ([document isKindOfClass:[FSTDeletedDocument class]]) { - FSTDeletedDocument *deletedDocument = (FSTDeletedDocument *)document; - proto.noDocument = [self encodedDeletedDocument:deletedDocument]; - proto.hasCommittedMutations = deletedDocument.hasCommittedMutations; - } else if ([document isKindOfClass:[FSTDocument class]]) { - FSTDocument *existingDocument = (FSTDocument *)document; - if (existingDocument.proto != nil) { - proto.document = existingDocument.proto; - } else { - proto.document = [self encodedDocument:existingDocument]; - } - proto.hasCommittedMutations = existingDocument.hasCommittedMutations; - } else if ([document isKindOfClass:[FSTUnknownDocument class]]) { - FSTUnknownDocument *unknownDocument = (FSTUnknownDocument *)document; - proto.unknownDocument = [self encodedUnknownDocument:unknownDocument]; - proto.hasCommittedMutations = YES; - } else { - HARD_FAIL("Unknown document type %s", NSStringFromClass([document class])); - } - - return proto; -} - -- (FSTMaybeDocument *)decodedMaybeDocument:(FSTPBMaybeDocument *)proto { - switch (proto.documentTypeOneOfCase) { - case FSTPBMaybeDocument_DocumentType_OneOfCase_Document: - return [self decodedDocument:proto.document - withCommittedMutations:proto.hasCommittedMutations]; - - case FSTPBMaybeDocument_DocumentType_OneOfCase_NoDocument: - return [self decodedDeletedDocument:proto.noDocument - withCommittedMutations:proto.hasCommittedMutations]; - - case FSTPBMaybeDocument_DocumentType_OneOfCase_UnknownDocument: - return [self decodedUnknownDocument:proto.unknownDocument]; - - default: - HARD_FAIL("Unknown MaybeDocument %s", proto); - } -} - -/** - * Encodes a Document for local storage. This differs from the v1 RPC serializer for Documents in - * that it preserves the updateTime, which is considered an output only value by the server. - */ -- (GCFSDocument *)encodedDocument:(FSTDocument *)document { - FSTSerializerBeta *remoteSerializer = self.remoteSerializer; - - GCFSDocument *proto = [GCFSDocument message]; - proto.name = [remoteSerializer encodedDocumentKey:document.key]; - proto.fields = [remoteSerializer encodedFields:document.data]; - proto.updateTime = [remoteSerializer encodedVersion:document.version]; - - return proto; -} - -/** Decodes a Document proto to the equivalent model. */ -- (FSTDocument *)decodedDocument:(GCFSDocument *)document - withCommittedMutations:(BOOL)committedMutations { - FSTSerializerBeta *remoteSerializer = self.remoteSerializer; - - FSTObjectValue *data = [remoteSerializer decodedFields:document.fields]; - DocumentKey key = [remoteSerializer decodedDocumentKey:document.name]; - SnapshotVersion version = [remoteSerializer decodedVersion:document.updateTime]; - return [FSTDocument documentWithData:data - key:key - version:version - state:committedMutations ? FSTDocumentStateCommittedMutations - : FSTDocumentStateSynced]; -} - -/** Encodes a NoDocument value to the equivalent proto. */ -- (FSTPBNoDocument *)encodedDeletedDocument:(FSTDeletedDocument *)document { - FSTSerializerBeta *remoteSerializer = self.remoteSerializer; - - FSTPBNoDocument *proto = [FSTPBNoDocument message]; - proto.name = [remoteSerializer encodedDocumentKey:document.key]; - proto.readTime = [remoteSerializer encodedVersion:document.version]; - return proto; -} - -/** Decodes a NoDocument proto to the equivalent model. */ -- (FSTDeletedDocument *)decodedDeletedDocument:(FSTPBNoDocument *)proto - withCommittedMutations:(BOOL)committedMutations { - FSTSerializerBeta *remoteSerializer = self.remoteSerializer; - - DocumentKey key = [remoteSerializer decodedDocumentKey:proto.name]; - SnapshotVersion version = [remoteSerializer decodedVersion:proto.readTime]; - return [FSTDeletedDocument documentWithKey:key - version:version - hasCommittedMutations:committedMutations]; -} - -/** Encodes an UnknownDocument value to the equivalent proto. */ -- (FSTPBUnknownDocument *)encodedUnknownDocument:(FSTUnknownDocument *)document { - FSTSerializerBeta *remoteSerializer = self.remoteSerializer; - - FSTPBUnknownDocument *proto = [FSTPBUnknownDocument message]; - proto.name = [remoteSerializer encodedDocumentKey:document.key]; - proto.version = [remoteSerializer encodedVersion:document.version]; - return proto; -} - -/** Decodes an UnknownDocument proto to the equivalent model. */ -- (FSTUnknownDocument *)decodedUnknownDocument:(FSTPBUnknownDocument *)proto { - FSTSerializerBeta *remoteSerializer = self.remoteSerializer; - - DocumentKey key = [remoteSerializer decodedDocumentKey:proto.name]; - SnapshotVersion version = [remoteSerializer decodedVersion:proto.version]; - return [FSTUnknownDocument documentWithKey:key version:version]; -} - -- (FSTPBWriteBatch *)encodedMutationBatch:(FSTMutationBatch *)batch { - FSTSerializerBeta *remoteSerializer = self.remoteSerializer; - - FSTPBWriteBatch *proto = [FSTPBWriteBatch message]; - proto.batchId = batch.batchID; - proto.localWriteTime = [remoteSerializer - encodedTimestamp:Timestamp{batch.localWriteTime.seconds, batch.localWriteTime.nanoseconds}]; - - NSMutableArray *baseWrites = proto.baseWritesArray; - for (FSTMutation *baseMutation : [batch baseMutations]) { - [baseWrites addObject:[remoteSerializer encodedMutation:baseMutation]]; - } - NSMutableArray *writes = proto.writesArray; - for (FSTMutation *mutation : [batch mutations]) { - [writes addObject:[remoteSerializer encodedMutation:mutation]]; - } - return proto; -} - -- (FSTMutationBatch *)decodedMutationBatch:(FSTPBWriteBatch *)batch { - FSTSerializerBeta *remoteSerializer = self.remoteSerializer; - - int batchID = batch.batchId; - - std::vector baseMutations; - for (GCFSWrite *write in batch.baseWritesArray) { - baseMutations.push_back([remoteSerializer decodedMutation:write]); - } - std::vector mutations; - for (GCFSWrite *write in batch.writesArray) { - mutations.push_back([remoteSerializer decodedMutation:write]); - } - - Timestamp localWriteTime = [remoteSerializer decodedTimestamp:batch.localWriteTime]; - - return [[FSTMutationBatch alloc] - initWithBatchID:batchID - localWriteTime:[FIRTimestamp timestampWithSeconds:localWriteTime.seconds() - nanoseconds:localWriteTime.nanoseconds()] - baseMutations:std::move(baseMutations) - mutations:std::move(mutations)]; -} - -- (FSTPBTarget *)encodedQueryData:(FSTQueryData *)queryData { - FSTSerializerBeta *remoteSerializer = self.remoteSerializer; - - HARD_ASSERT(queryData.purpose == FSTQueryPurposeListen, - "only queries with purpose %s may be stored, got %s", FSTQueryPurposeListen, - queryData.purpose); - - FSTPBTarget *proto = [FSTPBTarget message]; - proto.targetId = queryData.targetID; - proto.lastListenSequenceNumber = queryData.sequenceNumber; - proto.snapshotVersion = [remoteSerializer encodedVersion:queryData.snapshotVersion]; - proto.resumeToken = queryData.resumeToken; - - FSTQuery *query = queryData.query; - if ([query isDocumentQuery]) { - proto.documents = [remoteSerializer encodedDocumentsTarget:query]; - } else { - proto.query = [remoteSerializer encodedQueryTarget:query]; - } - - return proto; -} - -- (FSTQueryData *)decodedQueryData:(FSTPBTarget *)target { - FSTSerializerBeta *remoteSerializer = self.remoteSerializer; - - TargetId targetID = target.targetId; - ListenSequenceNumber sequenceNumber = target.lastListenSequenceNumber; - SnapshotVersion version = [remoteSerializer decodedVersion:target.snapshotVersion]; - NSData *resumeToken = target.resumeToken; - - FSTQuery *query; - switch (target.targetTypeOneOfCase) { - case FSTPBTarget_TargetType_OneOfCase_Documents: - query = [remoteSerializer decodedQueryFromDocumentsTarget:target.documents]; - break; - - case FSTPBTarget_TargetType_OneOfCase_Query: - query = [remoteSerializer decodedQueryFromQueryTarget:target.query]; - break; - - default: - HARD_FAIL("Unknown Target.targetType %s", target.targetTypeOneOfCase); - } - - return [[FSTQueryData alloc] initWithQuery:query - targetID:targetID - listenSequenceNumber:sequenceNumber - purpose:FSTQueryPurposeListen - snapshotVersion:version - resumeToken:resumeToken]; -} - -- (GPBTimestamp *)encodedVersion:(const SnapshotVersion &)version { - return [self.remoteSerializer encodedVersion:version]; -} - -- (SnapshotVersion)decodedVersion:(GPBTimestamp *)version { - return [self.remoteSerializer decodedVersion:version]; -} - -@end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalStore.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalStore.h deleted file mode 100644 index 8d696fe..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalStore.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include - -#import "Firestore/Source/Local/FSTLRUGarbageCollector.h" - -#include "Firestore/core/src/firebase/firestore/auth/user.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" -#include "Firestore/core/src/firebase/firestore/model/document_map.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" - -namespace firebase { -namespace firestore { -namespace remote { - -class RemoteEvent; - -} // namespace remote -} // namespace firestore -} // namespace firebase - -@class FSTLocalViewChanges; -@class FSTLocalWriteResult; -@class FSTMutation; -@class FSTMutationBatch; -@class FSTMutationBatchResult; -@class FSTQuery; -@class FSTQueryData; -@protocol FSTPersistence; - -NS_ASSUME_NONNULL_BEGIN - -/** - * Local storage in the Firestore client. Coordinates persistence components like the mutation - * queue and remote document cache to present a latency compensated view of stored data. - * - * The LocalStore is responsible for accepting mutations from the Sync Engine. Writes from the - * client are put into a queue as provisional Mutations until they are processed by the RemoteStore - * and confirmed as having been written to the server. - * - * The local store provides the local version of documents that have been modified locally. It - * maintains the constraint: - * - * LocalDocument = RemoteDocument + Active(LocalMutations) - * - * (Active mutations are those that are enqueued and have not been previously acknowledged or - * rejected). - * - * The RemoteDocument ("ground truth") state is provided via the applyChangeBatch method. It will - * be some version of a server-provided document OR will be a server-provided document PLUS - * acknowledged mutations: - * - * RemoteDocument' = RemoteDocument + Acknowledged(LocalMutations) - * - * Note that this "dirty" version of a RemoteDocument will not be identical to a server base - * version, since it has LocalMutations added to it pending getting an authoritative copy from the - * server. - * - * Since LocalMutations can be rejected by the server, we have to be able to revert a LocalMutation - * that has already been applied to the LocalDocument (typically done by replaying all remaining - * LocalMutations to the RemoteDocument to re-apply). - * - * It also maintains the persistence of mapping queries to resume tokens and target ids. - * - * The LocalStore must be able to efficiently execute queries against its local cache of the - * documents, to provide the initial set of results before any remote changes have been received. - */ -@interface FSTLocalStore : NSObject - -/** Creates a new instance of the FSTLocalStore with its required dependencies as parameters. */ -- (instancetype)initWithPersistence:(id)persistence - initialUser:(const firebase::firestore::auth::User &)initialUser - NS_DESIGNATED_INITIALIZER; - -- (instancetype)init NS_UNAVAILABLE; - -/** Performs any initial startup actions required by the local store. */ -- (void)start; - -/** - * Tells the FSTLocalStore that the currently authenticated user has changed. - * - * In response the local store switches the mutation queue to the new user and returns any - * resulting document changes. - */ -- (firebase::firestore::model::MaybeDocumentMap)userDidChange: - (const firebase::firestore::auth::User &)user; - -/** Accepts locally generated Mutations and commits them to storage. */ -- (FSTLocalWriteResult *)locallyWriteMutations:(std::vector &&)mutations; - -/** Returns the current value of a document with a given key, or nil if not found. */ -- (nullable FSTMaybeDocument *)readDocument:(const firebase::firestore::model::DocumentKey &)key; - -/** - * Acknowledges the given batch. - * - * On the happy path when a batch is acknowledged, the local store will - * - * + remove the batch from the mutation queue; - * + apply the changes to the remote document cache; - * + recalculate the latency compensated view implied by those changes (there may be mutations in - * the queue that affect the documents but haven't been acknowledged yet); and - * + give the changed documents back the sync engine - * - * @return The resulting (modified) documents. - */ -- (firebase::firestore::model::MaybeDocumentMap)acknowledgeBatchWithResult: - (FSTMutationBatchResult *)batchResult; - -/** - * Removes mutations from the MutationQueue for the specified batch. LocalDocuments will be - * recalculated. - * - * @return The resulting (modified) documents. - */ -- (firebase::firestore::model::MaybeDocumentMap)rejectBatchID: - (firebase::firestore::model::BatchId)batchID; - -/** Returns the last recorded stream token for the current user. */ -- (nullable NSData *)lastStreamToken; - -/** - * Sets the stream token for the current user without acknowledging any mutation batch. This is - * usually only useful after a stream handshake or in response to an error that requires clearing - * the stream token. - */ -- (void)setLastStreamToken:(nullable NSData *)streamToken; - -/** - * Returns the last consistent snapshot processed (used by the RemoteStore to determine whether to - * buffer incoming snapshots from the backend). - */ -- (const firebase::firestore::model::SnapshotVersion &)lastRemoteSnapshotVersion; - -/** - * Updates the "ground-state" (remote) documents. We assume that the remote event reflects any - * write batches that have been acknowledged or rejected (i.e. we do not re-apply local mutations - * to updates from this event). - * - * LocalDocuments are re-calculated if there are remaining mutations in the queue. - */ -- (firebase::firestore::model::MaybeDocumentMap)applyRemoteEvent: - (const firebase::firestore::remote::RemoteEvent &)remoteEvent; - -/** - * Returns the keys of the documents that are associated with the given targetID in the remote - * table. - */ -- (firebase::firestore::model::DocumentKeySet)remoteDocumentKeysForTarget: - (firebase::firestore::model::TargetId)targetID; - -/** - * Assigns @a query an internal ID so that its results can be pinned so they don't get GC'd. - * A query must be allocated in the local store before the store can be used to manage its view. - */ -- (FSTQueryData *)allocateQuery:(FSTQuery *)query; - -/** Unpin all the documents associated with @a query. */ -- (void)releaseQuery:(FSTQuery *)query; - -/** Runs @a query against all the documents in the local store and returns the results. */ -- (firebase::firestore::model::DocumentMap)executeQuery:(FSTQuery *)query; - -/** Notify the local store of the changed views to locally pin / unpin documents. */ -- (void)notifyLocalViewChanges:(NSArray *)viewChanges; - -/** - * Gets the mutation batch after the passed in batchId in the mutation queue or nil if empty. - * - * @param batchID The batch to search after, or -1 for the first mutation in the queue. - * @return the next mutation or nil if there wasn't one. - */ -- (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID: - (firebase::firestore::model::BatchId)batchID; - -- (firebase::firestore::local::LruResults)collectGarbage:(FSTLRUGarbageCollector *)garbageCollector; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalStore.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalStore.mm deleted file mode 100644 index 97d542b..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalStore.mm +++ /dev/null @@ -1,531 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Local/FSTLocalStore.h" - -#include -#include -#include -#include -#include - -#import "FIRTimestamp.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Local/FSTLRUGarbageCollector.h" -#import "Firestore/Source/Local/FSTLocalViewChanges.h" -#import "Firestore/Source/Local/FSTLocalWriteResult.h" -#import "Firestore/Source/Local/FSTPersistence.h" -#import "Firestore/Source/Local/FSTQueryData.h" -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Model/FSTMutationBatch.h" - -#include "Firestore/core/src/firebase/firestore/auth/user.h" -#include "Firestore/core/src/firebase/firestore/core/target_id_generator.h" -#include "Firestore/core/src/firebase/firestore/immutable/sorted_set.h" -#include "Firestore/core/src/firebase/firestore/local/local_documents_view.h" -#include "Firestore/core/src/firebase/firestore/local/mutation_queue.h" -#include "Firestore/core/src/firebase/firestore/local/query_cache.h" -#include "Firestore/core/src/firebase/firestore/local/reference_set.h" -#include "Firestore/core/src/firebase/firestore/local/remote_document_cache.h" -#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" -#include "Firestore/core/src/firebase/firestore/model/document_map.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/log.h" -#include "absl/memory/memory.h" - -using firebase::firestore::auth::User; -using firebase::firestore::core::TargetIdGenerator; -using firebase::firestore::local::LocalDocumentsView; -using firebase::firestore::local::LruResults; -using firebase::firestore::local::MutationQueue; -using firebase::firestore::local::QueryCache; -using firebase::firestore::local::ReferenceSet; -using firebase::firestore::local::RemoteDocumentCache; -using firebase::firestore::model::BatchId; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::DocumentKeySet; -using firebase::firestore::model::DocumentMap; -using firebase::firestore::model::DocumentVersionMap; -using firebase::firestore::model::FieldMask; -using firebase::firestore::model::FieldPath; -using firebase::firestore::model::MaybeDocumentMap; -using firebase::firestore::model::ListenSequenceNumber; -using firebase::firestore::model::Precondition; -using firebase::firestore::model::SnapshotVersion; -using firebase::firestore::model::TargetId; -using firebase::firestore::remote::RemoteEvent; -using firebase::firestore::remote::TargetChange; - -NS_ASSUME_NONNULL_BEGIN - -/** - * The maximum time to leave a resume token buffered without writing it out. This value is - * arbitrary: it's long enough to avoid several writes (possibly indefinitely if updates come more - * frequently than this) but short enough that restarting after crashing will still have a pretty - * recent resume token. - */ -static const int64_t kResumeTokenMaxAgeSeconds = 5 * 60; // 5 minutes - -@interface FSTLocalStore () - -/** Manages our in-memory or durable persistence. */ -@property(nonatomic, strong, readonly) id persistence; - -/** Maps a query to the data about that query. */ -@property(nonatomic) QueryCache *queryCache; - -@end - -@implementation FSTLocalStore { - /** Used to generate targetIDs for queries tracked locally. */ - TargetIdGenerator _targetIDGenerator; - /** The set of all cached remote documents. */ - RemoteDocumentCache *_remoteDocumentCache; - QueryCache *_queryCache; - /** The set of all mutations that have been sent but not yet been applied to the backend. */ - MutationQueue *_mutationQueue; - - /** The "local" view of all documents (layering mutationQueue on top of remoteDocumentCache). */ - std::unique_ptr _localDocuments; - - /** The set of document references maintained by any local views. */ - ReferenceSet _localViewReferences; - - /** Maps a targetID to data about its query. */ - std::unordered_map _targetIDs; -} - -- (instancetype)initWithPersistence:(id)persistence - initialUser:(const User &)initialUser { - if (self = [super init]) { - _persistence = persistence; - _mutationQueue = [persistence mutationQueueForUser:initialUser]; - _remoteDocumentCache = [persistence remoteDocumentCache]; - _queryCache = [persistence queryCache]; - _localDocuments = absl::make_unique(_remoteDocumentCache, _mutationQueue, - [_persistence indexManager]); - [_persistence.referenceDelegate addInMemoryPins:&_localViewReferences]; - - _targetIDGenerator = TargetIdGenerator::QueryCacheTargetIdGenerator(0); - } - return self; -} - -- (void)start { - [self startMutationQueue]; - TargetId targetID = _queryCache->highest_target_id(); - _targetIDGenerator = TargetIdGenerator::QueryCacheTargetIdGenerator(targetID); -} - -- (void)startMutationQueue { - self.persistence.run("Start MutationQueue", [&]() { _mutationQueue->Start(); }); -} - -- (MaybeDocumentMap)userDidChange:(const User &)user { - // Swap out the mutation queue, grabbing the pending mutation batches before and after. - std::vector oldBatches = self.persistence.run( - "OldBatches", - [&]() -> std::vector { return _mutationQueue->AllMutationBatches(); }); - - // The old one has a reference to the mutation queue, so nil it out first. - _localDocuments.reset(); - _mutationQueue = [self.persistence mutationQueueForUser:user]; - - [self startMutationQueue]; - - return self.persistence.run("NewBatches", [&]() -> MaybeDocumentMap { - std::vector newBatches = _mutationQueue->AllMutationBatches(); - - // Recreate our LocalDocumentsView using the new MutationQueue. - _localDocuments = absl::make_unique(_remoteDocumentCache, _mutationQueue, - [_persistence indexManager]); - - // Union the old/new changed keys. - DocumentKeySet changedKeys; - for (const std::vector &batches : {oldBatches, newBatches}) { - for (FSTMutationBatch *batch : batches) { - for (FSTMutation *mutation : [batch mutations]) { - changedKeys = changedKeys.insert(mutation.key); - } - } - } - - // Return the set of all (potentially) changed documents as the result of the user change. - return _localDocuments->GetDocuments(changedKeys); - }); -} - -- (FSTLocalWriteResult *)locallyWriteMutations:(std::vector &&)mutations { - FIRTimestamp *localWriteTime = [FIRTimestamp timestamp]; - DocumentKeySet keys; - for (FSTMutation *mutation : mutations) { - keys = keys.insert(mutation.key); - } - - return self.persistence.run("Locally write mutations", [&]() -> FSTLocalWriteResult * { - // Load and apply all existing mutations. This lets us compute the current base state for - // all non-idempotent transforms before applying any additional user-provided writes. - MaybeDocumentMap existingDocuments = _localDocuments->GetDocuments(keys); - - // For non-idempotent mutations (such as `FieldValue.increment()`), we record the base - // state in a separate patch mutation. This is later used to guarantee consistent values - // and prevents flicker even if the backend sends us an update that already includes our - // transform. - std::vector baseMutations; - for (FSTMutation *mutation : mutations) { - if (mutation.idempotent) { - continue; - } - - // Theoretically, we should only include non-idempotent fields in this field mask as this mask - // is used to prevent flicker for non-idempotent transforms by providing consistent base - // values. By including the fields for all DocumentTransforms, we incorrectly prevent rebasing - // of idempotent transforms (such as `arrayUnion()`) when any non-idempotent transforms are - // present. - // TODO(mrschmidt): Expose a method that only returns the a field mask for non-idempotent - // transforms - const FieldMask *fieldMask = [mutation fieldMask]; - if (fieldMask) { - // `documentsForKeys` is guaranteed to return a (nullable) entry for every document key. - FSTMaybeDocument *maybeDocument = existingDocuments.find(mutation.key)->second; - FSTObjectValue *baseValues = - [maybeDocument isKindOfClass:[FSTDocument class]] - ? [((FSTDocument *)maybeDocument).data objectByApplyingFieldMask:*fieldMask] - : [FSTObjectValue objectValue]; - // NOTE: The base state should only be applied if there's some existing document to - // override, so use a Precondition of exists=true - baseMutations.push_back([[FSTPatchMutation alloc] initWithKey:mutation.key - fieldMask:*fieldMask - value:baseValues - precondition:Precondition::Exists(true)]); - } - } - - FSTMutationBatch *batch = _mutationQueue->AddMutationBatch( - localWriteTime, std::move(baseMutations), std::move(mutations)); - MaybeDocumentMap changedDocuments = [batch applyToLocalDocumentSet:existingDocuments]; - return [FSTLocalWriteResult resultForBatchID:batch.batchID changes:std::move(changedDocuments)]; - }); -} - -- (MaybeDocumentMap)acknowledgeBatchWithResult:(FSTMutationBatchResult *)batchResult { - return self.persistence.run("Acknowledge batch", [&]() -> MaybeDocumentMap { - FSTMutationBatch *batch = batchResult.batch; - _mutationQueue->AcknowledgeBatch(batch, batchResult.streamToken); - [self applyBatchResult:batchResult]; - _mutationQueue->PerformConsistencyCheck(); - - return _localDocuments->GetDocuments(batch.keys); - }); -} - -- (MaybeDocumentMap)rejectBatchID:(BatchId)batchID { - return self.persistence.run("Reject batch", [&]() -> MaybeDocumentMap { - FSTMutationBatch *toReject = _mutationQueue->LookupMutationBatch(batchID); - HARD_ASSERT(toReject, "Attempt to reject nonexistent batch!"); - - _mutationQueue->RemoveMutationBatch(toReject); - _mutationQueue->PerformConsistencyCheck(); - - return _localDocuments->GetDocuments(toReject.keys); - }); -} - -- (nullable NSData *)lastStreamToken { - return _mutationQueue->GetLastStreamToken(); -} - -- (void)setLastStreamToken:(nullable NSData *)streamToken { - self.persistence.run("Set stream token", - [&]() { _mutationQueue->SetLastStreamToken(streamToken); }); -} - -- (const SnapshotVersion &)lastRemoteSnapshotVersion { - return self.queryCache->GetLastRemoteSnapshotVersion(); -} - -- (MaybeDocumentMap)applyRemoteEvent:(const RemoteEvent &)remoteEvent { - return self.persistence.run("Apply remote event", [&]() -> MaybeDocumentMap { - // TODO(gsoltis): move the sequence number into the reference delegate. - ListenSequenceNumber sequenceNumber = self.persistence.currentSequenceNumber; - - DocumentKeySet authoritativeUpdates; - for (const auto &entry : remoteEvent.target_changes()) { - TargetId targetID = entry.first; - const TargetChange &change = entry.second; - - // Do not ref/unref unassigned targetIDs - it may lead to leaks. - auto found = _targetIDs.find(targetID); - if (found == _targetIDs.end()) { - continue; - } - FSTQueryData *queryData = found->second; - - // When a global snapshot contains updates (either add or modify) we can completely trust - // these updates as authoritative and blindly apply them to our cache (as a defensive measure - // to promote self-healing in the unfortunate case that our cache is ever somehow corrupted / - // out-of-sync). - // - // If the document is only updated while removing it from a target then watch isn't obligated - // to send the absolute latest version: it can send the first version that caused the document - // not to match. - for (const DocumentKey &key : change.added_documents()) { - authoritativeUpdates = authoritativeUpdates.insert(key); - } - for (const DocumentKey &key : change.modified_documents()) { - authoritativeUpdates = authoritativeUpdates.insert(key); - } - - _queryCache->RemoveMatchingKeys(change.removed_documents(), targetID); - _queryCache->AddMatchingKeys(change.added_documents(), targetID); - - // Update the resume token if the change includes one. Don't clear any preexisting value. - // Bump the sequence number as well, so that documents being removed now are ordered later - // than documents that were previously removed from this target. - NSData *resumeToken = change.resume_token(); - if (resumeToken.length > 0) { - FSTQueryData *oldQueryData = queryData; - queryData = [queryData queryDataByReplacingSnapshotVersion:remoteEvent.snapshot_version() - resumeToken:resumeToken - sequenceNumber:sequenceNumber]; - _targetIDs[targetID] = queryData; - - if ([self shouldPersistQueryData:queryData oldQueryData:oldQueryData change:change]) { - _queryCache->UpdateTarget(queryData); - } - } - } - - MaybeDocumentMap changedDocs; - const DocumentKeySet &limboDocuments = remoteEvent.limbo_document_changes(); - DocumentKeySet updatedKeys; - for (const auto &kv : remoteEvent.document_updates()) { - updatedKeys = updatedKeys.insert(kv.first); - } - // Each loop iteration only affects its "own" doc, so it's safe to get all the remote - // documents in advance in a single call. - MaybeDocumentMap existingDocs = _remoteDocumentCache->GetAll(updatedKeys); - - for (const auto &kv : remoteEvent.document_updates()) { - const DocumentKey &key = kv.first; - FSTMaybeDocument *doc = kv.second; - FSTMaybeDocument *existingDoc = nil; - auto foundExisting = existingDocs.find(key); - if (foundExisting != existingDocs.end()) { - existingDoc = foundExisting->second; - } - - // If a document update isn't authoritative, make sure we don't apply an old document version - // to the remote cache. We make an exception for SnapshotVersion.MIN which can happen for - // manufactured events (e.g. in the case of a limbo document resolution failing). - if (!existingDoc || doc.version == SnapshotVersion::None() || - (authoritativeUpdates.contains(doc.key) && !existingDoc.hasPendingWrites) || - doc.version >= existingDoc.version) { - _remoteDocumentCache->Add(doc); - changedDocs = changedDocs.insert(key, doc); - } else { - LOG_DEBUG("FSTLocalStore Ignoring outdated watch update for %s. " - "Current version: %s Watch version: %s", - key.ToString(), existingDoc.version.timestamp().ToString(), - doc.version.timestamp().ToString()); - } - - // If this was a limbo resolution, make sure we mark when it was accessed. - if (limboDocuments.contains(key)) { - [self.persistence.referenceDelegate limboDocumentUpdated:key]; - } - } - - // HACK: The only reason we allow omitting snapshot version is so we can synthesize remote - // events when we get permission denied errors while trying to resolve the state of a locally - // cached document that is in limbo. - const SnapshotVersion &lastRemoteVersion = _queryCache->GetLastRemoteSnapshotVersion(); - const SnapshotVersion &remoteVersion = remoteEvent.snapshot_version(); - if (remoteVersion != SnapshotVersion::None()) { - HARD_ASSERT(remoteVersion >= lastRemoteVersion, - "Watch stream reverted to previous snapshot?? (%s < %s)", - remoteVersion.timestamp().ToString(), lastRemoteVersion.timestamp().ToString()); - _queryCache->SetLastRemoteSnapshotVersion(remoteVersion); - } - - return _localDocuments->GetLocalViewOfDocuments(changedDocs); - }); -} - -/** - * Returns YES if the newQueryData should be persisted during an update of an active target. - * QueryData should always be persisted when a target is being released and should not call this - * function. - * - * While the target is active, QueryData updates can be omitted when nothing about the target has - * changed except metadata like the resume token or snapshot version. Occasionally it's worth the - * extra write to prevent these values from getting too stale after a crash, but this doesn't have - * to be too frequent. - */ -- (BOOL)shouldPersistQueryData:(FSTQueryData *)newQueryData - oldQueryData:(FSTQueryData *)oldQueryData - change:(const TargetChange &)change { - // Avoid clearing any existing value - if (newQueryData.resumeToken.length == 0) return NO; - - // Any resume token is interesting if there isn't one already. - if (oldQueryData.resumeToken.length == 0) return YES; - - // Don't allow resume token changes to be buffered indefinitely. This allows us to be reasonably - // up-to-date after a crash and avoids needing to loop over all active queries on shutdown. - // Especially in the browser we may not get time to do anything interesting while the current - // tab is closing. - int64_t newSeconds = newQueryData.snapshotVersion.timestamp().seconds(); - int64_t oldSeconds = oldQueryData.snapshotVersion.timestamp().seconds(); - int64_t timeDelta = newSeconds - oldSeconds; - if (timeDelta >= kResumeTokenMaxAgeSeconds) return YES; - - // Otherwise if the only thing that has changed about a target is its resume token then it's not - // worth persisting. Note that the RemoteStore keeps an in-memory view of the currently active - // targets which includes the current resume token, so stream failure or user changes will still - // use an up-to-date resume token regardless of what we do here. - size_t changes = change.added_documents().size() + change.modified_documents().size() + - change.removed_documents().size(); - return changes > 0; -} - -- (void)notifyLocalViewChanges:(NSArray *)viewChanges { - self.persistence.run("NotifyLocalViewChanges", [&]() { - for (FSTLocalViewChanges *viewChange in viewChanges) { - for (const DocumentKey &key : viewChange.removedKeys) { - [self->_persistence.referenceDelegate removeReference:key]; - } - _localViewReferences.AddReferences(viewChange.addedKeys, viewChange.targetID); - _localViewReferences.AddReferences(viewChange.removedKeys, viewChange.targetID); - } - }); -} - -- (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(BatchId)batchID { - FSTMutationBatch *result = - self.persistence.run("NextMutationBatchAfterBatchID", [&]() -> FSTMutationBatch * { - return _mutationQueue->NextMutationBatchAfterBatchId(batchID); - }); - return result; -} - -- (nullable FSTMaybeDocument *)readDocument:(const DocumentKey &)key { - return self.persistence.run("ReadDocument", [&]() -> FSTMaybeDocument *_Nullable { - return _localDocuments->GetDocument(key); - }); -} - -- (FSTQueryData *)allocateQuery:(FSTQuery *)query { - FSTQueryData *queryData = self.persistence.run("Allocate query", [&]() -> FSTQueryData * { - FSTQueryData *cached = _queryCache->GetTarget(query); - // TODO(mcg): freshen last accessed date if cached exists? - if (!cached) { - cached = [[FSTQueryData alloc] initWithQuery:query - targetID:_targetIDGenerator.NextId() - listenSequenceNumber:self.persistence.currentSequenceNumber - purpose:FSTQueryPurposeListen]; - _queryCache->AddTarget(cached); - } - return cached; - }); - // Sanity check to ensure that even when resuming a query it's not currently active. - TargetId targetID = queryData.targetID; - HARD_ASSERT(_targetIDs.find(targetID) == _targetIDs.end(), - "Tried to allocate an already allocated query: %s", query); - _targetIDs[targetID] = queryData; - return queryData; -} - -- (void)releaseQuery:(FSTQuery *)query { - self.persistence.run("Release query", [&]() { - FSTQueryData *queryData = _queryCache->GetTarget(query); - HARD_ASSERT(queryData, "Tried to release nonexistent query: %s", query); - - TargetId targetID = queryData.targetID; - - auto found = _targetIDs.find(targetID); - FSTQueryData *cachedQueryData = found != _targetIDs.end() ? found->second : nil; - if (cachedQueryData.snapshotVersion > queryData.snapshotVersion) { - // If we've been avoiding persisting the resumeToken (see shouldPersistQueryData for - // conditions and rationale) we need to persist the token now because there will no - // longer be an in-memory version to fall back on. - queryData = cachedQueryData; - _queryCache->UpdateTarget(queryData); - } - - // References for documents sent via Watch are automatically removed when we delete a - // query's target data from the reference delegate. Since this does not remove references - // for locally mutated documents, we have to remove the target associations for these - // documents manually. - DocumentKeySet removed = _localViewReferences.RemoveReferences(targetID); - for (const DocumentKey &key : removed) { - [self.persistence.referenceDelegate removeReference:key]; - } - _targetIDs.erase(targetID); - [self.persistence.referenceDelegate removeTarget:queryData]; - }); -} - -- (DocumentMap)executeQuery:(FSTQuery *)query { - return self.persistence.run("ExecuteQuery", [&]() -> DocumentMap { - return _localDocuments->GetDocumentsMatchingQuery(query); - }); -} - -- (DocumentKeySet)remoteDocumentKeysForTarget:(TargetId)targetID { - return self.persistence.run("RemoteDocumentKeysForTarget", [&]() -> DocumentKeySet { - return _queryCache->GetMatchingKeys(targetID); - }); -} - -- (void)applyBatchResult:(FSTMutationBatchResult *)batchResult { - FSTMutationBatch *batch = batchResult.batch; - DocumentKeySet docKeys = batch.keys; - const DocumentVersionMap &versions = batchResult.docVersions; - for (const DocumentKey &docKey : docKeys) { - FSTMaybeDocument *_Nullable remoteDoc = _remoteDocumentCache->Get(docKey); - FSTMaybeDocument *_Nullable doc = remoteDoc; - - auto ackVersionIter = versions.find(docKey); - HARD_ASSERT(ackVersionIter != versions.end(), - "docVersions should contain every doc in the write."); - const SnapshotVersion &ackVersion = ackVersionIter->second; - if (!doc || doc.version < ackVersion) { - doc = [batch applyToRemoteDocument:doc documentKey:docKey mutationBatchResult:batchResult]; - if (!doc) { - HARD_ASSERT(!remoteDoc, "Mutation batch %s applied to document %s resulted in nil.", batch, - remoteDoc); - } else { - _remoteDocumentCache->Add(doc); - } - } - } - - _mutationQueue->RemoveMutationBatch(batch); -} - -- (LruResults)collectGarbage:(FSTLRUGarbageCollector *)garbageCollector { - return self.persistence.run("Collect garbage", [&]() -> LruResults { - return [garbageCollector collectWithLiveTargets:_targetIDs]; - }); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalViewChanges.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalViewChanges.h deleted file mode 100644 index 66ec863..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalViewChanges.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" -#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" - -@class FSTMutation; -@class FSTQuery; - -NS_ASSUME_NONNULL_BEGIN - -/** - * A set of changes to what documents are currently in view and out of view for a given query. - * These changes are sent to the LocalStore by the View (via the SyncEngine) and are used to pin / - * unpin documents as appropriate. - */ -@interface FSTLocalViewChanges : NSObject - -+ (instancetype)changesForTarget:(firebase::firestore::model::TargetId)targetID - addedKeys:(firebase::firestore::model::DocumentKeySet)addedKeys - removedKeys:(firebase::firestore::model::DocumentKeySet)removedKeys; - -+ (instancetype)changesForViewSnapshot:(const firebase::firestore::core::ViewSnapshot &)viewSnapshot - withTargetID:(firebase::firestore::model::TargetId)targetID; - -- (id)init NS_UNAVAILABLE; - -@property(readonly) firebase::firestore::model::TargetId targetID; - -- (const firebase::firestore::model::DocumentKeySet &)addedKeys; -- (const firebase::firestore::model::DocumentKeySet &)removedKeys; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalViewChanges.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalViewChanges.mm deleted file mode 100644 index 5169f6b..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalViewChanges.mm +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Local/FSTLocalViewChanges.h" - -#include - -#import "Firestore/Source/Model/FSTDocument.h" - -#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" - -using firebase::firestore::core::DocumentViewChange; -using firebase::firestore::core::ViewSnapshot; -using firebase::firestore::model::DocumentKeySet; -using firebase::firestore::model::TargetId; - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTLocalViewChanges () -- (instancetype)initWithTarget:(TargetId)targetID - addedKeys:(DocumentKeySet)addedKeys - removedKeys:(DocumentKeySet)removedKeys NS_DESIGNATED_INITIALIZER; -@end - -@implementation FSTLocalViewChanges { - DocumentKeySet _addedKeys; - DocumentKeySet _removedKeys; -} - -+ (instancetype)changesForViewSnapshot:(const ViewSnapshot &)viewSnapshot - withTargetID:(TargetId)targetID { - DocumentKeySet addedKeys; - DocumentKeySet removedKeys; - - for (const DocumentViewChange &docChange : viewSnapshot.document_changes()) { - switch (docChange.type()) { - case DocumentViewChange::Type::kAdded: - addedKeys = addedKeys.insert(docChange.document().key); - break; - - case DocumentViewChange::Type::kRemoved: - removedKeys = removedKeys.insert(docChange.document().key); - break; - - default: - // Do nothing. - break; - } - } - - return [self changesForTarget:targetID - addedKeys:std::move(addedKeys) - removedKeys:std::move(removedKeys)]; -} - -+ (instancetype)changesForTarget:(TargetId)targetID - addedKeys:(DocumentKeySet)addedKeys - removedKeys:(DocumentKeySet)removedKeys { - return [[FSTLocalViewChanges alloc] initWithTarget:targetID - addedKeys:std::move(addedKeys) - removedKeys:std::move(removedKeys)]; -} - -- (instancetype)initWithTarget:(TargetId)targetID - addedKeys:(DocumentKeySet)addedKeys - removedKeys:(DocumentKeySet)removedKeys { - self = [super init]; - if (self) { - _targetID = targetID; - _addedKeys = std::move(addedKeys); - _removedKeys = std::move(removedKeys); - } - return self; -} - -- (const DocumentKeySet &)addedKeys { - return _addedKeys; -} - -- (const DocumentKeySet &)removedKeys { - return _removedKeys; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalWriteResult.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalWriteResult.h deleted file mode 100644 index e4b208d..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalWriteResult.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include "Firestore/core/src/firebase/firestore/model/document_map.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" - -NS_ASSUME_NONNULL_BEGIN - -/** The result of a write to the local store. */ -@interface FSTLocalWriteResult : NSObject - -+ (instancetype)resultForBatchID:(firebase::firestore::model::BatchId)batchID - changes:(firebase::firestore::model::MaybeDocumentMap &&)changes; - -- (id)init __attribute__((unavailable("Use resultForBatchID:changes:"))); - -- (const firebase::firestore::model::MaybeDocumentMap &)changes; - -@property(nonatomic, assign, readonly) firebase::firestore::model::BatchId batchID; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalWriteResult.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalWriteResult.mm deleted file mode 100644 index fcad635..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTLocalWriteResult.mm +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Local/FSTLocalWriteResult.h" - -#include - -using firebase::firestore::model::BatchId; -using firebase::firestore::model::MaybeDocumentMap; - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTLocalWriteResult () -- (instancetype)initWithBatchID:(BatchId)batchID - changes:(MaybeDocumentMap &&)changes NS_DESIGNATED_INITIALIZER; -@end - -@implementation FSTLocalWriteResult { - MaybeDocumentMap _changes; -} - -- (const MaybeDocumentMap &)changes { - return _changes; -} - -+ (instancetype)resultForBatchID:(BatchId)batchID changes:(MaybeDocumentMap &&)changes { - return [[FSTLocalWriteResult alloc] initWithBatchID:batchID changes:std::move(changes)]; -} - -- (instancetype)initWithBatchID:(BatchId)batchID changes:(MaybeDocumentMap &&)changes { - self = [super init]; - if (self) { - _batchID = batchID; - _changes = std::move(changes); - } - return self; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTMemoryPersistence.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTMemoryPersistence.h deleted file mode 100644 index c293843..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTMemoryPersistence.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#import "Firestore/Source/Local/FSTLRUGarbageCollector.h" -#import "Firestore/Source/Local/FSTLocalSerializer.h" -#import "Firestore/Source/Local/FSTPersistence.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" - -NS_ASSUME_NONNULL_BEGIN - -/** - * An in-memory implementation of the FSTPersistence protocol. Values are stored only in RAM and - * are never persisted to any durable storage. - */ -@interface FSTMemoryPersistence : NSObject - -+ (instancetype)persistenceWithEagerGC; - -+ (instancetype)persistenceWithLruParams:(firebase::firestore::local::LruParams)lruParams - serializer:(FSTLocalSerializer *)serializer; - -@end - -/** - * Provides the eager GC implementation for memory persistence. - */ -@interface FSTMemoryEagerReferenceDelegate : NSObject - -- (instancetype)initWithPersistence:(FSTMemoryPersistence *)persistence; - -@end - -/** - * Provides the LRU GC implementation for memory persistence. - */ -@interface FSTMemoryLRUReferenceDelegate - : NSObject - -- (instancetype)initWithPersistence:(FSTMemoryPersistence *)persistence - serializer:(FSTLocalSerializer *)serializer - lruParams:(firebase::firestore::local::LruParams)lruParams; - -- (BOOL)isPinnedAtSequenceNumber:(firebase::firestore::model::ListenSequenceNumber)upperBound - document:(const firebase::firestore::model::DocumentKey &)key; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTMemoryPersistence.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTMemoryPersistence.mm deleted file mode 100644 index d60f7e3..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTMemoryPersistence.mm +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Local/FSTMemoryPersistence.h" - -#include -#include -#include -#include - -#include "Firestore/core/src/firebase/firestore/auth/user.h" -#include "Firestore/core/src/firebase/firestore/local/index_manager.h" -#include "Firestore/core/src/firebase/firestore/local/listen_sequence.h" -#include "Firestore/core/src/firebase/firestore/local/memory_index_manager.h" -#include "Firestore/core/src/firebase/firestore/local/memory_mutation_queue.h" -#include "Firestore/core/src/firebase/firestore/local/memory_query_cache.h" -#include "Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h" -#include "Firestore/core/src/firebase/firestore/local/reference_set.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "absl/memory/memory.h" - -using firebase::firestore::auth::HashUser; -using firebase::firestore::auth::User; -using firebase::firestore::local::ListenSequence; -using firebase::firestore::local::LruParams; -using firebase::firestore::local::MemoryIndexManager; -using firebase::firestore::local::MemoryMutationQueue; -using firebase::firestore::local::MemoryQueryCache; -using firebase::firestore::local::MemoryRemoteDocumentCache; -using firebase::firestore::local::ReferenceSet; -using firebase::firestore::local::TargetCallback; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::DocumentKeyHash; -using firebase::firestore::model::ListenSequenceNumber; -using firebase::firestore::model::TargetId; -using firebase::firestore::util::Status; - -using MutationQueues = std::unordered_map, HashUser>; - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTMemoryPersistence () - -- (MemoryQueryCache *)queryCache; - -- (MemoryRemoteDocumentCache *)remoteDocumentCache; - -- (MemoryIndexManager *)indexManager; - -- (MemoryMutationQueue *)mutationQueueForUser:(const User &)user; - -@property(nonatomic, readonly) MutationQueues &mutationQueues; - -@property(nonatomic, assign, getter=isStarted) BOOL started; - -// Make this property writable so we can wire up a delegate. -@property(nonatomic, strong) id referenceDelegate; - -@end - -@implementation FSTMemoryPersistence { - /** - * The QueryCache representing the persisted cache of queries. - * - * Note that this is retained here to make it easier to write tests affecting both the in-memory - * and LevelDB-backed persistence layers. Tests can create a new FSTLocalStore wrapping this - * FSTPersistence instance and this will make the in-memory persistence layer behave as if it - * were actually persisting values. - */ - std::unique_ptr _queryCache; - - /** The RemoteDocumentCache representing the persisted cache of remote documents. */ - std::unique_ptr _remoteDocumentCache; - - MemoryIndexManager _indexManager; - - FSTTransactionRunner _transactionRunner; - - id _referenceDelegate; -} - -+ (instancetype)persistenceWithEagerGC { - FSTMemoryPersistence *persistence = [[FSTMemoryPersistence alloc] init]; - persistence.referenceDelegate = - [[FSTMemoryEagerReferenceDelegate alloc] initWithPersistence:persistence]; - return persistence; -} - -+ (instancetype)persistenceWithLruParams:(firebase::firestore::local::LruParams)lruParams - serializer:(FSTLocalSerializer *)serializer { - FSTMemoryPersistence *persistence = [[FSTMemoryPersistence alloc] init]; - persistence.referenceDelegate = - [[FSTMemoryLRUReferenceDelegate alloc] initWithPersistence:persistence - serializer:serializer - lruParams:lruParams]; - return persistence; -} - -- (instancetype)init { - if (self = [super init]) { - _queryCache = absl::make_unique(self); - _remoteDocumentCache = absl::make_unique(self); - self.started = YES; - } - return self; -} - -- (void)setReferenceDelegate:(id)referenceDelegate { - _referenceDelegate = referenceDelegate; - id delegate = _referenceDelegate; - if ([delegate conformsToProtocol:@protocol(FSTTransactional)]) { - _transactionRunner.SetBackingPersistence((id)_referenceDelegate); - } -} - -- (void)shutdown { - // No durable state to ensure is closed on shutdown. - HARD_ASSERT(self.isStarted, "FSTMemoryPersistence shutdown without start!"); - self.started = NO; -} - -- (id)referenceDelegate { - return _referenceDelegate; -} - -- (ListenSequenceNumber)currentSequenceNumber { - return [_referenceDelegate currentSequenceNumber]; -} - -- (const FSTTransactionRunner &)run { - return _transactionRunner; -} - -- (MemoryMutationQueue *)mutationQueueForUser:(const User &)user { - const std::unique_ptr &existing = _mutationQueues[user]; - if (!existing) { - _mutationQueues[user] = absl::make_unique(self); - return _mutationQueues[user].get(); - } else { - return existing.get(); - } -} - -- (MemoryQueryCache *)queryCache { - return _queryCache.get(); -} - -- (MemoryRemoteDocumentCache *)remoteDocumentCache { - return _remoteDocumentCache.get(); -} - -- (MemoryIndexManager *)indexManager { - return &_indexManager; -} - -@end - -@implementation FSTMemoryLRUReferenceDelegate { - // This delegate should have the same lifetime as the persistence layer, but mark as - // weak to avoid retain cycle. - __weak FSTMemoryPersistence *_persistence; - // Tracks sequence numbers of when documents are used. Equivalent to sentinel rows in - // the leveldb implementation. - std::unordered_map _sequenceNumbers; - ReferenceSet *_additionalReferences; - FSTLRUGarbageCollector *_gc; - // PORTING NOTE: when this class is ported to C++, this does not need to be a pointer - std::unique_ptr _listenSequence; - ListenSequenceNumber _currentSequenceNumber; - FSTLocalSerializer *_serializer; -} - -- (instancetype)initWithPersistence:(FSTMemoryPersistence *)persistence - serializer:(FSTLocalSerializer *)serializer - lruParams:(firebase::firestore::local::LruParams)lruParams { - if (self = [super init]) { - _persistence = persistence; - _gc = [[FSTLRUGarbageCollector alloc] initWithDelegate:self params:lruParams]; - _currentSequenceNumber = kFSTListenSequenceNumberInvalid; - // Theoretically this is always 0, since this is all in-memory... - ListenSequenceNumber highestSequenceNumber = - _persistence.queryCache->highest_listen_sequence_number(); - _listenSequence = absl::make_unique(highestSequenceNumber); - _serializer = serializer; - } - return self; -} - -- (FSTLRUGarbageCollector *)gc { - return _gc; -} - -- (ListenSequenceNumber)currentSequenceNumber { - HARD_ASSERT(_currentSequenceNumber != kFSTListenSequenceNumberInvalid, - "Asking for a sequence number outside of a transaction"); - return _currentSequenceNumber; -} - -- (void)addInMemoryPins:(ReferenceSet *)set { - // Technically can't assert this, due to restartWithNoopGarbageCollector (for now...) - // FSTAssert(_additionalReferences == nil, @"Overwriting additional references"); - _additionalReferences = set; -} - -- (void)removeTarget:(FSTQueryData *)queryData { - FSTQueryData *updated = [queryData queryDataByReplacingSnapshotVersion:queryData.snapshotVersion - resumeToken:queryData.resumeToken - sequenceNumber:_currentSequenceNumber]; - _persistence.queryCache->UpdateTarget(updated); -} - -- (void)limboDocumentUpdated:(const DocumentKey &)key { - _sequenceNumbers[key] = self.currentSequenceNumber; -} - -- (void)startTransaction:(absl::string_view)label { - _currentSequenceNumber = _listenSequence->Next(); -} - -- (void)commitTransaction { - _currentSequenceNumber = kFSTListenSequenceNumberInvalid; -} - -- (void)enumerateTargetsUsingCallback:(const TargetCallback &)callback { - return _persistence.queryCache->EnumerateTargets(callback); -} - -- (void)enumerateMutationsUsingCallback: - (const firebase::firestore::local::OrphanedDocumentCallback &)callback { - for (const auto &entry : _sequenceNumbers) { - ListenSequenceNumber sequenceNumber = entry.second; - const DocumentKey &key = entry.first; - // Pass in the exact sequence number as the upper bound so we know it won't be pinned by being - // too recent. - if (![self isPinnedAtSequenceNumber:sequenceNumber document:key]) { - callback(key, sequenceNumber); - } - } -} - -- (int)removeTargetsThroughSequenceNumber:(ListenSequenceNumber)sequenceNumber - liveQueries:(const std::unordered_map &) - liveQueries { - return _persistence.queryCache->RemoveTargets(sequenceNumber, liveQueries); -} - -- (size_t)sequenceNumberCount { - size_t totalCount = _persistence.queryCache->size(); - [self enumerateMutationsUsingCallback:[&totalCount](const DocumentKey &key, - ListenSequenceNumber sequenceNumber) { - totalCount++; - }]; - return totalCount; -} - -- (int)removeOrphanedDocumentsThroughSequenceNumber:(ListenSequenceNumber)upperBound { - std::vector removed = - _persistence.remoteDocumentCache->RemoveOrphanedDocuments(self, upperBound); - for (const auto &key : removed) { - _sequenceNumbers.erase(key); - } - return static_cast(removed.size()); -} - -- (void)addReference:(const DocumentKey &)key { - _sequenceNumbers[key] = self.currentSequenceNumber; -} - -- (void)removeReference:(const DocumentKey &)key { - _sequenceNumbers[key] = self.currentSequenceNumber; -} - -- (BOOL)mutationQueuesContainKey:(const DocumentKey &)key { - const MutationQueues &queues = [_persistence mutationQueues]; - for (const auto &entry : queues) { - if (entry.second->ContainsKey(key)) { - return YES; - } - } - return NO; -} - -- (void)removeMutationReference:(const DocumentKey &)key { - _sequenceNumbers[key] = self.currentSequenceNumber; -} - -- (BOOL)isPinnedAtSequenceNumber:(ListenSequenceNumber)upperBound - document:(const DocumentKey &)key { - if ([self mutationQueuesContainKey:key]) { - return YES; - } - if (_additionalReferences->ContainsKey(key)) { - return YES; - } - if (_persistence.queryCache->Contains(key)) { - return YES; - } - auto it = _sequenceNumbers.find(key); - if (it != _sequenceNumbers.end() && it->second > upperBound) { - return YES; - } - return NO; -} - -- (size_t)byteSize { - // Note that this method is only used for testing because this delegate is only - // used for testing. The algorithm here (loop through everything, serialize it - // and count bytes) is inefficient and inexact, but won't run in production. - size_t count = 0; - count += _persistence.queryCache->CalculateByteSize(_serializer); - count += _persistence.remoteDocumentCache->CalculateByteSize(_serializer); - const MutationQueues &queues = [_persistence mutationQueues]; - for (const auto &entry : queues) { - count += entry.second->CalculateByteSize(_serializer); - } - return count; -} - -@end - -@implementation FSTMemoryEagerReferenceDelegate { - std::unique_ptr> _orphaned; - // This delegate should have the same lifetime as the persistence layer, but mark as - // weak to avoid retain cycle. - __weak FSTMemoryPersistence *_persistence; - ReferenceSet *_additionalReferences; -} - -- (instancetype)initWithPersistence:(FSTMemoryPersistence *)persistence { - if (self = [super init]) { - _persistence = persistence; - } - return self; -} - -- (ListenSequenceNumber)currentSequenceNumber { - return kFSTListenSequenceNumberInvalid; -} - -- (void)addInMemoryPins:(ReferenceSet *)set { - // We should be able to assert that _additionalReferences is nil, but due to restarts in spec - // tests it would fail. - _additionalReferences = set; -} - -- (void)removeTarget:(FSTQueryData *)queryData { - for (const DocumentKey &docKey : _persistence.queryCache->GetMatchingKeys(queryData.targetID)) { - _orphaned->insert(docKey); - } - _persistence.queryCache->RemoveTarget(queryData); -} - -- (void)addReference:(const DocumentKey &)key { - _orphaned->erase(key); -} - -- (void)removeReference:(const DocumentKey &)key { - _orphaned->insert(key); -} - -- (void)removeMutationReference:(const DocumentKey &)key { - _orphaned->insert(key); -} - -- (BOOL)isReferenced:(const DocumentKey &)key { - if (_persistence.queryCache->Contains(key)) { - return YES; - } - if ([self mutationQueuesContainKey:key]) { - return YES; - } - if (_additionalReferences->ContainsKey(key)) { - return YES; - } - return NO; -} - -- (void)limboDocumentUpdated:(const DocumentKey &)key { - if ([self isReferenced:key]) { - _orphaned->erase(key); - } else { - _orphaned->insert(key); - } -} - -- (void)startTransaction:(__unused absl::string_view)label { - _orphaned = absl::make_unique>(); -} - -- (BOOL)mutationQueuesContainKey:(const DocumentKey &)key { - const MutationQueues &queues = [_persistence mutationQueues]; - for (const auto &entry : queues) { - if (entry.second->ContainsKey(key)) { - return YES; - } - } - return NO; -} - -- (void)commitTransaction { - for (const auto &key : *_orphaned) { - if (![self isReferenced:key]) { - _persistence.remoteDocumentCache->Remove(key); - } - } - _orphaned.reset(); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTPersistence.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTPersistence.h deleted file mode 100644 index 8595f10..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTPersistence.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include "Firestore/core/src/firebase/firestore/auth/user.h" -#include "Firestore/core/src/firebase/firestore/local/index_manager.h" -#include "Firestore/core/src/firebase/firestore/local/mutation_queue.h" -#include "Firestore/core/src/firebase/firestore/local/query_cache.h" -#include "Firestore/core/src/firebase/firestore/local/reference_set.h" -#include "Firestore/core/src/firebase/firestore/local/remote_document_cache.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" - -@class FSTQueryData; -@protocol FSTReferenceDelegate; - -struct FSTTransactionRunner; - -NS_ASSUME_NONNULL_BEGIN - -/** - * FSTPersistence is the lowest-level shared interface to persistent storage in Firestore. - * - * FSTPersistence is used to create FSTMutationQueue and FSTRemoteDocumentCache instances backed - * by persistence (which might be in-memory or LevelDB). - * - * FSTPersistence also exposes an API to create and commit FSTWriteGroup instances. - * Implementations of FSTWriteGroup/FSTPersistence only need to guarantee that writes made - * against the FSTWriteGroup are not made to durable storage until commitGroup:action: is called - * here. Since memory-only storage components do not alter durable storage, they are free to ignore - * the group. - * - * This contract is enough to allow the FSTLocalStore be be written independently of whether or not - * the stored state actually is durably persisted. If persistent storage is enabled, writes are - * grouped together to avoid inconsistent state that could cause crashes. - * - * Concretely, when persistent storage is enabled, the persistent versions of FSTMutationQueue, - * FSTRemoteDocumentCache, and others (the mutators) will defer their writes into an FSTWriteGroup. - * Once the local store has completed one logical operation, it commits the write group using - * [FSTPersistence commitGroup:action:]. - * - * When persistent storage is disabled, the non-persistent versions of the mutators ignore the - * FSTWriteGroup and [FSTPersistence commitGroup:action:] is a no-op. This short-cut is allowed - * because memory-only storage leaves no state so it cannot be inconsistent. - * - * This simplifies the implementations of the mutators and allows memory-only implementations to - * supplement the persistent ones without requiring any special dual-store implementation of - * FSTPersistence. The cost is that the FSTLocalStore needs to be slightly careful about the order - * of its reads and writes in order to avoid relying on being able to read back uncommitted writes. - */ -@protocol FSTPersistence - -/** Releases any resources held during eager shutdown. */ -- (void)shutdown; - -/** - * Returns a MutationQueue representing the persisted mutations for the given user. - * - *

Note: The implementation is free to return the same instance every time this is called for a - * given user. In particular, the memory-backed implementation does this to emulate the persisted - * implementation to the extent possible (e.g. in the case of uid switching from - * sally=>jack=>sally, sally's mutation queue will be preserved). - */ -- (firebase::firestore::local::MutationQueue *)mutationQueueForUser: - (const firebase::firestore::auth::User &)user; - -/** Creates an FSTQueryCache representing the persisted cache of queries. */ -- (firebase::firestore::local::QueryCache *)queryCache; - -/** Creates a RemoteDocumentCache representing the persisted cache of remote documents. */ -- (firebase::firestore::local::RemoteDocumentCache *)remoteDocumentCache; - -/** Creates an IndexManager that manages our persisted query indexes. */ -- (firebase::firestore::local::IndexManager *)indexManager; - -@property(nonatomic, readonly, assign) const FSTTransactionRunner &run; - -/** - * This property provides access to hooks around the document reference lifecycle. It is initially - * nullable while being implemented, but the goal is to eventually have it be non-nil. - */ -@property(nonatomic, readonly, strong) id referenceDelegate; - -@property(nonatomic, readonly) - firebase::firestore::model::ListenSequenceNumber currentSequenceNumber; - -@end - -@protocol FSTTransactional - -- (void)startTransaction:(absl::string_view)label; - -- (void)commitTransaction; - -@end - -/** - * An FSTReferenceDelegate instance handles all of the hooks into the document-reference lifecycle. - * This includes being added to a target, being removed from a target, being subject to mutation, - * and being mutated by the user. - * - * Different implementations may do different things with each of these events. Not every - * implementation needs to do something with every lifecycle hook. - * - * Implementations that care about sequence numbers are responsible for generating them and making - * them available. - */ -@protocol FSTReferenceDelegate - -/** - * Registers an FSTReferenceSet of documents that should be considered 'referenced' and not eligible - * for removal during garbage collection. - */ -- (void)addInMemoryPins:(firebase::firestore::local::ReferenceSet *)set; - -/** - * Notify the delegate that a target was removed. - */ -- (void)removeTarget:(FSTQueryData *)queryData; - -/** - * Notify the delegate that the given document was added to a target. - */ -- (void)addReference:(const firebase::firestore::model::DocumentKey &)key; - -/** - * Notify the delegate that the given document was removed from a target. - */ -- (void)removeReference:(const firebase::firestore::model::DocumentKey &)key; - -/** - * Notify the delegate that a document is no longer being mutated by the user. - */ -- (void)removeMutationReference:(const firebase::firestore::model::DocumentKey &)key; - -/** - * Notify the delegate that a limbo document was updated. - */ -- (void)limboDocumentUpdated:(const firebase::firestore::model::DocumentKey &)key; - -@property(nonatomic, readonly) - firebase::firestore::model::ListenSequenceNumber currentSequenceNumber; - -@end - -struct FSTTransactionRunner { -// Intentionally disable nullability checking for this function. We cannot properly annotate -// the function because this function can handle both pointer and non-pointer types. It is an error -// to annotate non-pointer types with a nullability annotation. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnullability-completeness" - - /** - * The following two functions handle accepting callables and optionally running them within a - * transaction. Persistence layers that conform to the FSTTransactional protocol can set - * themselves as the backing persistence for a transaction runner, in which case a transaction - * will be started before a block is run, and committed after the block has executed. If there is - * no backing instance of FSTTransactional, the block will be run directly. - * - * There are two instances of operator() to handle the case where the block returns void, rather - * than a type. - * - * The transaction runner keeps a weak reference to the backing persistence so as not to cause a - * retain cycle. The reference is upgraded to strong (with a fatal error if it has disappeared) - * for the duration of running a transaction. - */ - - template - auto operator()(absl::string_view label, F block) const -> - typename std::enable_if::value, void>::type { - __strong id strongDb = _db; - if (!strongDb && _expect_db) { - HARD_FAIL("Transaction runner accessed without underlying db when it expected one"); - } - if (strongDb) { - [strongDb startTransaction:label]; - } - block(); - if (strongDb) { - [strongDb commitTransaction]; - } - } - - template - auto operator()(absl::string_view label, F block) const -> - typename std::enable_if::value, decltype(block())>::type { - using ReturnT = decltype(block()); - __strong id strongDb = _db; - if (!strongDb && _expect_db) { - HARD_FAIL("Transaction runner accessed without underlying db when it expected one"); - } - if (strongDb) { - [strongDb startTransaction:label]; - } - ReturnT result = block(); - if (strongDb) { - [strongDb commitTransaction]; - } - return result; - } -#pragma clang diagnostic pop - void SetBackingPersistence(id db) { - _db = db; - _expect_db = true; - } - - private: - __weak id _db; - bool _expect_db = false; -}; - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTQueryData.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTQueryData.h deleted file mode 100644 index f96f327..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTQueryData.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" - -@class FSTQuery; - -NS_ASSUME_NONNULL_BEGIN - -/** An enumeration of the different purposes we have for queries. */ -typedef NS_ENUM(NSInteger, FSTQueryPurpose) { - /** A regular, normal query. */ - FSTQueryPurposeListen, - - /** The query was used to refill a query after an existence filter mismatch. */ - FSTQueryPurposeExistenceFilterMismatch, - - /** The query was used to resolve a limbo document. */ - FSTQueryPurposeLimboResolution, -}; - -/** An immutable set of metadata that the store will need to keep track of for each query. */ -@interface FSTQueryData : NSObject - -- (instancetype)initWithQuery:(FSTQuery *)query - targetID:(firebase::firestore::model::TargetId)targetID - listenSequenceNumber:(firebase::firestore::model::ListenSequenceNumber)sequenceNumber - purpose:(FSTQueryPurpose)purpose - snapshotVersion:(firebase::firestore::model::SnapshotVersion)snapshotVersion - resumeToken:(NSData *)resumeToken NS_DESIGNATED_INITIALIZER; - -/** Convenience initializer for use when creating an FSTQueryData for the first time. */ -- (instancetype)initWithQuery:(FSTQuery *)query - targetID:(firebase::firestore::model::TargetId)targetID - listenSequenceNumber:(firebase::firestore::model::ListenSequenceNumber)sequenceNumber - purpose:(FSTQueryPurpose)purpose; - -- (instancetype)init NS_UNAVAILABLE; - -/** - * Creates a new query data instance with an updated snapshot version, resume token, and sequence - * number. - */ -- (instancetype) - queryDataByReplacingSnapshotVersion:(firebase::firestore::model::SnapshotVersion)snapshotVersion - resumeToken:(NSData *)resumeToken - sequenceNumber: - (firebase::firestore::model::ListenSequenceNumber)sequenceNumber; - -/** The latest snapshot version seen for this target. */ -- (const firebase::firestore::model::SnapshotVersion &)snapshotVersion; - -/** The query being listened to. */ -@property(nonatomic, strong, readonly) FSTQuery *query; - -/** - * The targetID to which the query corresponds, assigned by the FSTLocalStore for user queries or - * the FSTSyncEngine for limbo queries. - */ -@property(nonatomic, assign, readonly) firebase::firestore::model::TargetId targetID; - -@property(nonatomic, assign, readonly) - firebase::firestore::model::ListenSequenceNumber sequenceNumber; - -/** The purpose of the query. */ -@property(nonatomic, assign, readonly) FSTQueryPurpose purpose; - -/** - * An opaque, server-assigned token that allows watching a query to be resumed after disconnecting - * without retransmitting all the data that matches the query. The resume token essentially - * identifies a point in time from which the server should resume sending results. - */ -@property(nonatomic, copy, readonly) NSData *resumeToken; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTQueryData.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTQueryData.mm deleted file mode 100644 index dc174c3..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Local/FSTQueryData.mm +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Local/FSTQueryData.h" - -#include - -#import "Firestore/Source/Core/FSTQuery.h" - -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/util/hashing.h" - -namespace util = firebase::firestore::util; -using firebase::firestore::model::ListenSequenceNumber; -using firebase::firestore::model::SnapshotVersion; -using firebase::firestore::model::TargetId; - -NS_ASSUME_NONNULL_BEGIN - -@implementation FSTQueryData { - SnapshotVersion _snapshotVersion; -} - -- (instancetype)initWithQuery:(FSTQuery *)query - targetID:(TargetId)targetID - listenSequenceNumber:(ListenSequenceNumber)sequenceNumber - purpose:(FSTQueryPurpose)purpose - snapshotVersion:(SnapshotVersion)snapshotVersion - resumeToken:(NSData *)resumeToken { - self = [super init]; - if (self) { - _query = query; - _targetID = targetID; - _sequenceNumber = sequenceNumber; - _purpose = purpose; - _snapshotVersion = std::move(snapshotVersion); - _resumeToken = [resumeToken copy]; - } - return self; -} - -- (instancetype)initWithQuery:(FSTQuery *)query - targetID:(TargetId)targetID - listenSequenceNumber:(ListenSequenceNumber)sequenceNumber - purpose:(FSTQueryPurpose)purpose { - return [self initWithQuery:query - targetID:targetID - listenSequenceNumber:sequenceNumber - purpose:purpose - snapshotVersion:SnapshotVersion::None() - resumeToken:[NSData data]]; -} - -- (const firebase::firestore::model::SnapshotVersion &)snapshotVersion { - return _snapshotVersion; -} - -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[FSTQueryData class]]) { - return NO; - } - - FSTQueryData *other = (FSTQueryData *)object; - return [self.query isEqual:other.query] && self.targetID == other.targetID && - self.sequenceNumber == other.sequenceNumber && self.purpose == other.purpose && - self.snapshotVersion == other.snapshotVersion && - [self.resumeToken isEqual:other.resumeToken]; -} - -- (NSUInteger)hash { - return util::Hash([self.query hash], self.targetID, self.sequenceNumber, - static_cast(self.purpose), self.snapshotVersion.Hash(), - [self.resumeToken hash]); -} - -- (NSString *)description { - return [NSString - stringWithFormat:@"", - self.query, self.targetID, (unsigned long)self.purpose, - self.snapshotVersion.timestamp().ToString().c_str(), self.resumeToken]; -} - -- (instancetype)queryDataByReplacingSnapshotVersion:(SnapshotVersion)snapshotVersion - resumeToken:(NSData *)resumeToken - sequenceNumber:(ListenSequenceNumber)sequenceNumber { - return [[FSTQueryData alloc] initWithQuery:self.query - targetID:self.targetID - listenSequenceNumber:sequenceNumber - purpose:self.purpose - snapshotVersion:std::move(snapshotVersion) - resumeToken:resumeToken]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTDocument.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTDocument.h deleted file mode 100644 index acbec89..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTDocument.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/field_path.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" - -@class FSTFieldValue; -@class GCFSDocument; -@class FSTObjectValue; - -NS_ASSUME_NONNULL_BEGIN - -/** Describes the `hasPendingWrites` state of a document. */ -typedef NS_ENUM(NSInteger, FSTDocumentState) { - /** Local mutations applied via the mutation queue. Document is potentially inconsistent. */ - FSTDocumentStateLocalMutations, - /** Mutations applied based on a write acknowledgment. Document is potentially inconsistent. */ - FSTDocumentStateCommittedMutations, - /** No mutations applied. Document was sent to us by Watch. */ - FSTDocumentStateSynced -}; - -/** - * The result of a lookup for a given path may be an existing document or a tombstone that marks - * the path deleted. - */ -@interface FSTMaybeDocument : NSObject -- (id)init __attribute__((unavailable("Abstract base class"))); -- (const firebase::firestore::model::DocumentKey &)key; -- (const firebase::firestore::model::SnapshotVersion &)version; - -/** - * Whether this document has a local mutation applied that has not yet been acknowledged by Watch. - */ -- (bool)hasPendingWrites; - -@end - -@interface FSTDocument : FSTMaybeDocument -+ (instancetype)documentWithData:(FSTObjectValue *)data - key:(firebase::firestore::model::DocumentKey)key - version:(firebase::firestore::model::SnapshotVersion)version - state:(FSTDocumentState)state; - -+ (instancetype)documentWithData:(FSTObjectValue *)data - key:(firebase::firestore::model::DocumentKey)key - version:(firebase::firestore::model::SnapshotVersion)version - state:(FSTDocumentState)state - proto:(GCFSDocument *)proto; - -- (nullable FSTFieldValue *)fieldForPath:(const firebase::firestore::model::FieldPath &)path; -- (bool)hasLocalMutations; -- (bool)hasCommittedMutations; - -@property(nonatomic, strong, readonly) FSTObjectValue *data; - -/** - * Memoized serialized form of the document for optimization purposes (avoids repeated - * serialization). Might be nil. - */ -@property(nonatomic, strong, readonly) GCFSDocument *proto; - -@end - -@interface FSTDeletedDocument : FSTMaybeDocument -+ (instancetype)documentWithKey:(firebase::firestore::model::DocumentKey)key - version:(firebase::firestore::model::SnapshotVersion)version - hasCommittedMutations:(bool)committedMutations; - -- (bool)hasCommittedMutations; - -@end - -@interface FSTUnknownDocument : FSTMaybeDocument -+ (instancetype)documentWithKey:(firebase::firestore::model::DocumentKey)key - version:(firebase::firestore::model::SnapshotVersion)version; -@end - -/** An NSComparator suitable for comparing docs using only their keys. */ -extern const NSComparator FSTDocumentComparatorByKey; - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTDocument.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTDocument.mm deleted file mode 100644 index 1e35d5b..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTDocument.mm +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Model/FSTDocument.h" - -#include - -#import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Util/FSTClasses.h" - -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/field_path.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/hashing.h" -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" - -namespace util = firebase::firestore::util; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::FieldPath; -using firebase::firestore::model::SnapshotVersion; - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTMaybeDocument () - -- (instancetype)initWithKey:(DocumentKey)key - version:(SnapshotVersion)version NS_DESIGNATED_INITIALIZER; - -@end - -@implementation FSTMaybeDocument { - DocumentKey _key; - SnapshotVersion _version; -} - -- (instancetype)initWithKey:(DocumentKey)key version:(SnapshotVersion)version { - self = [super init]; - if (self) { - _key = std::move(key); - _version = std::move(version); - } - return self; -} - -- (bool)hasPendingWrites { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (id)copyWithZone:(NSZone *_Nullable)zone { - // All document types are immutable - return self; -} - -- (const DocumentKey &)key { - return _key; -} - -- (const SnapshotVersion &)version { - return _version; -} - -@end - -@implementation FSTDocument { - FSTDocumentState _documentState; -} - -+ (instancetype)documentWithData:(FSTObjectValue *)data - key:(DocumentKey)key - version:(SnapshotVersion)version - state:(FSTDocumentState)state { - return [[FSTDocument alloc] initWithData:data - key:std::move(key) - version:std::move(version) - state:state]; -} - -+ (instancetype)documentWithData:(FSTObjectValue *)data - key:(DocumentKey)key - version:(SnapshotVersion)version - state:(FSTDocumentState)state - proto:(GCFSDocument *)proto { - return [[FSTDocument alloc] initWithData:data - key:std::move(key) - version:std::move(version) - state:state - proto:proto]; -} - -- (instancetype)initWithData:(FSTObjectValue *)data - key:(DocumentKey)key - version:(SnapshotVersion)version - state:(FSTDocumentState)state { - self = [super initWithKey:std::move(key) version:std::move(version)]; - if (self) { - _data = data; - _documentState = state; - _proto = nil; - } - return self; -} - -- (instancetype)initWithData:(FSTObjectValue *)data - key:(DocumentKey)key - version:(SnapshotVersion)version - state:(FSTDocumentState)state - proto:(GCFSDocument *)proto { - self = [super initWithKey:std::move(key) version:std::move(version)]; - if (self) { - _data = data; - _documentState = state; - _proto = proto; - } - return self; -} - -- (bool)hasLocalMutations { - return _documentState == FSTDocumentStateLocalMutations; -} - -- (bool)hasCommittedMutations { - return _documentState == FSTDocumentStateCommittedMutations; -} - -- (bool)hasPendingWrites { - return self.hasLocalMutations || self.hasCommittedMutations; -} - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isKindOfClass:[FSTDocument class]]) { - return NO; - } - - FSTDocument *otherDoc = other; - return self.key == otherDoc.key && self.version == otherDoc.version && - _documentState == otherDoc->_documentState && [self.data isEqual:otherDoc.data]; -} - -- (NSUInteger)hash { - NSUInteger result = self.key.Hash(); - result = result * 31 + self.version.Hash(); - result = result * 31 + [self.data hash]; - result = result * 31 + _documentState; - return result; -} - -- (NSString *)description { - return [NSString stringWithFormat:@"", - self.key.ToString().c_str(), - self.version.timestamp().ToString().c_str(), - (long)_documentState, self.data]; -} - -- (nullable FSTFieldValue *)fieldForPath:(const FieldPath &)path { - return [_data valueForPath:path]; -} - -@end - -@implementation FSTDeletedDocument { - bool _hasCommittedMutations; -} - -+ (instancetype)documentWithKey:(DocumentKey)key - version:(SnapshotVersion)version - hasCommittedMutations:(bool)committedMutations { - FSTDeletedDocument *deletedDocument = [[FSTDeletedDocument alloc] initWithKey:std::move(key) - version:std::move(version)]; - - if (deletedDocument) { - deletedDocument->_hasCommittedMutations = committedMutations; - } - - return deletedDocument; -} - -- (bool)hasCommittedMutations { - return _hasCommittedMutations; -} - -- (bool)hasPendingWrites { - return self.hasCommittedMutations; -} - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isKindOfClass:[FSTDeletedDocument class]]) { - return NO; - } - - FSTDeletedDocument *otherDoc = other; - return self.key == otherDoc.key && self.version == otherDoc.version && - _hasCommittedMutations == otherDoc->_hasCommittedMutations; -} - -- (NSUInteger)hash { - NSUInteger result = self.key.Hash(); - result = result * 31 + self.version.Hash(); - result = result * 31 + (_hasCommittedMutations ? 1 : 0); - return result; -} - -- (NSString *)description { - return [NSString - stringWithFormat:@"", - self.key.ToString().c_str(), self.version.timestamp().ToString().c_str(), - _hasCommittedMutations]; -} - -@end - -@implementation FSTUnknownDocument - -+ (instancetype)documentWithKey:(DocumentKey)key version:(SnapshotVersion)version { - return [[FSTUnknownDocument alloc] initWithKey:std::move(key) version:std::move(version)]; -} - -- (bool)hasPendingWrites { - return true; -} - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isKindOfClass:[FSTUnknownDocument class]]) { - return NO; - } - - FSTDocument *otherDoc = other; - return self.key == otherDoc.key && self.version == otherDoc.version; -} - -- (NSUInteger)hash { - NSUInteger result = self.key.Hash(); - result = result * 31 + self.version.Hash(); - return result; -} - -- (NSString *)description { - return [NSString stringWithFormat:@"", - self.key.ToString().c_str(), - self.version.timestamp().ToString().c_str()]; -} - -@end - -const NSComparator FSTDocumentComparatorByKey = - ^NSComparisonResult(FSTMaybeDocument *doc1, FSTMaybeDocument *doc2) { - return CompareKeys(doc1.key, doc2.key); - }; - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTDocumentKey.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTDocumentKey.h deleted file mode 100644 index 80e6cc9..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTDocumentKey.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include -#include - -#include "Firestore/core/src/firebase/firestore/model/resource_path.h" - -// Using forward declaration to avoid circular dependency (`document_key.h` includes this header).` -namespace firebase { -namespace firestore { -namespace model { -class DocumentKey; -} -} -} - -NS_ASSUME_NONNULL_BEGIN - -/** - * `FSTDocumentKey` is a thin wrapper over `DocumentKey`, necessary until full migration is - * possible. Use the underlying `DocumentKey` for any operations. - */ -@interface FSTDocumentKey : NSObject - -+ (instancetype)keyWithDocumentKey:(const firebase::firestore::model::DocumentKey &)documentKey; - -/** Gets the underlying C++ representation. */ -- (const firebase::firestore::model::DocumentKey &)key; - -@end - -/** The field path string that represents the document's key. */ -extern NSString *const kDocumentKeyPath; - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTDocumentKey.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTDocumentKey.mm deleted file mode 100644 index 5fc78c1..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTDocumentKey.mm +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Model/FSTDocumentKey.h" - -#include -#include - -#import "Firestore/Source/Core/FSTFirestoreClient.h" - -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/hashing.h" -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" - -namespace util = firebase::firestore::util; -using firebase::firestore::model::ResourcePath; -using firebase::firestore::model::DocumentKey; - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTDocumentKey () { - // Forward most of the logic to the C++ implementation until FSTDocumentKey usages are completely - // migrated. - DocumentKey _delegate; -} -@end - -@implementation FSTDocumentKey - -+ (instancetype)keyWithDocumentKey:(const firebase::firestore::model::DocumentKey &)documentKey { - return [[FSTDocumentKey alloc] initWithDocumentKey:documentKey]; -} - -/** Designated initializer. */ -- (instancetype)initWithDocumentKey:(const DocumentKey &)key { - if (self = [super init]) { - _delegate = key; - } - return self; -} - -- (const DocumentKey &)key { - return _delegate; -} - -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[FSTDocumentKey class]]) { - return NO; - } - return _delegate == static_cast(object)->_delegate; -} - -- (NSUInteger)hash { - return _delegate.Hash(); -} - -- (NSString *)description { - return [NSString stringWithFormat:@"", _delegate.ToString().c_str()]; -} - -/** Implements NSCopying without actually copying because FSTDocumentKeys are immutable. */ -- (id)copyWithZone:(NSZone *_Nullable)zone { - return self; -} - -@end - -NSString *const kDocumentKeyPath = @"__name__"; - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTFieldValue.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTFieldValue.h deleted file mode 100644 index 5a9b696..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTFieldValue.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#import "Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h" - -#include "Firestore/core/src/firebase/firestore/model/database_id.h" -#include "Firestore/core/src/firebase/firestore/model/field_mask.h" -#include "Firestore/core/src/firebase/firestore/model/field_path.h" - -@class FSTDocumentKey; -@class FIRTimestamp; -@class FSTFieldValueOptions; -@class FIRGeoPoint; - -NS_ASSUME_NONNULL_BEGIN - -/** The order of types in Firestore; this order is defined by the backend. */ -typedef NS_ENUM(NSInteger, FSTTypeOrder) { - FSTTypeOrderNull, - FSTTypeOrderBoolean, - FSTTypeOrderNumber, - FSTTypeOrderTimestamp, - FSTTypeOrderString, - FSTTypeOrderBlob, - FSTTypeOrderReference, - FSTTypeOrderGeoPoint, - FSTTypeOrderArray, - FSTTypeOrderObject, -}; - -/** Defines the return value for pending server timestamps. */ -enum class ServerTimestampBehavior { None, Estimate, Previous }; - -/** Holds properties that define field value deserialization options. */ -@interface FSTFieldValueOptions : NSObject - -@property(nonatomic, readonly, assign) ServerTimestampBehavior serverTimestampBehavior; - -@property(nonatomic) BOOL timestampsInSnapshotsEnabled; - -- (instancetype)init NS_UNAVAILABLE; - -/** - * Creates an FSTFieldValueOptions instance that specifies deserialization behavior for pending - * server timestamps. - */ -- (instancetype)initWithServerTimestampBehavior:(ServerTimestampBehavior)serverTimestampBehavior - timestampsInSnapshotsEnabled:(BOOL)timestampsInSnapshotsEnabled - NS_DESIGNATED_INITIALIZER; - -@end - -/** - * Abstract base class representing an immutable data value as stored in Firestore. FSTFieldValue - * represents all the different kinds of values that can be stored in fields in a document. - * - * Supported types are: - * - Null - * - Boolean - * - Long - * - Double - * - Timestamp - * - ServerTimestamp (a sentinel used in uncommitted writes) - * - String - * - Binary - * - (Document) References - * - GeoPoint - * - Array - * - Object - */ -@interface FSTFieldValue<__covariant T> : NSObject - -/** Returns the FSTTypeOrder for this value. */ -- (FSTTypeOrder)typeOrder; - -/** - * Converts an FSTFieldValue into the value that users will see in document snapshots. - * - * TODO(mikelehen): This conversion should probably happen at the API level and right now `value` is - * used inappropriately in the serializer implementation, etc. We need to do some reworking. - */ -- (T)value; - -/** - * Converts an FSTFieldValue into the value that users will see in document snapshots. - * - * Options can be provided to configure the deserialization of some field values (such as server - * timestamps). - */ -- (T)valueWithOptions:(FSTFieldValueOptions *)options; - -/** Compares against another FSTFieldValue. */ -- (NSComparisonResult)compare:(FSTFieldValue *)other; - -@end - -/** - * A null value stored in Firestore. The |value| of a FSTNullValue is [NSNull null]. - */ -@interface FSTNullValue : FSTFieldValue -+ (instancetype)nullValue; -@end - -/** - * A boolean value stored in Firestore. - */ -@interface FSTBooleanValue : FSTFieldValue -+ (instancetype)trueValue; -+ (instancetype)falseValue; -+ (instancetype)booleanValue:(BOOL)value; -@end - -/** - * Base class inherited from by FSTIntegerValue and FSTDoubleValue. It implements proper number - * comparisons between the two types. - */ -@interface FSTNumberValue : FSTFieldValue -@end - -/** - * An integer value stored in Firestore. - */ -@interface FSTIntegerValue : FSTNumberValue -+ (instancetype)integerValue:(int64_t)value; -- (int64_t)internalValue; -@end - -/** - * A double-precision floating point number stored in Firestore. - */ -@interface FSTDoubleValue : FSTNumberValue -+ (instancetype)doubleValue:(double)value; -+ (instancetype)nanValue; -- (double)internalValue; -@end - -/** - * A string stored in Firestore. - */ -@interface FSTStringValue : FSTFieldValue -+ (instancetype)stringValue:(NSString *)value; -@end - -/** - * A timestamp value stored in Firestore. - */ -@interface FSTTimestampValue : FSTFieldValue -+ (instancetype)timestampValue:(FIRTimestamp *)value; -@end - -/** - * Represents a locally-applied Server Timestamp. - * - * Notes: - * - FSTServerTimestampValue instances are created as the result of applying an FSTTransformMutation - * (see [FSTTransformMutation applyTo]). They can only exist in the local view of a document. - * Therefore they do not need to be parsed or serialized. - * - When evaluated locally (e.g. via FSTDocumentSnapshot data), they by default evaluate to NSNull. - * This behavior can be configured by passing custom FSTFieldValueOptions to `valueWithOptions:`. - * - They sort after all FSTTimestampValues. With respect to other FSTServerTimestampValues, they - * sort by their localWriteTime. - */ -@interface FSTServerTimestampValue : FSTFieldValue -+ (instancetype)serverTimestampValueWithLocalWriteTime:(FIRTimestamp *)localWriteTime - previousValue:(nullable FSTFieldValue *)previousValue; - -@property(nonatomic, strong, readonly) FIRTimestamp *localWriteTime; -@property(nonatomic, strong, readonly, nullable) FSTFieldValue *previousValue; - -@end - -/** - * A geo point value stored in Firestore. - */ -@interface FSTGeoPointValue : FSTFieldValue -+ (instancetype)geoPointValue:(FIRGeoPoint *)value; -@end - -/** - * A blob value stored in Firestore. - */ -@interface FSTBlobValue : FSTFieldValue -+ (instancetype)blobValue:(NSData *)value; -@end - -/** - * A reference value stored in Firestore. - */ -@interface FSTReferenceValue : FSTFieldValue -+ (instancetype)referenceValue:(FSTDocumentKey *)value - databaseID:(const firebase::firestore::model::DatabaseId *)databaseID; -// Does not own this DatabaseId. -@property(nonatomic, assign, readonly) const firebase::firestore::model::DatabaseId *databaseID; -@end - -/** - * A structured object value stored in Firestore. - */ -// clang-format off -@interface FSTObjectValue : FSTFieldValue < NSDictionary * > - -- (instancetype)init NS_UNAVAILABLE; -// clang-format on - -/** Returns an empty FSTObjectValue. */ -+ (instancetype)objectValue; - -/** - * Initializes this FSTObjectValue with the given dictionary. - */ -- (instancetype)initWithDictionary:(NSDictionary *)value; - -/** - * Initializes this FSTObjectValue with the given immutable dictionary. - */ -- (instancetype)initWithImmutableDictionary: - (FSTImmutableSortedDictionary *)value NS_DESIGNATED_INITIALIZER; - -- (FSTImmutableSortedDictionary *)internalValue; - -/** Returns the value at the given path if it exists. Returns nil otherwise. */ -- (nullable FSTFieldValue *)valueForPath:(const firebase::firestore::model::FieldPath &)fieldPath; - -/** - * Returns a new object where the field at the named path has its value set to the given value. - * This object remains unmodified. - */ -- (FSTObjectValue *)objectBySettingValue:(FSTFieldValue *)value - forPath:(const firebase::firestore::model::FieldPath &)fieldPath; - -/** - * Returns a new object where the field at the named path has been removed. If any segment of the - * path does not exist within this object's structure, no change is performed. - */ -- (FSTObjectValue *)objectByDeletingPath:(const firebase::firestore::model::FieldPath &)fieldPath; - -/** - * Applies this field mask to the provided object value and returns an object that only contains - * fields that are specified in both the input object and this field mask. - */ -// TODO(mrschmidt): Once FieldValues are C++, move this to FieldMask to match other platforms. -- (FSTObjectValue *)objectByApplyingFieldMask: - (const firebase::firestore::model::FieldMask &)fieldMask; -@end - -/** - * An array value stored in Firestore. - */ -// clang-format off -@interface FSTArrayValue : FSTFieldValue < NSArray * > - -- (instancetype)init NS_UNAVAILABLE; -// clang-format on - -/** - * Initializes this instance with the given array of wrapped values. - * - * @param value An immutable array of FSTFieldValue objects. Caller is responsible for copying the - * value or releasing all references. - */ -- (instancetype)initWithValueNoCopy:(NSArray *)value NS_DESIGNATED_INITIALIZER; - -- (NSArray *)internalValue; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTFieldValue.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTFieldValue.mm deleted file mode 100644 index 7730f39..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTFieldValue.mm +++ /dev/null @@ -1,967 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Model/FSTFieldValue.h" - -#import "FIRDocumentSnapshot.h" -#import "FIRTimestamp.h" - -#import "Firestore/Source/API/FIRGeoPoint+Internal.h" -#import "Firestore/Source/Model/FSTDocumentKey.h" -#import "Firestore/Source/Util/FSTClasses.h" - -#include "Firestore/core/src/firebase/firestore/model/database_id.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/field_path.h" -#include "Firestore/core/src/firebase/firestore/util/comparison.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" - -namespace util = firebase::firestore::util; -using firebase::firestore::model::DatabaseId; -using firebase::firestore::model::FieldMask; -using firebase::firestore::model::FieldPath; -using firebase::firestore::util::Comparator; -using firebase::firestore::util::CompareMixedNumber; -using firebase::firestore::util::DoubleBitwiseEquals; -using firebase::firestore::util::DoubleBitwiseHash; -using firebase::firestore::util::MakeStringView; -using firebase::firestore::util::ReverseOrder; -using firebase::firestore::util::WrapCompare; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - FSTFieldValueOptions - -@implementation FSTFieldValueOptions - -- (instancetype)initWithServerTimestampBehavior:(ServerTimestampBehavior)serverTimestampBehavior - timestampsInSnapshotsEnabled:(BOOL)timestampsInSnapshotsEnabled { - self = [super init]; - - if (self) { - _serverTimestampBehavior = serverTimestampBehavior; - _timestampsInSnapshotsEnabled = timestampsInSnapshotsEnabled; - } - return self; -} - -@end - -#pragma mark - FSTFieldValue - -@interface FSTFieldValue () -- (NSComparisonResult)defaultCompare:(FSTFieldValue *)other; -@end - -@implementation FSTFieldValue - -- (FSTTypeOrder)typeOrder { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (id)value { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (id)valueWithOptions:(FSTFieldValueOptions *)options { - return [self value]; -} - -- (BOOL)isEqual:(id)other { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (NSUInteger)hash { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (NSComparisonResult)compare:(FSTFieldValue *)other { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (NSString *)description { - return [[self value] description]; -} - -- (NSComparisonResult)defaultCompare:(FSTFieldValue *)other { - if (self.typeOrder > other.typeOrder) { - return NSOrderedDescending; - } else { - HARD_ASSERT(self.typeOrder < other.typeOrder, - "defaultCompare should not be used for values of same type."); - return NSOrderedAscending; - } -} - -@end - -#pragma mark - FSTNullValue - -@implementation FSTNullValue - -+ (instancetype)nullValue { - static FSTNullValue *sharedInstance = nil; - static dispatch_once_t onceToken; - - dispatch_once(&onceToken, ^{ - sharedInstance = [[FSTNullValue alloc] init]; - }); - return sharedInstance; -} - -- (FSTTypeOrder)typeOrder { - return FSTTypeOrderNull; -} - -- (id)value { - return [NSNull null]; -} - -- (BOOL)isEqual:(id)other { - return [other isKindOfClass:[self class]]; -} - -- (NSUInteger)hash { - return 47; -} - -- (NSComparisonResult)compare:(FSTFieldValue *)other { - if ([other isKindOfClass:[self class]]) { - return NSOrderedSame; - } else { - return [self defaultCompare:other]; - } -} - -@end - -#pragma mark - FSTBooleanValue - -@interface FSTBooleanValue () -@property(nonatomic, assign, readonly) BOOL internalValue; -@end - -@implementation FSTBooleanValue - -+ (instancetype)trueValue { - static FSTBooleanValue *sharedInstance = nil; - static dispatch_once_t onceToken; - - dispatch_once(&onceToken, ^{ - sharedInstance = [[FSTBooleanValue alloc] initWithValue:YES]; - }); - return sharedInstance; -} - -+ (instancetype)falseValue { - static FSTBooleanValue *sharedInstance = nil; - static dispatch_once_t onceToken; - - dispatch_once(&onceToken, ^{ - sharedInstance = [[FSTBooleanValue alloc] initWithValue:NO]; - }); - return sharedInstance; -} - -+ (instancetype)booleanValue:(BOOL)value { - return value ? [FSTBooleanValue trueValue] : [FSTBooleanValue falseValue]; -} - -- (id)initWithValue:(BOOL)value { - self = [super init]; - if (self) { - _internalValue = value; - } - return self; -} - -- (FSTTypeOrder)typeOrder { - return FSTTypeOrderBoolean; -} - -- (id)value { - return self.internalValue ? @YES : @NO; -} - -- (BOOL)isEqual:(id)other { - // Since we create shared instances for true / false, we can use reference equality. - return self == other; -} - -- (NSUInteger)hash { - return self.internalValue ? 1231 : 1237; -} - -- (NSComparisonResult)compare:(FSTFieldValue *)other { - if ([other isKindOfClass:[FSTBooleanValue class]]) { - return WrapCompare(self.internalValue, ((FSTBooleanValue *)other).internalValue); - } else { - return [self defaultCompare:other]; - } -} - -@end - -#pragma mark - FSTNumberValue - -@implementation FSTNumberValue - -- (FSTTypeOrder)typeOrder { - return FSTTypeOrderNumber; -} - -- (NSComparisonResult)compare:(FSTFieldValue *)other { - if (![other isKindOfClass:[FSTNumberValue class]]) { - return [self defaultCompare:other]; - } else { - if ([self isKindOfClass:[FSTDoubleValue class]]) { - double thisDouble = ((FSTDoubleValue *)self).internalValue; - if ([other isKindOfClass:[FSTDoubleValue class]]) { - return WrapCompare(thisDouble, ((FSTDoubleValue *)other).internalValue); - } else { - HARD_ASSERT([other isKindOfClass:[FSTIntegerValue class]], "Unknown number value: %s", - other); - auto result = CompareMixedNumber(thisDouble, ((FSTIntegerValue *)other).internalValue); - return static_cast(result); - } - } else { - int64_t thisInt = ((FSTIntegerValue *)self).internalValue; - if ([other isKindOfClass:[FSTIntegerValue class]]) { - return WrapCompare(thisInt, ((FSTIntegerValue *)other).internalValue); - } else { - HARD_ASSERT([other isKindOfClass:[FSTDoubleValue class]], "Unknown number value: %s", - other); - double otherDouble = ((FSTDoubleValue *)other).internalValue; - auto result = ReverseOrder(CompareMixedNumber(otherDouble, thisInt)); - return static_cast(result); - } - } - } -} - -@end - -#pragma mark - FSTIntegerValue - -@interface FSTIntegerValue () -@property(nonatomic, assign, readonly) int64_t internalValue; -@end - -@implementation FSTIntegerValue - -+ (instancetype)integerValue:(int64_t)value { - return [[FSTIntegerValue alloc] initWithValue:value]; -} - -- (id)initWithValue:(int64_t)value { - self = [super init]; - if (self) { - _internalValue = value; - } - return self; -} - -- (id)value { - return @(self.internalValue); -} - -- (BOOL)isEqual:(id)other { - // NOTE: DoubleValue and LongValue instances may compare: the same, but that doesn't make them - // equal via isEqual: - return [other isKindOfClass:[FSTIntegerValue class]] && - self.internalValue == ((FSTIntegerValue *)other).internalValue; -} - -- (NSUInteger)hash { - return (((NSUInteger)self.internalValue) ^ (NSUInteger)(self.internalValue >> 32)); -} - -// NOTE: compare: is implemented in NumberValue. - -@end - -#pragma mark - FSTDoubleValue - -@interface FSTDoubleValue () -@property(nonatomic, assign, readonly) double internalValue; -@end - -@implementation FSTDoubleValue - -+ (instancetype)doubleValue:(double)value { - // Normalize NaNs to match the behavior on the backend (which uses Double.doubletoLongBits()). - if (isnan(value)) { - return [FSTDoubleValue nanValue]; - } - return [[FSTDoubleValue alloc] initWithValue:value]; -} - -+ (instancetype)nanValue { - static FSTDoubleValue *sharedInstance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - sharedInstance = [[FSTDoubleValue alloc] initWithValue:NAN]; - }); - return sharedInstance; -} - -- (id)initWithValue:(double)value { - self = [super init]; - if (self) { - _internalValue = value; - } - return self; -} - -- (id)value { - return @(self.internalValue); -} - -- (BOOL)isEqual:(id)other { - // NOTE: DoubleValue and LongValue instances may compare: the same, but that doesn't make them - // equal via isEqual: - - // NOTE: isEqual: should compare NaN equal to itself and -0.0 not equal to 0.0. - - return [other isKindOfClass:[FSTDoubleValue class]] && - DoubleBitwiseEquals(self.internalValue, ((FSTDoubleValue *)other).internalValue); -} - -- (NSUInteger)hash { - return DoubleBitwiseHash(self.internalValue); -} - -// NOTE: compare: is implemented in NumberValue. - -@end - -#pragma mark - FSTStringValue - -/** - * Specialization of Comparator for NSStrings. - */ -template <> -struct Comparator { - bool operator()(NSString *left, NSString *right) const { - Comparator lessThan; - return lessThan(MakeString(left), MakeString(right)); - } -}; - -@interface FSTStringValue () -@property(nonatomic, copy, readonly) NSString *internalValue; -@end - -// TODO(b/37267885): Add truncation support -@implementation FSTStringValue - -+ (instancetype)stringValue:(NSString *)value { - return [[FSTStringValue alloc] initWithValue:value]; -} - -- (id)initWithValue:(NSString *)value { - self = [super init]; - if (self) { - _internalValue = [value copy]; - } - return self; -} - -- (FSTTypeOrder)typeOrder { - return FSTTypeOrderString; -} - -- (id)value { - return self.internalValue; -} - -- (BOOL)isEqual:(id)other { - return [other isKindOfClass:[FSTStringValue class]] && - [self.internalValue isEqualToString:((FSTStringValue *)other).internalValue]; -} - -- (NSUInteger)hash { - return self.internalValue ? 1 : 0; -} - -- (NSComparisonResult)compare:(FSTFieldValue *)other { - if ([other isKindOfClass:[FSTStringValue class]]) { - return WrapCompare(self.internalValue, ((FSTStringValue *)other).internalValue); - } else { - return [self defaultCompare:other]; - } -} - -@end - -#pragma mark - FSTTimestampValue - -@interface FSTTimestampValue () -@property(nonatomic, strong, readonly) FIRTimestamp *internalValue; -@end - -@implementation FSTTimestampValue - -+ (instancetype)timestampValue:(FIRTimestamp *)value { - return [[FSTTimestampValue alloc] initWithValue:value]; -} - -- (id)initWithValue:(FIRTimestamp *)value { - self = [super init]; - if (self) { - _internalValue = value; // FIRTimestamp is immutable. - } - return self; -} - -- (FSTTypeOrder)typeOrder { - return FSTTypeOrderTimestamp; -} - -- (id)value { - return self.internalValue; -} - -- (id)valueWithOptions:(FSTFieldValueOptions *)options { - if (options.timestampsInSnapshotsEnabled) { - return self.value; - } else { - return [self.value dateValue]; - } -} - -- (BOOL)isEqual:(id)other { - return [other isKindOfClass:[FSTTimestampValue class]] && - [self.internalValue isEqual:((FSTTimestampValue *)other).internalValue]; -} - -- (NSUInteger)hash { - return [self.internalValue hash]; -} - -- (NSComparisonResult)compare:(FSTFieldValue *)other { - if ([other isKindOfClass:[FSTTimestampValue class]]) { - return [self.internalValue compare:((FSTTimestampValue *)other).internalValue]; - } else if ([other isKindOfClass:[FSTServerTimestampValue class]]) { - // Concrete timestamps come before server timestamps. - return NSOrderedAscending; - } else { - return [self defaultCompare:other]; - } -} - -@end -#pragma mark - FSTServerTimestampValue - -@implementation FSTServerTimestampValue - -+ (instancetype)serverTimestampValueWithLocalWriteTime:(FIRTimestamp *)localWriteTime - previousValue:(nullable FSTFieldValue *)previousValue { - return [[FSTServerTimestampValue alloc] initWithLocalWriteTime:localWriteTime - previousValue:previousValue]; -} - -- (id)initWithLocalWriteTime:(FIRTimestamp *)localWriteTime - previousValue:(nullable FSTFieldValue *)previousValue { - self = [super init]; - if (self) { - _localWriteTime = localWriteTime; - _previousValue = previousValue; - } - return self; -} - -- (FSTTypeOrder)typeOrder { - return FSTTypeOrderTimestamp; -} - -- (id)value { - return [NSNull null]; -} - -- (id)valueWithOptions:(FSTFieldValueOptions *)options { - switch (options.serverTimestampBehavior) { - case ServerTimestampBehavior::None: - return [NSNull null]; - case ServerTimestampBehavior::Estimate: - return [[FSTTimestampValue timestampValue:self.localWriteTime] valueWithOptions:options]; - case ServerTimestampBehavior::Previous: - return self.previousValue ? [self.previousValue valueWithOptions:options] : [NSNull null]; - default: - HARD_FAIL("Unexpected server timestamp option: %s", options.serverTimestampBehavior); - } -} - -- (BOOL)isEqual:(id)other { - return [other isKindOfClass:[FSTServerTimestampValue class]] && - [self.localWriteTime isEqual:((FSTServerTimestampValue *)other).localWriteTime]; -} - -- (NSUInteger)hash { - return [self.localWriteTime hash]; -} - -- (NSString *)description { - return [NSString stringWithFormat:@"", self.localWriteTime]; -} - -- (NSComparisonResult)compare:(FSTFieldValue *)other { - if ([other isKindOfClass:[FSTServerTimestampValue class]]) { - return [self.localWriteTime compare:((FSTServerTimestampValue *)other).localWriteTime]; - } else if ([other isKindOfClass:[FSTTimestampValue class]]) { - // Server timestamps come after all concrete timestamps. - return NSOrderedDescending; - } else { - return [self defaultCompare:other]; - } -} - -@end - -#pragma mark - FSTGeoPointValue - -@interface FSTGeoPointValue () -@property(nonatomic, strong, readonly) FIRGeoPoint *internalValue; -@end - -@implementation FSTGeoPointValue - -+ (instancetype)geoPointValue:(FIRGeoPoint *)value { - return [[FSTGeoPointValue alloc] initWithValue:value]; -} - -- (id)initWithValue:(FIRGeoPoint *)value { - self = [super init]; - if (self) { - _internalValue = value; // FIRGeoPoint is immutable. - } - return self; -} - -- (FSTTypeOrder)typeOrder { - return FSTTypeOrderGeoPoint; -} - -- (id)value { - return self.internalValue; -} - -- (BOOL)isEqual:(id)other { - return [other isKindOfClass:[FSTGeoPointValue class]] && - [self.internalValue isEqual:((FSTGeoPointValue *)other).internalValue]; -} - -- (NSUInteger)hash { - return [self.internalValue hash]; -} - -- (NSComparisonResult)compare:(FSTFieldValue *)other { - if ([other isKindOfClass:[FSTGeoPointValue class]]) { - return [self.internalValue compare:((FSTGeoPointValue *)other).internalValue]; - } else { - return [self defaultCompare:other]; - } -} - -@end -#pragma mark - FSTBlobValue - -static NSComparisonResult CompareBytes(NSData *left, NSData *right) { - NSUInteger minLength = MIN(left.length, right.length); - int result = memcmp(left.bytes, right.bytes, minLength); - if (result < 0) { - return NSOrderedAscending; - } else if (result > 0) { - return NSOrderedDescending; - } else if (left.length < right.length) { - return NSOrderedAscending; - } else if (left.length > right.length) { - return NSOrderedDescending; - } else { - return NSOrderedSame; - } -} - -@interface FSTBlobValue () -@property(nonatomic, copy, readonly) NSData *internalValue; -@end - -// TODO(b/37267885): Add truncation support -@implementation FSTBlobValue - -+ (instancetype)blobValue:(NSData *)value { - return [[FSTBlobValue alloc] initWithValue:value]; -} - -- (id)initWithValue:(NSData *)value { - self = [super init]; - if (self) { - _internalValue = [value copy]; - } - return self; -} - -- (FSTTypeOrder)typeOrder { - return FSTTypeOrderBlob; -} - -- (id)value { - return self.internalValue; -} - -- (BOOL)isEqual:(id)other { - return [other isKindOfClass:[FSTBlobValue class]] && - [self.internalValue isEqual:((FSTBlobValue *)other).internalValue]; -} - -- (NSUInteger)hash { - return [self.internalValue hash]; -} - -- (NSComparisonResult)compare:(FSTFieldValue *)other { - if ([other isKindOfClass:[FSTBlobValue class]]) { - return CompareBytes(self.internalValue, ((FSTBlobValue *)other).internalValue); - } else { - return [self defaultCompare:other]; - } -} - -@end - -#pragma mark - FSTReferenceValue - -@interface FSTReferenceValue () -@property(nonatomic, strong, readonly) FSTDocumentKey *key; -@end - -@implementation FSTReferenceValue - -+ (instancetype)referenceValue:(FSTDocumentKey *)value databaseID:(const DatabaseId *)databaseID { - return [[FSTReferenceValue alloc] initWithValue:value databaseID:databaseID]; -} - -- (id)initWithValue:(FSTDocumentKey *)value databaseID:(const DatabaseId *)databaseID { - self = [super init]; - if (self) { - _key = value; - _databaseID = databaseID; - } - return self; -} - -- (id)value { - return self.key; -} - -- (FSTTypeOrder)typeOrder { - return FSTTypeOrderReference; -} - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isKindOfClass:[FSTReferenceValue class]]) { - return NO; - } - - FSTReferenceValue *otherRef = (FSTReferenceValue *)other; - return self.key.key == otherRef.key.key && *self.databaseID == *otherRef.databaseID; -} - -- (NSUInteger)hash { - NSUInteger result = self.databaseID->Hash(); - result = 31 * result + [self.key hash]; - return result; -} - -- (NSComparisonResult)compare:(FSTFieldValue *)other { - if ([other isKindOfClass:[FSTReferenceValue class]]) { - FSTReferenceValue *ref = (FSTReferenceValue *)other; - NSComparisonResult cmp = - WrapCompare(self.databaseID->project_id(), ref.databaseID->project_id()); - if (cmp != NSOrderedSame) { - return cmp; - } - cmp = WrapCompare(self.databaseID->database_id(), ref.databaseID->database_id()); - return cmp != NSOrderedSame ? cmp : CompareKeys(self.key.key, ref.key.key); - } else { - return [self defaultCompare:other]; - } -} - -@end - -#pragma mark - FSTObjectValue - -static const NSComparator StringComparator = ^NSComparisonResult(NSString *left, NSString *right) { - return WrapCompare(left, right); -}; - -@interface FSTObjectValue () -@property(nonatomic, strong, readonly) - FSTImmutableSortedDictionary *internalValue; -@end - -@implementation FSTObjectValue - -+ (instancetype)objectValue { - static FSTObjectValue *sharedEmptyInstance = nil; - static dispatch_once_t onceToken; - - dispatch_once(&onceToken, ^{ - FSTImmutableSortedDictionary *empty = - [FSTImmutableSortedDictionary dictionaryWithComparator:StringComparator]; - sharedEmptyInstance = [[FSTObjectValue alloc] initWithImmutableDictionary:empty]; - }); - return sharedEmptyInstance; -} - -- (instancetype)initWithImmutableDictionary: - (FSTImmutableSortedDictionary *)value { - self = [super init]; - if (self) { - _internalValue = value; // FSTImmutableSortedDictionary is immutable. - } - return self; -} - -- (id)initWithDictionary:(NSDictionary *)value { - FSTImmutableSortedDictionary *dictionary = - [FSTImmutableSortedDictionary dictionaryWithDictionary:value comparator:StringComparator]; - return [self initWithImmutableDictionary:dictionary]; -} - -- (id)value { - NSMutableDictionary *result = [NSMutableDictionary dictionary]; - [self.internalValue - enumerateKeysAndObjectsUsingBlock:^(NSString *key, FSTFieldValue *obj, BOOL *stop) { - result[key] = [obj value]; - }]; - return result; -} - -- (id)valueWithOptions:(FSTFieldValueOptions *)options { - NSMutableDictionary *result = [NSMutableDictionary dictionary]; - [self.internalValue - enumerateKeysAndObjectsUsingBlock:^(NSString *key, FSTFieldValue *obj, BOOL *stop) { - result[key] = [obj valueWithOptions:options]; - }]; - return result; -} - -- (FSTTypeOrder)typeOrder { - return FSTTypeOrderObject; -} - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isKindOfClass:[FSTObjectValue class]]) { - return NO; - } - - FSTObjectValue *otherObj = other; - return [self.internalValue isEqual:otherObj.internalValue]; -} - -- (NSUInteger)hash { - return [self.internalValue hash]; -} - -- (NSComparisonResult)compare:(FSTFieldValue *)other { - if ([other isKindOfClass:[FSTObjectValue class]]) { - FSTImmutableSortedDictionary *selfDict = self.internalValue; - FSTImmutableSortedDictionary *otherDict = ((FSTObjectValue *)other).internalValue; - NSEnumerator *enumerator1 = [selfDict keyEnumerator]; - NSEnumerator *enumerator2 = [otherDict keyEnumerator]; - NSString *key1 = [enumerator1 nextObject]; - NSString *key2 = [enumerator2 nextObject]; - while (key1 && key2) { - NSComparisonResult keyCompare = [key1 compare:key2]; - if (keyCompare != NSOrderedSame) { - return keyCompare; - } - NSComparisonResult valueCompare = [selfDict[key1] compare:otherDict[key2]]; - if (valueCompare != NSOrderedSame) { - return valueCompare; - } - key1 = [enumerator1 nextObject]; - key2 = [enumerator2 nextObject]; - } - // Only equal if both enumerators are exhausted. - return WrapCompare(key1 != nil, key2 != nil); - } else { - return [self defaultCompare:other]; - } -} - -- (nullable FSTFieldValue *)valueForPath:(const FieldPath &)fieldPath { - FSTFieldValue *value = self; - for (size_t i = 0, max = fieldPath.size(); value && i < max; i++) { - if (![value isMemberOfClass:[FSTObjectValue class]]) { - return nil; - } - - NSString *fieldName = util::WrapNSStringNoCopy(fieldPath[i]); - value = ((FSTObjectValue *)value).internalValue[fieldName]; - } - - return value; -} - -- (FSTObjectValue *)objectBySettingValue:(FSTFieldValue *)value - forPath:(const FieldPath &)fieldPath { - HARD_ASSERT(fieldPath.size() > 0, "Cannot set value with an empty path"); - - NSString *childName = util::WrapNSString(fieldPath.first_segment()); - if (fieldPath.size() == 1) { - // Recursive base case: - return [self objectBySettingValue:value forField:childName]; - } else { - // Nested path. Recursively generate a new sub-object and then wrap a new FSTObjectValue - // around the result. - FSTFieldValue *child = [_internalValue objectForKey:childName]; - FSTObjectValue *childObject; - if ([child isKindOfClass:[FSTObjectValue class]]) { - childObject = (FSTObjectValue *)child; - } else { - // If the child is not found or is a primitive type, pretend as if an empty object lived - // there. - childObject = [FSTObjectValue objectValue]; - } - FSTFieldValue *newChild = [childObject objectBySettingValue:value forPath:fieldPath.PopFirst()]; - return [self objectBySettingValue:newChild forField:childName]; - } -} - -- (FSTObjectValue *)objectByDeletingPath:(const FieldPath &)fieldPath { - HARD_ASSERT(fieldPath.size() > 0, "Cannot delete an empty path"); - NSString *childName = util::WrapNSString(fieldPath.first_segment()); - if (fieldPath.size() == 1) { - return [[FSTObjectValue alloc] - initWithImmutableDictionary:[_internalValue dictionaryByRemovingObjectForKey:childName]]; - } else { - FSTFieldValue *child = _internalValue[childName]; - if ([child isKindOfClass:[FSTObjectValue class]]) { - FSTObjectValue *newChild = - [((FSTObjectValue *)child) objectByDeletingPath:fieldPath.PopFirst()]; - return [self objectBySettingValue:newChild forField:childName]; - } else { - // If the child is not found or is a primitive type, make no modifications - return self; - } - } -} - -- (FSTObjectValue *)objectBySettingValue:(FSTFieldValue *)value forField:(NSString *)field { - return [[FSTObjectValue alloc] - initWithImmutableDictionary:[_internalValue dictionaryBySettingObject:value forKey:field]]; -} - -- (FSTObjectValue *)objectByApplyingFieldMask:(const FieldMask &)fieldMask { - FSTObjectValue *filteredObject = self; - for (const FieldPath &path : fieldMask) { - if (path.empty()) { - return self; - } else { - FSTFieldValue *newValue = [self valueForPath:path]; - if (newValue) { - filteredObject = [filteredObject objectBySettingValue:newValue forPath:path]; - } - } - } - return filteredObject; -} - -@end - -@interface FSTArrayValue () -@property(nonatomic, strong, readonly) NSArray *internalValue; -@end - -#pragma mark - FSTArrayValue - -@implementation FSTArrayValue - -- (id)initWithValueNoCopy:(NSArray *)value { - self = [super init]; - if (self) { - // Does not copy, assumes the caller has already copied. - _internalValue = value; - } - return self; -} - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isKindOfClass:[self class]]) { - return NO; - } - - // NSArray's isEqual does the right thing for our purposes. - FSTArrayValue *otherArray = other; - return [self.internalValue isEqual:otherArray.internalValue]; -} - -- (NSUInteger)hash { - return [self.internalValue hash]; -} - -- (id)value { - NSMutableArray *result = [NSMutableArray arrayWithCapacity:_internalValue.count]; - [self.internalValue enumerateObjectsUsingBlock:^(FSTFieldValue *obj, NSUInteger idx, BOOL *stop) { - [result addObject:[obj value]]; - }]; - return result; -} - -- (id)valueWithOptions:(FSTFieldValueOptions *)options { - NSMutableArray *result = [NSMutableArray arrayWithCapacity:_internalValue.count]; - [self.internalValue enumerateObjectsUsingBlock:^(FSTFieldValue *obj, NSUInteger idx, BOOL *stop) { - [result addObject:[obj valueWithOptions:options]]; - }]; - return result; -} - -- (FSTTypeOrder)typeOrder { - return FSTTypeOrderArray; -} - -- (NSComparisonResult)compare:(FSTFieldValue *)other { - if ([other isKindOfClass:[FSTArrayValue class]]) { - NSArray *selfArray = self.internalValue; - NSArray *otherArray = ((FSTArrayValue *)other).internalValue; - NSUInteger minLength = MIN(selfArray.count, otherArray.count); - for (NSUInteger i = 0; i < minLength; i++) { - NSComparisonResult cmp = [selfArray[i] compare:otherArray[i]]; - if (cmp != NSOrderedSame) { - return cmp; - } - } - return WrapCompare(selfArray.count, otherArray.count); - } else { - return [self defaultCompare:other]; - } -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTMutation.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTMutation.h deleted file mode 100644 index 6eb38e2..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTMutation.h +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include -#include - -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/field_mask.h" -#include "Firestore/core/src/firebase/firestore/model/field_path.h" -#include "Firestore/core/src/firebase/firestore/model/field_transform.h" -#include "Firestore/core/src/firebase/firestore/model/precondition.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/model/transform_operations.h" - -#include "absl/types/optional.h" - -@class FSTDocument; -@class FSTFieldValue; -@class FSTMaybeDocument; -@class FSTObjectValue; -@class FIRTimestamp; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - FSTMutationResult - -@interface FSTMutationResult : NSObject - -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithVersion:(firebase::firestore::model::SnapshotVersion)version - transformResults:(NSArray *_Nullable)transformResults - NS_DESIGNATED_INITIALIZER; - -/** - * The version at which the mutation was committed. - * - * - For most operations, this is the updateTime in the WriteResult. - * - For deletes, it is the commitTime of the WriteResponse (because deletes are not stored - * and have no updateTime). - * - * Note that these versions can be different: No-op writes will not change the updateTime even - * though the commitTime advances. - */ -- (const firebase::firestore::model::SnapshotVersion &)version; - -/** - * The resulting fields returned from the backend after a FSTTransformMutation has been committed. - * Contains one FieldValue for each FieldTransform that was in the mutation. - * - * Will be nil if the mutation was not a FSTTransformMutation. - */ -@property(nonatomic, strong, readonly) NSArray *_Nullable transformResults; - -@end - -#pragma mark - FSTMutation - -/** - * Represents a Mutation of a document. Different subclasses of Mutation will perform different - * kinds of changes to a base document. For example, an FSTSetMutation replaces the value of a - * document and an FSTDeleteMutation deletes a document. - * - * Subclasses of FSTMutation need to implement `applyToRemoteDocument:mutationResult:` and - * `applyToLocalDocument:baseDocument:localWriteTime:` to implement the actual the behavior of - * mutations as applied to some source document. - * - * In addition to the value of the document mutations also operate on the version. For local - * mutations (mutations that haven't been committed yet), we preserve the existing version for Set, - * Patch, and Transform mutations. For local deletes, we reset the version to 0. - * - * Here's the expected transition table. - * - * MUTATION APPLIED TO RESULTS IN - * - * SetMutation Document(v3) Document(v3) - * SetMutation DeletedDocument(v3) Document(v0) - * SetMutation nil Document(v0) - * PatchMutation Document(v3) Document(v3) - * PatchMutation DeletedDocument(v3) DeletedDocument(v3) - * PatchMutation nil nil - * TransformMutation Document(v3) Document(v3) - * TransformMutation DeletedDocument(v3) DeletedDocument(v3) - * TransformMutation nil nil - * DeleteMutation Document(v3) DeletedDocument(v0) - * DeleteMutation DeletedDocument(v3) DeletedDocument(v0) - * DeleteMutation nil DeletedDocument(v0) - * - * For acknowledged mutations, we use the updateTime of the WriteResponse as the resulting version - * for Set, Patch, and Transform mutations. As deletes have no explicit update time, we use the - * commitTime of the WriteResponse for acknowledged deletes. - * - * If a mutation is acknowledged by the backend but fails the precondition check locally, we - * return an `FSTUnknownDocument` and rely on Watch to send us the updated version. - * - * Note that FSTTransformMutations don't create Documents (in the case of being applied to an - * FSTDeletedDocument), even though they would on the backend. This is because the client always - * combines the FSTTransformMutations with a FSTSetMutation or FSTPatchMutation and we only want to - * apply the transform if the prior mutation resulted in an FSTDocument (always true for an - * FSTSetMutation, but not necessarily for an FSTPatchMutation). - */ -@interface FSTMutation : NSObject - -- (id)init NS_UNAVAILABLE; - -- (instancetype)initWithKey:(firebase::firestore::model::DocumentKey)key - precondition:(firebase::firestore::model::Precondition)precondition - NS_DESIGNATED_INITIALIZER; - -/** - * Applies this mutation to the given FSTMaybeDocument for the purposes of computing a new remote - * document. If the input document doesn't match the expected state (e.g. it is nil or outdated), - * an `FSTUnknownDocument` can be returned. - * - * @param maybeDoc The document to mutate. The input document can be nil if the client has no - * knowledge of the pre-mutation state of the document. - * @param mutationResult The result of applying the mutation from the backend. - * @return The mutated document. The returned document may be an FSTUnknownDocument if the mutation - * could not be applied to the locally cached base document. - */ -- (FSTMaybeDocument *)applyToRemoteDocument:(nullable FSTMaybeDocument *)maybeDoc - mutationResult:(FSTMutationResult *)mutationResult; - -/** - * Applies this mutation to the given FSTMaybeDocument for the purposes of computing the new local - * view of a document. Both the input and returned documents can be nil. - * - * @param maybeDoc The document to mutate. The input document can be nil if the client has no - * knowledge of the pre-mutation state of the document. - * @param baseDoc The state of the document prior to this mutation batch. The input document can - * be nil if the client has no knowledge of the pre-mutation state of the document. - * @param localWriteTime A timestamp indicating the local write time of the batch this mutation is - * a part of. - * @return The mutated document. The returned document may be nil, but only if maybeDoc was nil - * and the mutation would not create a new document. - */ -- (nullable FSTMaybeDocument *)applyToLocalDocument:(nullable FSTMaybeDocument *)maybeDoc - baseDocument:(nullable FSTMaybeDocument *)baseDoc - localWriteTime:(FIRTimestamp *)localWriteTime; - -- (const firebase::firestore::model::DocumentKey &)key; - -- (const firebase::firestore::model::Precondition &)precondition; - -/** - * If applicable, returns the field mask for this mutation. Fields that are not included in this - * field mask are not modified when this mutation is applied. Mutations that replace all document - * values return 'nullptr'. - */ -- (const firebase::firestore::model::FieldMask *)fieldMask; - -/** Returns whether all operations in the mutation are idempotent. */ -@property(nonatomic, readonly) BOOL idempotent; - -@end - -#pragma mark - FSTSetMutation - -/** - * A mutation that creates or replaces the document at the given key with the object value - * contents. - */ -@interface FSTSetMutation : FSTMutation - -- (instancetype)initWithKey:(firebase::firestore::model::DocumentKey)key - precondition:(firebase::firestore::model::Precondition)precondition NS_UNAVAILABLE; - -/** - * Initializes the set mutation. - * - * @param key Identifies the location of the document to mutate. - * @param value An object value that describes the contents to store at the location named by the - * key. - * @param precondition The precondition for this mutation. - */ -- (instancetype)initWithKey:(firebase::firestore::model::DocumentKey)key - value:(FSTObjectValue *)value - precondition:(firebase::firestore::model::Precondition)precondition - NS_DESIGNATED_INITIALIZER; - -/** The object value to use when setting the document. */ -@property(nonatomic, strong, readonly) FSTObjectValue *value; -@end - -#pragma mark - FSTPatchMutation - -/** - * A mutation that modifies fields of the document at the given key with the given values. The - * values are applied through a field mask: - * - * * When a field is in both the mask and the values, the corresponding field is updated. - * * When a field is in neither the mask nor the values, the corresponding field is unmodified. - * * When a field is in the mask but not in the values, the corresponding field is deleted. - * * When a field is not in the mask but is in the values, the values map is ignored. - */ -@interface FSTPatchMutation : FSTMutation - -/** Returns the precondition for the given Precondition. */ -- (instancetype)initWithKey:(firebase::firestore::model::DocumentKey)key - precondition:(firebase::firestore::model::Precondition)precondition NS_UNAVAILABLE; - -/** - * Initializes a new patch mutation with an explicit FieldMask and FSTObjectValue representing - * the updates to perform - * - * @param key Identifies the location of the document to mutate. - * @param fieldMask The field mask specifying at what locations the data in value should be - * applied. - * @param value An FSTObjectValue containing the data to be written (using the paths in fieldMask - * to determine the locations at which it should be applied). - * @param precondition The precondition for this mutation. - */ -- (instancetype)initWithKey:(firebase::firestore::model::DocumentKey)key - fieldMask:(firebase::firestore::model::FieldMask)fieldMask - value:(FSTObjectValue *)value - precondition:(firebase::firestore::model::Precondition)precondition - NS_DESIGNATED_INITIALIZER; - -/** - * A mask to apply to |value|, where only fields that are in both the fieldMask and the value - * will be updated. - */ -- (const firebase::firestore::model::FieldMask *)fieldMask; - -/** The fields and associated values to use when patching the document. */ -@property(nonatomic, strong, readonly) FSTObjectValue *value; - -@end - -#pragma mark - FSTTransformMutation - -/** - * A mutation that modifies specific fields of the document with transform operations. Currently - * the only supported transform is a server timestamp, but IP Address, increment(n), etc. could - * be supported in the future. - * - * It is somewhat similar to an FSTPatchMutation in that it patches specific fields and has no - * effect when applied to nil or an FSTDeletedDocument (see comment on [FSTMutation applyTo] for - * rationale). - */ -@interface FSTTransformMutation : FSTMutation - -- (instancetype)initWithKey:(firebase::firestore::model::DocumentKey)key - precondition:(firebase::firestore::model::Precondition)precondition NS_UNAVAILABLE; - -/** - * Initializes a new transform mutation with the specified field transforms. - * - * @param key Identifies the location of the document to mutate. - * @param fieldTransforms A list of FieldTransform objects to perform to the document. - */ -- (instancetype)initWithKey:(firebase::firestore::model::DocumentKey)key - fieldTransforms:(std::vector)fieldTransforms - NS_DESIGNATED_INITIALIZER; - -/** The field transforms to use when transforming the document. */ -- (const std::vector &)fieldTransforms; - -@end - -#pragma mark - FSTDeleteMutation - -@interface FSTDeleteMutation : FSTMutation - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTMutation.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTMutation.mm deleted file mode 100644 index a805671..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTMutation.mm +++ /dev/null @@ -1,598 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Model/FSTMutation.h" - -#include -#include -#include -#include -#include - -#import "FIRTimestamp.h" - -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Util/FSTClasses.h" - -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/field_mask.h" -#include "Firestore/core/src/firebase/firestore/model/field_path.h" -#include "Firestore/core/src/firebase/firestore/model/field_transform.h" -#include "Firestore/core/src/firebase/firestore/model/precondition.h" -#include "Firestore/core/src/firebase/firestore/model/transform_operations.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" - -using firebase::firestore::model::ArrayTransform; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::FieldMask; -using firebase::firestore::model::FieldPath; -using firebase::firestore::model::FieldTransform; -using firebase::firestore::model::Precondition; -using firebase::firestore::model::ServerTimestampTransform; -using firebase::firestore::model::SnapshotVersion; -using firebase::firestore::model::TransformOperation; -using firebase::firestore::util::Hash; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - FSTMutationResult - -@implementation FSTMutationResult { - SnapshotVersion _version; -} - -- (instancetype)initWithVersion:(SnapshotVersion)version - transformResults:(nullable NSArray *)transformResults { - if (self = [super init]) { - _version = std::move(version); - _transformResults = transformResults; - } - return self; -} - -- (const SnapshotVersion &)version { - return _version; -} - -@end - -#pragma mark - FSTMutation - -@implementation FSTMutation { - DocumentKey _key; - Precondition _precondition; -} - -- (instancetype)initWithKey:(DocumentKey)key precondition:(Precondition)precondition { - if (self = [super init]) { - _key = std::move(key); - _precondition = std::move(precondition); - } - return self; -} - -- (FSTMaybeDocument *)applyToRemoteDocument:(nullable FSTMaybeDocument *)maybeDoc - mutationResult:(FSTMutationResult *)mutationResult { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (nullable FSTMaybeDocument *)applyToLocalDocument:(nullable FSTMaybeDocument *)maybeDoc - baseDocument:(nullable FSTMaybeDocument *)baseDoc - localWriteTime:(FIRTimestamp *)localWriteTime { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (const DocumentKey &)key { - return _key; -} - -- (const firebase::firestore::model::Precondition &)precondition { - return _precondition; -} - -- (BOOL)idempotent { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (const FieldMask *)fieldMask { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (void)verifyKeyMatches:(nullable FSTMaybeDocument *)maybeDoc { - if (maybeDoc) { - HARD_ASSERT(maybeDoc.key == self.key, "Can only set a document with the same key"); - } -} - -/** - * Returns the version from the given document for use as the result of a mutation. Mutations are - * defined to return the version of the base document only if it is an existing document. Deleted - * and unknown documents have a post-mutation version of {@code SnapshotVersion::None()}. - */ -- (const SnapshotVersion &)postMutationVersionForDocument:(FSTMaybeDocument *)maybeDoc { - return [maybeDoc isKindOfClass:[FSTDocument class]] ? maybeDoc.version : SnapshotVersion::None(); -} -@end - -#pragma mark - FSTSetMutation - -@implementation FSTSetMutation - -- (instancetype)initWithKey:(DocumentKey)key - value:(FSTObjectValue *)value - precondition:(Precondition)precondition { - if (self = [super initWithKey:std::move(key) precondition:std::move(precondition)]) { - _value = value; - } - return self; -} - -- (NSString *)description { - return [NSString stringWithFormat:@"", - self.key.ToString().c_str(), self.value, - self.precondition.description()]; -} - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isKindOfClass:[FSTSetMutation class]]) { - return NO; - } - - FSTSetMutation *otherMutation = (FSTSetMutation *)other; - return self.key == otherMutation.key && [self.value isEqual:otherMutation.value] && - self.precondition == otherMutation.precondition; -} - -- (NSUInteger)hash { - return Hash(self.key, self.precondition, [self.value hash]); -} - -- (nullable FSTMaybeDocument *)applyToLocalDocument:(nullable FSTMaybeDocument *)maybeDoc - baseDocument:(nullable FSTMaybeDocument *)baseDoc - localWriteTime:(FIRTimestamp *)localWriteTime { - [self verifyKeyMatches:maybeDoc]; - - if (!self.precondition.IsValidFor(maybeDoc)) { - return maybeDoc; - } - - SnapshotVersion version = [self postMutationVersionForDocument:maybeDoc]; - return [FSTDocument documentWithData:self.value - key:self.key - version:version - state:FSTDocumentStateLocalMutations]; -} - -- (FSTMaybeDocument *)applyToRemoteDocument:(nullable FSTMaybeDocument *)maybeDoc - mutationResult:(FSTMutationResult *)mutationResult { - [self verifyKeyMatches:maybeDoc]; - - HARD_ASSERT(!mutationResult.transformResults, "Transform results received by FSTSetMutation."); - - // Unlike applyToLocalView, if we're applying a mutation to a remote document the server has - // accepted the mutation so the precondition must have held. - - return [FSTDocument documentWithData:self.value - key:self.key - version:mutationResult.version - state:FSTDocumentStateCommittedMutations]; -} - -- (const FieldMask *)fieldMask { - return nullptr; -} - -- (BOOL)idempotent { - return YES; -} - -@end - -#pragma mark - FSTPatchMutation - -@implementation FSTPatchMutation { - FieldMask _fieldMask; -} - -- (instancetype)initWithKey:(DocumentKey)key - fieldMask:(FieldMask)fieldMask - value:(FSTObjectValue *)value - precondition:(Precondition)precondition { - self = [super initWithKey:std::move(key) precondition:std::move(precondition)]; - if (self) { - _fieldMask = std::move(fieldMask); - _value = value; - } - return self; -} - -- (const FieldMask *)fieldMask { - return &_fieldMask; -} - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isKindOfClass:[FSTPatchMutation class]]) { - return NO; - } - - FSTPatchMutation *otherMutation = (FSTPatchMutation *)other; - return self.key == otherMutation.key && _fieldMask == *(otherMutation.fieldMask) && - [self.value isEqual:otherMutation.value] && - self.precondition == otherMutation.precondition; -} - -- (NSUInteger)hash { - return Hash(self.key, self.precondition, _fieldMask, [self.value hash]); -} - -- (NSString *)description { - return [NSString stringWithFormat:@"", - self.key.ToString().c_str(), _fieldMask.ToString().c_str(), - self.value, self.precondition.description()]; -} - -/** - * Patches the data of document if available or creates a new document. Note that this does not - * check whether or not the precondition of this patch holds. - */ -- (FSTObjectValue *)patchDocument:(nullable FSTMaybeDocument *)maybeDoc { - FSTObjectValue *data; - if ([maybeDoc isKindOfClass:[FSTDocument class]]) { - data = ((FSTDocument *)maybeDoc).data; - } else { - data = [FSTObjectValue objectValue]; - } - return [self patchObjectValue:data]; -} - -- (nullable FSTMaybeDocument *)applyToLocalDocument:(nullable FSTMaybeDocument *)maybeDoc - baseDocument:(nullable FSTMaybeDocument *)baseDoc - localWriteTime:(FIRTimestamp *)localWriteTime { - [self verifyKeyMatches:maybeDoc]; - - if (!self.precondition.IsValidFor(maybeDoc)) { - return maybeDoc; - } - - FSTObjectValue *newData = [self patchDocument:maybeDoc]; - SnapshotVersion version = [self postMutationVersionForDocument:maybeDoc]; - - return [FSTDocument documentWithData:newData - key:self.key - version:version - state:FSTDocumentStateLocalMutations]; -} - -- (FSTMaybeDocument *)applyToRemoteDocument:(nullable FSTMaybeDocument *)maybeDoc - mutationResult:(FSTMutationResult *)mutationResult { - [self verifyKeyMatches:maybeDoc]; - - HARD_ASSERT(!mutationResult.transformResults, "Transform results received by FSTPatchMutation."); - - if (!self.precondition.IsValidFor(maybeDoc)) { - // Since the mutation was not rejected, we know that the precondition matched on the backend. - // We therefore must not have the expected version of the document in our cache and return a - // FSTUnknownDocument with the known updateTime. - return [FSTUnknownDocument documentWithKey:self.key version:mutationResult.version]; - } - - FSTObjectValue *newData = [self patchDocument:maybeDoc]; - - return [FSTDocument documentWithData:newData - key:self.key - version:mutationResult.version - state:FSTDocumentStateCommittedMutations]; -} - -- (FSTObjectValue *)patchObjectValue:(FSTObjectValue *)objectValue { - FSTObjectValue *result = objectValue; - for (const FieldPath &fieldPath : _fieldMask) { - if (!fieldPath.empty()) { - FSTFieldValue *newValue = [self.value valueForPath:fieldPath]; - if (newValue) { - result = [result objectBySettingValue:newValue forPath:fieldPath]; - } else { - result = [result objectByDeletingPath:fieldPath]; - } - } - } - return result; -} - -- (BOOL)idempotent { - return YES; -} - -@end - -@implementation FSTTransformMutation { - /** The field transforms to use when transforming the document. */ - std::vector _fieldTransforms; - FieldMask _fieldMask; -} - -- (instancetype)initWithKey:(DocumentKey)key - fieldTransforms:(std::vector)fieldTransforms { - // NOTE: We set a precondition of exists: true as a safety-check, since we always combine - // FSTTransformMutations with a FSTSetMutation or FSTPatchMutation which (if successful) should - // end up with an existing document. - if (self = [super initWithKey:std::move(key) precondition:Precondition::Exists(true)]) { - _fieldTransforms = std::move(fieldTransforms); - - std::set fields; - for (const auto &transform : _fieldTransforms) { - fields.insert(transform.path()); - } - - _fieldMask = FieldMask(std::move(fields)); - } - return self; -} - -- (const std::vector &)fieldTransforms { - return _fieldTransforms; -} - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isKindOfClass:[FSTTransformMutation class]]) { - return NO; - } - - FSTTransformMutation *otherMutation = (FSTTransformMutation *)other; - return self.key == otherMutation.key && self.fieldTransforms == otherMutation.fieldTransforms && - self.precondition == otherMutation.precondition; -} - -- (NSUInteger)hash { - NSUInteger result = self.key.Hash(); - result = 31 * result + self.precondition.Hash(); - for (const auto &transform : self.fieldTransforms) { - result = 31 * result + transform.Hash(); - } - return result; -} - -- (NSString *)description { - std::string fieldTransforms; - for (const auto &transform : self.fieldTransforms) { - fieldTransforms += " " + transform.path().CanonicalString(); - } - return [NSString stringWithFormat:@"", - self.key.ToString().c_str(), fieldTransforms.c_str(), - self.precondition.description()]; -} - -- (nullable FSTMaybeDocument *)applyToLocalDocument:(nullable FSTMaybeDocument *)maybeDoc - baseDocument:(nullable FSTMaybeDocument *)baseDoc - localWriteTime:(FIRTimestamp *)localWriteTime { - [self verifyKeyMatches:maybeDoc]; - - if (!self.precondition.IsValidFor(maybeDoc)) { - return maybeDoc; - } - - // We only support transforms with precondition exists, so we can only apply it to an existing - // document - HARD_ASSERT([maybeDoc isMemberOfClass:[FSTDocument class]], "Unknown MaybeDocument type %s", - [maybeDoc class]); - FSTDocument *doc = (FSTDocument *)maybeDoc; - - NSArray *transformResults = - [self localTransformResultsWithBaseDocument:baseDoc writeTime:localWriteTime]; - FSTObjectValue *newData = [self transformObject:doc.data transformResults:transformResults]; - - return [FSTDocument documentWithData:newData - key:doc.key - version:doc.version - state:FSTDocumentStateLocalMutations]; -} - -- (FSTMaybeDocument *)applyToRemoteDocument:(nullable FSTMaybeDocument *)maybeDoc - mutationResult:(FSTMutationResult *)mutationResult { - [self verifyKeyMatches:maybeDoc]; - - HARD_ASSERT(mutationResult.transformResults, - "Transform results missing for FSTTransformMutation."); - - if (!self.precondition.IsValidFor(maybeDoc)) { - // Since the mutation was not rejected, we know that the precondition matched on the backend. - // We therefore must not have the expected version of the document in our cache and return an - // FSTUnknownDocument with the known updateTime. - return [FSTUnknownDocument documentWithKey:self.key version:mutationResult.version]; - } - - // We only support transforms with precondition exists, so we can only apply it to an existing - // document - HARD_ASSERT([maybeDoc isMemberOfClass:[FSTDocument class]], "Unknown MaybeDocument type %s", - [maybeDoc class]); - FSTDocument *doc = (FSTDocument *)maybeDoc; - NSArray *transformResults = - [self serverTransformResultsWithBaseDocument:maybeDoc - serverTransformResults:mutationResult.transformResults]; - - FSTObjectValue *newData = [self transformObject:doc.data transformResults:transformResults]; - - return [FSTDocument documentWithData:newData - key:self.key - version:mutationResult.version - state:FSTDocumentStateCommittedMutations]; -} - -/** - * Creates an array of "transform results" (a transform result is a field value representing the - * result of applying a transform) for use after a FSTTransformMutation has been acknowledged by - * the server. - * - * @param baseDocument The document prior to applying this mutation batch. - * @param serverTransformResults The transform results received by the server. - * @return The transform results array. - */ -- (NSArray *) - serverTransformResultsWithBaseDocument:(nullable FSTMaybeDocument *)baseDocument - serverTransformResults:(NSArray *)serverTransformResults { - NSMutableArray *transformResults = [NSMutableArray array]; - HARD_ASSERT(self.fieldTransforms.size() == serverTransformResults.count, - "server transform result count (%s) should match field transforms count (%s)", - (unsigned long)serverTransformResults.count, self.fieldTransforms.size()); - - for (NSUInteger i = 0; i < serverTransformResults.count; i++) { - const FieldTransform &fieldTransform = self.fieldTransforms[i]; - const TransformOperation &transform = fieldTransform.transformation(); - - FSTFieldValue *previousValue = nil; - if ([baseDocument isMemberOfClass:[FSTDocument class]]) { - previousValue = [((FSTDocument *)baseDocument) fieldForPath:fieldTransform.path()]; - } - - [transformResults - addObject:transform.ApplyToRemoteDocument(previousValue, serverTransformResults[i])]; - } - return transformResults; -} - -/** - * Creates an array of "transform results" (a transform result is a field value representing the - * result of applying a transform) for use when applying an FSTTransformMutation locally. - * - * @param baseDocument The document prior to applying this mutation batch. - * @param localWriteTime The local time of the transform mutation (used to generate - * FSTServerTimestampValues). - * @return The transform results array. - */ -- (NSArray *)localTransformResultsWithBaseDocument: - (nullable FSTMaybeDocument *)baseDocument - writeTime:(FIRTimestamp *)localWriteTime { - NSMutableArray *transformResults = [NSMutableArray array]; - for (const FieldTransform &fieldTransform : self.fieldTransforms) { - const TransformOperation &transform = fieldTransform.transformation(); - - FSTFieldValue *previousValue = nil; - if ([baseDocument isMemberOfClass:[FSTDocument class]]) { - previousValue = [((FSTDocument *)baseDocument) fieldForPath:fieldTransform.path()]; - } - - [transformResults addObject:transform.ApplyToLocalView(previousValue, localWriteTime)]; - } - return transformResults; -} - -- (FSTObjectValue *)transformObject:(FSTObjectValue *)objectValue - transformResults:(NSArray *)transformResults { - HARD_ASSERT(transformResults.count == self.fieldTransforms.size(), - "Transform results length mismatch."); - - for (size_t i = 0; i < self.fieldTransforms.size(); i++) { - const FieldTransform &fieldTransform = self.fieldTransforms[i]; - const FieldPath &fieldPath = fieldTransform.path(); - objectValue = [objectValue objectBySettingValue:transformResults[i] forPath:fieldPath]; - } - return objectValue; -} - -- (const FieldMask *)fieldMask { - return &_fieldMask; -} - -- (BOOL)idempotent { - for (const auto &transform : self.fieldTransforms) { - if (!transform.idempotent()) { - return NO; - } - } - return YES; -} - -@end - -#pragma mark - FSTDeleteMutation - -@implementation FSTDeleteMutation - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isKindOfClass:[FSTDeleteMutation class]]) { - return NO; - } - - FSTDeleteMutation *otherMutation = (FSTDeleteMutation *)other; - return self.key == otherMutation.key && self.precondition == otherMutation.precondition; -} - -- (NSUInteger)hash { - return Hash(self.key, self.precondition); -} - -- (NSString *)description { - return [NSString stringWithFormat:@"", - self.key.ToString().c_str(), self.precondition.description()]; -} - -- (nullable FSTMaybeDocument *)applyToLocalDocument:(nullable FSTMaybeDocument *)maybeDoc - baseDocument:(nullable FSTMaybeDocument *)baseDoc - localWriteTime:(FIRTimestamp *)localWriteTime { - [self verifyKeyMatches:maybeDoc]; - - if (!self.precondition.IsValidFor(maybeDoc)) { - return maybeDoc; - } - - return [FSTDeletedDocument documentWithKey:self.key - version:SnapshotVersion::None() - hasCommittedMutations:NO]; -} - -- (FSTMaybeDocument *)applyToRemoteDocument:(nullable FSTMaybeDocument *)maybeDoc - mutationResult:(FSTMutationResult *)mutationResult { - [self verifyKeyMatches:maybeDoc]; - - if (mutationResult) { - HARD_ASSERT(!mutationResult.transformResults, - "Transform results received by FSTDeleteMutation."); - } - - // Unlike applyToLocalView, if we're applying a mutation to a remote document the server has - // accepted the mutation so the precondition must have held. - - // We store the deleted document at the commit version of the delete. Any document version - // that the server sends us before the delete was applied is discarded - return [FSTDeletedDocument documentWithKey:self.key - version:mutationResult.version - hasCommittedMutations:YES]; -} - -- (const FieldMask *)fieldMask { - return nullptr; -} - -- (BOOL)idempotent { - return YES; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTMutationBatch.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTMutationBatch.h deleted file mode 100644 index af07fcb..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTMutationBatch.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include -#include - -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" -#include "Firestore/core/src/firebase/firestore/model/document_map.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" - -@class FIRTimestamp; -@class FSTMaybeDocument; -@class FSTMutation; -@class FSTMutationResult; -@class FSTMutationBatchResult; - -namespace firebase { -namespace firestore { -namespace model { - -// TODO(wilhuff): make this type a member of MutationBatchResult once that's a C++ class. -using DocumentVersionMap = std::unordered_map; - -} // namespace model -} // namespace firestore -} // namespace firebase - -NS_ASSUME_NONNULL_BEGIN - -/** - * A batch of mutations that will be sent as one unit to the backend. Batches can be marked as a - * tombstone if the mutation queue does not remove them immediately. When a batch is a tombstone - * it has no mutations. - */ -@interface FSTMutationBatch : NSObject - -/** - * Initializes a mutation batch with the given batchID, localWriteTime, base mutations, and - * mutations. - */ -- (instancetype)initWithBatchID:(firebase::firestore::model::BatchId)batchID - localWriteTime:(FIRTimestamp *)localWriteTime - baseMutations:(std::vector &&)baseMutations - mutations:(std::vector &&)mutations NS_DESIGNATED_INITIALIZER; - -- (id)init NS_UNAVAILABLE; - -/** - * Applies all the mutations in this FSTMutationBatch to the specified document to create a new - * remote document. - * - * @param maybeDoc The document to apply mutations to. - * @param documentKey The key of the document to apply mutations to. - * @param mutationBatchResult The result of applying the MutationBatch to the backend. If omitted - * it's assumed that this is a local (latency-compensated) application and documents will have - * their hasLocalMutations flag set. - */ -- (FSTMaybeDocument *_Nullable) - applyToRemoteDocument:(FSTMaybeDocument *_Nullable)maybeDoc - documentKey:(const firebase::firestore::model::DocumentKey &)documentKey - mutationBatchResult:(FSTMutationBatchResult *_Nullable)mutationBatchResult; - -/** - * A helper version of applyTo for applying mutations locally (without a mutation batch result from - * the backend). - */ -- (FSTMaybeDocument *_Nullable) - applyToLocalDocument:(FSTMaybeDocument *_Nullable)maybeDoc - documentKey:(const firebase::firestore::model::DocumentKey &)documentKey; - -/** Computes the local view for all provided documents given the mutations in this batch. */ -- (firebase::firestore::model::MaybeDocumentMap)applyToLocalDocumentSet: - (const firebase::firestore::model::MaybeDocumentMap &)documentSet; - -/** Returns the set of unique keys referenced by all mutations in the batch. */ -- (firebase::firestore::model::DocumentKeySet)keys; - -/** The unique ID of this mutation batch. */ -@property(nonatomic, assign, readonly) firebase::firestore::model::BatchId batchID; - -/** The original write time of this mutation. */ -@property(nonatomic, strong, readonly) FIRTimestamp *localWriteTime; - -/** - * Mutations that are used to populate the base values when this mutation is applied locally. This - * can be used to locally overwrite values that are persisted in the remote document cache. Base - * mutations are never sent to the backend. - */ -- (const std::vector &)baseMutations; - -/** - * The user-provided mutations in this mutation batch. User-provided mutations are applied both - * locally and remotely on the backend. - */ -- (const std::vector &)mutations; - -@end - -#pragma mark - FSTMutationBatchResult - -/** The result of applying a mutation batch to the backend. */ -@interface FSTMutationBatchResult : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -/** - * Creates a new FSTMutationBatchResult for the given batch and results. There must be one result - * for each mutation in the batch. This static factory caches a document=>version mapping - * (as docVersions). - */ -+ (instancetype)resultWithBatch:(FSTMutationBatch *)batch - commitVersion:(firebase::firestore::model::SnapshotVersion)commitVersion - mutationResults:(std::vector)mutationResults - streamToken:(nullable NSData *)streamToken; - -- (const firebase::firestore::model::SnapshotVersion &)commitVersion; -- (const std::vector &)mutationResults; - -@property(nonatomic, strong, readonly) FSTMutationBatch *batch; -@property(nonatomic, strong, readonly, nullable) NSData *streamToken; - -- (const firebase::firestore::model::DocumentVersionMap &)docVersions; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTMutationBatch.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTMutationBatch.mm deleted file mode 100644 index 2d1e2c3..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Model/FSTMutationBatch.mm +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Model/FSTMutationBatch.h" - -#include -#include - -#import "FIRTimestamp.h" - -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Model/FSTMutation.h" - -#include "Firestore/core/src/firebase/firestore/model/document_map.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/hashing.h" -#include "Firestore/core/src/firebase/firestore/util/objc_compatibility.h" - -namespace objc = firebase::firestore::util::objc; -using firebase::firestore::model::BatchId; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::DocumentKeyHash; -using firebase::firestore::model::DocumentKeySet; -using firebase::firestore::model::DocumentVersionMap; -using firebase::firestore::model::MaybeDocumentMap; -using firebase::firestore::model::SnapshotVersion; -using firebase::firestore::util::Hash; - -NS_ASSUME_NONNULL_BEGIN - -@implementation FSTMutationBatch { - std::vector _baseMutations; - std::vector _mutations; -} - -- (instancetype)initWithBatchID:(BatchId)batchID - localWriteTime:(FIRTimestamp *)localWriteTime - baseMutations:(std::vector &&)baseMutations - mutations:(std::vector &&)mutations { - HARD_ASSERT(!mutations.empty(), "Cannot create an empty mutation batch"); - self = [super init]; - if (self) { - _batchID = batchID; - _localWriteTime = localWriteTime; - _baseMutations = std::move(baseMutations); - _mutations = std::move(mutations); - } - return self; -} - -- (const std::vector &)baseMutations { - return _baseMutations; -} - -- (const std::vector &)mutations { - return _mutations; -} - -- (BOOL)isEqual:(id)other { - if (self == other) { - return YES; - } else if (![other isKindOfClass:[FSTMutationBatch class]]) { - return NO; - } - - FSTMutationBatch *otherBatch = (FSTMutationBatch *)other; - return self.batchID == otherBatch.batchID && - [self.localWriteTime isEqual:otherBatch.localWriteTime] && - objc::Equals(_baseMutations, otherBatch.baseMutations) && - objc::Equals(_mutations, otherBatch.mutations); -} - -- (NSUInteger)hash { - NSUInteger result = (NSUInteger)self.batchID; - result = result * 31 + self.localWriteTime.hash; - for (FSTMutation *mutation : _baseMutations) { - result = result * 31 + [mutation hash]; - } - for (FSTMutation *mutation : _mutations) { - result = result * 31 + [mutation hash]; - } - return result; -} - -- (NSString *)description { - return - [NSString stringWithFormat:@"", - self.batchID, self.localWriteTime, objc::Description(_mutations)]; -} - -- (FSTMaybeDocument *_Nullable)applyToRemoteDocument:(FSTMaybeDocument *_Nullable)maybeDoc - documentKey:(const DocumentKey &)documentKey - mutationBatchResult: - (FSTMutationBatchResult *_Nullable)mutationBatchResult { - HARD_ASSERT(!maybeDoc || maybeDoc.key == documentKey, - "applyTo: key %s doesn't match maybeDoc key %s", documentKey.ToString(), - maybeDoc.key.ToString()); - - HARD_ASSERT(mutationBatchResult.mutationResults.size() == _mutations.size(), - "Mismatch between mutations length (%s) and results length (%s)", _mutations.size(), - mutationBatchResult.mutationResults.size()); - - for (size_t i = 0; i < _mutations.size(); i++) { - FSTMutation *mutation = _mutations[i]; - FSTMutationResult *mutationResult = mutationBatchResult.mutationResults[i]; - if (mutation.key == documentKey) { - maybeDoc = [mutation applyToRemoteDocument:maybeDoc mutationResult:mutationResult]; - } - } - return maybeDoc; -} - -- (FSTMaybeDocument *_Nullable)applyToLocalDocument:(FSTMaybeDocument *_Nullable)maybeDoc - documentKey:(const DocumentKey &)documentKey { - HARD_ASSERT(!maybeDoc || maybeDoc.key == documentKey, - "applyTo: key %s doesn't match maybeDoc key %s", documentKey.ToString(), - maybeDoc.key.ToString()); - - // First, apply the base state. This allows us to apply non-idempotent transform against a - // consistent set of values. - for (FSTMutation *mutation : _baseMutations) { - if (mutation.key == documentKey) { - maybeDoc = [mutation applyToLocalDocument:maybeDoc - baseDocument:maybeDoc - localWriteTime:self.localWriteTime]; - } - } - - FSTMaybeDocument *baseDoc = maybeDoc; - - // Second, apply all user-provided mutations. - for (FSTMutation *mutation : _mutations) { - if (mutation.key == documentKey) { - maybeDoc = [mutation applyToLocalDocument:maybeDoc - baseDocument:baseDoc - localWriteTime:self.localWriteTime]; - } - } - return maybeDoc; -} - -- (MaybeDocumentMap)applyToLocalDocumentSet:(const MaybeDocumentMap &)documentSet { - // TODO(mrschmidt): This implementation is O(n^2). If we iterate through the mutations first (as - // done in `applyToLocalDocument:documentKey:`), we can reduce the complexity to O(n). - - MaybeDocumentMap mutatedDocuments = documentSet; - for (FSTMutation *mutation : _mutations) { - const DocumentKey &key = mutation.key; - auto maybeDocument = mutatedDocuments.find(key); - FSTMaybeDocument *mutatedDocument = [self - applyToLocalDocument:(maybeDocument != mutatedDocuments.end() ? maybeDocument->second : nil) - documentKey:key]; - if (mutatedDocument) { - mutatedDocuments = mutatedDocuments.insert(key, mutatedDocument); - } - } - return mutatedDocuments; -} - -- (DocumentKeySet)keys { - DocumentKeySet set; - for (FSTMutation *mutation : _mutations) { - set = set.insert(mutation.key); - } - return set; -} - -@end - -#pragma mark - FSTMutationBatchResult - -@interface FSTMutationBatchResult () -- (instancetype)initWithBatch:(FSTMutationBatch *)batch - commitVersion:(SnapshotVersion)commitVersion - mutationResults:(std::vector)mutationResults - streamToken:(nullable NSData *)streamToken - docVersions:(DocumentVersionMap)docVersions NS_DESIGNATED_INITIALIZER; -@end - -@implementation FSTMutationBatchResult { - SnapshotVersion _commitVersion; - std::vector _mutationResults; - DocumentVersionMap _docVersions; -} - -- (instancetype)initWithBatch:(FSTMutationBatch *)batch - commitVersion:(SnapshotVersion)commitVersion - mutationResults:(std::vector)mutationResults - streamToken:(nullable NSData *)streamToken - docVersions:(DocumentVersionMap)docVersions { - if (self = [super init]) { - _batch = batch; - _commitVersion = std::move(commitVersion); - _mutationResults = std::move(mutationResults); - _streamToken = streamToken; - _docVersions = std::move(docVersions); - } - return self; -} - -- (const SnapshotVersion &)commitVersion { - return _commitVersion; -} - -- (const std::vector &)mutationResults { - return _mutationResults; -} - -- (const DocumentVersionMap &)docVersions { - return _docVersions; -} - -+ (instancetype)resultWithBatch:(FSTMutationBatch *)batch - commitVersion:(SnapshotVersion)commitVersion - mutationResults:(std::vector)mutationResults - streamToken:(nullable NSData *)streamToken { - HARD_ASSERT(batch.mutations.size() == mutationResults.size(), - "Mutations sent %s must equal results received %s", batch.mutations.size(), - mutationResults.size()); - - DocumentVersionMap docVersions; - std::vector mutations = batch.mutations; - for (size_t i = 0; i < mutations.size(); i++) { - absl::optional version = mutationResults[i].version; - if (!version) { - // deletes don't have a version, so we substitute the commitVersion - // of the entire batch. - version = commitVersion; - } - - docVersions[mutations[i].key] = version.value(); - } - - return [[FSTMutationBatchResult alloc] initWithBatch:batch - commitVersion:std::move(commitVersion) - mutationResults:std::move(mutationResults) - streamToken:streamToken - docVersions:std::move(docVersions)]; -} - -@end -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRCollectionReference.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRCollectionReference.h index 39be000..6623f51 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRCollectionReference.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRCollectionReference.h @@ -66,7 +66,7 @@ NS_SWIFT_NAME(CollectionReference) - (FIRDocumentReference *)documentWithPath:(NSString *)documentPath NS_SWIFT_NAME(document(_:)); /** - * Add a new document to this collection with the specified data, assigning it a document ID + * Adds a new document to this collection with the specified data, assigning it a document ID * automatically. * * @param data An `NSDictionary` containing the data for the new document. @@ -77,7 +77,7 @@ NS_SWIFT_NAME(CollectionReference) NS_SWIFT_NAME(addDocument(data:)); /** - * Add a new document to this collection with the specified data, assigning it a document ID + * Adds a new document to this collection with the specified data, assigning it a document ID * automatically. * * @param data An `NSDictionary` containing the data for the new document. diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRDocumentChange.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRDocumentChange.h index 3e4a012..1acff35 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRDocumentChange.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRDocumentChange.h @@ -20,8 +20,14 @@ NS_ASSUME_NONNULL_BEGIN @class FIRQueryDocumentSnapshot; +#if defined(NS_CLOSED_ENUM) /** An enumeration of document change types. */ -typedef NS_ENUM(NSInteger, FIRDocumentChangeType) { +typedef NS_CLOSED_ENUM(NSInteger, FIRDocumentChangeType) +#else +/** An enumeration of document change types. */ +typedef NS_ENUM(NSInteger, FIRDocumentChangeType) +#endif +{ /** Indicates a new document was added to the set of documents matching the query. */ FIRDocumentChangeTypeAdded, /** Indicates a document within the query was modified. */ diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRDocumentReference.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRDocumentReference.h index c110bcd..6afba82 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRDocumentReference.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRDocumentReference.h @@ -25,6 +25,9 @@ NS_ASSUME_NONNULL_BEGIN +/** + * A block type used to handle snapshot updates. + */ typedef void (^FIRDocumentSnapshotBlock)(FIRDocumentSnapshot *_Nullable snapshot, NSError *_Nullable error); diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRDocumentSnapshot.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRDocumentSnapshot.h index 9a3f61b..5d9fd31 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRDocumentSnapshot.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRDocumentSnapshot.h @@ -79,7 +79,7 @@ NS_SWIFT_NAME(DocumentSnapshot) * exist. * * Server-provided timestamps that have not yet been set to their final value will be returned as - * `NSNull`. You can use `dataWithOptions()` to configure this behavior. + * `NSNull`. You can use `dataWithServerTimestampBehavior()` to configure this behavior. * * @return An `NSDictionary` containing all fields in the document or `nil` if the document doesn't * exist. @@ -103,7 +103,7 @@ NS_SWIFT_NAME(DocumentSnapshot) * exist. * * The timestamps that have not yet been set to their final value will be returned as `NSNull`. The - * can use `get(_:options:)` to configure this behavior. + * can use `get(_:serverTimestampBehavior:)` to configure this behavior. * * @param field The field to retrieve. * @return The value contained in the field or `nil` if the document or field doesn't exist. @@ -115,7 +115,7 @@ NS_SWIFT_NAME(DocumentSnapshot) * exist. * * The timestamps that have not yet been set to their final value will be returned as `NSNull`. The - * can use `get(_:options:)` to configure this behavior. + * can use `get(_:serverTimestampBehavior:)` to configure this behavior. * * @param field The field to retrieve. * @param serverTimestampBehavior Configures how server timestamps that have not yet been set to @@ -159,7 +159,7 @@ NS_SWIFT_NAME(QueryDocumentSnapshot) * Retrieves all fields in the document as an `NSDictionary`. * * Server-provided timestamps that have not yet been set to their final value will be returned as - * `NSNull`. You can use `dataWithOptions()` to configure this behavior. + * `NSNull`. You can use `dataWithServerTimestampBehavior()` to configure this behavior. * * @return An `NSDictionary` containing all fields in the document. */ diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFieldPath.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFieldPath.h index 3445f2e..9f64fbd 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFieldPath.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFieldPath.h @@ -26,6 +26,7 @@ NS_ASSUME_NONNULL_BEGIN NS_SWIFT_NAME(FieldPath) @interface FIRFieldPath : NSObject +/** :nodoc: */ - (instancetype)init NS_UNAVAILABLE; /** diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFirestore.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFirestore.h index cd9302c..e232d4e 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFirestore.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFirestore.h @@ -16,6 +16,8 @@ #import +#import "FIRListenerRegistration.h" + @class FIRApp; @class FIRCollectionReference; @class FIRDocumentReference; @@ -92,12 +94,28 @@ NS_SWIFT_NAME(Firestore) */ - (FIRDocumentReference *)documentWithPath:(NSString *)documentPath NS_SWIFT_NAME(document(_:)); +#pragma mark - Collection Group Queries + +/** + * Creates and returns a new `Query` that includes all documents in the database that are contained + * in a collection or subcollection with the given collectionID. + * + * @param collectionID Identifies the collections to query over. Every collection or subcollection + * with this ID as the last segment of its path will be included. Cannot contain a slash. + * @return The created `Query`. + */ +- (FIRQuery *)collectionGroupWithID:(NSString *)collectionID NS_SWIFT_NAME(collectionGroup(_:)); + #pragma mark - Transactions and Write Batches /** * Executes the given updateBlock and then attempts to commit the changes applied within an atomic * transaction. * + * The maximum number of writes allowed in a single transaction is 500, but note that each usage of + * `FieldValue.serverTimestamp()`, `FieldValue.arrayUnion()`, `FieldValue.arrayRemove()`, or + * `FieldValue.increment()` inside a transaction counts as an additional write. + * * In the updateBlock, a set of reads and writes can be performed atomically using the * `FIRTransaction` object passed to the block. After the updateBlock is run, Firestore will attempt * to apply the changes to the server. If any of the data read has been modified outside of this @@ -129,6 +147,10 @@ NS_SWIFT_NAME(Firestore) * Creates a write batch, used for performing multiple writes as a single * atomic operation. * + * The maximum number of writes allowed in a single batch is 500, but note that each usage of + * `FieldValue.serverTimestamp()`, `FieldValue.arrayUnion()`, `FieldValue.arrayRemove()`, or + * `FieldValue.increment()` inside a batch counts as an additional write. + * Unlike transactions, write batches are persisted offline and therefore are preferable when you * don't need to condition your writes on read data. */ @@ -137,9 +159,7 @@ NS_SWIFT_NAME(Firestore) #pragma mark - Logging /** Enables or disables logging from the Firestore client. */ -+ (void)enableLogging:(BOOL)logging - DEPRECATED_MSG_ATTRIBUTE("Use FirebaseConfiguration.shared.setLoggerLevel(.debug) to enable " - "logging."); ++ (void)enableLogging:(BOOL)logging; #pragma mark - Network @@ -158,6 +178,83 @@ NS_SWIFT_NAME(Firestore) */ - (void)disableNetworkWithCompletion:(nullable void (^)(NSError *_Nullable error))completion; +/** + * Clears the persistent storage. This includes pending writes and cached documents. + * + * Must be called while the firestore instance is not started (after the app is shutdown or when + * the app is first initialized). On startup, this method must be called before other methods + * (other than `FIRFirestore.settings`). If the firestore instance is still running, the function + * will complete with an error code of `FailedPrecondition`. + * + * Note: `clearPersistence(completion:)` is primarily intended to help write reliable tests that + * use Firestore. It uses the most efficient mechanism possible for dropping existing data but + * does not attempt to securely overwrite or otherwise make cached data unrecoverable. For + * applications that are sensitive to the disclosure of cache data in between user sessions we + * strongly recommend not to enable persistence in the first place. + */ +- (void)clearPersistenceWithCompletion:(nullable void (^)(NSError *_Nullable error))completion; + +/** + * Waits until all currently pending writes for the active user have been acknowledged by the + * backend. + * + * The completion block is called immediately without error if there are no outstanding writes. + * Otherwise, the completion block is called when all previously issued writes (including those + * written in a previous app session) have been acknowledged by the backend. The completion + * block does not wait for writes that were added after the method is called. If you + * wish to wait for additional writes, you have to call `waitForPendingWritesWithCompletion` + * again. + * + * Any outstanding `waitForPendingWritesWithCompletion` completion blocks are called with an + * error during user change. + */ +- (void)waitForPendingWritesWithCompletion:(void (^)(NSError *_Nullable error))completion; + +/** + * Attaches a listener for a snapshots-in-sync event. Server-generated + * updates and local changes can affect multiple snapshot listeners. + * The snapshots-in-sync event indicates that all listeners affected by + * a given change have fired. + * + * NOTE: The snapshots-in-sync event only indicates that listeners are + * in sync with each other, but does not relate to whether those + * snapshots are in sync with the server. Use SnapshotMetadata in the + * individual listeners to determine if a snapshot is from the cache or + * the server. + * + * @param listener A callback to be called every time all snapshot + * listeners are in sync with each other. + * @return A FIRListenerRegistration object that can be used to remove the + * listener. + */ +- (id)addSnapshotsInSyncListener:(void (^)(void))listener + NS_SWIFT_NAME(addSnapshotsInSyncListener(_:)); + +#pragma mark - Terminating + +/** + * Terminates this `FIRFirestore` instance. + * + * After calling `terminate` only the `clearPersistence` method may be used. Any other method + * will throw an error. + * + * To restart after termination, simply create a new instance of FIRFirestore with + * `firestore` or `firestoreForApp` methods. + * + * Termination does not cancel any pending writes and any tasks that are awaiting a response from + * the server will not be resolved. The next time you start this instance, it will resume + * attempting to send these writes to the server. + * + * Note: Under normal circumstances, calling this method is not required. This + * method is useful only when you want to force this instance to release all of its resources or + * in combination with `clearPersistence` to ensure that all local state is destroyed + * between test runs. + * + * @param completion A block to execute once everything has been terminated. + */ +- (void)terminateWithCompletion:(nullable void (^)(NSError *_Nullable error))completion + NS_SWIFT_NAME(terminate(completion:)); + @end NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFirestoreSettings.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFirestoreSettings.h index 13ef56c..d12e387 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFirestoreSettings.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFirestoreSettings.h @@ -19,7 +19,8 @@ NS_ASSUME_NONNULL_BEGIN /** Used to set on-disk cache size to unlimited. Garbage collection will not run. */ -extern const int64_t kFIRFirestoreCacheSizeUnlimited NS_SWIFT_NAME(FirestoreCacheSizeUnlimited); +FOUNDATION_EXTERN const int64_t kFIRFirestoreCacheSizeUnlimited + NS_SWIFT_NAME(FirestoreCacheSizeUnlimited); /** Settings used to configure a `FIRFirestore` instance. */ NS_SWIFT_NAME(FirestoreSettings) diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFirestoreSource.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFirestoreSource.h index c133747..16a65cc 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFirestoreSource.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRFirestoreSource.h @@ -22,27 +22,32 @@ * methods can be configured to fetch results only from the server, only from * the local cache, or attempt to fetch results from the server and fall back to * the cache (which is the default). - * - * Setting the source to `Source.default` causes Firestore to try to retrieve an - * up-to-date (server-retrieved) snapshot, but fall back to returning cached - * data if the server can't be reached. - * - * Setting the source to `Source.server` causes Firestore to avoid the cache, - * generating an error if the server cannot be reached. Note that the cache will - * still be updated if the server request succeeds. Also note that - * latency-compensation still takes effect, so any pending write operations will - * be visible in the returned data (merged into the server-provided data). - * - * Setting the source to `Source.cache` causes Firestore to immediately return a - * value from the cache, ignoring the server completely (implying that the - * returned value may be stale with respect to the value on the server). If - * there is no data in the cache to satisfy the `getDocument[s]` call, - * `DocumentReference.getDocument()` will return an error and - * `QuerySnapshot.getDocuments()` will return an empty `QuerySnapshot` with no - * documents. */ typedef NS_ENUM(NSUInteger, FIRFirestoreSource) { + + /** + * Causes Firestore to try to retrieve an up-to-date (server-retrieved) + * snapshot, but fall back to returning cached data if the server can't be + * reached. + */ FIRFirestoreSourceDefault, + + /** + * Causes Firestore to avoid the cache, generating an error if the server + * cannot be reached. Note that the cache will still be updated if the + * server request succeeds. Also note that latency-compensation still takes + * effect, so any pending write operations will be visible in the returned + * data (merged into the server-provided data). + */ FIRFirestoreSourceServer, + + /** + * Causes Firestore to immediately return a value from the cache, ignoring + * the server completely (implying that the returned value may be stale with + * respect to the value on the server). If there is no data in the cache to + * satisfy the `getDocument[s]` call, `DocumentReference.getDocument()` will + * return an error and `QuerySnapshot.getDocuments()` will return an empty + * `QuerySnapshot` with no documents. + */ FIRFirestoreSourceCache } NS_SWIFT_NAME(FirestoreSource); diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRGeoPoint.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRGeoPoint.h index 290b2b4..4454225 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRGeoPoint.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRGeoPoint.h @@ -39,7 +39,14 @@ NS_SWIFT_NAME(GeoPoint) - (instancetype)initWithLatitude:(double)latitude longitude:(double)longitude NS_DESIGNATED_INITIALIZER; +/** + * The point's latitude. Must be a value between -90 and 90 (inclusive). + */ @property(nonatomic, readonly) double latitude; + +/** + * The point's longitude. Must be a value between -180 and 180 (inclusive). + */ @property(nonatomic, readonly) double longitude; @end diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRQuery.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRQuery.h index 436c185..a9da2fb 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRQuery.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRQuery.h @@ -26,6 +26,9 @@ NS_ASSUME_NONNULL_BEGIN +/** + * A block type used to handle failable snapshot method callbacks. + */ typedef void (^FIRQuerySnapshotBlock)(FIRQuerySnapshot *_Nullable snapshot, NSError *_Nullable error); @@ -65,11 +68,9 @@ NS_SWIFT_NAME(Query) * @param completion a block to execute once the documents have been successfully read. * documentSet will be `nil` only if error is `non-nil`. */ -// clang-format off - (void)getDocumentsWithSource:(FIRFirestoreSource)source completion:(FIRQuerySnapshotBlock)completion NS_SWIFT_NAME(getDocuments(source:completion:)); -// clang-format on /** * Attaches a listener for QuerySnapshot events. @@ -90,12 +91,10 @@ NS_SWIFT_NAME(Query) * * @return A FIRListenerRegistration that can be used to remove this listener. */ -// clang-format off - (id) -addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges - listener:(FIRQuerySnapshotBlock)listener + addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges + listener:(FIRQuerySnapshotBlock)listener NS_SWIFT_NAME(addSnapshotListener(includeMetadataChanges:listener:)); -// clang-format on #pragma mark - Filtering Data /** @@ -107,10 +106,8 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryWhereField:(NSString *)field isEqualTo:(id)value NS_SWIFT_NAME(whereField(_:isEqualTo:)); -// clang-format on /** * Creates and returns a new `FIRQuery` with the additional filter that documents must @@ -121,10 +118,8 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path isEqualTo:(id)value NS_SWIFT_NAME(whereField(_:isEqualTo:)); -// clang-format on /** * Creates and returns a new `FIRQuery` with the additional filter that documents must @@ -135,10 +130,8 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryWhereField:(NSString *)field isLessThan:(id)value NS_SWIFT_NAME(whereField(_:isLessThan:)); -// clang-format on /** * Creates and returns a new `FIRQuery` with the additional filter that documents must @@ -149,10 +142,8 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path isLessThan:(id)value NS_SWIFT_NAME(whereField(_:isLessThan:)); -// clang-format on /** * Creates and returns a new `FIRQuery` with the additional filter that documents must @@ -163,10 +154,8 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryWhereField:(NSString *)field isLessThanOrEqualTo:(id)value NS_SWIFT_NAME(whereField(_:isLessThanOrEqualTo:)); -// clang-format on /** * Creates and returns a new `FIRQuery` with the additional filter that documents must @@ -177,10 +166,8 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path isLessThanOrEqualTo:(id)value NS_SWIFT_NAME(whereField(_:isLessThanOrEqualTo:)); -// clang-format on /** * Creates and returns a new `FIRQuery` with the additional filter that documents must @@ -191,10 +178,8 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryWhereField:(NSString *)field isGreaterThan:(id)value NS_SWIFT_NAME(whereField(_:isGreaterThan:)); -// clang-format on /** * Creates and returns a new `FIRQuery` with the additional filter that documents must @@ -205,10 +190,8 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path isGreaterThan:(id)value NS_SWIFT_NAME(whereField(_:isGreaterThan:)); -// clang-format on /** * Creates and returns a new `FIRQuery` with the additional filter that documents must @@ -219,10 +202,8 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryWhereField:(NSString *)field isGreaterThanOrEqualTo:(id)value NS_SWIFT_NAME(whereField(_:isGreaterThanOrEqualTo:)); -// clang-format on /** * Creates and returns a new `FIRQuery` with the additional filter that documents must @@ -233,10 +214,8 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path isGreaterThanOrEqualTo:(id)value NS_SWIFT_NAME(whereField(_:isGreaterThanOrEqualTo:)); -// clang-format on /** * Creates and returns a new `FIRQuery` with the additional filter that documents must contain @@ -249,10 +228,8 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryWhereField:(NSString *)field arrayContains:(id)value NS_SWIFT_NAME(whereField(_:arrayContains:)); -// clang-format on /** * Creates and returns a new `FIRQuery` with the additional filter that documents must contain @@ -265,10 +242,71 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path arrayContains:(id)value NS_SWIFT_NAME(whereField(_:arrayContains:)); -// clang-format on + +/** + * Creates and returns a new `FIRQuery` with the additional filter that documents must contain + * the specified field, the value must be an array, and that array must contain at least one value + * from the provided array. + * + * A query can have only one `arrayContainsAny` filter and it cannot be combined with + * `arrayContains` or `in` filters. + * + * @param field The name of the field containing an array to search. + * @param values The array that contains the values to match. + * + * @return The created `FIRQuery`. + */ +- (FIRQuery *)queryWhereField:(NSString *)field + arrayContainsAny:(NSArray *)values NS_SWIFT_NAME(whereField(_:arrayContainsAny:)); + +/** + * Creates and returns a new `FIRQuery` with the additional filter that documents must contain + * the specified field, the value must be an array, and that array must contain at least one value + * from the provided array. + * + * A query can have only one `arrayContainsAny` filter and it cannot be combined with + * `arrayContains` or `in` filters. + * + * @param path The path of the field containing an array to search. + * @param values The array that contains the values to match. + * + * @return The created `FIRQuery`. + */ +- (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path + arrayContainsAny:(NSArray *)values + NS_SWIFT_NAME(whereField(_:arrayContainsAny:)); + +/** + * Creates and returns a new `FIRQuery` with the additional filter that documents must contain + * the specified field and the value must equal one of the values from the provided array. + * + * A query can have only one `in` filter, and it cannot be combined with an `arrayContainsAny` + * filter. + * + * @param field The name of the field to search. + * @param values The array that contains the values to match. + * + * @return The created `FIRQuery`. + */ +- (FIRQuery *)queryWhereField:(NSString *)field + in:(NSArray *)values NS_SWIFT_NAME(whereField(_:in:)); + +/** + * Creates and returns a new `FIRQuery` with the additional filter that documents must contain + * the specified field and the value must equal one of the values from the provided array. + * + * A query can have only one `in` filter, and it cannot be combined with an `arrayContainsAny` + * filter. + * + * @param path The path of the field to search. + * @param values The array that contains the values to match. + * + * @return The created `FIRQuery`. + */ +- (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path + in:(NSArray *)values NS_SWIFT_NAME(whereField(_:in:)); /** * Creates and returns a new `FIRQuery` with the additional filter that documents must @@ -279,9 +317,7 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryFilteredUsingPredicate:(NSPredicate *)predicate NS_SWIFT_NAME(filter(using:)); -// clang-format on #pragma mark - Sorting Data /** @@ -311,10 +347,8 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryOrderedByField:(NSString *)field descending:(BOOL)descending NS_SWIFT_NAME(order(by:descending:)); -// clang-format on /** * Creates and returns a new `FIRQuery` that's additionally sorted by the specified field, @@ -325,15 +359,13 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges * * @return The created `FIRQuery`. */ -// clang-format off - (FIRQuery *)queryOrderedByFieldPath:(FIRFieldPath *)path descending:(BOOL)descending NS_SWIFT_NAME(order(by:descending:)); -// clang-format on #pragma mark - Limiting Data /** - * Creates and returns a new `FIRQuery` that's additionally limited to only return up to - * the specified number of documents. + * Creates and returns a new `FIRQuery` that only returns the first matching documents up to + * the specified number. * * @param limit The maximum number of items to return. * @@ -341,6 +373,18 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges */ - (FIRQuery *)queryLimitedTo:(NSInteger)limit NS_SWIFT_NAME(limit(to:)); +/** + * Creates and returns a new `FIRQuery` that only returns the last matching documents up to + * the specified number. + * + * A query with a `limit(ToLast:)` clause must have at least one `orderBy` clause. + * + * @param limit The maximum number of items to return. + * + * @return The created `FIRQuery`. + */ +- (FIRQuery *)queryLimitedToLast:(NSInteger)limit NS_SWIFT_NAME(limit(toLast:)); + #pragma mark - Choosing Endpoints /** * Creates and returns a new `FIRQuery` that starts at the provided document (inclusive). The diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRTimestamp.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRTimestamp.h index cea316b..967d47c 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRTimestamp.h +++ b/Example/Pods/FirebaseFirestore/Firestore/Source/Public/FIRTimestamp.h @@ -62,6 +62,13 @@ NS_SWIFT_NAME(Timestamp) /** Returns a new NSDate corresponding to this timestamp. This may lose precision. */ - (NSDate *)dateValue; +/** + * Returns the result of comparing the receiver with another timestamp. + * @param other the other timestamp to compare. + * @return NSOrderedAscending if `other` is chronologically following self, + * NSOrderedDescending if `other` is chronologically preceding self, + * NSOrderedSame otherwise. + */ - (NSComparisonResult)compare:(FIRTimestamp *)other; /** diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Remote/FSTSerializerBeta.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Remote/FSTSerializerBeta.h deleted file mode 100644 index 4b6c087..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Remote/FSTSerializerBeta.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include - -#include "Firestore/core/include/firebase/firestore/timestamp.h" -#include "Firestore/core/src/firebase/firestore/model/database_id.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" - -@class FSTFieldValue; -@class FSTMaybeDocument; -@class FSTMutation; -@class FSTMutationBatch; -@class FSTMutationResult; -@class FSTObjectValue; -@class FSTQuery; -@class FSTQueryData; - -@class GCFSBatchGetDocumentsResponse; -@class GCFSDocument; -@class GCFSDocumentMask; -@class GCFSListenResponse; -@class GCFSTarget; -@class GCFSTarget_DocumentsTarget; -@class GCFSTarget_QueryTarget; -@class GCFSValue; -@class GCFSWrite; -@class GCFSWriteResult; - -@class GPBTimestamp; - -NS_ASSUME_NONNULL_BEGIN - -/** - * Converts internal model objects to their equivalent protocol buffer form. Methods starting with - * "encoded" convert to a protocol buffer and methods starting with "decoded" convert from a - * protocol buffer. - * - * Throws an exception if a protocol buffer is missing a critical field or has a value we can't - * interpret. - */ -@interface FSTSerializerBeta : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithDatabaseID:(const firebase::firestore::model::DatabaseId *)databaseID - NS_DESIGNATED_INITIALIZER; - -- (GPBTimestamp *)encodedTimestamp:(const firebase::Timestamp &)timestamp; -- (firebase::Timestamp)decodedTimestamp:(GPBTimestamp *)timestamp; - -- (GPBTimestamp *)encodedVersion:(const firebase::firestore::model::SnapshotVersion &)version; -- (firebase::firestore::model::SnapshotVersion)decodedVersion:(GPBTimestamp *)version; - -/** Returns the database ID, such as `projects/{project id}/databases/{database_id}`. */ -- (NSString *)encodedDatabaseID; - -/** - * Encodes the given document key as a fully qualified name. This includes the - * databaseId associated with this FSTSerializerBeta and the key path. - */ -- (NSString *)encodedDocumentKey:(const firebase::firestore::model::DocumentKey &)key; -- (firebase::firestore::model::DocumentKey)decodedDocumentKey:(NSString *)key; - -- (GCFSValue *)encodedFieldValue:(FSTFieldValue *)fieldValue; -- (FSTFieldValue *)decodedFieldValue:(GCFSValue *)valueProto; - -- (GCFSWrite *)encodedMutation:(FSTMutation *)mutation; -- (FSTMutation *)decodedMutation:(GCFSWrite *)mutation; - -- (FSTMutationResult *)decodedMutationResult:(GCFSWriteResult *)mutation - commitVersion:(const firebase::firestore::model::SnapshotVersion &) - commitVersion; - -- (nullable NSMutableDictionary *)encodedListenRequestLabelsForQueryData: - (FSTQueryData *)queryData; - -- (GCFSTarget *)encodedTarget:(FSTQueryData *)queryData; - -- (GCFSTarget_DocumentsTarget *)encodedDocumentsTarget:(FSTQuery *)query; -- (FSTQuery *)decodedQueryFromDocumentsTarget:(GCFSTarget_DocumentsTarget *)target; - -- (GCFSTarget_QueryTarget *)encodedQueryTarget:(FSTQuery *)query; -- (FSTQuery *)decodedQueryFromQueryTarget:(GCFSTarget_QueryTarget *)target; - -- (std::unique_ptr)decodedWatchChange: - (GCFSListenResponse *)watchChange; -- (firebase::firestore::model::SnapshotVersion)versionFromListenResponse: - (GCFSListenResponse *)watchChange; - -- (GCFSDocument *)encodedDocumentWithFields:(FSTObjectValue *)objectValue - key:(const firebase::firestore::model::DocumentKey &)key; - -/** - * Encodes an FSTObjectValue into a dictionary. - * @return a new dictionary that can be assigned to a field in another proto. - */ -- (NSMutableDictionary *)encodedFields:(FSTObjectValue *)value; - -- (FSTObjectValue *)decodedFields:(NSDictionary *)fields; - -- (FSTMaybeDocument *)decodedMaybeDocumentFromBatch:(GCFSBatchGetDocumentsResponse *)response; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Remote/FSTSerializerBeta.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Remote/FSTSerializerBeta.mm deleted file mode 100644 index e111572..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Remote/FSTSerializerBeta.mm +++ /dev/null @@ -1,1227 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Remote/FSTSerializerBeta.h" - -#include -#include -#include -#include -#include - -#import "Firestore/Protos/objc/google/firestore/v1/Common.pbobjc.h" -#import "Firestore/Protos/objc/google/firestore/v1/Document.pbobjc.h" -#import "Firestore/Protos/objc/google/firestore/v1/Firestore.pbobjc.h" -#import "Firestore/Protos/objc/google/firestore/v1/Query.pbobjc.h" -#import "Firestore/Protos/objc/google/firestore/v1/Write.pbobjc.h" -#import "Firestore/Protos/objc/google/rpc/Status.pbobjc.h" -#import "Firestore/Protos/objc/google/type/Latlng.pbobjc.h" - -#import "FIRFirestoreErrors.h" -#import "FIRGeoPoint.h" -#import "FIRTimestamp.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Local/FSTQueryData.h" -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Model/FSTMutationBatch.h" - -#include "Firestore/core/include/firebase/firestore/firestore_errors.h" -#include "Firestore/core/src/firebase/firestore/model/database_id.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/field_mask.h" -#include "Firestore/core/src/firebase/firestore/model/field_path.h" -#include "Firestore/core/src/firebase/firestore/model/field_transform.h" -#include "Firestore/core/src/firebase/firestore/model/precondition.h" -#include "Firestore/core/src/firebase/firestore/model/resource_path.h" -#include "Firestore/core/src/firebase/firestore/model/transform_operations.h" -#include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" -#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" -#include "absl/memory/memory.h" -#include "absl/types/optional.h" - -namespace util = firebase::firestore::util; -using firebase::Timestamp; -using firebase::firestore::FirestoreErrorCode; -using firebase::firestore::model::ArrayTransform; -using firebase::firestore::model::DatabaseId; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::FieldMask; -using firebase::firestore::model::FieldPath; -using firebase::firestore::model::FieldTransform; -using firebase::firestore::model::NumericIncrementTransform; -using firebase::firestore::model::Precondition; -using firebase::firestore::model::ResourcePath; -using firebase::firestore::model::ServerTimestampTransform; -using firebase::firestore::model::SnapshotVersion; -using firebase::firestore::model::TargetId; -using firebase::firestore::model::TransformOperation; -using firebase::firestore::remote::DocumentWatchChange; -using firebase::firestore::remote::ExistenceFilter; -using firebase::firestore::remote::ExistenceFilterWatchChange; -using firebase::firestore::remote::WatchChange; -using firebase::firestore::remote::WatchTargetChange; -using firebase::firestore::remote::WatchTargetChangeState; - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTSerializerBeta () -// Does not own this DatabaseId. -@property(nonatomic, assign, readonly) const DatabaseId *databaseID; -@end - -@implementation FSTSerializerBeta - -- (instancetype)initWithDatabaseID:(const DatabaseId *)databaseID { - self = [super init]; - if (self) { - _databaseID = databaseID; - } - return self; -} - -#pragma mark - SnapshotVersion <=> GPBTimestamp - -- (GPBTimestamp *)encodedTimestamp:(const Timestamp &)timestamp { - GPBTimestamp *result = [GPBTimestamp message]; - result.seconds = timestamp.seconds(); - result.nanos = timestamp.nanoseconds(); - return result; -} - -- (Timestamp)decodedTimestamp:(GPBTimestamp *)timestamp { - return Timestamp{timestamp.seconds, timestamp.nanos}; -} - -- (GPBTimestamp *)encodedVersion:(const SnapshotVersion &)version { - return [self encodedTimestamp:version.timestamp()]; -} - -- (SnapshotVersion)decodedVersion:(GPBTimestamp *)version { - return SnapshotVersion{[self decodedTimestamp:version]}; -} - -#pragma mark - FIRGeoPoint <=> GTPLatLng - -- (GTPLatLng *)encodedGeoPoint:(FIRGeoPoint *)geoPoint { - GTPLatLng *latLng = [GTPLatLng message]; - latLng.latitude = geoPoint.latitude; - latLng.longitude = geoPoint.longitude; - return latLng; -} - -- (FIRGeoPoint *)decodedGeoPoint:(GTPLatLng *)latLng { - return [[FIRGeoPoint alloc] initWithLatitude:latLng.latitude longitude:latLng.longitude]; -} - -#pragma mark - DocumentKey <=> Key proto - -- (NSString *)encodedDocumentKey:(const DocumentKey &)key { - return [self encodedResourcePathForDatabaseID:self.databaseID path:key.path()]; -} - -- (DocumentKey)decodedDocumentKey:(NSString *)name { - const ResourcePath path = [self decodedResourcePathWithDatabaseID:name]; - HARD_ASSERT(path[1] == self.databaseID->project_id(), - "Tried to deserialize key from different project."); - HARD_ASSERT(path[3] == self.databaseID->database_id(), - "Tried to deserialize key from different datbase."); - return DocumentKey{[self localResourcePathForQualifiedResourcePath:path]}; -} - -- (NSString *)encodedResourcePathForDatabaseID:(const DatabaseId *)databaseID - path:(const ResourcePath &)path { - return util::WrapNSString([self encodedResourcePathForDatabaseID:databaseID] - .Append("documents") - .Append(path) - .CanonicalString()); -} - -- (ResourcePath)decodedResourcePathWithDatabaseID:(NSString *)name { - const ResourcePath path = ResourcePath::FromString(util::MakeString(name)); - HARD_ASSERT([self validQualifiedResourcePath:path], "Tried to deserialize invalid key %s", - path.CanonicalString()); - return path; -} - -- (NSString *)encodedQueryPath:(const ResourcePath &)path { - return [self encodedResourcePathForDatabaseID:self.databaseID path:path]; -} - -- (ResourcePath)decodedQueryPath:(NSString *)name { - const ResourcePath resource = [self decodedResourcePathWithDatabaseID:name]; - if (resource.size() == 4) { - // In v1beta1 queries for collections at the root did not have a trailing "/documents". In v1 - // all resource paths contain "/documents". Preserve the ability to read the v1beta1 form for - // compatibility with queries persisted in the local query cache. - return ResourcePath{}; - } else { - return [self localResourcePathForQualifiedResourcePath:resource]; - } -} - -- (ResourcePath)encodedResourcePathForDatabaseID:(const DatabaseId *)databaseID { - return ResourcePath{"projects", databaseID->project_id(), "databases", databaseID->database_id()}; -} - -- (ResourcePath)localResourcePathForQualifiedResourcePath:(const ResourcePath &)resourceName { - HARD_ASSERT(resourceName.size() > 4 && resourceName[4] == "documents", - "Tried to deserialize invalid key %s", resourceName.CanonicalString()); - return resourceName.PopFirst(5); -} - -- (BOOL)validQualifiedResourcePath:(const ResourcePath &)path { - return path.size() >= 4 && path[0] == "projects" && path[2] == "databases"; -} - -- (NSString *)encodedDatabaseID { - return util::WrapNSString( - [self encodedResourcePathForDatabaseID:self.databaseID].CanonicalString()); -} - -#pragma mark - FSTFieldValue <=> Value proto - -- (GCFSValue *)encodedFieldValue:(FSTFieldValue *)fieldValue { - Class fieldClass = [fieldValue class]; - if (fieldClass == [FSTNullValue class]) { - return [self encodedNull]; - - } else if (fieldClass == [FSTBooleanValue class]) { - return [self encodedBool:[[fieldValue value] boolValue]]; - - } else if (fieldClass == [FSTIntegerValue class]) { - return [self encodedInteger:[[fieldValue value] longLongValue]]; - - } else if (fieldClass == [FSTDoubleValue class]) { - return [self encodedDouble:[[fieldValue value] doubleValue]]; - - } else if (fieldClass == [FSTStringValue class]) { - return [self encodedString:[fieldValue value]]; - - } else if (fieldClass == [FSTTimestampValue class]) { - FIRTimestamp *value = static_cast([fieldValue value]); - return [self encodedTimestampValue:Timestamp{value.seconds, value.nanoseconds}]; - } else if (fieldClass == [FSTGeoPointValue class]) { - return [self encodedGeoPointValue:[fieldValue value]]; - - } else if (fieldClass == [FSTBlobValue class]) { - return [self encodedBlobValue:[fieldValue value]]; - - } else if (fieldClass == [FSTReferenceValue class]) { - FSTReferenceValue *ref = (FSTReferenceValue *)fieldValue; - DocumentKey key = [[ref value] key]; - return [self encodedReferenceValueForDatabaseID:[ref databaseID] key:key]; - - } else if (fieldClass == [FSTObjectValue class]) { - GCFSValue *result = [GCFSValue message]; - result.mapValue = [self encodedMapValue:(FSTObjectValue *)fieldValue]; - return result; - - } else if (fieldClass == [FSTArrayValue class]) { - GCFSValue *result = [GCFSValue message]; - result.arrayValue = [self encodedArrayValue:(FSTArrayValue *)fieldValue]; - return result; - - } else { - HARD_FAIL("Unhandled type %s on %s", NSStringFromClass([fieldValue class]), fieldValue); - } -} - -- (FSTFieldValue *)decodedFieldValue:(GCFSValue *)valueProto { - switch (valueProto.valueTypeOneOfCase) { - case GCFSValue_ValueType_OneOfCase_NullValue: - return [FSTNullValue nullValue]; - - case GCFSValue_ValueType_OneOfCase_BooleanValue: - return [FSTBooleanValue booleanValue:valueProto.booleanValue]; - - case GCFSValue_ValueType_OneOfCase_IntegerValue: - return [FSTIntegerValue integerValue:valueProto.integerValue]; - - case GCFSValue_ValueType_OneOfCase_DoubleValue: - return [FSTDoubleValue doubleValue:valueProto.doubleValue]; - - case GCFSValue_ValueType_OneOfCase_StringValue: - return [FSTStringValue stringValue:valueProto.stringValue]; - - case GCFSValue_ValueType_OneOfCase_TimestampValue: { - Timestamp value = [self decodedTimestamp:valueProto.timestampValue]; - return [FSTTimestampValue - timestampValue:[FIRTimestamp timestampWithSeconds:value.seconds() - nanoseconds:value.nanoseconds()]]; - } - - case GCFSValue_ValueType_OneOfCase_GeoPointValue: - return [FSTGeoPointValue geoPointValue:[self decodedGeoPoint:valueProto.geoPointValue]]; - - case GCFSValue_ValueType_OneOfCase_BytesValue: - return [FSTBlobValue blobValue:valueProto.bytesValue]; - - case GCFSValue_ValueType_OneOfCase_ReferenceValue: - return [self decodedReferenceValue:valueProto.referenceValue]; - - case GCFSValue_ValueType_OneOfCase_ArrayValue: - return [self decodedArrayValue:valueProto.arrayValue]; - - case GCFSValue_ValueType_OneOfCase_MapValue: - return [self decodedMapValue:valueProto.mapValue]; - - default: - HARD_FAIL("Unhandled type %s on %s", valueProto.valueTypeOneOfCase, valueProto); - } -} - -- (GCFSValue *)encodedNull { - GCFSValue *result = [GCFSValue message]; - result.nullValue = GPBNullValue_NullValue; - return result; -} - -- (GCFSValue *)encodedBool:(BOOL)value { - GCFSValue *result = [GCFSValue message]; - result.booleanValue = value; - return result; -} - -- (GCFSValue *)encodedDouble:(double)value { - GCFSValue *result = [GCFSValue message]; - result.doubleValue = value; - return result; -} - -- (GCFSValue *)encodedInteger:(int64_t)value { - GCFSValue *result = [GCFSValue message]; - result.integerValue = value; - return result; -} - -- (GCFSValue *)encodedString:(NSString *)value { - GCFSValue *result = [GCFSValue message]; - result.stringValue = value; - return result; -} - -- (GCFSValue *)encodedTimestampValue:(const Timestamp &)value { - GCFSValue *result = [GCFSValue message]; - result.timestampValue = [self encodedTimestamp:value]; - return result; -} - -- (GCFSValue *)encodedGeoPointValue:(FIRGeoPoint *)value { - GCFSValue *result = [GCFSValue message]; - result.geoPointValue = [self encodedGeoPoint:value]; - return result; -} - -- (GCFSValue *)encodedBlobValue:(NSData *)value { - GCFSValue *result = [GCFSValue message]; - result.bytesValue = value; - return result; -} - -- (GCFSValue *)encodedReferenceValueForDatabaseID:(const DatabaseId *)databaseID - key:(const DocumentKey &)key { - HARD_ASSERT(*databaseID == *self.databaseID, "Database %s:%s cannot encode reference from %s:%s", - self.databaseID->project_id(), self.databaseID->database_id(), - databaseID->project_id(), databaseID->database_id()); - GCFSValue *result = [GCFSValue message]; - result.referenceValue = [self encodedResourcePathForDatabaseID:databaseID path:key.path()]; - return result; -} - -- (FSTReferenceValue *)decodedReferenceValue:(NSString *)resourceName { - const ResourcePath path = [self decodedResourcePathWithDatabaseID:resourceName]; - const std::string &project = path[1]; - const std::string &database = path[3]; - const DocumentKey key{[self localResourcePathForQualifiedResourcePath:path]}; - - const DatabaseId database_id(project, database); - HARD_ASSERT(database_id == *self.databaseID, "Database %s:%s cannot encode reference from %s:%s", - self.databaseID->project_id(), self.databaseID->database_id(), - database_id.project_id(), database_id.database_id()); - return [FSTReferenceValue referenceValue:[FSTDocumentKey keyWithDocumentKey:key] - databaseID:self.databaseID]; -} - -- (GCFSArrayValue *)encodedArrayValue:(FSTArrayValue *)arrayValue { - GCFSArrayValue *proto = [GCFSArrayValue message]; - NSMutableArray *protoContents = [proto valuesArray]; - - [[arrayValue internalValue] - enumerateObjectsUsingBlock:^(FSTFieldValue *value, NSUInteger idx, BOOL *stop) { - GCFSValue *converted = [self encodedFieldValue:value]; - [protoContents addObject:converted]; - }]; - return proto; -} - -- (FSTArrayValue *)decodedArrayValue:(GCFSArrayValue *)arrayValue { - NSMutableArray *contents = - [NSMutableArray arrayWithCapacity:arrayValue.valuesArray_Count]; - - [arrayValue.valuesArray - enumerateObjectsUsingBlock:^(GCFSValue *value, NSUInteger idx, BOOL *stop) { - [contents addObject:[self decodedFieldValue:value]]; - }]; - return [[FSTArrayValue alloc] initWithValueNoCopy:contents]; -} - -- (GCFSMapValue *)encodedMapValue:(FSTObjectValue *)value { - GCFSMapValue *result = [GCFSMapValue message]; - result.fields = [self encodedFields:value]; - return result; -} - -- (FSTObjectValue *)decodedMapValue:(GCFSMapValue *)map { - return [self decodedFields:map.fields]; -} - -/** - * Encodes an FSTObjectValue into a dictionary. - * @return a new dictionary that can be assigned to a field in another proto. - */ -- (NSMutableDictionary *)encodedFields:(FSTObjectValue *)value { - FSTImmutableSortedDictionary *fields = value.internalValue; - NSMutableDictionary *result = [NSMutableDictionary dictionary]; - [fields enumerateKeysAndObjectsUsingBlock:^(NSString *key, FSTFieldValue *obj, BOOL *stop) { - GCFSValue *converted = [self encodedFieldValue:obj]; - result[key] = converted; - }]; - return result; -} - -- (FSTObjectValue *)decodedFields:(NSDictionary *)fields { - __block FSTObjectValue *result = [FSTObjectValue objectValue]; - [fields enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, GCFSValue *_Nonnull obj, - BOOL *_Nonnull stop) { - FieldPath path{util::MakeString(key)}; - FSTFieldValue *value = [self decodedFieldValue:obj]; - result = [result objectBySettingValue:value forPath:path]; - }]; - return result; -} - -#pragma mark - FSTObjectValue <=> Document proto - -- (GCFSDocument *)encodedDocumentWithFields:(FSTObjectValue *)objectValue - key:(const DocumentKey &)key { - GCFSDocument *proto = [GCFSDocument message]; - proto.name = [self encodedDocumentKey:key]; - proto.fields = [self encodedFields:objectValue]; - return proto; -} - -#pragma mark - FSTMaybeDocument <= BatchGetDocumentsResponse proto - -- (FSTMaybeDocument *)decodedMaybeDocumentFromBatch:(GCFSBatchGetDocumentsResponse *)response { - switch (response.resultOneOfCase) { - case GCFSBatchGetDocumentsResponse_Result_OneOfCase_Found: - return [self decodedFoundDocument:response]; - case GCFSBatchGetDocumentsResponse_Result_OneOfCase_Missing: - return [self decodedDeletedDocument:response]; - default: - HARD_FAIL("Unknown document type: %s", response); - } -} - -- (FSTDocument *)decodedFoundDocument:(GCFSBatchGetDocumentsResponse *)response { - HARD_ASSERT(!!response.found, "Tried to deserialize a found document from a deleted document."); - const DocumentKey key = [self decodedDocumentKey:response.found.name]; - FSTObjectValue *value = [self decodedFields:response.found.fields]; - SnapshotVersion version = [self decodedVersion:response.found.updateTime]; - HARD_ASSERT(version != SnapshotVersion::None(), - "Got a document response with no snapshot version"); - - return [FSTDocument documentWithData:value - key:key - version:version - state:FSTDocumentStateSynced - proto:response.found]; -} - -- (FSTDeletedDocument *)decodedDeletedDocument:(GCFSBatchGetDocumentsResponse *)response { - HARD_ASSERT(!!response.missing, "Tried to deserialize a deleted document from a found document."); - const DocumentKey key = [self decodedDocumentKey:response.missing]; - SnapshotVersion version = [self decodedVersion:response.readTime]; - HARD_ASSERT(version != SnapshotVersion::None(), - "Got a no document response with no snapshot version"); - return [FSTDeletedDocument documentWithKey:key version:version hasCommittedMutations:NO]; -} - -#pragma mark - FSTMutation => GCFSWrite proto - -- (GCFSWrite *)encodedMutation:(FSTMutation *)mutation { - GCFSWrite *proto = [GCFSWrite message]; - - Class mutationClass = [mutation class]; - if (mutationClass == [FSTSetMutation class]) { - FSTSetMutation *set = (FSTSetMutation *)mutation; - proto.update = [self encodedDocumentWithFields:set.value key:set.key]; - - } else if (mutationClass == [FSTPatchMutation class]) { - FSTPatchMutation *patch = (FSTPatchMutation *)mutation; - proto.update = [self encodedDocumentWithFields:patch.value key:patch.key]; - proto.updateMask = [self encodedFieldMask:*(patch.fieldMask)]; - - } else if (mutationClass == [FSTTransformMutation class]) { - FSTTransformMutation *transform = (FSTTransformMutation *)mutation; - - proto.transform = [GCFSDocumentTransform message]; - proto.transform.document = [self encodedDocumentKey:transform.key]; - proto.transform.fieldTransformsArray = [self encodedFieldTransforms:transform.fieldTransforms]; - // NOTE: We set a precondition of exists: true as a safety-check, since we always combine - // FSTTransformMutations with an FSTSetMutation or FSTPatchMutation which (if successful) should - // end up with an existing document. - proto.currentDocument.exists = YES; - - } else if (mutationClass == [FSTDeleteMutation class]) { - FSTDeleteMutation *deleteMutation = (FSTDeleteMutation *)mutation; - proto.delete_p = [self encodedDocumentKey:deleteMutation.key]; - - } else { - HARD_FAIL("Unknown mutation type %s", NSStringFromClass(mutationClass)); - } - - if (!mutation.precondition.IsNone()) { - proto.currentDocument = [self encodedPrecondition:mutation.precondition]; - } - - return proto; -} - -- (FSTMutation *)decodedMutation:(GCFSWrite *)mutation { - Precondition precondition = [mutation hasCurrentDocument] - ? [self decodedPrecondition:mutation.currentDocument] - : Precondition::None(); - - switch (mutation.operationOneOfCase) { - case GCFSWrite_Operation_OneOfCase_Update: - if (mutation.hasUpdateMask) { - return [[FSTPatchMutation alloc] initWithKey:[self decodedDocumentKey:mutation.update.name] - fieldMask:[self decodedFieldMask:mutation.updateMask] - value:[self decodedFields:mutation.update.fields] - precondition:precondition]; - } else { - return [[FSTSetMutation alloc] initWithKey:[self decodedDocumentKey:mutation.update.name] - value:[self decodedFields:mutation.update.fields] - precondition:precondition]; - } - - case GCFSWrite_Operation_OneOfCase_Delete_p: - return [[FSTDeleteMutation alloc] initWithKey:[self decodedDocumentKey:mutation.delete_p] - precondition:precondition]; - - case GCFSWrite_Operation_OneOfCase_Transform: { - HARD_ASSERT(precondition == Precondition::Exists(true), - "Transforms must have precondition \"exists == true\""); - - return [[FSTTransformMutation alloc] - initWithKey:[self decodedDocumentKey:mutation.transform.document] - fieldTransforms:[self decodedFieldTransforms:mutation.transform.fieldTransformsArray]]; - } - - default: - // Note that insert is intentionally unhandled, since we don't ever deal in them. - HARD_FAIL("Unknown mutation operation: %s", mutation.operationOneOfCase); - } -} - -- (GCFSPrecondition *)encodedPrecondition:(const Precondition &)precondition { - HARD_ASSERT(!precondition.IsNone(), "Can't serialize an empty precondition"); - GCFSPrecondition *message = [GCFSPrecondition message]; - if (precondition.type() == Precondition::Type::UpdateTime) { - message.updateTime = [self encodedVersion:precondition.update_time()]; - } else if (precondition.type() == Precondition::Type::Exists) { - message.exists = precondition == Precondition::Exists(true); - } else { - HARD_FAIL("Unknown precondition: %s", precondition.description()); - } - return message; -} - -- (Precondition)decodedPrecondition:(GCFSPrecondition *)precondition { - switch (precondition.conditionTypeOneOfCase) { - case GCFSPrecondition_ConditionType_OneOfCase_GPBUnsetOneOfCase: - return Precondition::None(); - - case GCFSPrecondition_ConditionType_OneOfCase_Exists: - return Precondition::Exists(precondition.exists); - - case GCFSPrecondition_ConditionType_OneOfCase_UpdateTime: - return Precondition::UpdateTime([self decodedVersion:precondition.updateTime]); - - default: - HARD_FAIL("Unrecognized Precondition one-of case %s", precondition); - } -} - -- (GCFSDocumentMask *)encodedFieldMask:(const FieldMask &)fieldMask { - GCFSDocumentMask *mask = [GCFSDocumentMask message]; - for (const FieldPath &field : fieldMask) { - [mask.fieldPathsArray addObject:util::WrapNSString(field.CanonicalString())]; - } - return mask; -} - -- (FieldMask)decodedFieldMask:(GCFSDocumentMask *)fieldMask { - std::set fields; - for (NSString *path in fieldMask.fieldPathsArray) { - fields.insert(FieldPath::FromServerFormat(util::MakeString(path))); - } - return FieldMask(std::move(fields)); -} - -- (NSMutableArray *)encodedFieldTransforms: - (const std::vector &)fieldTransforms { - NSMutableArray *protos = [NSMutableArray array]; - for (const FieldTransform &fieldTransform : fieldTransforms) { - GCFSDocumentTransform_FieldTransform *proto = [self encodedFieldTransform:fieldTransform]; - [protos addObject:proto]; - } - return protos; -} - -- (GCFSDocumentTransform_FieldTransform *)encodedFieldTransform: - (const FieldTransform &)fieldTransform { - GCFSDocumentTransform_FieldTransform *proto = [GCFSDocumentTransform_FieldTransform message]; - proto.fieldPath = util::WrapNSString(fieldTransform.path().CanonicalString()); - if (fieldTransform.transformation().type() == TransformOperation::Type::ServerTimestamp) { - proto.setToServerValue = GCFSDocumentTransform_FieldTransform_ServerValue_RequestTime; - - } else if (fieldTransform.transformation().type() == TransformOperation::Type::ArrayUnion) { - proto.appendMissingElements = [self - encodedArrayTransformElements:ArrayTransform::Elements(fieldTransform.transformation())]; - - } else if (fieldTransform.transformation().type() == TransformOperation::Type::ArrayRemove) { - proto.removeAllFromArray_p = [self - encodedArrayTransformElements:ArrayTransform::Elements(fieldTransform.transformation())]; - } else if (fieldTransform.transformation().type() == TransformOperation::Type::Increment) { - const NumericIncrementTransform &incrementTransform = - static_cast(fieldTransform.transformation()); - proto.increment = [self encodedFieldValue:incrementTransform.operand()]; - } else { - HARD_FAIL("Unknown transform: %s type", fieldTransform.transformation().type()); - } - return proto; -} - -- (GCFSArrayValue *)encodedArrayTransformElements:(const std::vector &)elements { - GCFSArrayValue *proto = [GCFSArrayValue message]; - NSMutableArray *protoContents = [proto valuesArray]; - - for (FSTFieldValue *element : elements) { - GCFSValue *converted = [self encodedFieldValue:element]; - [protoContents addObject:converted]; - } - return proto; -} - -- (std::vector)decodedFieldTransforms: - (NSArray *)protos { - std::vector fieldTransforms; - fieldTransforms.reserve(protos.count); - - for (GCFSDocumentTransform_FieldTransform *proto in protos) { - switch (proto.transformTypeOneOfCase) { - case GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_SetToServerValue: { - HARD_ASSERT( - proto.setToServerValue == GCFSDocumentTransform_FieldTransform_ServerValue_RequestTime, - "Unknown transform setToServerValue: %s", proto.setToServerValue); - fieldTransforms.emplace_back( - FieldPath::FromServerFormat(util::MakeString(proto.fieldPath)), - absl::make_unique(ServerTimestampTransform::Get())); - break; - } - - case GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_AppendMissingElements: { - std::vector elements = - [self decodedArrayTransformElements:proto.appendMissingElements]; - fieldTransforms.emplace_back( - FieldPath::FromServerFormat(util::MakeString(proto.fieldPath)), - absl::make_unique(TransformOperation::Type::ArrayUnion, - std::move(elements))); - break; - } - - case GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_RemoveAllFromArray_p: { - std::vector elements = - [self decodedArrayTransformElements:proto.removeAllFromArray_p]; - fieldTransforms.emplace_back( - FieldPath::FromServerFormat(util::MakeString(proto.fieldPath)), - absl::make_unique(TransformOperation::Type::ArrayRemove, - std::move(elements))); - break; - } - - case GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_Increment: { - FSTNumberValue *operand = - static_cast([self decodedFieldValue:proto.increment]); - fieldTransforms.emplace_back(FieldPath::FromServerFormat(util::MakeString(proto.fieldPath)), - absl::make_unique(operand)); - break; - } - - default: - HARD_FAIL("Unknown transform: %s", proto); - } - } - - return fieldTransforms; -} - -- (std::vector)decodedArrayTransformElements:(GCFSArrayValue *)proto { - __block std::vector elements; - [proto.valuesArray enumerateObjectsUsingBlock:^(GCFSValue *value, NSUInteger idx, BOOL *stop) { - elements.push_back([self decodedFieldValue:value]); - }]; - return elements; -} - -#pragma mark - FSTMutationResult <= GCFSWriteResult proto - -- (FSTMutationResult *)decodedMutationResult:(GCFSWriteResult *)mutation - commitVersion:(const SnapshotVersion &)commitVersion { - // NOTE: Deletes don't have an updateTime. Use commitVersion instead. - SnapshotVersion version = - mutation.hasUpdateTime ? [self decodedVersion:mutation.updateTime] : commitVersion; - NSMutableArray *_Nullable transformResults = nil; - if (mutation.transformResultsArray.count > 0) { - transformResults = [NSMutableArray array]; - for (GCFSValue *result in mutation.transformResultsArray) { - [transformResults addObject:[self decodedFieldValue:result]]; - } - } - return [[FSTMutationResult alloc] initWithVersion:std::move(version) - transformResults:transformResults]; -} - -#pragma mark - FSTQueryData => GCFSTarget proto - -- (nullable NSMutableDictionary *)encodedListenRequestLabelsForQueryData: - (FSTQueryData *)queryData { - NSString *value = [self encodedLabelForPurpose:queryData.purpose]; - if (!value) { - return nil; - } - - NSMutableDictionary *result = - [NSMutableDictionary dictionaryWithCapacity:1]; - [result setObject:value forKey:@"goog-listen-tags"]; - return result; -} - -- (nullable NSString *)encodedLabelForPurpose:(FSTQueryPurpose)purpose { - switch (purpose) { - case FSTQueryPurposeListen: - return nil; - case FSTQueryPurposeExistenceFilterMismatch: - return @"existence-filter-mismatch"; - case FSTQueryPurposeLimboResolution: - return @"limbo-document"; - default: - HARD_FAIL("Unrecognized query purpose: %s", purpose); - } -} - -- (GCFSTarget *)encodedTarget:(FSTQueryData *)queryData { - GCFSTarget *result = [GCFSTarget message]; - FSTQuery *query = queryData.query; - - if ([query isDocumentQuery]) { - result.documents = [self encodedDocumentsTarget:query]; - } else { - result.query = [self encodedQueryTarget:query]; - } - - result.targetId = queryData.targetID; - if (queryData.resumeToken.length > 0) { - result.resumeToken = queryData.resumeToken; - } - - return result; -} - -- (GCFSTarget_DocumentsTarget *)encodedDocumentsTarget:(FSTQuery *)query { - GCFSTarget_DocumentsTarget *result = [GCFSTarget_DocumentsTarget message]; - NSMutableArray *docs = result.documentsArray; - [docs addObject:[self encodedQueryPath:query.path]]; - return result; -} - -- (FSTQuery *)decodedQueryFromDocumentsTarget:(GCFSTarget_DocumentsTarget *)target { - NSArray *documents = target.documentsArray; - HARD_ASSERT(documents.count == 1, "DocumentsTarget contained other than 1 document %s", - (unsigned long)documents.count); - - NSString *name = documents[0]; - return [FSTQuery queryWithPath:[self decodedQueryPath:name]]; -} - -- (GCFSTarget_QueryTarget *)encodedQueryTarget:(FSTQuery *)query { - // Dissect the path into parent, collectionId, and optional key filter. - GCFSTarget_QueryTarget *queryTarget = [GCFSTarget_QueryTarget message]; - const ResourcePath &path = query.path; - if (query.collectionGroup) { - HARD_ASSERT(path.size() % 2 == 0, - "Collection group queries should be within a document path or root."); - queryTarget.parent = [self encodedQueryPath:path]; - GCFSStructuredQuery_CollectionSelector *from = [GCFSStructuredQuery_CollectionSelector message]; - from.collectionId = query.collectionGroup; - from.allDescendants = YES; - [queryTarget.structuredQuery.fromArray addObject:from]; - } else { - HARD_ASSERT(path.size() % 2 != 0, "Document queries with filters are not supported."); - queryTarget.parent = [self encodedQueryPath:path.PopLast()]; - GCFSStructuredQuery_CollectionSelector *from = [GCFSStructuredQuery_CollectionSelector message]; - from.collectionId = util::WrapNSString(path.last_segment()); - [queryTarget.structuredQuery.fromArray addObject:from]; - } - - // Encode the filters. - GCFSStructuredQuery_Filter *_Nullable where = [self encodedFilters:query.filters]; - if (where) { - queryTarget.structuredQuery.where = where; - } - - NSArray *orders = [self encodedSortOrders:query.sortOrders]; - if (orders.count) { - [queryTarget.structuredQuery.orderByArray addObjectsFromArray:orders]; - } - - if (query.limit != NSNotFound) { - queryTarget.structuredQuery.limit.value = (int32_t)query.limit; - } - - if (query.startAt) { - queryTarget.structuredQuery.startAt = [self encodedBound:query.startAt]; - } - - if (query.endAt) { - queryTarget.structuredQuery.endAt = [self encodedBound:query.endAt]; - } - - return queryTarget; -} - -- (FSTQuery *)decodedQueryFromQueryTarget:(GCFSTarget_QueryTarget *)target { - ResourcePath path = [self decodedQueryPath:target.parent]; - - GCFSStructuredQuery *query = target.structuredQuery; - NSString *collectionGroup; - NSUInteger fromCount = query.fromArray_Count; - if (fromCount > 0) { - HARD_ASSERT(fromCount == 1, - "StructuredQuery.from with more than one collection is not supported."); - - GCFSStructuredQuery_CollectionSelector *from = query.fromArray[0]; - if (from.allDescendants) { - collectionGroup = from.collectionId; - } else { - path = path.Append(util::MakeString(from.collectionId)); - } - } - - NSArray *filterBy; - if (query.hasWhere) { - filterBy = [self decodedFilters:query.where]; - } else { - filterBy = @[]; - } - - NSArray *orderBy; - if (query.orderByArray_Count > 0) { - orderBy = [self decodedSortOrders:query.orderByArray]; - } else { - orderBy = @[]; - } - - NSInteger limit = NSNotFound; - if (query.hasLimit) { - limit = query.limit.value; - } - - FSTBound *_Nullable startAt; - if (query.hasStartAt) { - startAt = [self decodedBound:query.startAt]; - } - - FSTBound *_Nullable endAt; - if (query.hasEndAt) { - endAt = [self decodedBound:query.endAt]; - } - - return [[FSTQuery alloc] initWithPath:path - collectionGroup:collectionGroup - filterBy:filterBy - orderBy:orderBy - limit:limit - startAt:startAt - endAt:endAt]; -} - -#pragma mark Filters - -- (GCFSStructuredQuery_Filter *_Nullable)encodedFilters:(NSArray *)filters { - if (filters.count == 0) { - return nil; - } - NSMutableArray *protos = [NSMutableArray array]; - for (FSTFilter *filter in filters) { - if ([filter isKindOfClass:[FSTRelationFilter class]]) { - [protos addObject:[self encodedRelationFilter:(FSTRelationFilter *)filter]]; - } else { - [protos addObject:[self encodedUnaryFilter:filter]]; - } - } - if (protos.count == 1) { - // Special case: no existing filters and we only need to add one filter. This can be made the - // single root filter without a composite filter. - return protos[0]; - } - GCFSStructuredQuery_Filter *composite = [GCFSStructuredQuery_Filter message]; - composite.compositeFilter.op = GCFSStructuredQuery_CompositeFilter_Operator_And; - composite.compositeFilter.filtersArray = protos; - return composite; -} - -- (NSArray *)decodedFilters:(GCFSStructuredQuery_Filter *)proto { - NSMutableArray *result = [NSMutableArray array]; - - NSArray *filters; - if (proto.filterTypeOneOfCase == - GCFSStructuredQuery_Filter_FilterType_OneOfCase_CompositeFilter) { - HARD_ASSERT(proto.compositeFilter.op == GCFSStructuredQuery_CompositeFilter_Operator_And, - "Only AND-type composite filters are supported, got %s", proto.compositeFilter.op); - filters = proto.compositeFilter.filtersArray; - } else { - filters = @[ proto ]; - } - - for (GCFSStructuredQuery_Filter *filter in filters) { - switch (filter.filterTypeOneOfCase) { - case GCFSStructuredQuery_Filter_FilterType_OneOfCase_CompositeFilter: - HARD_FAIL("Nested composite filters are not supported"); - - case GCFSStructuredQuery_Filter_FilterType_OneOfCase_FieldFilter: - [result addObject:[self decodedRelationFilter:filter.fieldFilter]]; - break; - - case GCFSStructuredQuery_Filter_FilterType_OneOfCase_UnaryFilter: - [result addObject:[self decodedUnaryFilter:filter.unaryFilter]]; - break; - - default: - HARD_FAIL("Unrecognized Filter.filterType %s", filter.filterTypeOneOfCase); - } - } - return result; -} - -- (GCFSStructuredQuery_Filter *)encodedRelationFilter:(FSTRelationFilter *)filter { - GCFSStructuredQuery_Filter *proto = [GCFSStructuredQuery_Filter message]; - GCFSStructuredQuery_FieldFilter *fieldFilter = proto.fieldFilter; - fieldFilter.field = [self encodedFieldPath:filter.field]; - fieldFilter.op = [self encodedRelationFilterOperator:filter.filterOperator]; - fieldFilter.value = [self encodedFieldValue:filter.value]; - return proto; -} - -- (FSTRelationFilter *)decodedRelationFilter:(GCFSStructuredQuery_FieldFilter *)proto { - FieldPath fieldPath = FieldPath::FromServerFormat(util::MakeString(proto.field.fieldPath)); - FSTRelationFilterOperator filterOperator = [self decodedRelationFilterOperator:proto.op]; - FSTFieldValue *value = [self decodedFieldValue:proto.value]; - return [FSTRelationFilter filterWithField:fieldPath filterOperator:filterOperator value:value]; -} - -- (GCFSStructuredQuery_Filter *)encodedUnaryFilter:(FSTFilter *)filter { - GCFSStructuredQuery_Filter *proto = [GCFSStructuredQuery_Filter message]; - proto.unaryFilter.field = [self encodedFieldPath:filter.field]; - if ([filter isKindOfClass:[FSTNanFilter class]]) { - proto.unaryFilter.op = GCFSStructuredQuery_UnaryFilter_Operator_IsNan; - } else if ([filter isKindOfClass:[FSTNullFilter class]]) { - proto.unaryFilter.op = GCFSStructuredQuery_UnaryFilter_Operator_IsNull; - } else { - HARD_FAIL("Unrecognized filter: %s", filter); - } - return proto; -} - -- (FSTFilter *)decodedUnaryFilter:(GCFSStructuredQuery_UnaryFilter *)proto { - FieldPath field = FieldPath::FromServerFormat(util::MakeString(proto.field.fieldPath)); - switch (proto.op) { - case GCFSStructuredQuery_UnaryFilter_Operator_IsNan: - return [[FSTNanFilter alloc] initWithField:field]; - - case GCFSStructuredQuery_UnaryFilter_Operator_IsNull: - return [[FSTNullFilter alloc] initWithField:field]; - - default: - HARD_FAIL("Unrecognized UnaryFilter.operator %s", proto.op); - } -} - -- (GCFSStructuredQuery_FieldReference *)encodedFieldPath:(const FieldPath &)fieldPath { - GCFSStructuredQuery_FieldReference *ref = [GCFSStructuredQuery_FieldReference message]; - ref.fieldPath = util::WrapNSString(fieldPath.CanonicalString()); - return ref; -} - -- (GCFSStructuredQuery_FieldFilter_Operator)encodedRelationFilterOperator: - (FSTRelationFilterOperator)filterOperator { - switch (filterOperator) { - case FSTRelationFilterOperatorLessThan: - return GCFSStructuredQuery_FieldFilter_Operator_LessThan; - case FSTRelationFilterOperatorLessThanOrEqual: - return GCFSStructuredQuery_FieldFilter_Operator_LessThanOrEqual; - case FSTRelationFilterOperatorEqual: - return GCFSStructuredQuery_FieldFilter_Operator_Equal; - case FSTRelationFilterOperatorGreaterThanOrEqual: - return GCFSStructuredQuery_FieldFilter_Operator_GreaterThanOrEqual; - case FSTRelationFilterOperatorGreaterThan: - return GCFSStructuredQuery_FieldFilter_Operator_GreaterThan; - case FSTRelationFilterOperatorArrayContains: - return GCFSStructuredQuery_FieldFilter_Operator_ArrayContains; - default: - HARD_FAIL("Unhandled FSTRelationFilterOperator: %s", filterOperator); - } -} - -- (FSTRelationFilterOperator)decodedRelationFilterOperator: - (GCFSStructuredQuery_FieldFilter_Operator)filterOperator { - switch (filterOperator) { - case GCFSStructuredQuery_FieldFilter_Operator_LessThan: - return FSTRelationFilterOperatorLessThan; - case GCFSStructuredQuery_FieldFilter_Operator_LessThanOrEqual: - return FSTRelationFilterOperatorLessThanOrEqual; - case GCFSStructuredQuery_FieldFilter_Operator_Equal: - return FSTRelationFilterOperatorEqual; - case GCFSStructuredQuery_FieldFilter_Operator_GreaterThanOrEqual: - return FSTRelationFilterOperatorGreaterThanOrEqual; - case GCFSStructuredQuery_FieldFilter_Operator_GreaterThan: - return FSTRelationFilterOperatorGreaterThan; - case GCFSStructuredQuery_FieldFilter_Operator_ArrayContains: - return FSTRelationFilterOperatorArrayContains; - default: - HARD_FAIL("Unhandled FieldFilter.operator: %s", filterOperator); - } -} - -#pragma mark Property Orders - -- (NSArray *)encodedSortOrders:(NSArray *)orders { - NSMutableArray *protos = [NSMutableArray array]; - for (FSTSortOrder *order in orders) { - [protos addObject:[self encodedSortOrder:order]]; - } - return protos; -} - -- (NSArray *)decodedSortOrders:(NSArray *)protos { - NSMutableArray *result = [NSMutableArray arrayWithCapacity:protos.count]; - for (GCFSStructuredQuery_Order *orderProto in protos) { - [result addObject:[self decodedSortOrder:orderProto]]; - } - return result; -} - -- (GCFSStructuredQuery_Order *)encodedSortOrder:(FSTSortOrder *)sortOrder { - GCFSStructuredQuery_Order *proto = [GCFSStructuredQuery_Order message]; - proto.field = [self encodedFieldPath:sortOrder.field]; - if (sortOrder.ascending) { - proto.direction = GCFSStructuredQuery_Direction_Ascending; - } else { - proto.direction = GCFSStructuredQuery_Direction_Descending; - } - return proto; -} - -- (FSTSortOrder *)decodedSortOrder:(GCFSStructuredQuery_Order *)proto { - FieldPath fieldPath = FieldPath::FromServerFormat(util::MakeString(proto.field.fieldPath)); - BOOL ascending; - switch (proto.direction) { - case GCFSStructuredQuery_Direction_Ascending: - ascending = YES; - break; - case GCFSStructuredQuery_Direction_Descending: - ascending = NO; - break; - default: - HARD_FAIL("Unrecognized GCFSStructuredQuery_Direction %s", proto.direction); - } - return [FSTSortOrder sortOrderWithFieldPath:fieldPath ascending:ascending]; -} - -#pragma mark - Bounds/Cursors - -- (GCFSCursor *)encodedBound:(FSTBound *)bound { - GCFSCursor *proto = [GCFSCursor message]; - proto.before = bound.isBefore; - for (FSTFieldValue *fieldValue in bound.position) { - GCFSValue *value = [self encodedFieldValue:fieldValue]; - [proto.valuesArray addObject:value]; - } - return proto; -} - -- (FSTBound *)decodedBound:(GCFSCursor *)proto { - NSMutableArray *indexComponents = [NSMutableArray array]; - - for (GCFSValue *valueProto in proto.valuesArray) { - FSTFieldValue *value = [self decodedFieldValue:valueProto]; - [indexComponents addObject:value]; - } - - return [FSTBound boundWithPosition:indexComponents isBefore:proto.before]; -} - -#pragma mark - WatchChange <= GCFSListenResponse proto - -- (std::unique_ptr)decodedWatchChange:(GCFSListenResponse *)watchChange { - switch (watchChange.responseTypeOneOfCase) { - case GCFSListenResponse_ResponseType_OneOfCase_TargetChange: - return [self decodedTargetChangeFromWatchChange:watchChange.targetChange]; - - case GCFSListenResponse_ResponseType_OneOfCase_DocumentChange: - return [self decodedDocumentChange:watchChange.documentChange]; - - case GCFSListenResponse_ResponseType_OneOfCase_DocumentDelete: - return [self decodedDocumentDelete:watchChange.documentDelete]; - - case GCFSListenResponse_ResponseType_OneOfCase_DocumentRemove: - return [self decodedDocumentRemove:watchChange.documentRemove]; - - case GCFSListenResponse_ResponseType_OneOfCase_Filter: - return [self decodedExistenceFilterWatchChange:watchChange.filter]; - - default: - HARD_FAIL("Unknown WatchChange.changeType %s", watchChange.responseTypeOneOfCase); - } -} - -- (SnapshotVersion)versionFromListenResponse:(GCFSListenResponse *)watchChange { - // We have only reached a consistent snapshot for the entire stream if there is a read_time set - // and it applies to all targets (i.e. the list of targets is empty). The backend is guaranteed to - // send such responses. - if (watchChange.responseTypeOneOfCase != GCFSListenResponse_ResponseType_OneOfCase_TargetChange) { - return SnapshotVersion::None(); - } - if (watchChange.targetChange.targetIdsArray.count != 0) { - return SnapshotVersion::None(); - } - return [self decodedVersion:watchChange.targetChange.readTime]; -} - -- (std::unique_ptr)decodedTargetChangeFromWatchChange:(GCFSTargetChange *)change { - WatchTargetChangeState state = [self decodedWatchTargetChangeState:change.targetChangeType]; - __block std::vector targetIDs; - - [change.targetIdsArray enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { - targetIDs.push_back(value); - }]; - - NSData *resumeToken = change.resumeToken; - - util::Status cause; - if (change.hasCause) { - cause = util::Status{static_cast(change.cause.code), - util::MakeString(change.cause.message)}; - } - - return absl::make_unique(state, std::move(targetIDs), resumeToken, - std::move(cause)); -} - -- (WatchTargetChangeState)decodedWatchTargetChangeState:(GCFSTargetChange_TargetChangeType)state { - switch (state) { - case GCFSTargetChange_TargetChangeType_NoChange: - return WatchTargetChangeState::NoChange; - case GCFSTargetChange_TargetChangeType_Add: - return WatchTargetChangeState::Added; - case GCFSTargetChange_TargetChangeType_Remove: - return WatchTargetChangeState::Removed; - case GCFSTargetChange_TargetChangeType_Current: - return WatchTargetChangeState::Current; - case GCFSTargetChange_TargetChangeType_Reset: - return WatchTargetChangeState::Reset; - default: - HARD_FAIL("Unexpected TargetChange.state: %s", state); - } -} - -- (std::vector)decodedIntegerArray:(GPBInt32Array *)values { - __block std::vector result; - result.reserve(values.count); - [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { - result.push_back(value); - }]; - return result; -} - -- (std::unique_ptr)decodedDocumentChange:(GCFSDocumentChange *)change { - FSTObjectValue *value = [self decodedFields:change.document.fields]; - DocumentKey key = [self decodedDocumentKey:change.document.name]; - SnapshotVersion version = [self decodedVersion:change.document.updateTime]; - HARD_ASSERT(version != SnapshotVersion::None(), "Got a document change with no snapshot version"); - // The document may soon be re-serialized back to protos in order to store it in local - // persistence. Memoize the encoded form to avoid encoding it again. - FSTMaybeDocument *document = [FSTDocument documentWithData:value - key:key - version:version - state:FSTDocumentStateSynced - proto:change.document]; - - std::vector updatedTargetIDs = [self decodedIntegerArray:change.targetIdsArray]; - std::vector removedTargetIDs = [self decodedIntegerArray:change.removedTargetIdsArray]; - - return absl::make_unique( - std::move(updatedTargetIDs), std::move(removedTargetIDs), std::move(key), document); -} - -- (std::unique_ptr)decodedDocumentDelete:(GCFSDocumentDelete *)change { - DocumentKey key = [self decodedDocumentKey:change.document]; - // Note that version might be unset in which case we use SnapshotVersion::None() - SnapshotVersion version = [self decodedVersion:change.readTime]; - FSTMaybeDocument *document = [FSTDeletedDocument documentWithKey:key - version:version - hasCommittedMutations:NO]; - - std::vector removedTargetIDs = [self decodedIntegerArray:change.removedTargetIdsArray]; - - return absl::make_unique( - std::vector{}, std::move(removedTargetIDs), std::move(key), document); -} - -- (std::unique_ptr)decodedDocumentRemove:(GCFSDocumentRemove *)change { - DocumentKey key = [self decodedDocumentKey:change.document]; - std::vector removedTargetIDs = [self decodedIntegerArray:change.removedTargetIdsArray]; - - return absl::make_unique(std::vector{}, - std::move(removedTargetIDs), std::move(key), nil); -} - -- (std::unique_ptr)decodedExistenceFilterWatchChange:(GCFSExistenceFilter *)filter { - ExistenceFilter existenceFilter{filter.count}; - TargetId targetID = filter.targetId; - return absl::make_unique(existenceFilter, targetID); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Util/FSTAsyncQueryListener.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Util/FSTAsyncQueryListener.h deleted file mode 100644 index 8588fbe..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Util/FSTAsyncQueryListener.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" -#include "Firestore/core/src/firebase/firestore/util/executor.h" - -NS_ASSUME_NONNULL_BEGIN - -/** - * A wrapper class around QueryListener that dispatches events asynchronously. - */ -@interface FSTAsyncQueryListener : NSObject - -- (instancetype)initWithExecutor:(firebase::firestore::util::Executor*)executor - snapshotHandler:(firebase::firestore::core::ViewSnapshotHandler&&)snapshotHandler - NS_DESIGNATED_INITIALIZER; - -- (instancetype)init NS_UNAVAILABLE; - -/** - * Synchronously mutes the listener and raise no further events. This method is thread safe can be - * called from any queue. - */ -- (void)mute; - -/** Creates an asynchronous version of the provided snapshot handler. */ -- (firebase::firestore::core::ViewSnapshotHandler)asyncSnapshotHandler; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Util/FSTClasses.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Util/FSTClasses.h deleted file mode 100644 index 79d67c4..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Util/FSTClasses.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -NS_ASSUME_NONNULL_BEGIN - -// A convenience macro for unimplemented methods. Use as follows: -// -// @throw FSTAbstractMethodException(); // NOLINT -#define FSTAbstractMethodException() \ - [NSException exceptionWithName:NSInternalInconsistencyException \ - reason:[NSString stringWithFormat:@"You must override %s in a subclass", \ - __func__] \ - userInfo:nil]; - -// Declare a weak pointer to the given variable -#define FSTWeakify(var) __weak __typeof__(var) fstWeakPointerTo##var = var; - -// Declare a strong pointer to a variable that's been FSTWeakified. This creates a shadow of the -// original. -#define FSTStrongify(var) \ - _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow\"") \ - __strong __typeof__(var) var = fstWeakPointerTo##var; \ - _Pragma("clang diagnostic pop") - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Util/FSTUsageValidation.h b/Example/Pods/FirebaseFirestore/Firestore/Source/Util/FSTUsageValidation.h deleted file mode 100644 index afc5412..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Util/FSTUsageValidation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import - -NS_ASSUME_NONNULL_BEGIN - -/** Helper for creating a general exception for invalid usage of an API. */ -NSException *FSTInvalidUsage(NSString *exceptionName, NSString *format, ...); - -/** - * Macro to throw exceptions in response to API usage errors. Avoids the lint warning you usually - * get when using @throw and (unlike a function) doesn't trigger warnings about not all codepaths - * returning a value. - * - * Exceptions should only be used for programmer errors made by consumers of the SDK, e.g. - * invalid method arguments. - * - * For recoverable runtime errors, use NSError**. - * For internal programming errors, use HARD_FAIL(). - */ -#define FSTThrowInvalidUsage(exceptionName, format, ...) \ - do { \ - @throw FSTInvalidUsage(exceptionName, format, ##__VA_ARGS__); \ - } while (0) - -#define FSTThrowInvalidArgument(format, ...) \ - do { \ - @throw FSTInvalidUsage(@"FIRInvalidArgumentException", format, ##__VA_ARGS__); \ - } while (0) - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/Source/Util/FSTUsageValidation.mm b/Example/Pods/FirebaseFirestore/Firestore/Source/Util/FSTUsageValidation.mm deleted file mode 100644 index 93abf87..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/Source/Util/FSTUsageValidation.mm +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/Source/Util/FSTUsageValidation.h" - -NS_ASSUME_NONNULL_BEGIN - -NSException *FSTInvalidUsage(NSString *exceptionName, NSString *format, ...) { - va_list arg_list; - va_start(arg_list, format); - NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list]; - va_end(arg_list); - - return [[NSException alloc] initWithName:exceptionName reason:formattedString userInfo:nil]; -} - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/include/firebase/firestore/firestore_errors.h b/Example/Pods/FirebaseFirestore/Firestore/core/include/firebase/firestore/firestore_errors.h index 92c0c92..339a88f 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/include/firebase/firestore/firestore_errors.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/include/firebase/firestore/firestore_errors.h @@ -23,14 +23,11 @@ namespace firestore { /** * Error codes used by Cloud Firestore. * - * The codes are in sync with the Firestore iOS client SDK header file - * FIRFirestoreErrors.h. + * The codes are in sync across Firestore SDKs on various platforms. */ -enum FirestoreErrorCode { - /** - * The operation completed successfully. NSError objects will never have a - * code with this value. - */ +enum Error { + /** The operation completed successfully. */ + // Note: NSError objects will never have a code with this value. Ok = 0, /** The operation was cancelled (typically by the caller). */ @@ -109,10 +106,6 @@ enum FirestoreErrorCode { Unauthenticated = 16 }; -// TODO(zxu123): decide whether we actually want an Error class or just use -// enum. -using Error = FirestoreErrorCode; - } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/include/firebase/firestore/geo_point.h b/Example/Pods/FirebaseFirestore/Firestore/core/include/firebase/firestore/geo_point.h index cc366be..ac56e74 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/include/firebase/firestore/geo_point.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/include/firebase/firestore/geo_point.h @@ -17,6 +17,9 @@ #ifndef FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_GEO_POINT_H_ #define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_GEO_POINT_H_ +#include +#include + namespace firebase { namespace firestore { @@ -29,56 +32,84 @@ namespace firestore { */ class GeoPoint { public: - /** - * Creates a `GeoPoint` with both latitude and longitude being 0. - */ - GeoPoint(); + /** Creates a `GeoPoint` with both latitude and longitude set to 0. */ + GeoPoint() = default; /** - * Creates a `GeoPoint` from the provided latitude and longitude degrees. + * Creates a `GeoPoint` from the provided latitude and longitude values. * - * @param latitude The latitude as number between -90 and 90. - * @param longitude The longitude as number between -180 and 180. + * @param latitude The latitude as number of degrees between -90 and 90. + * @param longitude The longitude as number of degrees between -180 and 180. */ GeoPoint(double latitude, double longitude); + /** Copy constructor, `GeoPoint` is trivially copyable. */ GeoPoint(const GeoPoint& other) = default; + + /** Move constructor, equivalent to copying. */ GeoPoint(GeoPoint&& other) = default; + + /** Copy assignment operator, `GeoPoint` is trivially copyable. */ GeoPoint& operator=(const GeoPoint& other) = default; + + /** Move assignment operator, equivalent to copying. */ GeoPoint& operator=(GeoPoint&& other) = default; + /** Returns the latitude value of this `GeoPoint`. */ double latitude() const { return latitude_; } + /** Returns the latitude value of this `GeoPoint`. */ double longitude() const { return longitude_; } + /** + * Returns a string representation of this `GeoPoint` for logging/debugging + * purposes. + * + * @note: the exact string representation is unspecified and subject to + * change; don't rely on the format of the string. + */ + std::string ToString() const; + + /** + * Outputs the string representation of this `GeoPoint` to the given stream. + * + * @see `ToString()` for comments on the representation format. + */ + friend std::ostream& operator<<(std::ostream& out, const GeoPoint& geo_point); + private: - double latitude_; - double longitude_; + double latitude_ = 0.0; + double longitude_ = 0.0; }; -/** Compares against another GeoPoint. */ +/** Checks whether `lhs` and `rhs` are in ascending order. */ bool operator<(const GeoPoint& lhs, const GeoPoint& rhs); +/** Checks whether `lhs` and `rhs` are in descending order. */ inline bool operator>(const GeoPoint& lhs, const GeoPoint& rhs) { return rhs < lhs; } +/** Checks whether `lhs` and `rhs` are in non-ascending order. */ inline bool operator>=(const GeoPoint& lhs, const GeoPoint& rhs) { return !(lhs < rhs); } +/** Checks whether `lhs` and `rhs` are in non-descending order. */ inline bool operator<=(const GeoPoint& lhs, const GeoPoint& rhs) { return !(lhs > rhs); } +/** Checks `lhs` and `rhs` for inequality. */ inline bool operator!=(const GeoPoint& lhs, const GeoPoint& rhs) { return lhs < rhs || lhs > rhs; } +/** Checks `lhs` and `rhs` for equality. */ inline bool operator==(const GeoPoint& lhs, const GeoPoint& rhs) { return !(lhs != rhs); } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/include/firebase/firestore/timestamp.h b/Example/Pods/FirebaseFirestore/Firestore/core/include/firebase/firestore/timestamp.h index fe4ac8f..49c60d3 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/include/firebase/firestore/timestamp.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/include/firebase/firestore/timestamp.h @@ -46,7 +46,7 @@ class Timestamp { * Creates a new timestamp representing the epoch (with seconds and * nanoseconds set to 0). */ - Timestamp(); + Timestamp() = default; /** * Creates a new timestamp. @@ -63,6 +63,18 @@ class Timestamp { */ Timestamp(int64_t seconds, int32_t nanoseconds); + /** Copy constructor, `Timestamp` is trivially copyable. */ + Timestamp(const Timestamp& other) = default; + + /** Move constructor, equivalent to copying. */ + Timestamp(Timestamp&& other) = default; + + /** Copy assignment operator, `Timestamp` is trivially copyable. */ + Timestamp& operator=(const Timestamp& other) = default; + + /** Move assignment operator, equivalent to copying. */ + Timestamp& operator=(Timestamp&& other) = default; + /** * Creates a new timestamp with the current date. * @@ -145,10 +157,16 @@ class Timestamp { * Returns a string representation of this `Timestamp` for logging/debugging * purposes. * - * Note: the exact string representation is unspecified and subject to change; - * don't rely on the format of the string. + * @note: the exact string representation is unspecified and subject to + * change; don't rely on the format of the string. */ std::string ToString() const; + + /** + * Outputs the string representation of this `Timestamp` to the given stream. + * + * @see `ToString()` for comments on the representation format. + */ friend std::ostream& operator<<(std::ostream& out, const Timestamp& timestamp); @@ -161,28 +179,34 @@ class Timestamp { int32_t nanoseconds_ = 0; }; +/** Checks whether `lhs` and `rhs` are in ascending order. */ inline bool operator<(const Timestamp& lhs, const Timestamp& rhs) { return lhs.seconds() < rhs.seconds() || (lhs.seconds() == rhs.seconds() && lhs.nanoseconds() < rhs.nanoseconds()); } +/** Checks whether `lhs` and `rhs` are in descending order. */ inline bool operator>(const Timestamp& lhs, const Timestamp& rhs) { return rhs < lhs; } +/** Checks whether `lhs` and `rhs` are in non-ascending order. */ inline bool operator>=(const Timestamp& lhs, const Timestamp& rhs) { return !(lhs < rhs); } +/** Checks whether `lhs` and `rhs` are in non-descending order. */ inline bool operator<=(const Timestamp& lhs, const Timestamp& rhs) { return !(lhs > rhs); } +/** Checks `lhs` and `rhs` for inequality. */ inline bool operator!=(const Timestamp& lhs, const Timestamp& rhs) { return lhs < rhs || lhs > rhs; } +/** Checks `lhs` and `rhs` for equality. */ inline bool operator==(const Timestamp& lhs, const Timestamp& rhs) { return !(lhs != rhs); } @@ -212,13 +236,4 @@ std::chrono::time_point Timestamp::ToTimePoint() const { } // namespace firebase -namespace std { -template <> -struct hash { - // Note: specialization of `std::hash` is provided for convenience only. The - // implementation is subject to change. - size_t operator()(const firebase::Timestamp& timestamp) const; -}; -} // namespace std - #endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_TIMESTAMP_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/collection_reference.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/collection_reference.cc new file mode 100644 index 0000000..1cfb5eb --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/collection_reference.cc @@ -0,0 +1,104 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/api/collection_reference.h" + +#include + +#include "Firestore/core/src/firebase/firestore/api/document_reference.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/autoid.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" +#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" + +namespace firebase { +namespace firestore { +namespace api { +namespace { + +using core::Query; +using model::DocumentKey; +using model::ResourcePath; +using util::ThrowInvalidArgument; + +Query MakeQuery(model::ResourcePath path) { + if (path.size() % 2 != 1) { + ThrowInvalidArgument( + "Invalid collection reference. Collection references " + "must have an odd number of segments, but %s has %s", + path.CanonicalString(), path.size()); + } + + return Query(std::move(path)); +} + +} // namespace + +CollectionReference::CollectionReference(model::ResourcePath path, + std::shared_ptr firestore) + : Query(MakeQuery(std::move(path)), std::move(firestore)) { +} + +bool operator==(const CollectionReference& lhs, + const CollectionReference& rhs) { + return lhs.firestore() == rhs.firestore() && lhs.query() == rhs.query(); +} + +size_t CollectionReference::Hash() const { + return util::Hash(firestore().get(), query()); +} + +std::string CollectionReference::collection_id() const { + return query().path().last_segment(); +} + +absl::optional CollectionReference::parent() const { + ResourcePath parent_path = query().path().PopLast(); + if (parent_path.empty()) { + return absl::nullopt; + } else { + return DocumentReference(DocumentKey(std::move(parent_path)), firestore()); + } +} + +std::string CollectionReference::path() const { + return query().path().CanonicalString(); +} + +DocumentReference CollectionReference::Document( + const std::string& document_path) const { + ResourcePath sub_path = ResourcePath::FromString(document_path); + ResourcePath path = query().path().Append(sub_path); + return DocumentReference(std::move(path), firestore()); +} + +DocumentReference CollectionReference::AddDocument( + core::ParsedSetData&& data, util::StatusCallback callback) const { + DocumentReference doc_ref = Document(); + doc_ref.SetData(std::move(data), std::move(callback)); + return doc_ref; +} + +DocumentReference CollectionReference::Document() const { + DocumentKey key(query().path().Append(util::CreateAutoId())); + return DocumentReference(std::move(key), firestore()); +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/collection_reference.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/collection_reference.h new file mode 100644 index 0000000..2cbc45a --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/collection_reference.h @@ -0,0 +1,106 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_COLLECTION_REFERENCE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_COLLECTION_REFERENCE_H_ + +#include +#include + +#include "Firestore/core/src/firebase/firestore/api/query_core.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace core { + +class ParsedSetData; + +} // namespace core + +namespace api { + +class DocumentReference; + +/** + * A `CollectionReference` object can be used for adding documents, getting + * document references, and querying for documents (using the methods inherited + * from `Query`). + */ +class CollectionReference : public Query { + public: + CollectionReference() = default; + CollectionReference(model::ResourcePath path, + std::shared_ptr firestore); + + /** ID of the referenced collection. */ + std::string collection_id() const; + + /** + * For subcollections, `parent` returns the containing `DocumentReference`. + * For root collections, nullopt is returned. + */ + absl::optional parent() const; + + /** + * A string containing the slash-separated path to this `CollectionReference` + * (relative to the root of the database). + */ + std::string path() const; + + /** + * Returns a `DocumentReference` pointing to a new document with an + * auto-generated ID. + */ + DocumentReference Document() const; + + /** + * Gets a `DocumentReference` referring to the document at the specified path, + * relative to this collection's own path. + * + * @param document_path The slash-separated relative path of the document for + * which to get a `DocumentReference`. + * + * @return The `DocumentReference` for the specified document path. + */ + DocumentReference Document(const std::string& document_path) const; + + /** + * Add a new document to this collection with the specified data, assigning it + * a document ID automatically. + * + * @param data A `ParsedSetData` containing the data for the new document. + * @param callback A callback to execute once the document has been + * successfully written to the server. This callback will not be called + * while the client is offline, though local changes will be visible + * immediately. + * + * @return A `DocumentReference` pointing to the newly created document. + */ + DocumentReference AddDocument(core::ParsedSetData&& data, + util::StatusCallback callback) const; + + size_t Hash() const; +}; + +bool operator==(const CollectionReference& lhs, const CollectionReference& rhs); + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_COLLECTION_REFERENCE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_change.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_change.cc new file mode 100644 index 0000000..55c076d --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_change.cc @@ -0,0 +1,37 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/api/document_change.h" + +#include "Firestore/core/src/firebase/firestore/util/hashing.h" + +namespace firebase { +namespace firestore { +namespace api { + +size_t DocumentChange::Hash() const { + return util::Hash(type_, document_, old_index_, new_index_); +} + +bool operator==(const DocumentChange& lhs, const DocumentChange& rhs) { + return lhs.type() == rhs.type() && lhs.document() == rhs.document() && + lhs.old_index() == rhs.old_index() && + lhs.new_index() == rhs.new_index(); +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_change.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_change.h new file mode 100644 index 0000000..36fdf56 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_change.h @@ -0,0 +1,86 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_DOCUMENT_CHANGE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_DOCUMENT_CHANGE_H_ + +#include +#include + +#include "Firestore/core/src/firebase/firestore/api/document_snapshot.h" + +namespace firebase { +namespace firestore { +namespace api { + +class DocumentChange { + public: + enum class Type { Added, Modified, Removed }; + + DocumentChange() = default; + DocumentChange(Type type, + DocumentSnapshot document, + size_t old_index, + size_t new_index) + : type_(type), + document_(std::move(document)), + old_index_(old_index), + new_index_(new_index) { + } + + size_t Hash() const; + + Type type() const { + return type_; + } + + DocumentSnapshot document() const { + return document_; + } + + size_t old_index() const { + return old_index_; + } + + size_t new_index() const { + return new_index_; + } + + const std::shared_ptr& firestore() const { + return document_.firestore(); + } + + /** + * A sentinel return value for old_index() and new_index() indicating that + * there's no relevant index to return because the document was newly added + * or removed respectively. + */ + static constexpr size_t npos = static_cast(-1); + + private: + Type type_; + DocumentSnapshot document_; + size_t old_index_; + size_t new_index_; +}; + +bool operator==(const DocumentChange& lhs, const DocumentChange& rhs); + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_DOCUMENT_CHANGE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_reference.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_reference.cc new file mode 100644 index 0000000..51a5ce8 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_reference.cc @@ -0,0 +1,252 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/api/document_reference.h" + +#include // NOLINT(build/c++11) +#include + +#include "Firestore/core/src/firebase/firestore/api/collection_reference.h" +#include "Firestore/core/src/firebase/firestore/api/firestore.h" +#include "Firestore/core/src/firebase/firestore/api/query_listener_registration.h" +#include "Firestore/core/src/firebase/firestore/api/source.h" +#include "Firestore/core/src/firebase/firestore/core/firestore_client.h" +#include "Firestore/core/src/firebase/firestore/core/user_data.h" +#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" +#include "Firestore/core/src/firebase/firestore/model/delete_mutation.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/document_set.h" +#include "Firestore/core/src/firebase/firestore/model/precondition.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/error_apple.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/statusor.h" + +namespace firebase { +namespace firestore { +namespace api { + +using core::AsyncEventListener; +using core::EventListener; +using core::ListenOptions; +using core::QueryListener; +using core::ViewSnapshot; +using model::DeleteMutation; +using model::Document; +using model::DocumentKey; +using model::Precondition; +using model::ResourcePath; +using util::Status; +using util::StatusOr; +using util::StatusOrCallback; + +DocumentReference::DocumentReference(model::ResourcePath path, + std::shared_ptr firestore) + : firestore_{std::move(firestore)} { + if (path.size() % 2 != 0) { + HARD_FAIL( + "Invalid document reference. Document references must have an even " + "number of segments, but %s has %s", + path.CanonicalString(), path.size()); + } + key_ = DocumentKey{std::move(path)}; +} + +size_t DocumentReference::Hash() const { + return util::Hash(firestore_.get(), key_); +} + +const std::string& DocumentReference::document_id() const { + return key_.path().last_segment(); +} + +CollectionReference DocumentReference::Parent() const { + return CollectionReference{key_.path().PopLast(), firestore_}; +} + +std::string DocumentReference::Path() const { + return key_.path().CanonicalString(); +} + +CollectionReference DocumentReference::GetCollectionReference( + const std::string& collection_path) const { + ResourcePath sub_path = ResourcePath::FromString(collection_path); + ResourcePath path = key_.path().Append(sub_path); + return CollectionReference{path, firestore_}; +} + +void DocumentReference::SetData(core::ParsedSetData&& set_data, + util::StatusCallback callback) { + firestore_->client()->WriteMutations( + std::move(set_data).ToMutations(key(), Precondition::None()), + std::move(callback)); +} + +void DocumentReference::UpdateData(core::ParsedUpdateData&& update_data, + util::StatusCallback callback) { + firestore_->client()->WriteMutations( + std::move(update_data).ToMutations(key(), Precondition::Exists(true)), + std::move(callback)); +} + +void DocumentReference::DeleteDocument(util::StatusCallback callback) { + DeleteMutation mutation(key_, Precondition::None()); + firestore_->client()->WriteMutations({mutation}, std::move(callback)); +} + +void DocumentReference::GetDocument(Source source, + DocumentSnapshot::Listener&& callback) { + if (source == Source::Cache) { + firestore_->client()->GetDocumentFromLocalCache(*this, std::move(callback)); + return; + } + + ListenOptions options( + /*include_query_metadata_changes=*/true, + /*include_document_metadata_changes=*/true, + /*wait_for_sync_when_online=*/true); + + class ListenOnce : public EventListener { + public: + ListenOnce(Source source, DocumentSnapshot::Listener&& listener) + : source_(source), listener_(std::move(listener)) { + } + + void OnEvent(StatusOr maybe_snapshot) override { + if (!maybe_snapshot.ok()) { + listener_->OnEvent(std::move(maybe_snapshot)); + return; + } + + DocumentSnapshot snapshot = std::move(maybe_snapshot).ValueOrDie(); + + // Remove query first before passing event to user to avoid user actions + // affecting the now stale query. + std::unique_ptr registration = + registration_promise_.get_future().get(); + registration->Remove(); + + if (!snapshot.exists() && snapshot.metadata().from_cache()) { + // TODO(dimond): Reconsider how to raise missing documents when + // offline. If we're online and the document doesn't exist then we + // call the callback with a document with document.exists set to + // false. If we're offline however, we call the callback + // with an error. Two options: 1) Cache the negative response from the + // server so we can deliver that even when you're offline. + // 2) Actually call the callback with an error if the + // document doesn't exist when you are offline. + listener_->OnEvent( + Status{Error::Unavailable, + "Failed to get document because the client is offline."}); + } else if (snapshot.exists() && snapshot.metadata().from_cache() && + source_ == Source::Server) { + listener_->OnEvent( + Status{Error::Unavailable, + "Failed to get document from server. (However, " + "this document does exist in the local cache. Run " + "again without setting source to " + "FirestoreSourceServer to retrieve the cached " + "document.)"}); + } else { + listener_->OnEvent(std::move(snapshot)); + } + } + + void Resolve(std::unique_ptr registration) { + registration_promise_.set_value(std::move(registration)); + } + + private: + Source source_; + DocumentSnapshot::Listener listener_; + + std::promise> registration_promise_; + }; + auto listener = absl::make_unique(source, std::move(callback)); + auto listener_unowned = listener.get(); + + std::unique_ptr registration = + AddSnapshotListener(std::move(options), std::move(listener)); + + listener_unowned->Resolve(std::move(registration)); +} + +std::unique_ptr DocumentReference::AddSnapshotListener( + ListenOptions options, DocumentSnapshot::Listener&& user_listener) { + // Convert from ViewSnapshots to DocumentSnapshots. + class Converter : public EventListener { + public: + Converter(DocumentReference* parent, + DocumentSnapshot::Listener&& user_listener) + : firestore_(parent->firestore_), + key_(parent->key_), + user_listener_(std::move(user_listener)) { + } + + void OnEvent(StatusOr maybe_snapshot) override { + if (!maybe_snapshot.ok()) { + user_listener_->OnEvent(maybe_snapshot.status()); + return; + } + + ViewSnapshot snapshot = std::move(maybe_snapshot).ValueOrDie(); + HARD_ASSERT(snapshot.documents().size() <= 1, + "Too many documents returned on a document query"); + absl::optional document = + snapshot.documents().GetDocument(key_); + + bool has_pending_writes = + document ? snapshot.mutated_keys().contains(key_) + // We don't raise `has_pending_writes` for deleted documents. + : false; + + DocumentSnapshot result{ + firestore_, key_, document, + SnapshotMetadata{has_pending_writes, snapshot.from_cache()}}; + user_listener_->OnEvent(std::move(result)); + } + + private: + std::shared_ptr firestore_; + DocumentKey key_; + DocumentSnapshot::Listener user_listener_; + }; + auto view_listener = + absl::make_unique(this, std::move(user_listener)); + + // Call the view_listener on the user Executor. + auto async_listener = AsyncEventListener::Create( + firestore_->client()->user_executor(), std::move(view_listener)); + + core::Query query(key_.path()); + std::shared_ptr query_listener = + firestore_->client()->ListenToQuery(std::move(query), options, + async_listener); + + return absl::make_unique( + firestore_->client(), std::move(async_listener), + std::move(query_listener)); +} + +bool operator==(const DocumentReference& lhs, const DocumentReference& rhs) { + return lhs.firestore() == rhs.firestore() && lhs.key() == rhs.key(); +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_reference.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_reference.h index d107d45..04629c0 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_reference.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_reference.h @@ -17,50 +17,47 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_DOCUMENT_REFERENCE_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_DOCUMENT_REFERENCE_H_ -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import - +#include #include #include -#include - -#import "FIRDocumentReference.h" -#import "FIRFirestoreSource.h" #include "Firestore/core/src/firebase/firestore/api/document_snapshot.h" #include "Firestore/core/src/firebase/firestore/api/listener_registration.h" #include "Firestore/core/src/firebase/firestore/core/listen_options.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" -#include "Firestore/core/src/firebase/firestore/util/statusor_callback.h" - -NS_ASSUME_NONNULL_BEGIN - -@class FIRFirestore; -@class FSTMutation; +#include "Firestore/core/src/firebase/firestore/util/nullability.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" namespace firebase { namespace firestore { +namespace core { + +class ParsedSetData; +class ParsedUpdateData; + +} // namespace core + namespace api { +class CollectionReference; class Firestore; +enum class Source; class DocumentReference { public: - using Completion = void (^)(NSError* _Nullable error) _Nullable; - DocumentReference() = default; - DocumentReference(model::ResourcePath path, Firestore* firestore); - DocumentReference(model::DocumentKey document_key, Firestore* firestore) - : firestore_{firestore}, key_{std::move(document_key)} { + DocumentReference(model::ResourcePath path, + std::shared_ptr firestore); + DocumentReference(model::DocumentKey document_key, + std::shared_ptr firestore) + : firestore_{std::move(firestore)}, key_{std::move(document_key)} { } size_t Hash() const; - Firestore* firestore() const { + const std::shared_ptr& firestore() const { return firestore_; } const model::DocumentKey& key() const { @@ -69,29 +66,27 @@ class DocumentReference { const std::string& document_id() const; - // TODO(varconst) uncomment when core API CollectionReference is implemented. - // CollectionReference Parent() const; + CollectionReference Parent() const; std::string Path() const; - // TODO(varconst) uncomment when core API CollectionReference is implemented. - // CollectionReference GetCollectionReference( - // const std::string& collection_path) const; + CollectionReference GetCollectionReference( + const std::string& collection_path) const; - void SetData(std::vector&& mutations, Completion completion); + void SetData(core::ParsedSetData&& set_data, util::StatusCallback callback); - void UpdateData(std::vector&& mutations, Completion completion); + void UpdateData(core::ParsedUpdateData&& update_data, + util::StatusCallback callback); - void DeleteDocument(Completion completion); + void DeleteDocument(util::StatusCallback callback); - void GetDocument(FIRFirestoreSource source, - DocumentSnapshot::Listener&& completion); + void GetDocument(Source source, DocumentSnapshot::Listener&& callback); - ListenerRegistration AddSnapshotListener( + std::unique_ptr AddSnapshotListener( core::ListenOptions options, DocumentSnapshot::Listener&& listener); private: - Firestore* firestore_ = nullptr; + std::shared_ptr firestore_; model::DocumentKey key_; }; @@ -101,6 +96,4 @@ bool operator==(const DocumentReference& lhs, const DocumentReference& rhs); } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_DOCUMENT_REFERENCE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_reference.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_reference.mm deleted file mode 100644 index 5e8de27..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_reference.mm +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/api/document_reference.h" - -#include // NOLINT(build/c++11) -#include - -#import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h" -#import "Firestore/Source/API/FIRFirestore+Internal.h" -#import "Firestore/Source/API/FIRListenerRegistration+Internal.h" -#import "Firestore/Source/Core/FSTEventManager.h" -#import "Firestore/Source/Core/FSTFirestoreClient.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" - -#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/document_set.h" -#include "Firestore/core/src/firebase/firestore/model/precondition.h" -#include "Firestore/core/src/firebase/firestore/model/resource_path.h" -#include "Firestore/core/src/firebase/firestore/util/error_apple.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/hashing.h" -#include "Firestore/core/src/firebase/firestore/util/objc_compatibility.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" -#include "Firestore/core/src/firebase/firestore/util/statusor.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace firebase { -namespace firestore { -namespace api { - -namespace objc = util::objc; -using core::AsyncEventListener; -using core::EventListener; -using core::ViewSnapshot; -using model::DocumentKey; -using model::Precondition; -using model::ResourcePath; -using util::MakeNSError; -using util::Status; -using util::StatusOr; -using util::StatusOrCallback; - -DocumentReference::DocumentReference(model::ResourcePath path, - Firestore* firestore) - : firestore_{firestore} { - if (path.size() % 2 != 0) { - HARD_FAIL( - "Invalid document reference. Document references must have an even " - "number of segments, but %s has %s", - path.CanonicalString(), path.size()); - } - key_ = DocumentKey{std::move(path)}; -} - -size_t DocumentReference::Hash() const { - return util::Hash(firestore_, key_); -} - -const std::string& DocumentReference::document_id() const { - return key_.path().last_segment(); -} - -// TODO(varconst) uncomment when core API CollectionReference is implemented. -// CollectionReference DocumentReference::Parent() const { -// return CollectionReference{firestore_, key_.path().PopLast()}; -// } - -std::string DocumentReference::Path() const { - return key_.path().CanonicalString(); -} - -// TODO(varconst) uncomment when core API CollectionReference is implemented. -// CollectionReference DocumentReference::GetCollectionReference( -// const std::string& collection_path) const { -// ResourcePath sub_path = ResourcePath::FromString(collection_path); -// ResourcePath path = key_.path().Append(sub_path); -// return CollectionReference{firestore_, path}; -// } - -void DocumentReference::SetData(std::vector&& mutations, - Completion completion) { - [firestore_->client() writeMutations:std::move(mutations) - completion:completion]; -} - -void DocumentReference::UpdateData(std::vector&& mutations, - Completion completion) { - return [firestore_->client() writeMutations:std::move(mutations) - completion:completion]; -} - -void DocumentReference::DeleteDocument(Completion completion) { - FSTDeleteMutation* mutation = - [[FSTDeleteMutation alloc] initWithKey:key_ - precondition:Precondition::None()]; - [firestore_->client() writeMutations:{mutation} completion:completion]; -} - -void DocumentReference::GetDocument(FIRFirestoreSource source, - DocumentSnapshot::Listener&& completion) { - if (source == FIRFirestoreSourceCache) { - [firestore_->client() getDocumentFromLocalCache:*this - completion:std::move(completion)]; - return; - } - - ListenOptions options( - /*include_query_metadata_changes=*/true, - /*include_document_metadata_changes=*/true, - /*wait_for_sync_when_online=*/true); - - class ListenOnce : public EventListener { - public: - ListenOnce(FIRFirestoreSource source, - DocumentSnapshot::Listener&& completion) - : source_(source), completion_(std::move(completion)) { - } - - void OnEvent(StatusOr maybe_snapshot) override { - if (!maybe_snapshot.ok()) { - completion_->OnEvent(std::move(maybe_snapshot)); - return; - } - - DocumentSnapshot snapshot = std::move(maybe_snapshot).ValueOrDie(); - - // Remove query first before passing event to user to avoid user actions - // affecting the now stale query. - ListenerRegistration registration = - registration_promise_.get_future().get(); - registration.Remove(); - - if (!snapshot.exists() && snapshot.metadata().from_cache()) { - // TODO(dimond): Reconsider how to raise missing documents when - // offline. If we're online and the document doesn't exist then we - // call the completion with a document with document.exists set to - // false. If we're offline however, we call the completion handler - // with an error. Two options: 1) Cache the negative response from the - // server so we can deliver that even when you're offline. - // 2) Actually call the completion handler with an error if the - // document doesn't exist when you are offline. - completion_->OnEvent( - Status{FirestoreErrorCode::Unavailable, - "Failed to get document because the client is offline."}); - } else if (snapshot.exists() && snapshot.metadata().from_cache() && - source_ == FIRFirestoreSourceServer) { - completion_->OnEvent( - Status{FirestoreErrorCode::Unavailable, - "Failed to get document from server. (However, " - "this document does exist in the local cache. Run " - "again without setting source to " - "FIRFirestoreSourceServer to retrieve the cached " - "document.)"}); - } else { - completion_->OnEvent(std::move(snapshot)); - } - } - - void Resolve(ListenerRegistration&& registration) { - registration_promise_.set_value(std::move(registration)); - } - - private: - FIRFirestoreSource source_; - DocumentSnapshot::Listener completion_; - - std::promise registration_promise_; - }; - auto listener = absl::make_unique(source, std::move(completion)); - auto listener_unowned = listener.get(); - - ListenerRegistration registration = - AddSnapshotListener(std::move(options), std::move(listener)); - - listener_unowned->Resolve(std::move(registration)); -} - -ListenerRegistration DocumentReference::AddSnapshotListener( - ListenOptions options, DocumentSnapshot::Listener&& user_listener) { - FSTQuery* query = [FSTQuery queryWithPath:key_.path()]; - - // Convert from ViewSnapshots to DocumentSnapshots. - class Converter : public EventListener { - public: - Converter(DocumentReference* parent, - DocumentSnapshot::Listener&& user_listener) - : firestore_(parent->firestore_), - key_(parent->key_), - user_listener_(std::move(user_listener)) { - } - - void OnEvent(StatusOr maybe_snapshot) override { - if (!maybe_snapshot.ok()) { - user_listener_->OnEvent(maybe_snapshot.status()); - return; - } - - ViewSnapshot snapshot = std::move(maybe_snapshot).ValueOrDie(); - HARD_ASSERT(snapshot.documents().size() <= 1, - "Too many documents returned on a document query"); - FSTDocument* document = snapshot.documents().GetDocument(key_); - - bool has_pending_writes = - document ? snapshot.mutated_keys().contains(key_) - // We don't raise `has_pending_writes` for deleted documents. - : false; - - DocumentSnapshot result{firestore_, key_, document, snapshot.from_cache(), - has_pending_writes}; - user_listener_->OnEvent(std::move(result)); - } - - private: - Firestore* firestore_; - DocumentKey key_; - DocumentSnapshot::Listener user_listener_; - }; - auto view_listener = - absl::make_unique(this, std::move(user_listener)); - - // Call the view_listener on the user Executor. - auto async_listener = AsyncEventListener::Create( - firestore_->client().userExecutor, std::move(view_listener)); - - std::shared_ptr query_listener = - [firestore_->client() listenToQuery:query - options:options - listener:async_listener]; - return ListenerRegistration(firestore_->client(), std::move(async_listener), - std::move(query_listener)); -} - -bool operator==(const DocumentReference& lhs, const DocumentReference& rhs) { - return lhs.firestore() == rhs.firestore() && lhs.key() == rhs.key(); -} - -} // namespace api -} // namespace firestore -} // namespace firebase - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_snapshot.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_snapshot.cc new file mode 100644 index 0000000..f67d549 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_snapshot.cc @@ -0,0 +1,101 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/api/document_snapshot.h" + +#include "Firestore/core/src/firebase/firestore/api/document_reference.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace api { + +using model::Document; +using model::DocumentKey; +using model::FieldPath; +using model::FieldValue; +using model::ObjectValue; + +DocumentSnapshot DocumentSnapshot::FromDocument( + std::shared_ptr firestore, + model::Document document, + SnapshotMetadata metadata) { + return DocumentSnapshot{std::move(firestore), document.key(), document, + std::move(metadata)}; +} + +DocumentSnapshot DocumentSnapshot::FromNoDocument( + std::shared_ptr firestore, + model::DocumentKey key, + SnapshotMetadata metadata) { + return DocumentSnapshot{std::move(firestore), key, absl::nullopt, + std::move(metadata)}; +} + +DocumentSnapshot::DocumentSnapshot(std::shared_ptr firestore, + model::DocumentKey document_key, + absl::optional document, + SnapshotMetadata metadata) + : firestore_{std::move(firestore)}, + internal_key_{std::move(document_key)}, + internal_document_{std::move(document)}, + metadata_{std::move(metadata)} { +} + +size_t DocumentSnapshot::Hash() const { + return util::Hash(firestore_.get(), internal_key_, internal_document_, + metadata_); +} + +bool DocumentSnapshot::exists() const { + return internal_document_.has_value(); +} + +const absl::optional& DocumentSnapshot::internal_document() const { + return internal_document_; +} + +DocumentReference DocumentSnapshot::CreateReference() const { + return DocumentReference{internal_key_, firestore_}; +} + +const std::string& DocumentSnapshot::document_id() const { + return internal_key_.path().last_segment(); +} + +absl::optional DocumentSnapshot::GetData() const { + return internal_document_ ? internal_document_->data() + : absl::optional{}; +} + +absl::optional DocumentSnapshot::GetValue( + const FieldPath& field_path) const { + return internal_document_ ? internal_document_->field(field_path) + : absl::optional{}; +} + +bool operator==(const DocumentSnapshot& lhs, const DocumentSnapshot& rhs) { + return lhs.firestore_ == rhs.firestore_ && + lhs.internal_key_ == rhs.internal_key_ && + lhs.internal_document_ == rhs.internal_document_ && + lhs.metadata_ == rhs.metadata_; +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_snapshot.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_snapshot.h index e0662e1..26caa0f 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_snapshot.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_snapshot.h @@ -17,26 +17,17 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_DOCUMENT_SNAPSHOT_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_DOCUMENT_SNAPSHOT_H_ -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import - #include #include #include -#import "Firestore/Source/Model/FSTFieldValue.h" - #include "Firestore/core/src/firebase/firestore/api/snapshot_metadata.h" #include "Firestore/core/src/firebase/firestore/core/event_listener.h" +#include "Firestore/core/src/firebase/firestore/model/document.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" - -NS_ASSUME_NONNULL_BEGIN - -@class FSTDocument; +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "absl/types/optional.h" namespace firebase { namespace firestore { @@ -51,36 +42,19 @@ class DocumentSnapshot { DocumentSnapshot() = default; - DocumentSnapshot(Firestore* firestore, - model::DocumentKey document_key, - FSTDocument* _Nullable document, - SnapshotMetadata metadata) - : firestore_{firestore}, - internal_key_{std::move(document_key)}, - internal_document_{document}, - metadata_{std::move(metadata)} { - } + static DocumentSnapshot FromDocument(std::shared_ptr firestore, + model::Document document, + SnapshotMetadata metadata); - DocumentSnapshot(Firestore* firestore, - model::DocumentKey document_key, - FSTDocument* _Nullable document, - bool from_cache, - bool has_pending_writes) - : firestore_{firestore}, - internal_key_{std::move(document_key)}, - internal_document_{document}, - metadata_{has_pending_writes, from_cache} { - } + static DocumentSnapshot FromNoDocument(std::shared_ptr firestore, + model::DocumentKey key, + SnapshotMetadata metadata); size_t Hash() const; - bool exists() const { - return internal_document_ != nil; - } - FSTDocument* internal_document() const { - return internal_document_; - } - std::string document_id() const; + bool exists() const; + const absl::optional& internal_document() const; + const std::string& document_id() const; const SnapshotMetadata& metadata() const { return metadata_; @@ -88,10 +62,11 @@ class DocumentSnapshot { DocumentReference CreateReference() const; - FSTObjectValue* _Nullable GetData() const; - id _Nullable GetValue(const model::FieldPath& field_path) const; + absl::optional GetData() const; + absl::optional GetValue( + const model::FieldPath& field_path) const; - Firestore* firestore() const { + const std::shared_ptr& firestore() const { return firestore_; } @@ -99,16 +74,29 @@ class DocumentSnapshot { const DocumentSnapshot& rhs); private: - Firestore* firestore_ = nullptr; + // TODO(b/146372592): Make this public once we can use Abseil across + // iOS/public C++ library boundaries. + friend class DocumentReference; + + DocumentSnapshot(std::shared_ptr firestore, + model::DocumentKey document_key, + absl::optional document, + SnapshotMetadata metadata); + + private: + std::shared_ptr firestore_; model::DocumentKey internal_key_; - FSTDocument* internal_document_ = nil; + absl::optional internal_document_; SnapshotMetadata metadata_; }; +inline bool operator!=(const DocumentSnapshot& lhs, + const DocumentSnapshot& rhs) { + return !(lhs == rhs); +} + } // namespace api } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_DOCUMENT_SNAPSHOT_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_snapshot.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_snapshot.mm deleted file mode 100644 index f07885b..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/document_snapshot.mm +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/api/document_snapshot.h" - -#import "Firestore/Source/API/FIRDocumentReference+Internal.h" -#import "Firestore/Source/Model/FSTDocument.h" - -#include "Firestore/core/src/firebase/firestore/util/hashing.h" -#include "Firestore/core/src/firebase/firestore/util/objc_compatibility.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace firebase { -namespace firestore { -namespace api { - -namespace objc = util::objc; -using model::DocumentKey; -using model::FieldPath; - -size_t DocumentSnapshot::Hash() const { - return util::Hash(firestore_, internal_key_, internal_document_, metadata_); -} - -DocumentReference DocumentSnapshot::CreateReference() const { - return DocumentReference{internal_key_, firestore_}; -} - -std::string DocumentSnapshot::document_id() const { - return internal_key_.path().last_segment(); -} - -FSTObjectValue* _Nullable DocumentSnapshot::GetData() const { - return internal_document_ == nil ? nil : [internal_document_ data]; -} - -id _Nullable DocumentSnapshot::GetValue(const FieldPath& field_path) const { - return [[internal_document_ data] valueForPath:field_path]; -} - -bool operator==(const DocumentSnapshot& lhs, const DocumentSnapshot& rhs) { - return lhs.firestore_ == rhs.firestore_ && - lhs.internal_key_ == rhs.internal_key_ && - objc::Equals(lhs.internal_document_, rhs.internal_document_) && - lhs.metadata_ == rhs.metadata_; -} - -} // namespace api -} // namespace firestore -} // namespace firebase - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/firestore.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/firestore.cc new file mode 100644 index 0000000..80ca8b0 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/firestore.cc @@ -0,0 +1,214 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/api/firestore.h" + +#include "Firestore/core/src/firebase/firestore/api/collection_reference.h" +#include "Firestore/core/src/firebase/firestore/api/document_reference.h" +#include "Firestore/core/src/firebase/firestore/api/settings.h" +#include "Firestore/core/src/firebase/firestore/api/snapshots_in_sync_listener_registration.h" +#include "Firestore/core/src/firebase/firestore/api/write_batch.h" +#include "Firestore/core/src/firebase/firestore/core/firestore_client.h" +#include "Firestore/core/src/firebase/firestore/core/query.h" +#include "Firestore/core/src/firebase/firestore/core/transaction.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_persistence.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/async_queue.h" +#include "Firestore/core/src/firebase/firestore/util/executor.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "absl/memory/memory.h" + +namespace firebase { +namespace firestore { +namespace api { + +using auth::CredentialsProvider; +using core::AsyncEventListener; +using core::DatabaseInfo; +using core::FirestoreClient; +using core::Transaction; +using local::LevelDbPersistence; +using model::DocumentKey; +using model::ResourcePath; +using util::AsyncQueue; +using util::Empty; +using util::Executor; +using util::Status; + +Firestore::Firestore(model::DatabaseId database_id, + std::string persistence_key, + std::shared_ptr credentials_provider, + std::shared_ptr worker_queue, + void* extension) + : database_id_{std::move(database_id)}, + credentials_provider_{std::move(credentials_provider)}, + persistence_key_{std::move(persistence_key)}, + worker_queue_{std::move(worker_queue)}, + extension_{extension} { +} + +Firestore::~Firestore() { + std::lock_guard lock{mutex_}; + + // If the client hasn't been configured yet we don't need to create it just + // to tear it down. + if (!client_) return; + + client_->Terminate(); +} + +const std::shared_ptr& Firestore::client() { + HARD_ASSERT(client_, "Client is not yet configured."); + return client_; +} + +const std::shared_ptr& Firestore::worker_queue() { + return worker_queue_; +} + +const Settings& Firestore::settings() const { + std::lock_guard lock{mutex_}; + return settings_; +} + +void Firestore::set_settings(const Settings& settings) { + std::lock_guard lock{mutex_}; + if (client_) { + HARD_FAIL( + "Firestore instance has already been started and its settings can " + "no longer be changed. You can only set settings before calling any " + "other methods on a Firestore instance."); + } + settings_ = settings; +} + +void Firestore::set_user_executor(std::unique_ptr user_executor) { + std::lock_guard lock{mutex_}; + HARD_ASSERT(!client_ && user_executor, + "set_user_executor() must be called with a valid executor, " + "before the client is initialized."); + user_executor_ = std::move(user_executor); +} + +CollectionReference Firestore::GetCollection( + const std::string& collection_path) { + EnsureClientConfigured(); + ResourcePath path = ResourcePath::FromString(collection_path); + return CollectionReference{std::move(path), shared_from_this()}; +} + +DocumentReference Firestore::GetDocument(const std::string& document_path) { + EnsureClientConfigured(); + return DocumentReference{ResourcePath::FromString(document_path), + shared_from_this()}; +} + +WriteBatch Firestore::GetBatch() { + EnsureClientConfigured(); + return WriteBatch(shared_from_this()); +} + +core::Query Firestore::GetCollectionGroup(std::string collection_id) { + EnsureClientConfigured(); + + return core::Query(ResourcePath::Empty(), std::make_shared( + std::move(collection_id))); +} + +void Firestore::RunTransaction( + core::TransactionUpdateCallback update_callback, + core::TransactionResultCallback result_callback) { + EnsureClientConfigured(); + + client_->Transaction(5, std::move(update_callback), + std::move(result_callback)); +} + +void Firestore::Terminate(util::StatusCallback callback) { + // The client must be initialized to ensure that all subsequent API usage + // throws an exception. + EnsureClientConfigured(); + client_->TerminateAsync(std::move(callback)); +} + +void Firestore::WaitForPendingWrites(util::StatusCallback callback) { + EnsureClientConfigured(); + client_->WaitForPendingWrites(std::move(callback)); +} + +void Firestore::ClearPersistence(util::StatusCallback callback) { + worker_queue()->EnqueueEvenAfterShutdown([this, callback] { + auto Yield = [=](Status status) { + if (callback) { + this->user_executor_->Execute([=] { callback(status); }); + } + }; + + { + std::lock_guard lock{mutex_}; + if (client_ && !client()->is_terminated()) { + Yield(util::Status( + Error::FailedPrecondition, + "Persistence cannot be cleared while the client is running.")); + return; + } + } + + Yield(LevelDbPersistence::ClearPersistence(MakeDatabaseInfo())); + }); +} + +void Firestore::EnableNetwork(util::StatusCallback callback) { + EnsureClientConfigured(); + client_->EnableNetwork(std::move(callback)); +} + +void Firestore::DisableNetwork(util::StatusCallback callback) { + EnsureClientConfigured(); + client_->DisableNetwork(std::move(callback)); +} + +std::unique_ptr Firestore::AddSnapshotsInSyncListener( + std::unique_ptr> listener) { + EnsureClientConfigured(); + auto async_listener = AsyncEventListener::Create( + client_->user_executor(), std::move(listener)); + client_->AddSnapshotsInSyncListener(std::move(async_listener)); + return absl::make_unique( + client_, std::move(async_listener)); +} + +void Firestore::EnsureClientConfigured() { + std::lock_guard lock{mutex_}; + + if (!client_) { + HARD_ASSERT(worker_queue_, "Expected non-null worker queue"); + client_ = FirestoreClient::Create(MakeDatabaseInfo(), settings_, + std::move(credentials_provider_), + user_executor_, worker_queue_); + } +} + +DatabaseInfo Firestore::MakeDatabaseInfo() const { + return DatabaseInfo(database_id_, persistence_key_, settings_.host(), + settings_.ssl_enabled()); +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/firestore.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/firestore.h index 4be3b0b..d77960a 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/firestore.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/firestore.h @@ -17,55 +17,51 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_FIRESTORE_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_FIRESTORE_H_ -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import - #include #include // NOLINT(build/c++11) #include #include -#include "dispatch/dispatch.h" +#include "Firestore/core/src/firebase/firestore/api/listener_registration.h" +#include "Firestore/core/src/firebase/firestore/api/settings.h" #include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" +#include "Firestore/core/src/firebase/firestore/core/database_info.h" +#include "Firestore/core/src/firebase/firestore/core/event_listener.h" +#include "Firestore/core/src/firebase/firestore/core/transaction.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" - -NS_ASSUME_NONNULL_BEGIN - -@class FIRApp; -@class FIRCollectionReference; -@class FIRFirestore; -@class FIRFirestoreSettings; -@class FIRQuery; -@class FIRTransaction; -@class FIRWriteBatch; -@class FSTFirestoreClient; +#include "Firestore/core/src/firebase/firestore/util/empty.h" +#include "Firestore/core/src/firebase/firestore/util/nullability.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" +#include "absl/types/any.h" namespace firebase { namespace firestore { +namespace core { + +class FirestoreClient; +class Query; + +} // namespace core + namespace api { +class CollectionReference; class DocumentReference; +class WriteBatch; -class Firestore { +class Firestore : public std::enable_shared_from_this { public: - using TransactionBlock = id _Nullable (^)(FIRTransaction*, NSError** error); - using ErrorCompletion = void (^)(NSError* _Nullable error); - using ResultOrErrorCompletion = void (^)(id _Nullable result, - NSError* _Nullable error); - Firestore() = default; - Firestore(std::string project_id, - std::string database, + Firestore(model::DatabaseId database_id, std::string persistence_key, - std::unique_ptr credentials_provider, - std::unique_ptr worker_queue, + std::shared_ptr credentials_provider, + std::shared_ptr worker_queue, void* extension); + ~Firestore(); + const model::DatabaseId& database_id() const { return database_id_; } @@ -74,48 +70,51 @@ class Firestore { return persistence_key_; } - FSTFirestoreClient* client() { - return client_; - } + const std::shared_ptr& client(); - util::AsyncQueue* worker_queue(); + const std::shared_ptr& worker_queue(); void* extension() { return extension_; } - FIRFirestoreSettings* settings() const; - void set_settings(FIRFirestoreSettings* settings); + const Settings& settings() const; + void set_settings(const Settings& settings); + + void set_user_executor(std::unique_ptr user_executor); - FIRCollectionReference* GetCollection(absl::string_view collection_path); - DocumentReference GetDocument(absl::string_view document_path); - FIRWriteBatch* GetBatch(); - FIRQuery* GetCollectionGroup(NSString* collection_id); + CollectionReference GetCollection(const std::string& collection_path); + DocumentReference GetDocument(const std::string& document_path); + WriteBatch GetBatch(); + core::Query GetCollectionGroup(std::string collection_id); - void RunTransaction(TransactionBlock update_block, - dispatch_queue_t queue, - ResultOrErrorCompletion completion); + void RunTransaction(core::TransactionUpdateCallback update_callback, + core::TransactionResultCallback result_callback); - void Shutdown(ErrorCompletion completion); + void Terminate(util::StatusCallback callback); + void ClearPersistence(util::StatusCallback callback); + void WaitForPendingWrites(util::StatusCallback callback); + std::unique_ptr AddSnapshotsInSyncListener( + std::unique_ptr> listener); - void EnableNetwork(ErrorCompletion completion); - void DisableNetwork(ErrorCompletion completion); + void EnableNetwork(util::StatusCallback callback); + void DisableNetwork(util::StatusCallback callback); private: void EnsureClientConfigured(); + core::DatabaseInfo MakeDatabaseInfo() const; model::DatabaseId database_id_; - std::unique_ptr credentials_provider_; + std::shared_ptr credentials_provider_; std::string persistence_key_; - FSTFirestoreClient* client_ = nil; + std::shared_ptr client_; - // Ownership will be transferred to `FSTFirestoreClient` as soon as the - // client is created. - std::unique_ptr worker_queue_; + std::shared_ptr user_executor_; + std::shared_ptr worker_queue_; void* extension_ = nullptr; - FIRFirestoreSettings* settings_ = nil; + Settings settings_; mutable std::mutex mutex_; }; @@ -124,6 +123,4 @@ class Firestore { } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_FIRESTORE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/firestore.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/firestore.mm deleted file mode 100644 index e248dbc..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/firestore.mm +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/api/firestore.h" - -#import "FIRFirestoreSettings.h" -#import "Firestore/Source/API/FIRCollectionReference+Internal.h" -#import "Firestore/Source/API/FIRDocumentReference+Internal.h" -#import "Firestore/Source/API/FIRFirestore+Internal.h" -#import "Firestore/Source/API/FIRQuery+Internal.h" -#import "Firestore/Source/API/FIRTransaction+Internal.h" -#import "Firestore/Source/API/FIRWriteBatch+Internal.h" -#import "Firestore/Source/Core/FSTFirestoreClient.h" -#import "Firestore/Source/Core/FSTQuery.h" - -#include "Firestore/core/src/firebase/firestore/api/document_reference.h" -#include "Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.h" -#include "Firestore/core/src/firebase/firestore/core/transaction.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/resource_path.h" -#include "Firestore/core/src/firebase/firestore/util/async_queue.h" -#include "Firestore/core/src/firebase/firestore/util/executor_libdispatch.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "absl/memory/memory.h" - -namespace firebase { -namespace firestore { -namespace api { - -using firebase::firestore::api::Firestore; -using firebase::firestore::auth::CredentialsProvider; -using firebase::firestore::core::DatabaseInfo; -using firebase::firestore::core::Transaction; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::ResourcePath; -using util::AsyncQueue; -using util::Executor; -using util::ExecutorLibdispatch; - -Firestore::Firestore(std::string project_id, - std::string database, - std::string persistence_key, - std::unique_ptr credentials_provider, - std::unique_ptr worker_queue, - void* extension) - : database_id_{std::move(project_id), std::move(database)}, - credentials_provider_{std::move(credentials_provider)}, - persistence_key_{std::move(persistence_key)}, - worker_queue_{std::move(worker_queue)}, - extension_{extension} { - settings_ = [[FIRFirestoreSettings alloc] init]; -} - -AsyncQueue* Firestore::worker_queue() { - return [client_ workerQueue]; -} - -FIRFirestoreSettings* Firestore::settings() const { - std::lock_guard lock{mutex_}; - // Disallow mutation of our internal settings - return [settings_ copy]; -} - -void Firestore::set_settings(FIRFirestoreSettings* settings) { - std::lock_guard lock{mutex_}; - // As a special exception, don't throw if the same settings are passed - // repeatedly. This should make it more friendly to create a Firestore - // instance. - if (client_ && ![settings_ isEqual:settings]) { - HARD_FAIL( - "Firestore instance has already been started and its settings can " - "no longer be changed. You can only set settings before calling any " - "other methods on a Firestore instance."); - } - settings_ = [settings copy]; -} - -FIRCollectionReference* Firestore::GetCollection( - absl::string_view collection_path) { - EnsureClientConfigured(); - ResourcePath path = ResourcePath::FromString(collection_path); - return [FIRCollectionReference - referenceWithPath:path - firestore:[FIRFirestore recoverFromFirestore:this]]; -} - -DocumentReference Firestore::GetDocument(absl::string_view document_path) { - EnsureClientConfigured(); - return DocumentReference{ResourcePath::FromString(document_path), this}; -} - -FIRWriteBatch* Firestore::GetBatch() { - EnsureClientConfigured(); - FIRFirestore* wrapper = [FIRFirestore recoverFromFirestore:this]; - - return [FIRWriteBatch writeBatchWithFirestore:wrapper]; -} - -FIRQuery* Firestore::GetCollectionGroup(NSString* collection_id) { - EnsureClientConfigured(); - FIRFirestore* wrapper = [FIRFirestore recoverFromFirestore:this]; - - return - [FIRQuery referenceWithQuery:[FSTQuery queryWithPath:ResourcePath::Empty() - collectionGroup:collection_id] - firestore:wrapper]; -} - -void Firestore::RunTransaction(TransactionBlock update_block, - dispatch_queue_t queue, - ResultOrErrorCompletion completion) { - EnsureClientConfigured(); - FIRFirestore* wrapper = [FIRFirestore recoverFromFirestore:this]; - - FSTTransactionBlock wrapped_update = - ^(std::shared_ptr internal_transaction, - void (^internal_completion)(id _Nullable, NSError* _Nullable)) { - FIRTransaction* transaction = [FIRTransaction - transactionWithInternalTransaction:std::move(internal_transaction) - firestore:wrapper]; - - dispatch_async(queue, ^{ - NSError* _Nullable error = nil; - id _Nullable result = update_block(transaction, &error); - if (error) { - // Force the result to be nil in the case of an error, in case the - // user set both. - result = nil; - } - internal_completion(result, error); - }); - }; - - [client_ transactionWithRetries:5 - updateBlock:wrapped_update - completion:completion]; -} - -void Firestore::Shutdown(ErrorCompletion completion) { - if (!client_) { - if (completion) { - // We should be dispatching the callback on the user dispatch queue - // but if the client is nil here that queue was never created. - completion(nil); - } - } else { - [client_ shutdownWithCompletion:completion]; - } -} - -void Firestore::EnableNetwork(ErrorCompletion completion) { - EnsureClientConfigured(); - [client_ enableNetworkWithCompletion:completion]; -} - -void Firestore::DisableNetwork(ErrorCompletion completion) { - EnsureClientConfigured(); - [client_ disableNetworkWithCompletion:completion]; -} - -void Firestore::EnsureClientConfigured() { - std::lock_guard lock{mutex_}; - - if (!client_) { - // These values are validated elsewhere; this is just double-checking: - HARD_ASSERT(settings_.host, "FirestoreSettings.host cannot be nil."); - HARD_ASSERT(settings_.dispatchQueue, - "FirestoreSettings.dispatchQueue cannot be nil."); - - DatabaseInfo database_info(database_id_, persistence_key_, - util::MakeString(settings_.host), - settings_.sslEnabled); - - std::unique_ptr user_executor = - absl::make_unique(settings_.dispatchQueue); - - HARD_ASSERT(worker_queue_, "Expected non-null worker queue"); - client_ = - [FSTFirestoreClient clientWithDatabaseInfo:database_info - settings:settings_ - credentialsProvider:credentials_provider_.get() - userExecutor:std::move(user_executor) - workerQueue:std::move(worker_queue_)]; - } -} - -} // namespace api -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/listener_registration.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/listener_registration.h index 10fe4d0..0daef04 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/listener_registration.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/listener_registration.h @@ -17,33 +17,21 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_LISTENER_REGISTRATION_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_LISTENER_REGISTRATION_H_ -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import - -#include -#include - -#include "Firestore/core/src/firebase/firestore/core/event_listener.h" -#include "Firestore/core/src/firebase/firestore/core/query_listener.h" - -@class FSTFirestoreClient; - -NS_ASSUME_NONNULL_BEGIN - namespace firebase { namespace firestore { +namespace core { +class FirestoreClient; +} + namespace api { /** * An internal handle that encapsulates a user's ability to request that we - * stop listening to a query. When a user calls Remove(), ListenerRegistration - * will synchronously mute the listener and then send a request to the - * FirestoreClient to actually unlisten. + * stop listening to a listener. When a user calls Remove(), + * ListenerRegistration will synchronously mute the listener and then send a + * request to the FirestoreClient to actually unlisten. * - * ListenerRegistration will not automaticlaly stop listening if it is + * ListenerRegistration will not automatically stop listening if it is * destroyed. We allow users to fire and forget listens if they never want to * stop them. * @@ -57,37 +45,17 @@ namespace api { */ class ListenerRegistration { public: - ListenerRegistration( - FSTFirestoreClient* client, - std::shared_ptr> - async_listener, - std::shared_ptr query_listener) - : client_(client), - async_listener_(std::move(async_listener)), - query_listener_(std::move(query_listener)) { - } + virtual ~ListenerRegistration() = default; /** - * Removes the listener being tracked by this FIRListenerRegistration. After + * Removes the listener being tracked in this ListenerRegistration. After * the initial call, subsequent calls have no effect. */ - void Remove(); - - private: - /** The client that was used to register this listen. */ - FSTFirestoreClient* client_ = nil; - - /** The async listener that is used to mute events synchronously. */ - std::weak_ptr> async_listener_; - - /** The internal QueryListener that can be used to unlisten the query. */ - std::weak_ptr query_listener_; + virtual void Remove() = 0; }; } // namespace api } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_LISTENER_REGISTRATION_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/listener_registration.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/listener_registration.mm deleted file mode 100644 index b885953..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/listener_registration.mm +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/api/listener_registration.h" - -#import "Firestore/Source/Core/FSTFirestoreClient.h" - -namespace firebase { -namespace firestore { -namespace api { - -void ListenerRegistration::Remove() { - auto async_listener = async_listener_.lock(); - if (async_listener) { - async_listener->Mute(); - async_listener_.reset(); - } - - auto query_listener = query_listener_.lock(); - if (query_listener) { - [client_ removeListener:query_listener]; - query_listener_.reset(); - } - - client_ = nil; -} - -} // namespace api -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_core.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_core.cc new file mode 100644 index 0000000..ffe8c7b --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_core.cc @@ -0,0 +1,446 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/api/query_core.h" + +#include // NOLINT(build/c++11) +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/api/firestore.h" +#include "Firestore/core/src/firebase/firestore/api/query_listener_registration.h" +#include "Firestore/core/src/firebase/firestore/core/field_filter.h" +#include "Firestore/core/src/firebase/firestore/core/filter.h" +#include "Firestore/core/src/firebase/firestore/core/firestore_client.h" +#include "Firestore/core/src/firebase/firestore/core/operator.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" +#include "absl/algorithm/container.h" + +namespace firebase { +namespace firestore { +namespace api { + +namespace util = firebase::firestore::util; +using core::AsyncEventListener; +using core::Bound; +using core::Direction; +using core::EventListener; +using core::FieldFilter; +using core::Filter; +using core::IsArrayOperator; +using core::IsDisjunctiveOperator; +using core::ListenOptions; +using core::QueryListener; +using core::ViewSnapshot; +using model::DocumentKey; +using model::FieldPath; +using model::FieldValue; +using model::ResourcePath; +using util::Status; +using util::StatusOr; +using util::ThrowInvalidArgument; + +using Operator = Filter::Operator; + +Query::Query(core::Query query, std::shared_ptr firestore) + : firestore_{std::move(firestore)}, query_{std::move(query)} { +} + +bool operator==(const Query& lhs, const Query& rhs) { + return lhs.firestore() == rhs.firestore() && lhs.query() == rhs.query(); +} + +size_t Query::Hash() const { + return util::Hash(firestore_.get(), query()); +} + +void Query::GetDocuments(Source source, QuerySnapshot::Listener&& callback) { + ValidateHasExplicitOrderByForLimitToLast(); + if (source == Source::Cache) { + firestore_->client()->GetDocumentsFromLocalCache(*this, + std::move(callback)); + return; + } + + ListenOptions options( + /*include_query_metadata_changes=*/true, + /*include_document_metadata_changes=*/true, + /*wait_for_sync_when_online=*/true); + + class ListenOnce : public EventListener { + public: + ListenOnce(Source source, QuerySnapshot::Listener&& listener) + : source_(source), listener_(std::move(listener)) { + } + + void OnEvent(StatusOr maybe_snapshot) override { + if (!maybe_snapshot.ok()) { + listener_->OnEvent(std::move(maybe_snapshot)); + return; + } + + QuerySnapshot snapshot = std::move(maybe_snapshot).ValueOrDie(); + + // Remove query first before passing event to user to avoid user actions + // affecting the now stale query. + std::unique_ptr registration = + registration_promise_.get_future().get(); + registration->Remove(); + + if (snapshot.metadata().from_cache() && source_ == Source::Server) { + listener_->OnEvent(Status{ + Error::Unavailable, + "Failed to get documents from server. (However, these documents " + "may exist in the local cache. Run again without setting source to " + "FirestoreSourceServer to retrieve the cached documents.)"}); + } else { + listener_->OnEvent(std::move(snapshot)); + } + }; + + void Resolve(std::unique_ptr registration) { + registration_promise_.set_value(std::move(registration)); + } + + private: + Source source_; + QuerySnapshot::Listener listener_; + + std::promise> registration_promise_; + }; + + auto listener = absl::make_unique(source, std::move(callback)); + auto listener_unowned = listener.get(); + + std::unique_ptr registration = + AddSnapshotListener(std::move(options), std::move(listener)); + + listener_unowned->Resolve(std::move(registration)); +} + +std::unique_ptr Query::AddSnapshotListener( + ListenOptions options, QuerySnapshot::Listener&& user_listener) { + ValidateHasExplicitOrderByForLimitToLast(); + // Convert from ViewSnapshots to QuerySnapshots. + class Converter : public EventListener { + public: + Converter(Query* parent, QuerySnapshot::Listener&& user_listener) + : firestore_(parent->firestore()), + query_(parent->query()), + user_listener_(std::move(user_listener)) { + } + + void OnEvent(StatusOr maybe_snapshot) override { + if (!maybe_snapshot.status().ok()) { + user_listener_->OnEvent(maybe_snapshot.status()); + return; + } + + ViewSnapshot snapshot = std::move(maybe_snapshot).ValueOrDie(); + SnapshotMetadata metadata(snapshot.has_pending_writes(), + snapshot.from_cache()); + + QuerySnapshot result(firestore_, query_, std::move(snapshot), + std::move(metadata)); + + user_listener_->OnEvent(result); + } + + private: + std::shared_ptr firestore_; + core::Query query_; + QuerySnapshot::Listener user_listener_; + }; + auto view_listener = + absl::make_unique(this, std::move(user_listener)); + + // Call the view_listener on the user Executor. + auto async_listener = AsyncEventListener::Create( + firestore_->client()->user_executor(), std::move(view_listener)); + + std::shared_ptr query_listener = + firestore_->client()->ListenToQuery(this->query(), options, + async_listener); + + return absl::make_unique( + firestore_->client(), std::move(async_listener), + std::move(query_listener)); +} + +Query Query::Filter(FieldPath field_path, + Filter::Operator op, + FieldValue field_value, + const std::function& type_describer) const { + if (field_path.IsKeyFieldPath()) { + if (IsArrayOperator(op)) { + ThrowInvalidArgument( + "Invalid query. You can't perform %s queries on document " + "ID since document IDs are not arrays.", + Describe(op)); + } else if (op == Filter::Operator::In) { + ValidateDisjunctiveFilterElements(field_value, op); + std::vector references; + for (const auto& array_value : field_value.array_value()) { + references.push_back( + ParseExpectedReferenceValue(array_value, type_describer)); + } + field_value = FieldValue::FromArray(references); + } else { + field_value = ParseExpectedReferenceValue(field_value, type_describer); + } + } else { + if (IsDisjunctiveOperator(op)) { + ValidateDisjunctiveFilterElements(field_value, op); + } + } + + FieldFilter filter = FieldFilter::Create(field_path, op, field_value); + ValidateNewFilter(filter); + + return Wrap(query_.AddingFilter(std::move(filter))); +} + +Query Query::OrderBy(FieldPath field_path, bool descending) const { + return OrderBy(field_path, Direction::FromDescending(descending)); +} + +Query Query::OrderBy(FieldPath field_path, Direction direction) const { + ValidateNewOrderByPath(field_path); + if (query_.start_at()) { + ThrowInvalidArgument( + "Invalid query. You must not specify a starting point " + "before specifying the order by."); + } + if (query_.end_at()) { + ThrowInvalidArgument( + "Invalid query. You must not specify an ending point " + "before specifying the order by."); + } + return Wrap( + query_.AddingOrderBy(core::OrderBy(std::move(field_path), direction))); +} + +Query Query::LimitToFirst(int32_t limit) const { + if (limit <= 0) { + ThrowInvalidArgument( + "Invalid Query. Query limit (%s) is invalid. Limit must be positive.", + limit); + } + return Wrap(query_.WithLimitToFirst(limit)); +} + +Query Query::LimitToLast(int32_t limit) const { + if (limit <= 0) { + ThrowInvalidArgument( + "Invalid Query. Query limit (%s) is invalid. Limit must be positive.", + limit); + } + return Wrap(query_.WithLimitToLast(limit)); +} + +Query Query::StartAt(Bound bound) const { + return Wrap(query_.StartingAt(std::move(bound))); +} + +Query Query::EndAt(Bound bound) const { + return Wrap(query_.EndingAt(std::move(bound))); +} + +void Query::ValidateNewFilter(const class Filter& filter) const { + if (filter.IsAFieldFilter()) { + FieldFilter field_filter(filter); + + if (field_filter.IsInequality()) { + const FieldPath* existing_inequality = query_.InequalityFilterField(); + const FieldPath* new_inequality = &filter.field(); + + if (existing_inequality && *existing_inequality != *new_inequality) { + ThrowInvalidArgument( + "Invalid Query. All where filters with an inequality (lessThan, " + "lessThanOrEqual, greaterThan, or greaterThanOrEqual) must be on " + "the same field. But you have inequality filters on '%s' and '%s'", + existing_inequality->CanonicalString(), + new_inequality->CanonicalString()); + } + + const FieldPath* first_order_by_field = query_.FirstOrderByField(); + if (first_order_by_field) { + ValidateOrderByField(*first_order_by_field, filter.field()); + } + + } else { + // You can have at most 1 disjunctive filter and 1 array filter. Check if + // the new filter conflicts with an existing one. + absl::optional conflicting_op; + Operator filter_op = field_filter.op(); + + if (IsDisjunctiveOperator(filter_op)) { + conflicting_op = query_.FirstDisjunctiveOperator(); + } + if (!conflicting_op.has_value() && IsArrayOperator(filter_op)) { + conflicting_op = query_.FirstArrayOperator(); + } + if (conflicting_op) { + // We special case when it's a duplicate op to give a slightly clearer + // error message. + if (*conflicting_op == filter_op) { + ThrowInvalidArgument( + "Invalid Query. You cannot use more than one '%s' filter.", + Describe(filter_op)); + } else { + ThrowInvalidArgument( + "Invalid Query. You cannot use '%s' filters with" + " '%s' filters.", + Describe(filter_op), Describe(conflicting_op.value())); + } + } + } + } +} + +void Query::ValidateNewOrderByPath(const FieldPath& field_path) const { + if (!query_.FirstOrderByField()) { + // This is the first order by. It must match any inequality. + const FieldPath* inequality_field = query_.InequalityFilterField(); + if (inequality_field) { + ValidateOrderByField(field_path, *inequality_field); + } + } +} + +void Query::ValidateOrderByField(const FieldPath& order_by_field, + const FieldPath& inequality_field) const { + if (order_by_field != inequality_field) { + ThrowInvalidArgument( + "Invalid query. You have a where filter with an inequality " + "(lessThan, lessThanOrEqual, greaterThan, or greaterThanOrEqual) on " + "field '%s' and so you must also use '%s' as your first queryOrderedBy " + "field, but your first queryOrderedBy is currently on field '%s' " + "instead.", + inequality_field.CanonicalString(), inequality_field.CanonicalString(), + order_by_field.CanonicalString()); + } +} + +void Query::ValidateHasExplicitOrderByForLimitToLast() const { + if (query_.has_limit_to_last() && query_.explicit_order_bys().empty()) { + ThrowInvalidArgument( + "limit(toLast:) queries require specifying at least one OrderBy() " + "clause."); + } +} + +void Query::ValidateDisjunctiveFilterElements( + const model::FieldValue& field_value, core::Filter::Operator op) const { + HARD_ASSERT( + field_value.type() == FieldValue::Type::Array, + "A FieldValue of Array type is required for disjunctive filters."); + if (field_value.array_value().size() == 0) { + ThrowInvalidArgument( + "Invalid Query. A non-empty array is required for '%s'" + " filters.", + Describe(op)); + } + if (field_value.array_value().size() > 10) { + ThrowInvalidArgument( + "Invalid Query. '%s' filters support a maximum of 10" + " elements in the value array.", + Describe(op)); + } + + std::vector array = field_value.array_value(); + for (const auto& val : array) { + if (val.is_null()) { + ThrowInvalidArgument( + "Invalid Query. '%s' filters cannot contain 'null' in" + " the value array.", + Describe(op)); + } + if (val.is_nan()) { + ThrowInvalidArgument( + "Invalid Query. '%s' filters cannot contain 'NaN' in" + " the value array.", + Describe(op)); + } + } +} + +FieldValue Query::ParseExpectedReferenceValue( + const model::FieldValue& field_value, + const std::function& type_describer) const { + if (field_value.type() == FieldValue::Type::String) { + const std::string& document_key = field_value.string_value(); + if (document_key.empty()) { + ThrowInvalidArgument( + "Invalid query. When querying by document ID you must provide a " + "valid document ID, but it was an empty string."); + } + if (!query().IsCollectionGroupQuery() && + document_key.find('/') != std::string::npos) { + ThrowInvalidArgument( + "Invalid query. When querying a collection by document ID you must " + "provide a plain document ID, but '%s' contains a '/' character.", + document_key); + } + ResourcePath path = + query().path().Append(ResourcePath::FromString(document_key)); + if (!DocumentKey::IsDocumentKey(path)) { + ThrowInvalidArgument( + "Invalid query. When querying a collection group by document ID, " + "the value provided must result in a valid document path, but '%s' " + "is not because it has an odd number of segments.", + path.CanonicalString()); + } + return FieldValue::FromReference(firestore_->database_id(), + DocumentKey{path}); + } else if (field_value.type() == FieldValue::Type::Reference) { + return field_value; + } else { + ThrowInvalidArgument( + "Invalid query. When querying by document ID you must provide a " + "valid string or DocumentReference, but it was of type: %s", + type_describer()); + } +} + +std::string Query::Describe(Filter::Operator op) const { + switch (op) { + case Filter::Operator::LessThan: + return "lessThan"; + case Filter::Operator::LessThanOrEqual: + return "lessThanOrEqual"; + case Filter::Operator::Equal: + return "equal"; + case Filter::Operator::GreaterThanOrEqual: + return "greaterThanOrEqual"; + case Filter::Operator::GreaterThan: + return "greaterThan"; + case Filter::Operator::ArrayContains: + return "arrayContains"; + case Filter::Operator::In: + return "in"; + case Filter::Operator::ArrayContainsAny: + return "arrayContainsAny"; + } + + UNREACHABLE(); +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_core.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_core.h new file mode 100644 index 0000000..46b029d --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_core.h @@ -0,0 +1,213 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_QUERY_CORE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_QUERY_CORE_H_ + +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/api/listener_registration.h" +#include "Firestore/core/src/firebase/firestore/api/query_snapshot.h" +#include "Firestore/core/src/firebase/firestore/api/source.h" +#include "Firestore/core/src/firebase/firestore/core/bound.h" +#include "Firestore/core/src/firebase/firestore/core/direction.h" +#include "Firestore/core/src/firebase/firestore/core/event_listener.h" +#include "Firestore/core/src/firebase/firestore/core/filter.h" +#include "Firestore/core/src/firebase/firestore/core/listen_options.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" + +namespace firebase { +namespace firestore { +namespace api { + +class Firestore; + +/** + * A `Query` refers to a Firestore Query which you can read or listen to. You + * can also construct refined `Query` objects by adding filters and ordering. + */ +class Query { + public: + Query() = default; + + Query(core::Query query, std::shared_ptr firestore); + + size_t Hash() const; + + const std::shared_ptr& firestore() const { + return firestore_; + } + + const core::Query& query() const { + return query_; + } + + /** + * Reads the documents matching this query. + * + * @param source indicates whether the results should be fetched from the + * cache only (`Source::Cache`), the server only (`Source::Server`), or to + * attempt the server and fall back to the cache (`Source::Default`). + * @param callback a callback to execute once the documents have been + * successfully read. + */ + void GetDocuments(Source source, QuerySnapshot::Listener&& callback); + + /** + * Attaches a listener for QuerySnapshot events. + * + * @param options Whether metadata-only changes (i.e. only + * `DocumentSnapshot::metadata()` changed) should trigger snapshot events. + * @param listener The listener to attach. + * + * @return A ListenerRegistration that can be used to remove this listener. + */ + std::unique_ptr AddSnapshotListener( + core::ListenOptions options, QuerySnapshot::Listener&& listener); + + /** + * Creates and returns a new `Query` with the additional filter that documents + * must contain the specified field and the value must be equal to the + * specified value. + * + * @param field_path The name of the field to compare. + * @param op The operator to apply. + * @param field_value The value against which to compare the field. + * @param type_describer A function that will produce a description of the + * type of field_value. + * + * @return The created `Query`. + */ + Query Filter(model::FieldPath field_path, + core::Filter::Operator op, + model::FieldValue field_value, + const std::function& type_describer) const; + + /** + * Creates and returns a new `Query` that's additionally sorted by the + * specified field. + * + * @param field_path The field to sort by. + * @param descending If true, sorts descending instead of ascending. + * + * @return The created `Query`. + */ + Query OrderBy(model::FieldPath field_path, bool descending) const; + + /** + * Creates and returns a new `Query` that's additionally sorted by the + * specified field. + * + * @param field_path The field to sort by. + * @param direction The direction in which to sort. + * + * @return The created `Query`. + */ + Query OrderBy(model::FieldPath field_path, core::Direction direction) const; + + /** + * Creates and returns a new `Query` that only returns the first matching + * documents up to the specified number. + * + * @param limit The maximum number of items to return. + * + * @return The created `Query`. + */ + Query LimitToFirst(int32_t limit) const; + + /** + * Creates and returns a new `Query` that only returns the last matching + * documents up to the specified number. + * + * You must specify at least one `OrderBy` clause for `LimitToLast` queries, + * it is an error otherwise when the query is executed. + * + * @param limit The maximum number of items to return. + * + * @return The created `Query`. + */ + Query LimitToLast(int32_t limit) const; + + /** + * Creates and returns a new `Query` that starts at the given bound. The + * starting position is relative to the order of the query. The bound must + * contain all of the fields provided in the orderBy of this query. + * + * @param bound The bound of the query to start at. + * + * @return The created `Query`. + */ + Query StartAt(core::Bound bound) const; + + /** + * Creates and returns a new `Query` that ends at the given bound. The ending + * position is relative to the order of the query. The bound must contain all + * of the fields provided in the orderBy of this query. + * + * @param bound The bound of the query to end at. + * + * @return The created `Query`. + */ + Query EndAt(core::Bound bound) const; + + /** + * Creates a new `Query` with the given internal query. + */ + Query Wrap(core::Query chained_query) const { + return Query(std::move(chained_query), firestore_); + } + + private: + void ValidateNewFilter(const core::Filter& filter) const; + void ValidateNewOrderByPath(const model::FieldPath& field_path) const; + void ValidateOrderByField(const model::FieldPath& order_by_field, + const model::FieldPath& inequality_field) const; + void ValidateHasExplicitOrderByForLimitToLast() const; + /** + * Validates that the value passed into a disjunctive filter satisfies all + * array requirements. + */ + void ValidateDisjunctiveFilterElements(const model::FieldValue& field_value, + core::Filter::Operator op) const; + + /** + * Parses the given FieldValue into a Reference, throwing appropriate errors + * if the value is anything other than a Reference or String, or if the string + * is malformed. + */ + model::FieldValue ParseExpectedReferenceValue( + const model::FieldValue& field_value, + const std::function& type_describer) const; + + std::string Describe(core::Filter::Operator op) const; + + std::shared_ptr firestore_; + core::Query query_; +}; + +bool operator==(const Query& lhs, const Query& rhs); + +inline bool operator!=(const Query& lhs, const Query& rhs) { + return !(lhs == rhs); +} + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_QUERY_CORE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_listener_registration.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_listener_registration.cc new file mode 100644 index 0000000..a7af879 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_listener_registration.cc @@ -0,0 +1,52 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/api/query_listener_registration.h" +#include "Firestore/core/src/firebase/firestore/core/firestore_client.h" + +namespace firebase { +namespace firestore { +namespace api { + +QueryListenerRegistration::QueryListenerRegistration( + std::shared_ptr client, + std::shared_ptr> + async_listener, + std::shared_ptr query_listener) + : client_(std::move(client)), + async_listener_(std::move(async_listener)), + query_listener_(std::move(query_listener)) { +} + +void QueryListenerRegistration::Remove() { + auto async_listener = async_listener_.lock(); + if (async_listener) { + async_listener->Mute(); + async_listener_.reset(); + } + + auto query_listener = query_listener_.lock(); + if (query_listener) { + client_->RemoveListener(query_listener); + query_listener_.reset(); + } + + client_.reset(); +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_listener_registration.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_listener_registration.h new file mode 100644 index 0000000..ca60c76 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_listener_registration.h @@ -0,0 +1,68 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_QUERY_LISTENER_REGISTRATION_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_QUERY_LISTENER_REGISTRATION_H_ + +#include +#include + +#include "Firestore/core/src/firebase/firestore/api/listener_registration.h" +#include "Firestore/core/src/firebase/firestore/core/event_listener.h" +#include "Firestore/core/src/firebase/firestore/core/query_listener.h" +#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" + +namespace firebase { +namespace firestore { +namespace core { +class FirestoreClient; +} + +namespace api { + +/** + * An internal handle that encapsulates a user's ability to request that we + * stop listening to a query. + */ +class QueryListenerRegistration : public ListenerRegistration { + public: + QueryListenerRegistration( + std::shared_ptr client, + std::shared_ptr> + async_listener, + std::shared_ptr query_listener); + + /** + * Removes the listener being tracked by this QueryListenerRegistration. + */ + void Remove() override; + + private: + /** The client that was used to register this listen. */ + std::shared_ptr client_; + + /** The async listener that is used to mute events synchronously. */ + std::weak_ptr> async_listener_; + + /** The internal QueryListener that can be used to unlisten the query. */ + std::weak_ptr query_listener_; +}; + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_QUERY_LISTENER_REGISTRATION_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_snapshot.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_snapshot.cc new file mode 100644 index 0000000..6724a53 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_snapshot.cc @@ -0,0 +1,169 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/api/query_snapshot.h" + +#include + +#include "Firestore/core/src/firebase/firestore/api/query_core.h" +#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" +#include "Firestore/core/src/firebase/firestore/model/document_set.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace api { + +using api::Firestore; +using core::DocumentViewChange; +using core::ViewSnapshot; +using model::Document; +using model::DocumentComparator; +using model::DocumentSet; +using util::ThrowInvalidArgument; + +QuerySnapshot::QuerySnapshot(std::shared_ptr firestore, + core::Query query, + core::ViewSnapshot&& snapshot, + SnapshotMetadata metadata) + : firestore_(std::move(firestore)), + internal_query_(std::move(query)), + snapshot_(std::move(snapshot)), + metadata_(std::move(metadata)) { +} + +Query QuerySnapshot::query() const { + return Query(internal_query_, firestore_); +} + +const core::Query& QuerySnapshot::internal_query() const { + return internal_query_; +} + +bool operator==(const QuerySnapshot& lhs, const QuerySnapshot& rhs) { + return lhs.firestore_ == rhs.firestore_ && + lhs.internal_query_ == rhs.internal_query_ && + lhs.snapshot_ == rhs.snapshot_ && lhs.metadata_ == rhs.metadata_; +} + +size_t QuerySnapshot::Hash() const { + return util::Hash(firestore_.get(), internal_query_, snapshot_, metadata_); +} + +void QuerySnapshot::ForEachDocument( + const std::function& callback) const { + DocumentSet document_set = snapshot_.documents(); + bool from_cache = metadata_.from_cache(); + + for (const Document& document : document_set) { + bool has_pending_writes = snapshot_.mutated_keys().contains(document.key()); + auto snap = DocumentSnapshot::FromDocument( + firestore_, document, SnapshotMetadata(has_pending_writes, from_cache)); + callback(std::move(snap)); + } +} + +static DocumentChange::Type DocumentChangeTypeForChange( + const DocumentViewChange& change) { + switch (change.type()) { + case DocumentViewChange::Type::Added: + return DocumentChange::Type::Added; + case DocumentViewChange::Type::Modified: + case DocumentViewChange::Type::Metadata: + return DocumentChange::Type::Modified; + case DocumentViewChange::Type::Removed: + return DocumentChange::Type::Removed; + } + + HARD_FAIL("Unknown DocumentViewChange::Type: %s", change.type()); +} + +void QuerySnapshot::ForEachChange( + bool include_metadata_changes, + const std::function& callback) const { + if (include_metadata_changes && snapshot_.excludes_metadata_changes()) { + ThrowInvalidArgument( + "To include metadata changes with your document " + "changes, you must call " + "addSnapshotListener(includeMetadataChanges:true)."); + } + + if (snapshot_.old_documents().empty()) { + // Special case the first snapshot because index calculation is easy and + // fast. Also all changes on the first snapshot are adds so there are also + // no metadata-only changes to filter out. + DocumentComparator doc_comparator = snapshot_.query().Comparator(); + absl::optional last_document; + size_t index = 0; + for (const DocumentViewChange& change : snapshot_.document_changes()) { + const Document& doc = change.document(); + SnapshotMetadata metadata( + /*pending_writes=*/snapshot_.mutated_keys().contains(doc.key()), + /*from_cache=*/snapshot_.from_cache()); + auto document = + DocumentSnapshot::FromDocument(firestore_, doc, std::move(metadata)); + + HARD_ASSERT(change.type() == DocumentViewChange::Type::Added, + "Invalid event type for first snapshot"); + HARD_ASSERT(!last_document || util::Ascending(doc_comparator.Compare( + *last_document, change.document())), + "Got added events in wrong order"); + + callback(DocumentChange(DocumentChange::Type::Added, std::move(document), + DocumentChange::npos, index++)); + last_document = doc; + } + + } else { + // A DocumentSet that is updated incrementally as changes are applied to use + // to lookup the index of a document. + DocumentSet index_tracker = snapshot_.old_documents(); + for (const DocumentViewChange& change : snapshot_.document_changes()) { + if (!include_metadata_changes && + change.type() == DocumentViewChange::Type::Metadata) { + continue; + } + + const Document& doc = change.document(); + SnapshotMetadata metadata( + /*pending_writes=*/snapshot_.mutated_keys().contains(doc.key()), + /*from_cache=*/snapshot_.from_cache()); + auto document = DocumentSnapshot::FromDocument(firestore_, doc, metadata); + + size_t old_index = DocumentChange::npos; + size_t new_index = DocumentChange::npos; + if (change.type() != DocumentViewChange::Type::Added) { + old_index = index_tracker.IndexOf(change.document().key()); + HARD_ASSERT(old_index != DocumentSet::npos, + "Index for document not found"); + index_tracker = index_tracker.erase(change.document().key()); + } + if (change.type() != DocumentViewChange::Type::Removed) { + index_tracker = index_tracker.insert(change.document()); + new_index = index_tracker.IndexOf(change.document().key()); + } + + DocumentChange::Type type = DocumentChangeTypeForChange(change); + callback(DocumentChange(type, std::move(document), old_index, new_index)); + } + } +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_snapshot.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_snapshot.h index 7c5f49d..91569bf 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_snapshot.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_snapshot.h @@ -17,42 +17,35 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_QUERY_SNAPSHOT_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_QUERY_SNAPSHOT_H_ -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import - #include +#include #include +#include "Firestore/core/src/firebase/firestore/api/document_change.h" #include "Firestore/core/src/firebase/firestore/api/document_snapshot.h" #include "Firestore/core/src/firebase/firestore/api/snapshot_metadata.h" +#include "Firestore/core/src/firebase/firestore/core/event_listener.h" +#include "Firestore/core/src/firebase/firestore/core/query.h" #include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" #include "Firestore/core/src/firebase/firestore/model/document_set.h" -NS_ASSUME_NONNULL_BEGIN - -@class FSTQuery; - namespace firebase { namespace firestore { namespace api { +class Query; + /** * A `QuerySnapshot` contains zero or more `DocumentSnapshot` objects. */ class QuerySnapshot { public: - QuerySnapshot(Firestore* firestore, - FSTQuery* query, + using Listener = std::unique_ptr>; + + QuerySnapshot(std::shared_ptr firestore, + core::Query query, core::ViewSnapshot&& snapshot, - SnapshotMetadata metadata) - : firestore_(firestore), - internal_query_(query), - snapshot_(std::move(snapshot)), - metadata_(std::move(metadata)) { - } + SnapshotMetadata metadata); size_t Hash() const; @@ -68,17 +61,13 @@ class QuerySnapshot { return snapshot_.documents().size(); } - Firestore* firestore() const { + const std::shared_ptr& firestore() const { return firestore_; } - FSTQuery* internal_query() const { - return internal_query_; - } + Query query() const; - const core::ViewSnapshot& view_snapshot() const { - return snapshot_; - } + const core::Query& internal_query() const; /** * Metadata about this snapshot, concerning its source and if it has local @@ -92,11 +81,18 @@ class QuerySnapshot { void ForEachDocument( const std::function& callback) const; + /** + * Iterates over the `DocumentChanges` representing the changes between + * the prior snapshot and this one. + */ + void ForEachChange(bool include_metadata_changes, + const std::function& callback) const; + friend bool operator==(const QuerySnapshot& lhs, const QuerySnapshot& rhs); private: - Firestore* firestore_ = nullptr; - FSTQuery* internal_query_ = nil; + std::shared_ptr firestore_; + core::Query internal_query_; core::ViewSnapshot snapshot_; SnapshotMetadata metadata_; }; @@ -105,6 +101,4 @@ class QuerySnapshot { } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_QUERY_SNAPSHOT_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_snapshot.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_snapshot.mm deleted file mode 100644 index 7992cc1..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/query_snapshot.mm +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/api/query_snapshot.h" - -#include - -#import "Firestore/Source/API/FIRDocumentChange+Internal.h" -#import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h" -#import "Firestore/Source/API/FIRFirestore+Internal.h" -#import "Firestore/Source/API/FIRQuery+Internal.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" - -#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" -#include "Firestore/core/src/firebase/firestore/model/document_set.h" -#include "Firestore/core/src/firebase/firestore/util/objc_compatibility.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace firebase { -namespace firestore { -namespace api { - -namespace objc = util::objc; -using api::Firestore; -using core::ViewSnapshot; -using model::DocumentSet; - -bool operator==(const QuerySnapshot& lhs, const QuerySnapshot& rhs) { - return lhs.firestore_ == rhs.firestore_ && - objc::Equals(lhs.internal_query_, rhs.internal_query_) && - lhs.snapshot_ == rhs.snapshot_ && lhs.metadata_ == rhs.metadata_; -} - -size_t QuerySnapshot::Hash() const { - return util::Hash(firestore_, internal_query_, snapshot_, metadata_); -} - -void QuerySnapshot::ForEachDocument( - const std::function& callback) const { - DocumentSet documentSet = snapshot_.documents(); - bool from_cache = metadata_.from_cache(); - - for (FSTDocument* document : documentSet) { - bool has_pending_writes = snapshot_.mutated_keys().contains(document.key); - DocumentSnapshot snap(firestore_, document.key, document, from_cache, - has_pending_writes); - callback(std::move(snap)); - } -} - -} // namespace api -} // namespace firestore -} // namespace firebase - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/settings.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/settings.cc new file mode 100644 index 0000000..26b155b --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/settings.cc @@ -0,0 +1,47 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/api/settings.h" + +#include "Firestore/core/src/firebase/firestore/util/hashing.h" + +namespace firebase { +namespace firestore { +namespace api { + +constexpr const char* Settings::DefaultHost; +constexpr bool Settings::DefaultSslEnabled; +constexpr bool Settings::DefaultPersistenceEnabled; +constexpr int64_t Settings::DefaultCacheSizeBytes; +constexpr int64_t Settings::MinimumCacheSizeBytes; +constexpr bool Settings::DefaultTimestampsInSnapshotsEnabled; + +size_t Settings::Hash() const { + return util::Hash(host_, ssl_enabled_, persistence_enabled_, + timestamps_in_snapshots_enabled_, cache_size_bytes_); +} + +bool operator==(const Settings& lhs, const Settings& rhs) { + return lhs.host_ == rhs.host_ && lhs.ssl_enabled_ == rhs.ssl_enabled_ && + lhs.persistence_enabled_ == rhs.persistence_enabled_ && + lhs.timestamps_in_snapshots_enabled_ == + rhs.timestamps_in_snapshots_enabled_ && + lhs.cache_size_bytes_ == rhs.cache_size_bytes_; +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/settings.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/settings.h new file mode 100644 index 0000000..972714f --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/settings.h @@ -0,0 +1,101 @@ + +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_SETTINGS_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_SETTINGS_H_ + +#include + +namespace firebase { +namespace firestore { +namespace api { + +/** + * Represents settings associated with a FirestoreClient. + * + * PORTING NOTE: We exclude the user callback std::executor in order to avoid + * ownership complexity. + */ +class Settings { + public: + // Note: a constexpr array of char (`char[]`) doesn't work with Visual Studio + // 2015. + static constexpr const char* DefaultHost = "firestore.googleapis.com"; + static constexpr bool DefaultSslEnabled = true; + static constexpr bool DefaultPersistenceEnabled = true; + static constexpr int64_t DefaultCacheSizeBytes = 100 * 1024 * 1024; + static constexpr int64_t MinimumCacheSizeBytes = 1 * 1024 * 1024; + static constexpr int64_t CacheSizeUnlimited = -1; + static constexpr bool DefaultTimestampsInSnapshotsEnabled = true; + + Settings() = default; + + void set_host(const std::string& value) { + host_ = value; + } + const std::string& host() const { + return host_; + } + + void set_ssl_enabled(bool value) { + ssl_enabled_ = value; + } + bool ssl_enabled() const { + return ssl_enabled_; + } + + void set_persistence_enabled(bool value) { + persistence_enabled_ = value; + } + bool persistence_enabled() const { + return persistence_enabled_; + } + + void set_timestamps_in_snapshots_enabled(bool value) { + timestamps_in_snapshots_enabled_ = value; + } + bool timestamps_in_snapshots_enabled() const { + return timestamps_in_snapshots_enabled_; + } + + void set_cache_size_bytes(int64_t value) { + cache_size_bytes_ = value; + } + int64_t cache_size_bytes() const { + return cache_size_bytes_; + } + bool gc_enabled() const { + return cache_size_bytes_ != CacheSizeUnlimited; + } + + friend bool operator==(const Settings& lhs, const Settings& rhs); + + size_t Hash() const; + + private: + std::string host_ = DefaultHost; + bool ssl_enabled_ = DefaultSslEnabled; + bool persistence_enabled_ = DefaultPersistenceEnabled; + bool timestamps_in_snapshots_enabled_ = DefaultTimestampsInSnapshotsEnabled; + int64_t cache_size_bytes_ = DefaultCacheSizeBytes; +}; + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_SETTINGS_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/snapshots_in_sync_listener_registration.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/snapshots_in_sync_listener_registration.cc new file mode 100644 index 0000000..6ed29ae --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/snapshots_in_sync_listener_registration.cc @@ -0,0 +1,46 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/api/snapshots_in_sync_listener_registration.h" + +#include + +#include "Firestore/core/src/firebase/firestore/core/firestore_client.h" + +namespace firebase { +namespace firestore { +namespace api { + +SnapshotsInSyncListenerRegistration::SnapshotsInSyncListenerRegistration( + std::shared_ptr client, + std::shared_ptr> async_listener) + : client_(std::move(client)), async_listener_(std::move(async_listener)) { +} + +void SnapshotsInSyncListenerRegistration::Remove() { + auto async_listener = async_listener_.lock(); + if (async_listener) { + async_listener->Mute(); + async_listener_.reset(); + } + + client_->RemoveSnapshotsInSyncListener(async_listener); + client_.reset(); +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/snapshots_in_sync_listener_registration.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/snapshots_in_sync_listener_registration.h new file mode 100644 index 0000000..1d94fbf --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/snapshots_in_sync_listener_registration.h @@ -0,0 +1,66 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_SNAPSHOTS_IN_SYNC_LISTENER_REGISTRATION_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_SNAPSHOTS_IN_SYNC_LISTENER_REGISTRATION_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/api/listener_registration.h" +#include "Firestore/core/src/firebase/firestore/core/event_listener.h" +#include "Firestore/core/src/firebase/firestore/util/empty.h" + +namespace firebase { +namespace firestore { +namespace core { + +class FirestoreClient; + +} // namespace core + +namespace api { + +/** + * An internal handle that encapsulates a user's ability to request that we + * stop listening to the snapshots-in-sync listener. When a user calls Remove(), + * SnapshotsInSyncListenerRegistration will synchronously mute the listener and + * then send a request to actually unlisten. + */ +class SnapshotsInSyncListenerRegistration : public ListenerRegistration { + public: + SnapshotsInSyncListenerRegistration( + std::shared_ptr client, + std::shared_ptr> async_listener); + + /** + * Removes the listener being tracked by this FIRListenerRegistration. After + * the initial call, subsequent calls have no effect. + */ + void Remove() override; + + private: + /** The client that was used to register this listen. */ + std::shared_ptr client_; + + /** The async listener that is used to mute events synchronously. */ + std::weak_ptr> async_listener_; +}; + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_SNAPSHOTS_IN_SYNC_LISTENER_REGISTRATION_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/source.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/source.h new file mode 100644 index 0000000..be1ec0d --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/source.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_SOURCE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_SOURCE_H_ + +namespace firebase { +namespace firestore { +namespace api { + +/** + * An enum that configures the behavior of `DocumentReference.GetDocument()` and + * `Query.GetDocuments()`. By providing a source enum the `GetDocument[s]` + * methods can be configured to fetch results only from the server, only from + * the local cache, or attempt to fetch results from the server and fall back to + * the cache (which is the default). + * + * See `FIRFirestoreSource` for more details. + */ +enum class Source { Default, Server, Cache }; + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_SOURCE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/write_batch.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/write_batch.cc new file mode 100644 index 0000000..a4b7f8a --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/write_batch.cc @@ -0,0 +1,93 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/api/write_batch.h" + +#include + +#include "Firestore/core/src/firebase/firestore/api/document_reference.h" +#include "Firestore/core/src/firebase/firestore/api/firestore.h" +#include "Firestore/core/src/firebase/firestore/core/firestore_client.h" +#include "Firestore/core/src/firebase/firestore/core/user_data.h" +#include "Firestore/core/src/firebase/firestore/model/delete_mutation.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" + +namespace firebase { +namespace firestore { +namespace api { + +using model::DeleteMutation; +using model::Mutation; +using model::Precondition; +using util::ThrowIllegalState; +using util::ThrowInvalidArgument; + +void WriteBatch::SetData(const DocumentReference& reference, + core::ParsedSetData&& set_data) { + VerifyNotCommitted(); + ValidateReference(reference); + + std::vector append_mutations = std::move(set_data).ToMutations( + reference.key(), model::Precondition::None()); + std::move(append_mutations.begin(), append_mutations.end(), + std::back_inserter(mutations_)); +} + +void WriteBatch::UpdateData(const DocumentReference& reference, + core::ParsedUpdateData&& update_data) { + VerifyNotCommitted(); + ValidateReference(reference); + + std::vector append_mutations = + std::move(update_data) + .ToMutations(reference.key(), model::Precondition::Exists(true)); + std::move(append_mutations.begin(), append_mutations.end(), + std::back_inserter(mutations_)); +} + +void WriteBatch::DeleteData(const DocumentReference& reference) { + VerifyNotCommitted(); + ValidateReference(reference); + + mutations_.push_back(DeleteMutation(reference.key(), Precondition::None())); +} + +void WriteBatch::Commit(util::StatusCallback callback) { + VerifyNotCommitted(); + + committed_ = true; + firestore_->client()->WriteMutations(std::move(mutations_), + std::move(callback)); +} + +void WriteBatch::VerifyNotCommitted() const { + if (committed_) { + ThrowIllegalState( + "A write batch can no longer be used after commit has been called."); + } +} + +void WriteBatch::ValidateReference(const DocumentReference& reference) const { + if (reference.firestore() != firestore_) { + ThrowInvalidArgument( + "Provided document reference is from a different " + "Firestore instance."); + } +} + +} // namespace api +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/write_batch.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/write_batch.h new file mode 100644 index 0000000..c332e35 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/api/write_batch.h @@ -0,0 +1,72 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_WRITE_BATCH_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_WRITE_BATCH_H_ + +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/api/document_reference.h" +#include "Firestore/core/src/firebase/firestore/model/mutation.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" + +namespace firebase { +namespace firestore { +namespace core { + +class ParsedSetData; +class ParsedUpdateData; + +} // namespace core + +namespace api { + +class Firestore; + +class WriteBatch { + public: + explicit WriteBatch(std::shared_ptr firestore) + : firestore_{std::move(firestore)} { + } + + void SetData(const DocumentReference& reference, + core::ParsedSetData&& set_data); + void UpdateData(const DocumentReference& reference, + core::ParsedUpdateData&& update_data); + void DeleteData(const DocumentReference& reference); + + void Commit(util::StatusCallback callback); + + const std::shared_ptr& firestore() const { + return firestore_; + } + + private: + std::shared_ptr firestore_; + std::vector mutations_; + bool committed_ = false; + + void VerifyNotCommitted() const; + void ValidateReference(const DocumentReference& reference) const; +}; + +} // namespace api +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_API_WRITE_BATCH_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/credentials_provider.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/credentials_provider.h index cf952e0..20c71b4 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/credentials_provider.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/credentials_provider.h @@ -63,7 +63,7 @@ class CredentialsProvider { * Call with nullptr to remove previous listener. */ virtual void SetCredentialChangeListener( - CredentialChangeListener changeListener) = 0; + CredentialChangeListener change_listener) = 0; protected: /** diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.cc index ebea459..b217cd5 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.cc @@ -29,9 +29,9 @@ void EmptyCredentialsProvider::GetToken(TokenListener completion) { } void EmptyCredentialsProvider::SetCredentialChangeListener( - CredentialChangeListener changeListener) { - if (changeListener) { - changeListener(User::Unauthenticated()); + CredentialChangeListener change_listener) { + if (change_listener) { + change_listener(User::Unauthenticated()); } } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.h index 67b018e..3f43be7 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.h @@ -29,7 +29,7 @@ class EmptyCredentialsProvider : public CredentialsProvider { void GetToken(TokenListener completion) override; void InvalidateToken() override; void SetCredentialChangeListener( - CredentialChangeListener changeListener) override; + CredentialChangeListener change_listener) override; }; } // namespace auth diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.h index 5a36ac5..2e293f5 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.h @@ -14,14 +14,13 @@ * limitations under the License. */ -// Right now, FirebaseCredentialsProvider only support APPLE build. +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_AUTH_FIREBASE_CREDENTIALS_PROVIDER_APPLE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_AUTH_FIREBASE_CREDENTIALS_PROVIDER_APPLE_H_ + #if !defined(__OBJC__) #error "This header only supports Objective-C++." #endif // !defined(__OBJC__) -#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_AUTH_FIREBASE_CREDENTIALS_PROVIDER_APPLE_H_ -#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_AUTH_FIREBASE_CREDENTIALS_PROVIDER_APPLE_H_ - #import #include @@ -71,7 +70,7 @@ class FirebaseCredentialsProvider : public CredentialsProvider { void GetToken(TokenListener completion) override; void SetCredentialChangeListener( - CredentialChangeListener changeListener) override; + CredentialChangeListener change_listener) override; void InvalidateToken() override; @@ -108,7 +107,7 @@ class FirebaseCredentialsProvider : public CredentialsProvider { }; /** - * Handle used to stop receiving auth changes once userChangeListener is + * Handle used to stop receiving auth changes once CredentialChangeListener is * removed. */ id auth_listener_handle_; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm index f167d3f..e4621a5 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm @@ -22,13 +22,10 @@ #import #import +#include "Firestore/core/src/firebase/firestore/util/error_apple.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" -// NB: This is also defined in Firestore/Source/Public/FIRFirestoreErrors.h -// NOLINTNEXTLINE: public constant -NSString* const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; - namespace firebase { namespace firestore { namespace auth { @@ -83,7 +80,7 @@ HARD_ASSERT(auth_listener_handle_, "GetToken cannot be called after listener removed."); - // Take note of the current value of the tokenCounter so that this method can + // Take note of the current value of the token_counter so that this method can // fail if there is a token change while the request is outstanding. int initial_token_counter = contents_->token_counter; @@ -100,8 +97,8 @@ // Cancel the request since the user changed while the request was // outstanding so the response is likely for a previous user (which // user, we can't be sure). - completion(util::Status(FirestoreErrorCode::Aborted, - "getToken aborted due to token change.")); + completion(util::Status(Error::Aborted, + "GetToken aborted due to token change.")); } else { if (error == nil) { if (token != nil) { @@ -110,9 +107,9 @@ completion(Token::Unauthenticated()); } } else { - FirestoreErrorCode error_code = FirestoreErrorCode::Unknown; + Error error_code = Error::Unknown; if (error.domain == FIRFirestoreErrorDomain) { - error_code = static_cast(error.code); + error_code = static_cast(error.code); } completion(util::Status(error_code, util::MakeString(error.localizedDescription))); @@ -137,19 +134,19 @@ } void FirebaseCredentialsProvider::SetCredentialChangeListener( - CredentialChangeListener changeListener) { + CredentialChangeListener change_listener) { std::unique_lock lock(contents_->mutex); - if (changeListener) { + if (change_listener) { HARD_ASSERT(!change_listener_, "set change_listener twice!"); // Fire initial event. - changeListener(contents_->current_user); + change_listener(contents_->current_user); } else { HARD_ASSERT(auth_listener_handle_, "removed change_listener twice!"); HARD_ASSERT(change_listener_, "change_listener removed without being set!"); [[NSNotificationCenter defaultCenter] removeObserver:auth_listener_handle_]; auth_listener_handle_ = nil; } - change_listener_ = changeListener; + change_listener_ = change_listener; } } // namespace auth diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/array_contains_any_filter.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/array_contains_any_filter.cc new file mode 100644 index 0000000..47d43f3 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/array_contains_any_filter.cc @@ -0,0 +1,71 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/array_contains_any_filter.h" + +#include +#include + +#include "absl/algorithm/container.h" + +namespace firebase { +namespace firestore { +namespace core { + +using model::Document; +using model::FieldPath; +using model::FieldValue; + +using Operator = Filter::Operator; + +class ArrayContainsAnyFilter::Rep : public FieldFilter::Rep { + public: + Rep(FieldPath field, FieldValue value) + : FieldFilter::Rep( + std::move(field), Operator::ArrayContainsAny, std::move(value)) { + } + + Type type() const override { + return Type::kArrayContainsAnyFilter; + } + + bool Matches(const model::Document& doc) const override; +}; + +ArrayContainsAnyFilter::ArrayContainsAnyFilter(FieldPath field, + FieldValue value) + : FieldFilter(std::make_shared(std::move(field), std::move(value))) { +} + +bool ArrayContainsAnyFilter::Rep::Matches(const Document& doc) const { + const FieldValue::Array& array_value = value().array_value(); + absl::optional maybe_lhs = doc.field(field()); + if (!maybe_lhs) return false; + + const FieldValue& lhs = *maybe_lhs; + if (lhs.type() != FieldValue::Type::Array) return false; + + for (const auto& val : lhs.array_value()) { + if (absl::c_linear_search(array_value, val)) { + return true; + } + } + return false; +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/array_contains_any_filter.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/array_contains_any_filter.h new file mode 100644 index 0000000..a0ff8fe --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/array_contains_any_filter.h @@ -0,0 +1,44 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_ARRAY_CONTAINS_ANY_FILTER_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_ARRAY_CONTAINS_ANY_FILTER_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/core/field_filter.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" + +namespace firebase { +namespace firestore { +namespace core { + +/** + * A Filter that implements the array-contains-any operator. + */ +class ArrayContainsAnyFilter : public FieldFilter { + public: + ArrayContainsAnyFilter(model::FieldPath field, model::FieldValue value); + + private: + class Rep; +}; + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_ARRAY_CONTAINS_ANY_FILTER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/array_contains_filter.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/array_contains_filter.cc new file mode 100644 index 0000000..1d15d30 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/array_contains_filter.cc @@ -0,0 +1,66 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/array_contains_filter.h" + +#include +#include + +#include "absl/algorithm/container.h" + +namespace firebase { +namespace firestore { +namespace core { + +using model::Document; +using model::FieldPath; +using model::FieldValue; + +using Operator = Filter::Operator; + +class ArrayContainsFilter::Rep : public FieldFilter::Rep { + public: + Rep(FieldPath field, FieldValue value) + : FieldFilter::Rep( + std::move(field), Operator::ArrayContains, std::move(value)) { + } + + Type type() const override { + return Type::kArrayContainsFilter; + } + + bool Matches(const model::Document& doc) const override; +}; + +ArrayContainsFilter::ArrayContainsFilter(FieldPath field, FieldValue value) + : FieldFilter( + std::make_shared(std::move(field), std::move(value))) { +} + +bool ArrayContainsFilter::Rep::Matches(const Document& doc) const { + absl::optional maybe_lhs = doc.field(field()); + if (!maybe_lhs) return false; + + const FieldValue& lhs = *maybe_lhs; + if (lhs.type() != FieldValue::Type::Array) return false; + + const FieldValue::Array& contents = lhs.array_value(); + return absl::c_linear_search(contents, value()); +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/array_contains_filter.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/array_contains_filter.h new file mode 100644 index 0000000..2c4a230 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/array_contains_filter.h @@ -0,0 +1,44 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_ARRAY_CONTAINS_FILTER_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_ARRAY_CONTAINS_FILTER_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/core/field_filter.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" + +namespace firebase { +namespace firestore { +namespace core { + +/** + * A Filter that implements the array-contains operator. + */ +class ArrayContainsFilter : public FieldFilter { + public: + ArrayContainsFilter(model::FieldPath field, model::FieldValue value); + + private: + class Rep; +}; + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_ARRAY_CONTAINS_FILTER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/bound.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/bound.cc new file mode 100644 index 0000000..92bc63f --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/bound.cc @@ -0,0 +1,98 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/bound.h" + +#include + +#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "Firestore/core/src/firebase/firestore/util/to_string.h" + +namespace firebase { +namespace firestore { +namespace core { + +using model::FieldPath; +using model::FieldValue; +using util::ComparisonResult; + +bool Bound::SortsBeforeDocument(const OrderByList& order_by, + const model::Document& document) const { + HARD_ASSERT(position_.size() <= order_by.size(), + "Bound has more components than the provided order by."); + + ComparisonResult result = ComparisonResult::Same; + for (size_t idx = 0; idx < position_.size(); ++idx) { + const FieldValue& field_value = position_[idx]; + const OrderBy& ordering_component = order_by[idx]; + + ComparisonResult comparison; + if (ordering_component.field() == FieldPath::KeyFieldPath()) { + HARD_ASSERT( + field_value.type() == FieldValue::Type::Reference, + "Bound has a non-key value where the key path is being used %s", + field_value.ToString()); + const auto& ref = field_value.reference_value(); + comparison = ref.key().CompareTo(document.key()); + + } else { + absl::optional doc_value = + document.field(ordering_component.field()); + HARD_ASSERT( + doc_value.has_value(), + "Field should exist since document matched the orderBy already."); + comparison = field_value.CompareTo(*doc_value); + } + + comparison = ordering_component.direction().ApplyTo(comparison); + if (!util::Same(comparison)) { + result = comparison; + break; + } + } + + return before_ ? result <= ComparisonResult::Same + : result < ComparisonResult::Same; +} + +std::string Bound::CanonicalId() const { + std::string result = before_ ? "b:" : "a:"; + for (const FieldValue& component : position_) { + result.append(component.ToString()); + } + return result; +} + +std::string Bound::ToString() const { + return util::StringFormat("Bound(position=%s, before=%s)", + util::ToString(position_), util::ToString(before_)); +} + +std::ostream& operator<<(std::ostream& os, const Bound& bound) { + return os << bound.ToString(); +} + +bool operator==(const Bound& lhs, const Bound& rhs) { + return lhs.position() == rhs.position() && lhs.before() == rhs.before(); +} + +size_t Bound::Hash() const { + return util::Hash(position_, before_); +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/bound.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/bound.h new file mode 100644 index 0000000..69579cd --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/bound.h @@ -0,0 +1,102 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_BOUND_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_BOUND_H_ + +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/core/order_by.h" +#include "Firestore/core/src/firebase/firestore/model/document.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" + +namespace firebase { +namespace firestore { +namespace core { + +/** + * Bound represents the starting or ending position in query results. + * + * The bound is specified with components representing a position in the results + * and whether it's just before or just after the position (relative to whatever + * the query order is). + * + * The position represents a logical index position for a query. It's a prefix + * of values for the (potentially implicit) order by clauses of a query. + * + * Bound provides a function to determine whether a document comes before or + * after a bound. This is influenced by whether the position is just before or + * just after the provided values. + */ +class Bound { + public: + /** + * Creates a new bound. + * + * @param position The position relative to the sort order. + * @param is_before Whether this bound is just before or just after the + * position. + */ + Bound(std::vector position, bool is_before) + : position_(std::move(position)), before_(is_before) { + } + + /** + * The index position of this bound represented as an array of field values. + */ + const std::vector& position() const { + return position_; + } + + /** Whether this bound is just before or just after the provided position */ + bool before() const { + return before_; + } + + /** + * Returns true if the given document comes before this bound using the + * provided sort order. + */ + bool SortsBeforeDocument(const OrderByList& order_by, + const model::Document& document) const; + + std::string CanonicalId() const; + + std::string ToString() const; + + size_t Hash() const; + + private: + std::vector position_; + bool before_; +}; + +std::ostream& operator<<(std::ostream& os, const Bound& bound); + +bool operator==(const Bound& lhs, const Bound& rhs); + +inline bool operator!=(const Bound& lhs, const Bound& rhs) { + return !(lhs == rhs); +} + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_BOUND_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/database_info.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/database_info.cc index c0960bc..77c8503 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/database_info.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/database_info.cc @@ -22,12 +22,11 @@ namespace firebase { namespace firestore { namespace core { -DatabaseInfo::DatabaseInfo( - const firebase::firestore::model::DatabaseId& database_id, - std::string persistence_key, - std::string host, - bool ssl_enabled) - : database_id_{database_id}, +DatabaseInfo::DatabaseInfo(model::DatabaseId database_id, + std::string persistence_key, + std::string host, + bool ssl_enabled) + : database_id_{std::move(database_id)}, persistence_key_{std::move(persistence_key)}, host_{std::move(host)}, ssl_enabled_{ssl_enabled} { diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/database_info.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/database_info.h index 138aead..56933df 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/database_info.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/database_info.h @@ -28,12 +28,6 @@ namespace core { /** DatabaseInfo contains data about the database. */ class DatabaseInfo { public: -#if defined(__OBJC__) - // For objective-c++ initialization; to be removed after migration. - // Do NOT use in C++ code. - DatabaseInfo() = default; -#endif // defined(__OBJC__) - /** * Creates a new DatabaseInfo. * @@ -43,12 +37,14 @@ class DatabaseInfo { * @param host The hostname of the Firestore backend. * @param ssl_enabled Whether to use SSL when connecting. */ - DatabaseInfo(const firebase::firestore::model::DatabaseId& database_id, + DatabaseInfo(model::DatabaseId database_id, std::string persistence_key, std::string host, bool ssl_enabled); - const firebase::firestore::model::DatabaseId& database_id() const { + DatabaseInfo() = default; + + const model::DatabaseId& database_id() const { return database_id_; } @@ -65,10 +61,10 @@ class DatabaseInfo { } private: - firebase::firestore::model::DatabaseId database_id_; + model::DatabaseId database_id_; std::string persistence_key_; std::string host_; - bool ssl_enabled_; + bool ssl_enabled_ = false; }; } // namespace core diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/direction.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/direction.cc new file mode 100644 index 0000000..801b989 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/direction.cc @@ -0,0 +1,46 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/direction.h" + +#include + +namespace firebase { +namespace firestore { +namespace core { + +const Direction Direction::Ascending(Direction::AscendingModifier); +const Direction Direction::Descending(Direction::DescendingModifier); + +std::string Direction::CanonicalId() const { + return comparison_modifier_ == AscendingModifier ? "asc" : "desc"; +} + +util::ComparisonResult Direction::ApplyTo(util::ComparisonResult result) const { + if (comparison_modifier_ == AscendingModifier) { + return result; + } else { + return util::ReverseOrder(result); + } +} + +std::ostream& operator<<(std::ostream& os, const Direction& direction) { + return os << direction.CanonicalId(); +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/direction.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/direction.h new file mode 100644 index 0000000..df70421 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/direction.h @@ -0,0 +1,84 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_DIRECTION_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_DIRECTION_H_ + +#include +#include + +#include "Firestore/core/src/firebase/firestore/util/comparison.h" +#include "absl/base/attributes.h" + +namespace firebase { +namespace firestore { +namespace core { + +/** Interface used for all query orderings. All Directions are immutable. */ +class Direction { + public: + ABSL_CONST_INIT static const Direction Ascending; + ABSL_CONST_INIT static const Direction Descending; + + /** + * Creates a Direction from a boolean. This is useful only because the + * public Objective-C API uses it. + */ + static const Direction& FromDescending(bool descending) { + return descending ? Descending : Ascending; + } + + Direction() = default; + + /** + * Changes the direction of the given ComparisonResult if the direction is + * Descending. + */ + util::ComparisonResult ApplyTo(util::ComparisonResult) const; + + int comparison_modifier() const { + return comparison_modifier_; + } + + std::string CanonicalId() const; + + private: + enum { + AscendingModifier = 1, + DescendingModifier = -1, + }; + + constexpr explicit Direction(int comparison_modifier) + : comparison_modifier_(comparison_modifier) { + } + int comparison_modifier_ = AscendingModifier; +}; + +std::ostream& operator<<(std::ostream& os, const Direction& direction); + +inline bool operator==(const Direction& lhs, const Direction& rhs) { + return lhs.comparison_modifier() == rhs.comparison_modifier(); +} + +inline bool operator!=(const Direction& lhs, const Direction& rhs) { + return !(lhs == rhs); +} + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_DIRECTION_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/event_listener.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/event_listener.h index dcb9b80..24651a1 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/event_listener.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/event_listener.h @@ -22,8 +22,8 @@ #include #include "Firestore/core/src/firebase/firestore/util/executor.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "Firestore/core/src/firebase/firestore/util/statusor.h" -#include "Firestore/core/src/firebase/firestore/util/statusor_callback.h" #include "absl/memory/memory.h" namespace firebase { @@ -61,7 +61,8 @@ class AsyncEventListener public: using DelegateListener = std::unique_ptr>; - AsyncEventListener(util::Executor* executor, DelegateListener&& delegate) + AsyncEventListener(const std::shared_ptr& executor, + DelegateListener&& delegate) : executor_(executor), delegate_(std::move(delegate)) { // std::atomic's constructor is not atomic, so assign after contruction // (since assignment is atomic). @@ -69,10 +70,10 @@ class AsyncEventListener } static std::shared_ptr> Create( - util::Executor* executor, DelegateListener&& delegate); + std::shared_ptr executor, DelegateListener&& delegate); static std::shared_ptr> Create( - util::Executor* executor, EventListener&& delegate) { + std::shared_ptr executor, EventListener&& delegate) { return Create(executor, absl::make_unique(std::move(delegate))); } @@ -87,7 +88,7 @@ class AsyncEventListener private: std::atomic muted_; - util::Executor* executor_; + std::shared_ptr executor_; DelegateListener delegate_; }; @@ -113,7 +114,7 @@ std::unique_ptr> EventListener::Create( template std::shared_ptr> AsyncEventListener::Create( - util::Executor* executor, DelegateListener&& delegate) { + std::shared_ptr executor, DelegateListener&& delegate) { return std::make_shared>(executor, std::move(delegate)); } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/event_manager.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/event_manager.cc new file mode 100644 index 0000000..d843138 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/event_manager.cc @@ -0,0 +1,154 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include + +#include "Firestore/core/src/firebase/firestore/core/event_manager.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" + +namespace firebase { +namespace firestore { +namespace core { + +using util::Empty; + +EventManager::EventManager(QueryEventSource* query_event_source) + : query_event_source_(query_event_source) { + query_event_source->SetCallback(this); +} + +model::TargetId EventManager::AddQueryListener( + std::shared_ptr listener) { + const Query& query = listener->query(); + + auto inserted = queries_.emplace(query, QueryListenersInfo{}); + bool first_listen = inserted.second; + QueryListenersInfo& query_info = inserted.first->second; + + query_info.listeners.push_back(listener); + + bool raised_event = listener->OnOnlineStateChanged(online_state_); + HARD_ASSERT(!raised_event, + "OnOnlineStateChanged() shouldn't raise an event " + "for brand-new listeners."); + + if (query_info.view_snapshot().has_value()) { + raised_event = listener->OnViewSnapshot(query_info.view_snapshot().value()); + if (raised_event) { + RaiseSnapshotsInSyncEvent(); + } + } + + if (first_listen) { + query_info.target_id = query_event_source_->Listen(query); + } + return query_info.target_id; +} + +void EventManager::RemoveQueryListener( + std::shared_ptr listener) { + const Query& query = listener->query(); + bool last_listen = false; + + auto found_iter = queries_.find(query); + if (found_iter != queries_.end()) { + QueryListenersInfo& query_info = found_iter->second; + query_info.Erase(listener); + last_listen = query_info.listeners.empty(); + } + + if (last_listen) { + queries_.erase(found_iter); + query_event_source_->StopListening(query); + } +} + +void EventManager::AddSnapshotsInSyncListener( + const std::shared_ptr>& listener) { + snapshots_in_sync_listeners_.insert(listener); + listener->OnEvent(Empty()); +} + +void EventManager::RemoveSnapshotsInSyncListener( + const std::shared_ptr>& listener) { + snapshots_in_sync_listeners_.erase(listener); +} + +void EventManager::HandleOnlineStateChange(model::OnlineState online_state) { + bool raised_event = false; + online_state_ = online_state; + + for (auto&& kv : queries_) { + QueryListenersInfo& info = kv.second; + for (auto&& listener : info.listeners) { + if (listener->OnOnlineStateChanged(online_state_)) { + raised_event = true; + } + } + } + if (raised_event) { + RaiseSnapshotsInSyncEvent(); + } +} + +void EventManager::RaiseSnapshotsInSyncEvent() { + Empty empty{}; + for (const auto& listener : snapshots_in_sync_listeners_) { + listener->OnEvent(empty); + } +} + +void EventManager::OnViewSnapshots( + std::vector&& snapshots) { + bool raised_event = false; + for (ViewSnapshot& snapshot : snapshots) { + const Query& query = snapshot.query(); + auto found_iter = queries_.find(query); + if (found_iter != queries_.end()) { + QueryListenersInfo& query_info = found_iter->second; + for (const auto& listener : query_info.listeners) { + if (listener->OnViewSnapshot(snapshot)) { + raised_event = true; + } + } + query_info.set_view_snapshot(std::move(snapshot)); + } + } + if (raised_event) { + RaiseSnapshotsInSyncEvent(); + } +} + +void EventManager::OnError(const core::Query& query, + const util::Status& error) { + auto found_iter = queries_.find(query); + if (found_iter == queries_.end()) { + return; + } + + QueryListenersInfo& query_info = found_iter->second; + for (const auto& listener : query_info.listeners) { + listener->OnError(error); + } + + // Remove all listeners. NOTE: We don't need to call + // `SyncEngine::StopListening()` after an error. + queries_.erase(found_iter); +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/event_manager.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/event_manager.h new file mode 100644 index 0000000..b3a16cf --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/event_manager.h @@ -0,0 +1,124 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_EVENT_MANAGER_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_EVENT_MANAGER_H_ + +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/core/query.h" +#include "Firestore/core/src/firebase/firestore/core/query_listener.h" +#include "Firestore/core/src/firebase/firestore/core/sync_engine.h" +#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/util/empty.h" +#include "Firestore/core/src/firebase/firestore/util/nullability.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" +#include "absl/algorithm/container.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace core { + +/** + * EventManager is responsible for mapping queries to query event listeners. + * It handles "fan-out". (Identical queries will re-use the same watch on the + * backend.) + */ +class EventManager : public SyncEngineCallback { + public: + explicit EventManager(QueryEventSource* query_event_source_); + + /** + * Adds a query listener that will be called with new snapshots for the query. + * The EventManager is responsible for multiplexing many listeners to a single + * listen in the SyncEngine and will perform a listen if it's the first + * QueryListener added for a query. + * + * Returns the TargetId of the listen call in the SyncEngine. + */ + model::TargetId AddQueryListener( + std::shared_ptr listener); + + /** + * Removes a previously added listener. It's a no-op if the listener is not + * found. + */ + void RemoveQueryListener(std::shared_ptr listener); + + void AddSnapshotsInSyncListener( + const std::shared_ptr>& listener); + void RemoveSnapshotsInSyncListener( + const std::shared_ptr>& listener); + + // Implements `QueryEventCallback`. + void HandleOnlineStateChange(model::OnlineState online_state) override; + void OnViewSnapshots(std::vector&& snapshots) override; + void OnError(const core::Query& query, const util::Status& error) override; + + private: + /** + * Call all global snapshot listeners that have been set. + */ + void RaiseSnapshotsInSyncEvent(); + + /** + * Holds the listeners and the last received ViewSnapshot for a query being + * tracked by EventManager. + */ + struct QueryListenersInfo { + model::TargetId target_id; + std::vector> listeners; + + bool Erase(const std::shared_ptr& listener) { + auto found_iter = absl::c_find(listeners, listener); + auto found = found_iter != listeners.end(); + if (found) { + listeners.erase(found_iter); + } + return found; + } + + const absl::optional& view_snapshot() const { + return snapshot_; + } + + void set_view_snapshot(const absl::optional& snapshot) { + snapshot_ = snapshot; + } + + private: + // Other members are public in this struct, ensure that any reads are + // copies by requiring reads to go through a const getter. + absl::optional snapshot_; + }; + + QueryEventSource* query_event_source_ = nullptr; + model::OnlineState online_state_ = model::OnlineState::Unknown; + std::unordered_map queries_; + std::unordered_set>> + snapshots_in_sync_listeners_; +}; + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_EVENT_MANAGER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/field_filter.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/field_filter.cc new file mode 100644 index 0000000..ea15096 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/field_filter.cc @@ -0,0 +1,197 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/field_filter.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/core/array_contains_any_filter.h" +#include "Firestore/core/src/firebase/firestore/core/array_contains_filter.h" +#include "Firestore/core/src/firebase/firestore/core/in_filter.h" +#include "Firestore/core/src/firebase/firestore/core/key_field_filter.h" +#include "Firestore/core/src/firebase/firestore/core/key_field_in_filter.h" +#include "Firestore/core/src/firebase/firestore/core/operator.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" +#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "absl/algorithm/container.h" +#include "absl/strings/str_cat.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace core { + +using model::FieldPath; +using model::FieldValue; +using util::ComparisonResult; +using util::ThrowInvalidArgument; + +namespace { + +const char* CanonicalName(Filter::Operator op) { + switch (op) { + case Filter::Operator::LessThan: + return "<"; + case Filter::Operator::LessThanOrEqual: + return "<="; + case Filter::Operator::Equal: + return "=="; + case Filter::Operator::GreaterThanOrEqual: + return ">="; + case Filter::Operator::GreaterThan: + return ">"; + case Filter::Operator::ArrayContains: + // The canonical name for this is array_contains for compatibility with + // existing entries in `query_targets` stored on user devices. This cannot + // be changed without causing users to lose their associated resume + // tokens. + return "array_contains"; + case Filter::Operator::In: + return "in"; + case Filter::Operator::ArrayContainsAny: + return "array-contains-any"; + } + + UNREACHABLE(); +} + +} // namespace + +FieldFilter FieldFilter::Create(FieldPath path, + Operator op, + FieldValue value_rhs) { + if (path.IsKeyFieldPath()) { + if (op == Filter::Operator::In) { + HARD_ASSERT(value_rhs.type() == FieldValue::Type::Array, + "Comparing on key with IN, but the value was not an Array"); + return KeyFieldInFilter(std::move(path), std::move(value_rhs)); + } else { + HARD_ASSERT(value_rhs.type() == FieldValue::Type::Reference, + "Comparing on key, but filter value not a Reference."); + HARD_ASSERT(!IsArrayOperator(op), + "%s queries don't make sense on document keys.", + CanonicalName(op)); + return KeyFieldFilter(std::move(path), op, std::move(value_rhs)); + } + + } else if (value_rhs.type() == FieldValue::Type::Null) { + if (op != Filter::Operator::Equal) { + ThrowInvalidArgument( + "Invalid Query. Null supports only equality comparisons."); + } + Rep filter(std::move(path), op, std::move(value_rhs)); + return FieldFilter(std::make_shared(std::move(filter))); + + } else if (value_rhs.is_nan()) { + if (op != Filter::Operator::Equal) { + ThrowInvalidArgument( + "Invalid Query. NaN supports only equality comparisons."); + } + Rep filter(std::move(path), op, std::move(value_rhs)); + return FieldFilter(std::make_shared(std::move(filter))); + + } else if (op == Operator::ArrayContains) { + return ArrayContainsFilter(std::move(path), std::move(value_rhs)); + + } else if (op == Operator::In) { + HARD_ASSERT(value_rhs.type() == FieldValue::Type::Array, + "IN filter has invalid value: %s", value_rhs.type()); + return InFilter(std::move(path), std::move(value_rhs)); + + } else if (op == Operator::ArrayContainsAny) { + HARD_ASSERT(value_rhs.type() == FieldValue::Type::Array, + "arrayContainsAny filter has invalid value: %s", + value_rhs.type()); + return ArrayContainsAnyFilter(std::move(path), std::move(value_rhs)); + } else { + Rep filter(std::move(path), op, std::move(value_rhs)); + return FieldFilter(std::make_shared(std::move(filter))); + } +} + +FieldFilter::FieldFilter(const Filter& other) : Filter(other) { + HARD_ASSERT(IsAFieldFilter()); +} + +FieldFilter::FieldFilter(std::shared_ptr rep) + : Filter(std::move(rep)) { +} + +FieldFilter::Rep::Rep(FieldPath field, Operator op, FieldValue value_rhs) + : field_(std::move(field)), op_(op), value_rhs_(std::move(value_rhs)) { +} + +bool FieldFilter::Rep::IsInequality() const { + return op_ == Operator::LessThan || op_ == Operator::LessThanOrEqual || + op_ == Operator::GreaterThan || op_ == Operator::GreaterThanOrEqual; +} + +bool FieldFilter::Rep::Matches(const model::Document& doc) const { + absl::optional maybe_lhs = doc.field(field_); + if (!maybe_lhs) return false; + + const FieldValue& lhs = *maybe_lhs; + + // Only compare types with matching backend order (such as double and int). + return FieldValue::Comparable(lhs.type(), value_rhs_.type()) && + MatchesComparison(lhs.CompareTo(value_rhs_)); +} + +bool FieldFilter::Rep::MatchesComparison(ComparisonResult comparison) const { + switch (op_) { + case Operator::LessThan: + return comparison == ComparisonResult::Ascending; + case Operator::LessThanOrEqual: + return comparison == ComparisonResult::Ascending || + comparison == ComparisonResult::Same; + case Operator::Equal: + return comparison == ComparisonResult::Same; + case Operator::GreaterThanOrEqual: + return comparison == ComparisonResult::Descending || + comparison == ComparisonResult::Same; + case Operator::GreaterThan: + return comparison == ComparisonResult::Descending; + default: + HARD_FAIL("Operator %s unsuitable for comparison", op_); + } +} + +std::string FieldFilter::Rep::CanonicalId() const { + return absl::StrCat(field_.CanonicalString(), CanonicalName(op_), + value_rhs_.ToString()); +} + +std::string FieldFilter::Rep::ToString() const { + return util::StringFormat("%s %s %s", field_.CanonicalString(), + CanonicalName(op_), value_rhs_.ToString()); +} + +size_t FieldFilter::Rep::Hash() const { + return util::Hash(field_, op_, value_rhs_); +} + +bool FieldFilter::Rep::Equals(const Filter::Rep& other) const { + if (type() != other.type()) return false; + + const auto& other_rep = static_cast(other); + return op_ == other_rep.op_ && field_ == other_rep.field_ && + value_rhs_ == other_rep.value_rhs_; +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/field_filter.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/field_filter.h new file mode 100644 index 0000000..32f1ccf --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/field_filter.h @@ -0,0 +1,136 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_FIELD_FILTER_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_FIELD_FILTER_H_ + +#include +#include + +#include "Firestore/core/src/firebase/firestore/core/filter.h" +#include "Firestore/core/src/firebase/firestore/model/document.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" + +namespace firebase { +namespace firestore { +namespace core { + +/** + * FieldFilter is a document filter constraint on a query with a single + * relation operator. + */ +class FieldFilter : public Filter { + public: + /** + * Creates a Filter instance for the provided path, operator, and value. + */ + static FieldFilter Create(model::FieldPath path, + Operator op, + model::FieldValue value_rhs); + + explicit FieldFilter(const Filter& filter); + + const model::FieldPath& field() const { + return field_filter_rep().field_; + } + + Operator op() const { + return field_filter_rep().op_; + } + + const model::FieldValue& value() const { + return field_filter_rep().value_rhs_; + } + + protected: + class Rep : public Filter::Rep { + public: + Type type() const override { + return Type::kFieldFilter; + } + + bool IsAFieldFilter() const override { + return true; + } + + bool IsInequality() const override; + + const model::FieldPath& field() const override { + return field_; + } + + Operator op() const { + return op_; + } + + const model::FieldValue& value() const { + return value_rhs_; + } + + bool Matches(const model::Document& doc) const override; + + std::string CanonicalId() const override; + + std::string ToString() const override; + + size_t Hash() const override; + + protected: + /** + * Creates a new filter that compares fields and values. Only intended to be + * called from Filter::Create(). + * + * @param field A path to a field in the document to filter on. The LHS of + * the expression. + * @param op The binary operator to apply. + * @param value_rhs A constant value to compare `field` to. The RHS of the + * expression. + */ + Rep(model::FieldPath field, Operator op, model::FieldValue value_rhs); + + bool MatchesComparison(util::ComparisonResult result) const; + + private: + friend class FieldFilter; + + bool Equals(const Filter::Rep& other) const override; + + bool MatchesValue(const model::FieldValue& lhs) const; + + /** The left hand side of the relation. A path into a document field. */ + model::FieldPath field_; + + /** The type of equality/inequality operator to use in the relation. */ + Operator op_; + + /** The right hand side of the relation. A constant value to compare to. */ + model::FieldValue value_rhs_; + }; + + explicit FieldFilter(std::shared_ptr rep); + + private: + const Rep& field_filter_rep() const { + return static_cast(rep()); + } +}; + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_FIELD_FILTER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/filter.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/filter.cc index ea0fab3..f2b64b3 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/filter.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/filter.cc @@ -16,24 +16,20 @@ #include "Firestore/core/src/firebase/firestore/core/filter.h" -#include - -#include "Firestore/core/src/firebase/firestore/core/relation_filter.h" +#include namespace firebase { namespace firestore { namespace core { -using model::FieldPath; -using model::FieldValue; +bool operator==(const Filter& lhs, const Filter& rhs) { + return lhs.rep_ == nullptr + ? rhs.rep_ == nullptr + : (rhs.rep_ != nullptr && lhs.rep_->Equals(*rhs.rep_)); +} -std::shared_ptr Filter::Create(FieldPath path, - Operator op, - FieldValue value_rhs) { - // TODO(rsgowman): Java performs a number of checks here, and then invokes the - // ctor of the relevant Filter subclass. Port those checks here. - return std::make_shared(std::move(path), op, - std::move(value_rhs)); +std::ostream& operator<<(std::ostream& os, const Filter& filter) { + return os << filter.ToString(); } } // namespace core diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/filter.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/filter.h index 4748566..e85709d 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/filter.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/filter.h @@ -17,9 +17,11 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_FILTER_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_FILTER_H_ +#include #include #include +#include "Firestore/core/src/firebase/firestore/immutable/append_only_list.h" #include "Firestore/core/src/firebase/firestore/model/document.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" #include "Firestore/core/src/firebase/firestore/model/field_value.h" @@ -31,38 +33,130 @@ namespace core { /** Interface used for all query filters. All filters are immutable. */ class Filter { public: + /** + * Operator is a value relation operator that can be used to filter documents. + * It is similar to NSPredicateOperatorType, but only has operators supported + * by Firestore. + */ enum class Operator { LessThan, LessThanOrEqual, Equal, - GreaterThan, GreaterThanOrEqual, + GreaterThan, + ArrayContains, + In, + ArrayContainsAny, }; + // For lack of RTTI, all subclasses must identify themselves so that + // comparisons properly take type into account. + enum class Type { + kArrayContainsAnyFilter, + kArrayContainsFilter, + kFieldFilter, + kInFilter, + kKeyFieldFilter, + kKeyFieldInFilter, + }; + + Type type() const { + return rep_->type(); + } + /** - * Creates a Filter instance for the provided path, operator, and value. + * Returns true if this instance is FieldFilter or any derived class. + * Equivalent to `instanceof FieldFilter` on other platforms. * - * Note that if the relational operator is Equal and the value is NullValue or - * NaN, then this will return the appropriate NullFilter or NaNFilter class - * instead of a RelationFilter. + * Note this is different than checking `type() == Type::kFieldFilter` which + * is only true if the type is exactly FieldFilter. */ - static std::shared_ptr Create(model::FieldPath path, - Operator op, - model::FieldValue value_rhs); + bool IsAFieldFilter() const { + return rep_->IsAFieldFilter(); + } - virtual ~Filter() { + bool IsInequality() const { + return rep_->IsInequality(); } /** Returns the field the Filter operates over. */ - virtual const model::FieldPath& field() const = 0; + const model::FieldPath& field() const { + return rep_->field(); + } /** Returns true if a document matches the filter. */ - virtual bool Matches(const model::Document& doc) const = 0; + bool Matches(const model::Document& doc) const { + return rep_->Matches(doc); + } /** A unique ID identifying the filter; used when serializing queries. */ - virtual std::string CanonicalId() const = 0; + std::string CanonicalId() const { + return rep_->CanonicalId(); + } + + /** A debug description of the Filter. */ + std::string ToString() const { + return rep_->ToString(); + } + + size_t Hash() const { + return rep_->Hash(); + } + + friend bool operator==(const Filter& lhs, const Filter& rhs); + + protected: + class Rep { + public: + virtual ~Rep() = default; + + virtual Type type() const = 0; + + virtual bool IsAFieldFilter() const { + return false; + } + + virtual bool IsInequality() const { + return false; + } + + /** Returns the field the Filter operates over. */ + virtual const model::FieldPath& field() const = 0; + + /** Returns true if a document matches the filter. */ + virtual bool Matches(const model::Document& doc) const = 0; + + /** A unique ID identifying the filter; used when serializing queries. */ + virtual std::string CanonicalId() const = 0; + + virtual bool Equals(const Rep& other) const = 0; + + virtual size_t Hash() const = 0; + + /** A debug description of the Filter. */ + virtual std::string ToString() const = 0; + }; + + explicit Filter(std::shared_ptr rep) : rep_(rep) { + } + + const Rep& rep() const { + return *rep_; + } + + private: + std::shared_ptr rep_; }; +inline bool operator!=(const Filter& lhs, const Filter& rhs) { + return !(lhs == rhs); +} + +/** A list of Filters, as used in Queries and elsewhere. */ +using FilterList = immutable::AppendOnlyList; + +std::ostream& operator<<(std::ostream& os, const Filter& filter); + } // namespace core } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/firestore_client.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/firestore_client.cc new file mode 100644 index 0000000..674a5dd --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/firestore_client.cc @@ -0,0 +1,484 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/firestore_client.h" + +#include // NOLINT(build/c++11) +#include +#include + +#include "Firestore/core/src/firebase/firestore/api/settings.h" +#include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" +#include "Firestore/core/src/firebase/firestore/core/database_info.h" +#include "Firestore/core/src/firebase/firestore/core/event_manager.h" +#include "Firestore/core/src/firebase/firestore/core/view.h" +#include "Firestore/core/src/firebase/firestore/local/index_free_query_engine.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_opener.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_persistence.h" +#include "Firestore/core/src/firebase/firestore/local/local_serializer.h" +#include "Firestore/core/src/firebase/firestore/local/memory_persistence.h" +#include "Firestore/core/src/firebase/firestore/local/query_result.h" +#include "Firestore/core/src/firebase/firestore/model/database_id.h" +#include "Firestore/core/src/firebase/firestore/model/document_set.h" +#include "Firestore/core/src/firebase/firestore/model/mutation.h" +#include "Firestore/core/src/firebase/firestore/remote/datastore.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_store.h" +#include "Firestore/core/src/firebase/firestore/remote/serializer.h" +#include "Firestore/core/src/firebase/firestore/util/async_queue.h" +#include "Firestore/core/src/firebase/firestore/util/delayed_constructor.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/statusor.h" +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" +#include "absl/memory/memory.h" + +namespace firebase { +namespace firestore { +namespace core { + +using api::DocumentReference; +using api::DocumentSnapshot; +using api::ListenerRegistration; +using api::QuerySnapshot; +using api::Settings; +using api::SnapshotMetadata; +using auth::CredentialsProvider; +using auth::User; +using firestore::Error; +using local::IndexFreeQueryEngine; +using local::LevelDbOpener; +using local::LocalSerializer; +using local::LocalStore; +using local::LruParams; +using local::MemoryPersistence; +using local::QueryResult; +using model::DatabaseId; +using model::Document; +using model::DocumentKeySet; +using model::DocumentMap; +using model::MaybeDocument; +using model::Mutation; +using model::OnlineState; +using remote::Datastore; +using remote::RemoteStore; +using remote::Serializer; +using util::AsyncQueue; +using util::DelayedConstructor; +using util::DelayedOperation; +using util::Empty; +using util::Executor; +using util::Path; +using util::Status; +using util::StatusCallback; +using util::StatusOr; +using util::StatusOrCallback; +using util::ThrowIllegalState; +using util::TimerId; + +std::shared_ptr FirestoreClient::Create( + const DatabaseInfo& database_info, + const api::Settings& settings, + std::shared_ptr credentials_provider, + std::shared_ptr user_executor, + std::shared_ptr worker_queue) { + // Have to use `new` because `make_shared` cannot access private constructor. + std::shared_ptr shared_client( + new FirestoreClient(database_info, std::move(credentials_provider), + std::move(user_executor), std::move(worker_queue))); + + std::weak_ptr weak_client(shared_client); + auto credential_change_listener = [weak_client, settings](User user) mutable { + auto shared_client = weak_client.lock(); + if (!shared_client) return; + + if (!shared_client->credentials_initialized_) { + shared_client->credentials_initialized_ = true; + + // When we register the credentials listener for the first time, + // it is invoked synchronously on the calling thread. This ensures that + // the first item enqueued on the worker queue is + // `FirestoreClient::Initialize()`. + shared_client->worker_queue()->Enqueue([shared_client, user, settings] { + shared_client->Initialize(user, settings); + }); + } else { + shared_client->worker_queue()->Enqueue([shared_client, user] { + shared_client->worker_queue()->VerifyIsCurrentQueue(); + + LOG_DEBUG("Credential Changed. Current user: %s", user.uid()); + shared_client->sync_engine_->HandleCredentialChange(user); + }); + } + }; + + shared_client->credentials_provider_->SetCredentialChangeListener( + credential_change_listener); + + HARD_ASSERT( + shared_client->credentials_initialized_, + "CredentialChangeListener not invoked during client initialization"); + + return shared_client; +} + +FirestoreClient::FirestoreClient( + const DatabaseInfo& database_info, + std::shared_ptr credentials_provider, + std::shared_ptr user_executor, + std::shared_ptr worker_queue) + : database_info_(database_info), + credentials_provider_(std::move(credentials_provider)), + worker_queue_(std::move(worker_queue)), + user_executor_(std::move(user_executor)) { +} + +void FirestoreClient::Initialize(const User& user, const Settings& settings) { + // Do all of our initialization on our own dispatch queue. + worker_queue()->VerifyIsCurrentQueue(); + LOG_DEBUG("Initializing. Current user: %s", user.uid()); + + // Note: The initialization work must all be synchronous (we can't dispatch + // more work) since external write/listen operations could get queued to run + // before that subsequent work completes. + if (settings.persistence_enabled()) { + LevelDbOpener opener(database_info_); + + auto created = + opener.Create(LruParams::WithCacheSize(settings.cache_size_bytes())); + // If leveldb fails to start then just throw up our hands: the error is + // unrecoverable. There's nothing an end-user can do and nearly all + // failures indicate the developer is doing something grossly wrong so we + // should stop them cold in their tracks with a failure they can't ignore. + HARD_ASSERT(created.ok(), "Failed to open DB: %s", + created.status().ToString()); + + auto ldb = std::move(created).ValueOrDie(); + lru_delegate_ = ldb->reference_delegate(); + + persistence_ = std::move(ldb); + if (settings.gc_enabled()) { + ScheduleLruGarbageCollection(); + } + } else { + persistence_ = MemoryPersistence::WithEagerGarbageCollector(); + } + + query_engine_ = absl::make_unique(); + local_store_ = absl::make_unique(persistence_.get(), + query_engine_.get(), user); + + auto datastore = std::make_shared(database_info_, worker_queue(), + credentials_provider_); + + std::weak_ptr weak_this(shared_from_this()); + remote_store_ = absl::make_unique( + local_store_.get(), std::move(datastore), worker_queue(), + [weak_this](OnlineState online_state) { + weak_this.lock()->sync_engine_->HandleOnlineStateChange(online_state); + }); + + sync_engine_ = absl::make_unique(local_store_.get(), + remote_store_.get(), user); + + event_manager_ = absl::make_unique(sync_engine_.get()); + + // Setup wiring for remote store. + remote_store_->set_sync_engine(sync_engine_.get()); + + // NOTE: RemoteStore depends on LocalStore (for persisting stream tokens, + // refilling mutation queue, etc.) so must be started after LocalStore. + local_store_->Start(); + remote_store_->Start(); +} + +/** + * Schedules a callback to try running LRU garbage collection. Reschedules + * itself after the GC has run. + */ +void FirestoreClient::ScheduleLruGarbageCollection() { + std::chrono::milliseconds delay = + gc_has_run_ ? regular_gc_delay_ : initial_gc_delay_; + std::weak_ptr weak_this = shared_from_this(); + lru_callback_ = worker_queue()->EnqueueAfterDelay( + delay, TimerId::GarbageCollectionDelay, [weak_this] { + auto shared_this = weak_this.lock(); + if (!shared_this) return; + + shared_this->local_store_->CollectGarbage( + shared_this->lru_delegate_->garbage_collector()); + shared_this->gc_has_run_ = true; + shared_this->ScheduleLruGarbageCollection(); + }); +} + +void FirestoreClient::DisableNetwork(StatusCallback callback) { + VerifyNotTerminated(); + auto shared_this = shared_from_this(); + worker_queue()->Enqueue([shared_this, callback] { + shared_this->remote_store_->DisableNetwork(); + if (callback) { + shared_this->user_executor()->Execute([=] { callback(Status::OK()); }); + } + }); +} + +void FirestoreClient::EnableNetwork(StatusCallback callback) { + VerifyNotTerminated(); + auto shared_this = shared_from_this(); + worker_queue()->Enqueue([shared_this, callback] { + shared_this->remote_store_->EnableNetwork(); + if (callback) { + shared_this->user_executor()->Execute([=] { callback(Status::OK()); }); + } + }); +} + +void FirestoreClient::TerminateAsync(StatusCallback callback) { + auto shared_this = shared_from_this(); + worker_queue()->EnqueueAndInitiateShutdown([shared_this, callback] { + shared_this->TerminateInternal(); + + if (callback) { + shared_this->user_executor()->Execute([=] { callback(Status::OK()); }); + } + }); +} + +void FirestoreClient::Terminate() { + std::promise signal_terminated; + worker_queue()->EnqueueAndInitiateShutdown([&, this] { + TerminateInternal(); + signal_terminated.set_value(); + }); + signal_terminated.get_future().wait(); +} + +void FirestoreClient::TerminateInternal() { + if (!remote_store_) return; + + credentials_provider_->SetCredentialChangeListener(nullptr); + + // If we've scheduled LRU garbage collection, cancel it. + if (lru_callback_) { + lru_callback_.Cancel(); + } + remote_store_->Shutdown(); + persistence_->Shutdown(); + + // Clear the remote store to indicate terminate is complete. + remote_store_.reset(); +} + +void FirestoreClient::WaitForPendingWrites(StatusCallback callback) { + VerifyNotTerminated(); + + // Dispatch the result back onto the user dispatch queue. + auto shared_this = shared_from_this(); + auto async_callback = [shared_this, callback](util::Status status) { + if (callback) { + shared_this->user_executor()->Execute( + [=] { callback(std::move(status)); }); + } + }; + + worker_queue()->Enqueue([shared_this, async_callback] { + shared_this->sync_engine_->RegisterPendingWritesCallback( + std::move(async_callback)); + }); +} + +void FirestoreClient::VerifyNotTerminated() { + if (is_terminated()) { + ThrowIllegalState("The client has already been terminated."); + } +} + +bool FirestoreClient::is_terminated() const { + // Technically, the worker queue is still running, but only accepting tasks + // related to termination or supposed to be run after termination. It is + // effectively terminated to the eyes of users. + return worker_queue()->is_shutting_down(); +} + +std::shared_ptr FirestoreClient::ListenToQuery( + Query query, + ListenOptions options, + ViewSnapshot::SharedListener&& listener) { + VerifyNotTerminated(); + + auto query_listener = QueryListener::Create( + std::move(query), std::move(options), std::move(listener)); + + auto shared_this = shared_from_this(); + worker_queue()->Enqueue([shared_this, query_listener] { + shared_this->event_manager_->AddQueryListener(std::move(query_listener)); + }); + + return query_listener; +} + +void FirestoreClient::RemoveListener( + const std::shared_ptr& listener) { + // Checks for termination but does not throw error, allowing it to be an no-op + // if client is already terminated. + if (is_terminated()) { + return; + } + auto shared_this = shared_from_this(); + worker_queue()->Enqueue([shared_this, listener] { + shared_this->event_manager_->RemoveQueryListener(listener); + }); +} + +void FirestoreClient::GetDocumentFromLocalCache( + const DocumentReference& doc, DocumentSnapshot::Listener&& callback) { + VerifyNotTerminated(); + + // TODO(c++14): move `callback` into lambda. + auto shared_callback = absl::ShareUniquePtr(std::move(callback)); + auto shared_this = shared_from_this(); + worker_queue()->Enqueue([shared_this, doc, shared_callback] { + absl::optional maybe_document = + shared_this->local_store_->ReadDocument(doc.key()); + StatusOr maybe_snapshot; + + if (maybe_document && maybe_document->is_document()) { + Document document(*maybe_document); + maybe_snapshot = DocumentSnapshot::FromDocument( + doc.firestore(), document, + SnapshotMetadata{ + /*has_pending_writes=*/document.has_local_mutations(), + /*from_cache=*/true}); + } else if (maybe_document && maybe_document->is_no_document()) { + maybe_snapshot = DocumentSnapshot::FromNoDocument( + doc.firestore(), doc.key(), + SnapshotMetadata{/*has_pending_writes=*/false, + /*from_cache=*/true}); + } else { + maybe_snapshot = + Status{Error::Unavailable, + "Failed to get document from cache. (However, this document " + "may exist on the server. Run again without setting source to " + "FirestoreSourceCache to attempt to retrieve the document "}; + } + + if (shared_callback) { + shared_this->user_executor()->Execute( + [=] { shared_callback->OnEvent(std::move(maybe_snapshot)); }); + } + }); +} + +void FirestoreClient::GetDocumentsFromLocalCache( + const api::Query& query, QuerySnapshot::Listener&& callback) { + VerifyNotTerminated(); + + // TODO(c++14): move `callback` into lambda. + auto shared_callback = absl::ShareUniquePtr(std::move(callback)); + auto shared_this = shared_from_this(); + worker_queue()->Enqueue([shared_this, query, shared_callback] { + QueryResult query_result = shared_this->local_store_->ExecuteQuery( + query.query(), /* use_previous_results= */ true); + + View view(query.query(), query_result.remote_keys()); + ViewDocumentChanges view_doc_changes = + view.ComputeDocumentChanges(query_result.documents().underlying_map()); + ViewChange view_change = view.ApplyChanges(view_doc_changes); + HARD_ASSERT( + view_change.limbo_changes().empty(), + "View returned limbo documents during local-only query execution."); + + HARD_ASSERT(view_change.snapshot().has_value(), "Expected a snapshot"); + + ViewSnapshot snapshot = std::move(view_change.snapshot()).value(); + SnapshotMetadata metadata(snapshot.has_pending_writes(), + snapshot.from_cache()); + + QuerySnapshot result(query.firestore(), query.query(), std::move(snapshot), + std::move(metadata)); + + if (shared_callback) { + shared_this->user_executor()->Execute( + [=] { shared_callback->OnEvent(std::move(result)); }); + } + }); +} + +void FirestoreClient::WriteMutations(std::vector&& mutations, + StatusCallback callback) { + VerifyNotTerminated(); + + // TODO(c++14): move `mutations` into lambda (C++14). + auto shared_this = shared_from_this(); + worker_queue()->Enqueue([shared_this, mutations, callback]() mutable { + if (mutations.empty()) { + if (callback) { + shared_this->user_executor()->Execute([=] { callback(Status::OK()); }); + } + } else { + shared_this->sync_engine_->WriteMutations( + std::move(mutations), [callback, shared_this](Status error) { + // Dispatch the result back onto the user dispatch queue. + if (callback) { + shared_this->user_executor()->Execute( + [=] { callback(std::move(error)); }); + } + }); + } + }); +} + +void FirestoreClient::Transaction(int retries, + TransactionUpdateCallback update_callback, + TransactionResultCallback result_callback) { + VerifyNotTerminated(); + + // Dispatch the result back onto the user dispatch queue. + auto shared_this = shared_from_this(); + auto async_callback = [shared_this, result_callback](Status status) { + if (result_callback) { + shared_this->user_executor()->Execute( + [=] { result_callback(std::move(status)); }); + } + }; + + worker_queue()->Enqueue([shared_this, retries, update_callback, + async_callback] { + shared_this->sync_engine_->Transaction(retries, shared_this->worker_queue(), + std::move(update_callback), + std::move(async_callback)); + }); +} + +void FirestoreClient::AddSnapshotsInSyncListener( + const std::shared_ptr>& user_listener) { + auto shared_this = shared_from_this(); + worker_queue()->Enqueue([shared_this, user_listener] { + shared_this->event_manager_->AddSnapshotsInSyncListener( + std::move(user_listener)); + }); +} + +void FirestoreClient::RemoveSnapshotsInSyncListener( + const std::shared_ptr>& user_listener) { + event_manager_->RemoveSnapshotsInSyncListener(user_listener); +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/firestore_client.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/firestore_client.h new file mode 100644 index 0000000..723cea9 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/firestore_client.h @@ -0,0 +1,227 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_FIRESTORE_CLIENT_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_FIRESTORE_CLIENT_H_ + +#include +#include + +#include "Firestore/core/src/firebase/firestore/api/document_reference.h" +#include "Firestore/core/src/firebase/firestore/api/document_snapshot.h" +#include "Firestore/core/src/firebase/firestore/api/listener_registration.h" +#include "Firestore/core/src/firebase/firestore/api/query_core.h" +#include "Firestore/core/src/firebase/firestore/api/settings.h" +#include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" +#include "Firestore/core/src/firebase/firestore/core/database_info.h" +#include "Firestore/core/src/firebase/firestore/core/listen_options.h" +#include "Firestore/core/src/firebase/firestore/core/query.h" +#include "Firestore/core/src/firebase/firestore/core/query_listener.h" +#include "Firestore/core/src/firebase/firestore/core/transaction.h" +#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" +#include "Firestore/core/src/firebase/firestore/local/local_store.h" +#include "Firestore/core/src/firebase/firestore/model/database_id.h" +#include "Firestore/core/src/firebase/firestore/model/mutation.h" +#include "Firestore/core/src/firebase/firestore/util/async_queue.h" +#include "Firestore/core/src/firebase/firestore/util/delayed_constructor.h" +#include "Firestore/core/src/firebase/firestore/util/empty.h" +#include "Firestore/core/src/firebase/firestore/util/executor.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" + +namespace firebase { +namespace firestore { +namespace local { + +class LruDelegate; +class QueryEngine; +class Persistence; + +} // namespace local + +namespace remote { + +class RemoteStore; + +} // namespace remote + +namespace core { + +class EventManager; +class SyncEngine; + +/** + * FirestoreClient is a top-level class that constructs and owns all of the + * pieces of the client SDK architecture. + */ +class FirestoreClient : public std::enable_shared_from_this { + public: + /** + * Creates a fully initialized `FirestoreClient`. + * + * PORTING NOTE: We use factory function instead of public constructor + * because `FirestoreClient` is supposed to be managed by shared_ptr, and + * it is invalid to call `shared_from_this()` from constructors. + * The factory function enforces that `FirestoreClient` has to be managed + * by a shared pointer. + */ + static std::shared_ptr Create( + const DatabaseInfo& database_info, + const api::Settings& settings, + std::shared_ptr credentials_provider, + std::shared_ptr user_executor, + std::shared_ptr worker_queue); + + /** + * Terminates this client, cancels all writes / listeners, and releases all + * resources. + */ + void TerminateAsync(util::StatusCallback callback); + + /** + * Synchronously terminates this client, cancels all writes / listeners, and + * releases all resources. + */ + void Terminate(); + + /** + * Passes a callback that is triggered when all the pending writes at the + * time when this method is called received server acknowledgement. + * An acknowledgement can be either acceptance or rejections. + */ + void WaitForPendingWrites(util::StatusCallback callback); + + /** Disables the network connection. Pending operations will not complete. */ + void DisableNetwork(util::StatusCallback callback); + + /** Enables the network connection and requeues all pending operations. */ + void EnableNetwork(util::StatusCallback callback); + + /** Starts listening to a query. */ + std::shared_ptr ListenToQuery( + Query query, + ListenOptions options, + ViewSnapshot::SharedListener&& listener); + + /** Stops listening to a query previously listened to. */ + void RemoveListener(const std::shared_ptr& listener); + + /** + * Retrieves a document from the cache via the indicated callback. If the doc + * doesn't exist, an error will be sent to the callback. + */ + void GetDocumentFromLocalCache(const api::DocumentReference& doc, + api::DocumentSnapshot::Listener&& callback); + + /** + * Retrieves a (possibly empty) set of documents from the cache via the + * indicated callback. + */ + void GetDocumentsFromLocalCache(const api::Query& query, + api::QuerySnapshot::Listener&& callback); + + /** + * Write mutations. callback will be notified when it's written to the + * backend. + */ + void WriteMutations(std::vector&& mutations, + util::StatusCallback callback); + + /** + * Tries to execute the transaction in update_callback up to retries times. + */ + void Transaction(int retries, + TransactionUpdateCallback update_callback, + TransactionResultCallback result_callback); + + /** + * Adds a listener to be called when a snapshots-in-sync event fires. + */ + void AddSnapshotsInSyncListener( + const std::shared_ptr>& listener); + + /** + * Removes a specific listener for snapshots-in-sync events. + */ + void RemoveSnapshotsInSyncListener( + const std::shared_ptr>& listener); + + /** The database ID of the DatabaseInfo this client was initialized with. */ + const model::DatabaseId& database_id() const { + return database_info_.database_id(); + } + + /** + * Dispatch queue for user callbacks / events. This will often be the "Main + * Dispatch Queue" of the app but the developer can configure it to a + * different queue if they so choose. + */ + const std::shared_ptr& user_executor() const { + return user_executor_; + } + + /** For usage in this class and testing only. */ + const std::shared_ptr& worker_queue() const { + return worker_queue_; + } + bool is_terminated() const; + + private: + FirestoreClient( + const DatabaseInfo& database_info, + std::shared_ptr credentials_provider, + std::shared_ptr user_executor, + std::shared_ptr worker_queue); + + void Initialize(const auth::User& user, const api::Settings& settings); + + void VerifyNotTerminated(); + + void TerminateInternal(); + + void ScheduleLruGarbageCollection(); + + DatabaseInfo database_info_; + std::shared_ptr credentials_provider_; + /** + * Async queue responsible for all of our internal processing. When we get + * incoming work from the user (via public API) or the network (incoming gRPC + * messages), we should always dispatch onto this queue. This ensures our + * internal data structures are never accessed from multiple threads + * simultaneously. + */ + std::shared_ptr worker_queue_; + std::shared_ptr user_executor_; + + std::unique_ptr persistence_; + std::unique_ptr local_store_; + std::unique_ptr query_engine_; + std::unique_ptr remote_store_; + std::unique_ptr sync_engine_; + std::unique_ptr event_manager_; + + std::chrono::milliseconds initial_gc_delay_ = std::chrono::minutes(1); + std::chrono::milliseconds regular_gc_delay_ = std::chrono::minutes(5); + bool gc_has_run_ = false; + bool credentials_initialized_ = false; + local::LruDelegate* _Nullable lru_delegate_; + util::DelayedOperation lru_callback_; +}; + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_FIRESTORE_CLIENT_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/in_filter.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/in_filter.cc new file mode 100644 index 0000000..03aaf83 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/in_filter.cc @@ -0,0 +1,61 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/in_filter.h" + +#include +#include + +#include "absl/algorithm/container.h" + +namespace firebase { +namespace firestore { +namespace core { + +using model::Document; +using model::FieldPath; +using model::FieldValue; + +using Operator = Filter::Operator; + +class InFilter::Rep : public FieldFilter::Rep { + public: + Rep(FieldPath field, FieldValue value) + : FieldFilter::Rep(std::move(field), Operator::In, std::move(value)) { + } + + Type type() const override { + return Type::kInFilter; + } + + bool Matches(const model::Document& doc) const override; +}; + +InFilter::InFilter(FieldPath field, FieldValue value) + : FieldFilter( + std::make_shared(std::move(field), std::move(value))) { +} + +bool InFilter::Rep::Matches(const Document& doc) const { + const FieldValue::Array& array_value = value().array_value(); + absl::optional maybe_lhs = doc.field(field()); + if (!maybe_lhs) return false; + return absl::c_linear_search(array_value, *maybe_lhs); +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/in_filter.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/in_filter.h new file mode 100644 index 0000000..44c62cd --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/in_filter.h @@ -0,0 +1,44 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_IN_FILTER_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_IN_FILTER_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/core/field_filter.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" + +namespace firebase { +namespace firestore { +namespace core { + +/** + * A Filter that implements the IN operator. + */ +class InFilter : public FieldFilter { + public: + InFilter(model::FieldPath field, model::FieldValue value); + + private: + class Rep; +}; + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_IN_FILTER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/key_field_filter.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/key_field_filter.cc new file mode 100644 index 0000000..832d2bd --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/key_field_filter.cc @@ -0,0 +1,63 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/key_field_filter.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "absl/algorithm/container.h" + +namespace firebase { +namespace firestore { +namespace core { + +using model::Document; +using model::DocumentKey; +using model::FieldPath; +using model::FieldValue; + +using Operator = Filter::Operator; + +class KeyFieldFilter::Rep : public FieldFilter::Rep { + public: + Rep(FieldPath field, Operator op, FieldValue value) + : FieldFilter::Rep(std::move(field), op, std::move(value)) { + } + + Type type() const override { + return Type::kKeyFieldFilter; + } + + bool Matches(const model::Document& doc) const override; +}; + +KeyFieldFilter::KeyFieldFilter(FieldPath field, Operator op, FieldValue value) + : FieldFilter( + std::make_shared(std::move(field), op, std::move(value))) { +} + +bool KeyFieldFilter::Rep::Matches(const Document& doc) const { + const DocumentKey& lhs_key = doc.key(); + const DocumentKey& rhs_key = value().reference_value().key(); + + return MatchesComparison(lhs_key.CompareTo(rhs_key)); +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/key_field_filter.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/key_field_filter.h new file mode 100644 index 0000000..6ff0ee4 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/key_field_filter.h @@ -0,0 +1,45 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_KEY_FIELD_FILTER_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_KEY_FIELD_FILTER_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/core/field_filter.h" + +namespace firebase { +namespace firestore { +namespace core { + +/** + * A Filter that matches on key fields (i.e. '__name__'). + */ +class KeyFieldFilter : public FieldFilter { + public: + KeyFieldFilter(model::FieldPath field, + core::Filter::Operator op, + model::FieldValue value); + + private: + class Rep; +}; + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_KEY_FIELD_FILTER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/key_field_in_filter.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/key_field_in_filter.cc new file mode 100644 index 0000000..c88b930 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/key_field_in_filter.cc @@ -0,0 +1,72 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/key_field_in_filter.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "absl/algorithm/container.h" + +namespace firebase { +namespace firestore { +namespace core { + +using model::Document; +using model::DocumentKey; +using model::FieldPath; +using model::FieldValue; + +using Operator = Filter::Operator; + +class KeyFieldInFilter::Rep : public FieldFilter::Rep { + public: + Rep(FieldPath field, FieldValue value) + : FieldFilter::Rep(std::move(field), Operator::In, std::move(value)) { + const FieldValue::Array& array_value = this->value().array_value(); + for (const auto& ref_value : array_value) { + HARD_ASSERT(ref_value.type() == FieldValue::Type::Reference, + "Comparing on key with IN, but an array value was not" + " a Reference"); + } + } + + Type type() const override { + return Type::kKeyFieldInFilter; + } + + bool Matches(const model::Document& doc) const override; +}; + +KeyFieldInFilter::KeyFieldInFilter(FieldPath field, FieldValue value) + : FieldFilter( + std::make_shared(std::move(field), std::move(value))) { +} + +bool KeyFieldInFilter::Rep::Matches(const Document& doc) const { + const FieldValue::Array& array_value = value().array_value(); + for (const auto& rhs : array_value) { + if (doc.key() == rhs.reference_value().key()) { + return true; + } + } + return false; +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/key_field_in_filter.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/key_field_in_filter.h new file mode 100644 index 0000000..641d053 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/key_field_in_filter.h @@ -0,0 +1,43 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_KEY_FIELD_IN_FILTER_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_KEY_FIELD_IN_FILTER_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/core/field_filter.h" + +namespace firebase { +namespace firestore { +namespace core { + +/** + * A Filter that matches on an array of key fields. + */ +class KeyFieldInFilter : public FieldFilter { + public: + KeyFieldInFilter(model::FieldPath field, model::FieldValue value); + + private: + class Rep; +}; + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_KEY_FIELD_IN_FILTER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/operator.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/operator.h new file mode 100644 index 0000000..ee86549 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/operator.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_OPERATOR_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_OPERATOR_H_ + +#include "Firestore/core/src/firebase/firestore/core/filter.h" + +namespace firebase { +namespace firestore { +namespace core { + +inline bool IsArrayOperator(Filter::Operator op) { + return op == Filter::Operator::ArrayContains || + op == Filter::Operator::ArrayContainsAny; +} + +inline bool IsDisjunctiveOperator(Filter::Operator op) { + return op == Filter::Operator::In || op == Filter::Operator::ArrayContainsAny; +} + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_OPERATOR_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/order_by.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/order_by.cc new file mode 100644 index 0000000..741fb47 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/order_by.cc @@ -0,0 +1,69 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/order_by.h" + +#include + +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/util/string_format.h" +#include "absl/strings/str_cat.h" + +namespace firebase { +namespace firestore { +namespace core { + +using model::Document; +using model::FieldPath; +using model::FieldValue; +using util::ComparisonResult; + +ComparisonResult OrderBy::Compare(const Document& lhs, + const Document& rhs) const { + ComparisonResult result; + if (field_ == FieldPath::KeyFieldPath()) { + result = lhs.key().CompareTo(rhs.key()); + } else { + absl::optional value1 = lhs.field(field_); + absl::optional value2 = rhs.field(field_); + HARD_ASSERT(value1.has_value() && value2.has_value(), + "Trying to compare documents on fields that don't exist."); + result = value1->CompareTo(*value2); + } + + return direction_.ApplyTo(result); +} + +std::string OrderBy::CanonicalId() const { + return absl::StrCat(field_.CanonicalString(), direction_.CanonicalId()); +} + +std::string OrderBy::ToString() const { + return util::StringFormat("OrderBy(path=%s, dir=%s)", + field_.CanonicalString(), direction_.CanonicalId()); +} + +std::ostream& operator<<(std::ostream& os, const OrderBy& order) { + return os << order.ToString(); +} + +bool operator==(const OrderBy& lhs, const OrderBy& rhs) { + return lhs.field() == rhs.field() && lhs.direction() == rhs.direction(); +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/order_by.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/order_by.h new file mode 100644 index 0000000..b0a44f6 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/order_by.h @@ -0,0 +1,96 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_ORDER_BY_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_ORDER_BY_H_ + +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/core/direction.h" +#include "Firestore/core/src/firebase/firestore/immutable/append_only_list.h" +#include "Firestore/core/src/firebase/firestore/model/document.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/util/comparison.h" + +namespace firebase { +namespace firestore { +namespace core { + +/** OrderBy is a field and direction by which to order query results. */ +class OrderBy { + public: + static std::shared_ptr Create(model::FieldPath field, + Direction direction) { + return std::make_shared(std::move(field), direction); + } + + OrderBy() = default; + + /** Creates a new sort order with the given field and direction. */ + OrderBy(model::FieldPath field, Direction direction) + : field_(std::move(field)), direction_(direction) { + } + + /** The field by which to sort. */ + const model::FieldPath& field() const { + return field_; + } + + /** The direction of the sort. */ + const Direction& direction() const { + return direction_; + } + + bool ascending() const { + return direction_ == Direction::Ascending; + } + + /** + * Compares two documents based on the field and direction of this sort + * order. + */ + util::ComparisonResult Compare(const model::Document& lhs, + const model::Document& rhs) const; + + /** A unique ID identifying the filter; used when serializing queries. */ + std::string CanonicalId() const; + + std::string ToString() const; + + private: + model::FieldPath field_; + Direction direction_; +}; + +/** A list of OrderBys, as used in Queries and elsewhere. */ +using OrderByList = immutable::AppendOnlyList; + +std::ostream& operator<<(std::ostream& os, const OrderBy& order); + +bool operator==(const OrderBy& lhs, const OrderBy& rhs); + +inline bool operator!=(const OrderBy& lhs, const OrderBy& rhs) { + return !(lhs == rhs); +} + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_ORDER_BY_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query.cc index 0c0a0fd..5aec0db 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query.cc @@ -17,61 +17,349 @@ #include "Firestore/core/src/firebase/firestore/core/query.h" #include +#include +#include "Firestore/core/src/firebase/firestore/core/field_filter.h" +#include "Firestore/core/src/firebase/firestore/core/operator.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/equality.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "absl/algorithm/container.h" +#include "absl/strings/str_cat.h" namespace firebase { namespace firestore { namespace core { +using Operator = Filter::Operator; +using Type = Filter::Type; + using model::Document; +using model::DocumentComparator; using model::DocumentKey; +using model::FieldPath; using model::ResourcePath; +using util::ComparisonResult; + +Query::Query(ResourcePath path, std::string collection_group) + : path_(std::move(path)), + collection_group_( + std::make_shared(std::move(collection_group))) { +} + +// MARK: - Accessors + +bool Query::IsDocumentQuery() const { + return DocumentKey::IsDocumentKey(path_) && !collection_group_ && + filters_.empty(); +} + +bool Query::MatchesAllDocuments() const { + return filters_.empty() && limit_ == Target::kNoLimit && !start_at_ && + !end_at_ && + (explicit_order_bys_.empty() || + (explicit_order_bys_.size() == 1 && + explicit_order_bys_.front().field().IsKeyFieldPath())); +} + +const FieldPath* Query::InequalityFilterField() const { + for (const auto& filter : filters_) { + if (filter.IsInequality()) { + return &filter.field(); + } + } + return nullptr; +} + +absl::optional Query::FirstArrayOperator() const { + for (const auto& filter : filters_) { + if (filter.IsAFieldFilter()) { + FieldFilter relation_filter(filter); + if (IsArrayOperator(relation_filter.op())) { + return relation_filter.op(); + } + } + } + return absl::nullopt; +} + +absl::optional Query::FirstDisjunctiveOperator() const { + for (const auto& filter : filters_) { + if (filter.IsAFieldFilter()) { + FieldFilter relation_filter(filter); + if (IsDisjunctiveOperator(relation_filter.op())) { + return relation_filter.op(); + } + } + } + return absl::nullopt; +} + +const OrderByList& Query::order_bys() const { + if (memoized_order_bys_.empty()) { + const FieldPath* inequality_field = InequalityFilterField(); + const FieldPath* first_order_by_field = FirstOrderByField(); + if (inequality_field && !first_order_by_field) { + // In order to implicitly add key ordering, we must also add the + // inequality filter field for it to be a valid query. Note that the + // default inequality field and key ordering is ascending. + if (inequality_field->IsKeyFieldPath()) { + memoized_order_bys_ = { + OrderBy(FieldPath::KeyFieldPath(), Direction::Ascending), + }; + } else { + memoized_order_bys_ = { + OrderBy(*inequality_field, Direction::Ascending), + OrderBy(FieldPath::KeyFieldPath(), Direction::Ascending), + }; + } + } else { + HARD_ASSERT( + !inequality_field || *inequality_field == *first_order_by_field, + "First orderBy %s should match inequality field %s.", + first_order_by_field->CanonicalString(), + inequality_field->CanonicalString()); + + OrderByList result = explicit_order_bys_; + + bool found_explicit_key_order = false; + for (const OrderBy& order_by : explicit_order_bys_) { + if (order_by.field().IsKeyFieldPath()) { + found_explicit_key_order = true; + break; + } + } + + if (!found_explicit_key_order) { + // The direction of the implicit key ordering always matches the + // direction of the last explicit sort order + Direction last_direction = explicit_order_bys_.empty() + ? Direction::Ascending + : explicit_order_bys_.back().direction(); + result = result.emplace_back(FieldPath::KeyFieldPath(), last_direction); + } + + memoized_order_bys_ = std::move(result); + } + } + return memoized_order_bys_; +} + +const FieldPath* Query::FirstOrderByField() const { + if (explicit_order_bys_.empty()) { + return nullptr; + } + + return &explicit_order_bys_.front().field(); +} + +LimitType Query::limit_type() const { + return limit_type_; +} + +int32_t Query::limit() const { + HARD_ASSERT(limit_type_ != LimitType::None, + "Called limit() when no limit was set"); + return limit_; +} + +// MARK: - Builder methods + +Query Query::AddingFilter(Filter filter) const { + HARD_ASSERT(!IsDocumentQuery(), "No filter is allowed for document query"); + + const FieldPath* new_inequality_field = nullptr; + if (filter.IsInequality()) { + new_inequality_field = &filter.field(); + } + const FieldPath* query_inequality_field = InequalityFilterField(); + HARD_ASSERT(!query_inequality_field || !new_inequality_field || + *query_inequality_field == *new_inequality_field, + "Query must only have one inequality field."); + + // TODO(rsgowman): ensure first orderby must match inequality field + + return Query(path_, collection_group_, filters_.push_back(std::move(filter)), + explicit_order_bys_, limit_, limit_type_, start_at_, end_at_); +} + +Query Query::AddingOrderBy(OrderBy order_by) const { + HARD_ASSERT(!IsDocumentQuery(), "No ordering is allowed for document query"); + + if (explicit_order_bys_.empty()) { + const FieldPath* inequality = InequalityFilterField(); + HARD_ASSERT(inequality == nullptr || *inequality == order_by.field(), + "First OrderBy must match inequality field."); + } + + return Query(path_, collection_group_, filters_, + explicit_order_bys_.push_back(std::move(order_by)), limit_, + limit_type_, start_at_, end_at_); +} + +Query Query::WithLimitToFirst(int32_t limit) const { + return Query(path_, collection_group_, filters_, explicit_order_bys_, limit, + LimitType::First, start_at_, end_at_); +} + +Query Query::WithLimitToLast(int32_t limit) const { + return Query(path_, collection_group_, filters_, explicit_order_bys_, limit, + LimitType::Last, start_at_, end_at_); +} + +Query Query::StartingAt(Bound bound) const { + return Query(path_, collection_group_, filters_, explicit_order_bys_, limit_, + limit_type_, std::make_shared(std::move(bound)), end_at_); +} + +Query Query::EndingAt(Bound bound) const { + return Query(path_, collection_group_, filters_, explicit_order_bys_, limit_, + limit_type_, start_at_, + std::make_shared(std::move(bound))); +} + +Query Query::AsCollectionQueryAtPath(ResourcePath path) const { + return Query(path, /*collection_group=*/nullptr, filters_, + explicit_order_bys_, limit_, limit_type_, start_at_, end_at_); +} + +// MARK: - Matching bool Query::Matches(const Document& doc) const { - return MatchesPath(doc) && MatchesOrderBy(doc) && MatchesFilters(doc) && - MatchesBounds(doc); + return MatchesPathAndCollectionGroup(doc) && MatchesOrderBy(doc) && + MatchesFilters(doc) && MatchesBounds(doc); } -bool Query::MatchesPath(const Document& doc) const { - ResourcePath doc_path = doc.key().path(); - if (DocumentKey::IsDocumentKey(path_)) { +bool Query::MatchesPathAndCollectionGroup(const Document& doc) const { + const ResourcePath& doc_path = doc.key().path(); + if (collection_group_) { + // NOTE: path_ is currently always empty since we don't expose Collection + // Group queries rooted at a document path yet. + return doc.key().HasCollectionId(*collection_group_) && + path_.IsPrefixOf(doc_path); + } else if (DocumentKey::IsDocumentKey(path_)) { + // Exact match for document queries. return path_ == doc_path; } else { - return path_.IsPrefixOf(doc_path) && path_.size() == doc_path.size() - 1; + // Shallow ancestor queries by default. + return path_.IsImmediateParentOf(doc_path); } } bool Query::MatchesFilters(const Document& doc) const { - return std::all_of(filters_.begin(), filters_.end(), - [&](const std::shared_ptr& filter) { - return filter->Matches(doc); - }); + for (const auto& filter : filters_) { + if (!filter.Matches(doc)) return false; + } + return true; } -bool Query::MatchesOrderBy(const Document&) const { - // TODO(rsgowman): Implement this correctly. +bool Query::MatchesOrderBy(const Document& doc) const { + for (const OrderBy& order_by : explicit_order_bys_) { + const FieldPath& field_path = order_by.field(); + // order by key always matches + if (field_path != FieldPath::KeyFieldPath() && + doc.field(field_path) == absl::nullopt) { + return false; + } + } return true; } -bool Query::MatchesBounds(const Document&) const { - // TODO(rsgowman): Implement this correctly. +bool Query::MatchesBounds(const Document& doc) const { + const OrderByList& ordering = order_bys(); + if (start_at_ && !start_at_->SortsBeforeDocument(ordering, doc)) { + return false; + } + if (end_at_ && end_at_->SortsBeforeDocument(ordering, doc)) { + return false; + } return true; } -Query Query::Filter(std::shared_ptr filter) const { - HARD_ASSERT(!DocumentKey::IsDocumentKey(path_), - "No filter is allowed for document query"); +model::DocumentComparator Query::Comparator() const { + OrderByList ordering = order_bys(); - // TODO(rsgowman): ensure only one inequality field - // TODO(rsgowman): ensure first orderby must match inequality field + bool has_key_ordering = false; + for (const OrderBy& order_by : ordering) { + if (order_by.field() == FieldPath::KeyFieldPath()) { + has_key_ordering = true; + break; + } + } + HARD_ASSERT(has_key_ordering, + "QueryComparator needs to have a key ordering."); + + return DocumentComparator( + [ordering](const Document& doc1, const Document& doc2) { + for (const OrderBy& order_by : ordering) { + ComparisonResult comp = order_by.Compare(doc1, doc2); + if (!util::Same(comp)) return comp; + } + return ComparisonResult::Same; + }); +} + +const std::string Query::CanonicalId() const { + if (limit_type_ != LimitType::None) { + return absl::StrCat(ToTarget().CanonicalId(), + "|lt:", (limit_type_ == LimitType::Last) ? "l" : "f"); + } + return ToTarget().CanonicalId(); +} + +size_t Query::Hash() const { + return util::Hash(CanonicalId()); +} + +std::string Query::ToString() const { + return absl::StrCat("Query(canonical_id=", CanonicalId(), ")"); +} + +const Target& Query::ToTarget() const& { + if (memoized_target == nullptr) { + if (limit_type_ == LimitType::Last) { + // Flip the orderBy directions since we want the last results + OrderByList new_order_bys; + for (const auto& order_by : order_bys()) { + Direction dir = order_by.direction() == Direction::Descending + ? Direction::Ascending + : Direction::Descending; + new_order_bys = new_order_bys.push_back(OrderBy(order_by.field(), dir)); + } + + // We need to swap the cursors to match the now-flipped query ordering. + auto new_start_at = + (end_at_ != nullptr) + ? std::make_shared(end_at_->position(), !end_at_->before()) + : nullptr; + auto new_end_at = (start_at_ != nullptr) + ? std::make_shared(start_at_->position(), + !start_at_->before()) + : nullptr; + + Target target(path(), collection_group(), filters(), new_order_bys, + limit_, new_start_at, new_end_at); + memoized_target = std::make_shared(std::move(target)); + } else { + Target target(path(), collection_group(), filters(), order_bys(), limit_, + start_at(), end_at()); + memoized_target = std::make_shared(std::move(target)); + } + } + + return *memoized_target; +} + +std::ostream& operator<<(std::ostream& os, const Query& query) { + return os << query.ToString(); +} - std::vector> updated_filters = filters_; - updated_filters.push_back(std::move(filter)); - return Query(path_, std::move(updated_filters)); +bool operator==(const Query& lhs, const Query& rhs) { + return (lhs.limit_type_ == rhs.limit_type_) && + (lhs.ToTarget() == rhs.ToTarget()); } } // namespace core diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query.h index 1d9bb37..c6512fe 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query.h @@ -17,93 +17,272 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_QUERY_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_QUERY_H_ +#include +#include #include +#include #include #include +#include "Firestore/core/src/firebase/firestore/core/bound.h" #include "Firestore/core/src/firebase/firestore/core/filter.h" +#include "Firestore/core/src/firebase/firestore/core/order_by.h" +#include "Firestore/core/src/firebase/firestore/core/target.h" +#include "Firestore/core/src/firebase/firestore/immutable/append_only_list.h" #include "Firestore/core/src/firebase/firestore/model/document.h" +#include "Firestore/core/src/firebase/firestore/model/document_set.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" namespace firebase { namespace firestore { namespace core { +using CollectionGroupId = std::shared_ptr; + +enum class LimitType { None, First, Last }; + /** - * Represents the internal structure of a Firestore Query. Query instances are - * immutable. + * Encapsulates all the query attributes we support in the SDK. It represents + * query features visible to user, and can be run against the LocalStore. + * `Query` is first convert to `Target` to run against RemoteStore to query + * backend results, because `Target` encapsulates features backend knows about. */ class Query { public: - /** - * Creates and returns a new Query. - * - * @param path The path to the collection to be queried over. - * @return A new instance of Query. - */ - static Query AtPath(model::ResourcePath path) { - return Query(std::move(path), {}); - } + Query() = default; - static Query Invalid() { - return Query::AtPath(model::ResourcePath::Empty()); + explicit Query(model::ResourcePath path, + CollectionGroupId collection_group = nullptr) + : path_(std::move(path)), collection_group_(std::move(collection_group)) { } - /** Initializes a query with all of its components directly. */ + /** + * Initializes a Query with a path and optional additional query constraints. + * Path must currently be empty if this is a collection group query. + */ Query(model::ResourcePath path, - std::vector> - filters /* TODO(rsgowman): other params */) - : path_(std::move(path)), filters_(std::move(filters)) { + CollectionGroupId collection_group, + FilterList filters, + OrderByList explicit_order_bys, + int32_t limit, + LimitType limit_type, + std::shared_ptr start_at, + std::shared_ptr end_at) + : path_(std::move(path)), + collection_group_(std::move(collection_group)), + filters_(std::move(filters)), + explicit_order_bys_(std::move(explicit_order_bys)), + limit_(limit), + limit_type_(limit_type), + start_at_(std::move(start_at)), + end_at_(std::move(end_at)) { } + Query(model::ResourcePath path, std::string collection_group); + + // MARK: - Accessors + /** The base path of the query. */ const model::ResourcePath& path() const { return path_; } + /** The collection group of the query, if any. */ + const std::shared_ptr& collection_group() const { + return collection_group_; + } + + /** Returns true if this Query is for a specific document. */ + bool IsDocumentQuery() const; + + /** Returns true if this Query is a collection group query. */ + bool IsCollectionGroupQuery() const { + return collection_group_ != nullptr; + } + + /** + * Returns true if this query does not specify any query constraints that + * could remove results. + */ + bool MatchesAllDocuments() const; + /** The filters on the documents returned by the query. */ - const std::vector>& filters() const { + const FilterList& filters() const { return filters_; } - /** Returns true if the document matches the constraints of this query. */ - bool Matches(const model::Document& doc) const; + /** + * Returns the field of the first filter on this Query that's an inequality, + * or nullptr if there are no inequalities. + */ + const model::FieldPath* InequalityFilterField() const; - /** Returns true if this Query is for a specific document. */ - bool IsDocumentQuery() const { - return model::DocumentKey::IsDocumentKey(path_) && filters_.empty(); + /** + * Returns the first array operator (array-contains or array-contains-any) + * found on a filter, or absl::nullopt if there are no array operators. + */ + absl::optional FirstArrayOperator() const; + + /** + * Returns the first disjunctive operator (IN or array-contains-any) found + * on a filter, or absl::nullopt if there are no disjunctive operators. + */ + absl::optional FirstDisjunctiveOperator() const; + + /** + * Returns the list of ordering constraints that were explicitly requested on + * the query by the user. + * + * Note that the actual query performed might add additional sort orders to + * match the behavior of the backend. + */ + const OrderByList& explicit_order_bys() const { + return explicit_order_bys_; } + /** + * Returns the full list of ordering constraints on the query. + * + * This might include additional sort orders added implicitly to match the + * backend behavior. + */ + const OrderByList& order_bys() const; + + /** Returns the first field in an order-by constraint, or nullptr if none. */ + const model::FieldPath* FirstOrderByField() const; + + bool has_limit_to_first() const { + return limit_type_ == LimitType::First && limit_ != Target::kNoLimit; + } + + bool has_limit_to_last() const { + return limit_type_ == LimitType::Last && limit_ != Target::kNoLimit; + } + + LimitType limit_type() const; + + int32_t limit() const; + + const std::shared_ptr& start_at() const { + return start_at_; + } + + const std::shared_ptr& end_at() const { + return end_at_; + } + + // MARK: - Builder methods + /** * Returns a copy of this Query object with the additional specified filter. */ - Query Filter(std::shared_ptr filter) const; + Query AddingFilter(Filter filter) const; + + /** + * Returns a copy of this Query object with the additional specified order by. + */ + Query AddingOrderBy(OrderBy order_by) const; + + /** + * Returns a new `Query` that returns the first matching documents up to + * the specified number. + * + * @param limit The maximum number of results to return. If + * `limit == kNoLimit`, then no limit is applied. Otherwise, if + * `limit <= 0`, behavior is unspecified. + */ + Query WithLimitToFirst(int32_t limit) const; + + /** + * Returns a new `Query` that returns the last matching documents up to + * the specified number. + * + * You must specify at least one `OrderBy` clause for `LimitToLast` queries, + * it is an error otherwise. + * + * @param limit The maximum number of results to return. If + * `limit == kNoLimit`, then no limit is applied. Otherwise, if + * `limit <= 0`, behavior is unspecified. + */ + Query WithLimitToLast(int32_t limit) const; + + /** + * Returns a copy of this Query starting at the provided bound. + */ + Query StartingAt(Bound bound) const; + + /** + * Returns a copy of this Query ending at the provided bound. + */ + Query EndingAt(Bound bound) const; + + // MARK: - Matching + + /** + * Converts this collection group query into a collection query at a specific + * path. This is used when executing collection group queries, since we have + * to split the query into a set of collection queries, one for each + * collection in the group. + */ + Query AsCollectionQueryAtPath(model::ResourcePath path) const; + + /** Returns true if the document matches the constraints of this query. */ + bool Matches(const model::Document& doc) const; + + /** + * Returns a comparator that will sort documents according to the order by + * clauses in this query. + */ + model::DocumentComparator Comparator() const; + + const std::string CanonicalId() const; + + std::string ToString() const; + + /** + * Returns a `Target` instance this query will be mapped to in backend + * and local store. + */ + const Target& ToTarget() const&; + + friend std::ostream& operator<<(std::ostream& os, const Query& query); + + friend bool operator==(const Query& lhs, const Query& rhs); + size_t Hash() const; private: - bool MatchesPath(const model::Document& doc) const; + bool MatchesPathAndCollectionGroup(const model::Document& doc) const; bool MatchesFilters(const model::Document& doc) const; bool MatchesOrderBy(const model::Document& doc) const; bool MatchesBounds(const model::Document& doc) const; model::ResourcePath path_; + std::shared_ptr collection_group_; // Filters are shared across related Query instance. i.e. when you call // Query::Filter(f), a new Query instance is created that contains all of the // existing filters, plus the new one. (Both Query and Filter objects are // immutable.) Filters are not shared across unrelated Query instances. - std::vector> filters_; + FilterList filters_; - // TODO(rsgowman): Port collection group queries logic. -}; + // A list of fields given to sort by. This does not include the implicit key + // sort at the end. + OrderByList explicit_order_bys_; -inline bool operator==(const Query& lhs, const Query& rhs) { - // TODO(rsgowman): check limit (once it exists) - // TODO(rsgowman): check orderby (once it exists) - // TODO(rsgowman): check startat (once it exists) - // TODO(rsgowman): check endat (once it exists) - return lhs.path() == rhs.path() && lhs.filters() == rhs.filters(); -} + // The memoized list of sort orders. + mutable OrderByList memoized_order_bys_; + + int32_t limit_ = Target::kNoLimit; + LimitType limit_type_ = LimitType::None; + + std::shared_ptr start_at_; + std::shared_ptr end_at_; + + // The corresponding Target of this Query instance. + mutable std::shared_ptr memoized_target; +}; +bool operator==(const Query& lhs, const Query& rhs); inline bool operator!=(const Query& lhs, const Query& rhs) { return !(lhs == rhs); } @@ -112,4 +291,15 @@ inline bool operator!=(const Query& lhs, const Query& rhs) { } // namespace firestore } // namespace firebase +namespace std { + +template <> +struct hash { + size_t operator()(const firebase::firestore::core::Query& query) const { + return query.Hash(); + } +}; + +} // namespace std + #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_QUERY_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query_listener.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query_listener.cc new file mode 100644 index 0000000..4079f56 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query_listener.cc @@ -0,0 +1,160 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/query_listener.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/document_set.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace core { + +using model::OnlineState; +using model::TargetId; +using util::Status; + +QueryListener::QueryListener(Query query, + ListenOptions options, + ViewSnapshot::SharedListener&& listener) + : query_(std::move(query)), + options_(std::move(options)), + listener_(std::move(listener)) { +} + +bool QueryListener::OnViewSnapshot(ViewSnapshot snapshot) { + HARD_ASSERT( + !snapshot.document_changes().empty() || snapshot.sync_state_changed(), + "We got a new snapshot with no changes?"); + bool raised_event = false; + if (!options_.include_document_metadata_changes()) { + // Remove the metadata-only changes. + std::vector changes; + for (const DocumentViewChange& change : snapshot.document_changes()) { + if (change.type() != DocumentViewChange::Type::Metadata) { + changes.push_back(change); + } + } + + snapshot = ViewSnapshot{snapshot.query(), + snapshot.documents(), + snapshot.old_documents(), + std::move(changes), + snapshot.mutated_keys(), + snapshot.from_cache(), + snapshot.sync_state_changed(), + /*excludes_metadata_changes=*/true}; + } + + if (!raised_initial_event_) { + if (ShouldRaiseInitialEvent(snapshot, online_state_)) { + RaiseInitialEvent(snapshot); + raised_event = true; + } + } else if (ShouldRaiseEvent(snapshot)) { + listener_->OnEvent(snapshot); + raised_event = true; + } + + snapshot_ = std::move(snapshot); + return raised_event; +} + +void QueryListener::OnError(Status error) { + listener_->OnEvent(std::move(error)); +} + +/** + * Returns whether a snaphsot was raised. + */ +bool QueryListener::OnOnlineStateChanged(OnlineState online_state) { + online_state_ = online_state; + bool raised_event = false; + if (snapshot_.has_value() && !raised_initial_event_ && + ShouldRaiseInitialEvent(snapshot_.value(), online_state)) { + RaiseInitialEvent(snapshot_.value()); + raised_event = true; + } + return raised_event; +} + +bool QueryListener::ShouldRaiseInitialEvent(const ViewSnapshot& snapshot, + OnlineState online_state) const { + HARD_ASSERT(!raised_initial_event_, + "Determining whether to raise initial event, but already had " + "first event."); + + // Always raise the first event when we're synced + if (!snapshot.from_cache()) { + return true; + } + + // NOTE: We consider OnlineState::Unknown as online (it should become Offline + // or Online if we wait long enough). + bool maybe_online = online_state != OnlineState::Offline; + + // Don't raise the event if we're online, aren't synced yet (checked + // above) and are waiting for a sync. + if (options_.wait_for_sync_when_online() && maybe_online) { + HARD_ASSERT(snapshot.from_cache(), + "Waiting for sync, but snapshot is not from cache."); + return false; + } + + // Raise data from cache if we have any documents or we are offline + return !snapshot.documents().empty() || online_state == OnlineState::Offline; +} + +bool QueryListener::ShouldRaiseEvent(const ViewSnapshot& snapshot) const { + // We don't need to handle include_document_metadata_changes() here because + // the Metadata only changes have already been stripped out if needed. At this + // point the only changes we will see are the ones we should propagate. + if (!snapshot.document_changes().empty()) { + return true; + } + + bool has_pending_writes_changed = + snapshot_.has_value() && + snapshot_.value().has_pending_writes() != snapshot.has_pending_writes(); + if (snapshot.sync_state_changed() || has_pending_writes_changed) { + return options_.include_query_metadata_changes(); + } + + // Generally we should have hit one of the cases above, but it's possible to + // get here if there were only metadata document changes and they got stripped + // out. + return false; +} + +void QueryListener::RaiseInitialEvent(const ViewSnapshot& snapshot) { + HARD_ASSERT(!raised_initial_event_, + "Trying to raise initial events for second time"); + + ViewSnapshot modified_snapshot = ViewSnapshot::FromInitialDocuments( + snapshot.query(), snapshot.documents(), snapshot.mutated_keys(), + snapshot.from_cache(), snapshot.excludes_metadata_changes()); + raised_initial_event_ = true; + listener_->OnEvent(std::move(modified_snapshot)); +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query_listener.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query_listener.h index 60cf13c..4fd3a63 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query_listener.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query_listener.h @@ -17,26 +17,16 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_QUERY_LISTENER_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_QUERY_LISTENER_H_ -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import - #include #include #include "Firestore/core/src/firebase/firestore/core/listen_options.h" +#include "Firestore/core/src/firebase/firestore/core/query.h" #include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" #include "Firestore/core/src/firebase/firestore/model/types.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" -#include "Firestore/core/src/firebase/firestore/util/statusor_callback.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "absl/types/optional.h" -@class FSTQuery; - -NS_ASSUME_NONNULL_BEGIN - namespace firebase { namespace firestore { namespace core { @@ -48,43 +38,43 @@ namespace core { class QueryListener { public: static std::shared_ptr Create( - FSTQuery* query, + Query query, ListenOptions options, ViewSnapshot::SharedListener&& listener) { - return std::make_shared(query, std::move(options), + return std::make_shared(std::move(query), std::move(options), std::move(listener)); } static std::shared_ptr Create( - FSTQuery* query, ViewSnapshot::SharedListener&& listener) { - return Create(query, ListenOptions::DefaultOptions(), std::move(listener)); + Query query, ViewSnapshot::SharedListener&& listener) { + return Create(std::move(query), ListenOptions::DefaultOptions(), + std::move(listener)); } static std::shared_ptr Create( - FSTQuery* query, + Query query, ListenOptions options, util::StatusOrCallback&& listener) { auto event_listener = EventListener::Create(std::move(listener)); - return Create(query, std::move(options), std::move(event_listener)); + return Create(std::move(query), std::move(options), + std::move(event_listener)); } static std::shared_ptr Create( - FSTQuery* query, util::StatusOrCallback&& listener) { - return Create(query, ListenOptions::DefaultOptions(), std::move(listener)); + Query query, util::StatusOrCallback&& listener) { + return Create(std::move(query), ListenOptions::DefaultOptions(), + std::move(listener)); } - QueryListener(FSTQuery* query, + QueryListener(Query query, ListenOptions options, - ViewSnapshot::SharedListener&& listener) - : query_(query), - options_(std::move(options)), - listener_(std::move(listener)) { - } + ViewSnapshot::SharedListener&& listener); + virtual ~QueryListener() { } - FSTQuery* query() const { + const Query& query() const { return query_; } @@ -93,9 +83,18 @@ class QueryListener { return snapshot_; } - virtual void OnViewSnapshot(ViewSnapshot snapshot); + /** + * Applies the new ViewSnapshot to this listener, raising a user-facing event + * if applicable (depending on what changed, whether the user has opted into + * metadata-only changes, etc.). Returns true if a user-facing event was + * indeed raised. + */ + virtual bool OnViewSnapshot(ViewSnapshot snapshot); + virtual void OnError(util::Status error); - virtual void OnOnlineStateChanged(model::OnlineState online_state); + + /** Returns whether a snapshot was raised. */ + virtual bool OnOnlineStateChanged(model::OnlineState online_state); private: bool ShouldRaiseInitialEvent(const ViewSnapshot& snapshot, @@ -103,7 +102,7 @@ class QueryListener { bool ShouldRaiseEvent(const ViewSnapshot& snapshot) const; void RaiseInitialEvent(const ViewSnapshot& snapshot); - FSTQuery* query_ = nil; + Query query_; ListenOptions options_; /** @@ -129,6 +128,4 @@ class QueryListener { } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_QUERY_LISTENER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query_listener.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query_listener.mm deleted file mode 100644 index df901f8..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/query_listener.mm +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#import "Firestore/core/src/firebase/firestore/core/query_listener.h" - -#include -#include - -#include "Firestore/core/src/firebase/firestore/model/document_set.h" -#include "Firestore/core/src/firebase/firestore/util/error_apple.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" -#include "absl/types/optional.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace firebase { -namespace firestore { -namespace core { - -using model::OnlineState; -using model::TargetId; -using util::MakeStatus; -using util::Status; - -void QueryListener::OnViewSnapshot(ViewSnapshot snapshot) { - HARD_ASSERT( - !snapshot.document_changes().empty() || snapshot.sync_state_changed(), - "We got a new snapshot with no changes?"); - - if (!options_.include_document_metadata_changes()) { - // Remove the metadata-only changes. - std::vector changes; - for (const DocumentViewChange& change : snapshot.document_changes()) { - if (change.type() != DocumentViewChange::Type::kMetadata) { - changes.push_back(change); - } - } - - snapshot = ViewSnapshot{snapshot.query(), - snapshot.documents(), - snapshot.old_documents(), - std::move(changes), - snapshot.mutated_keys(), - snapshot.from_cache(), - snapshot.sync_state_changed(), - /*excludes_metadata_changes=*/true}; - } - - if (!raised_initial_event_) { - if (ShouldRaiseInitialEvent(snapshot, online_state_)) { - RaiseInitialEvent(snapshot); - } - } else if (ShouldRaiseEvent(snapshot)) { - listener_->OnEvent(snapshot); - } - - snapshot_ = std::move(snapshot); -} - -void QueryListener::OnError(Status error) { - listener_->OnEvent(std::move(error)); -} - -void QueryListener::OnOnlineStateChanged(OnlineState online_state) { - online_state_ = online_state; - if (snapshot_.has_value() && !raised_initial_event_ && - ShouldRaiseInitialEvent(snapshot_.value(), online_state)) { - RaiseInitialEvent(snapshot_.value()); - } -} - -bool QueryListener::ShouldRaiseInitialEvent(const ViewSnapshot& snapshot, - OnlineState online_state) const { - HARD_ASSERT(!raised_initial_event_, "Determining whether to raise initial " - "event, but already had first event."); - - // Always raise the first event when we're synced - if (!snapshot.from_cache()) { - return true; - } - - // NOTE: We consider OnlineState::Unknown as online (it should become Offline - // or Online if we wait long enough). - bool maybe_online = online_state != OnlineState::Offline; - - // Don't raise the event if we're online, aren't synced yet (checked - // above) and are waiting for a sync. - if (options_.wait_for_sync_when_online() && maybe_online) { - HARD_ASSERT(snapshot.from_cache(), - "Waiting for sync, but snapshot is not from cache."); - return false; - } - - // Raise data from cache if we have any documents or we are offline - return !snapshot.documents().empty() || online_state == OnlineState::Offline; -} - -bool QueryListener::ShouldRaiseEvent(const ViewSnapshot& snapshot) const { - // We don't need to handle include_document_metadata_changes() here because - // the Metadata only changes have already been stripped out if needed. At this - // point the only changes we will see are the ones we should propagate. - if (!snapshot.document_changes().empty()) { - return true; - } - - bool has_pending_writes_changed = - snapshot_.has_value() && - snapshot_.value().has_pending_writes() != snapshot.has_pending_writes(); - if (snapshot.sync_state_changed() || has_pending_writes_changed) { - return options_.include_query_metadata_changes(); - } - - // Generally we should have hit one of the cases above, but it's possible to - // get here if there were only metadata docChanges and they got stripped out. - return false; -} - -void QueryListener::RaiseInitialEvent(const ViewSnapshot& snapshot) { - HARD_ASSERT(!raised_initial_event_, - "Trying to raise initial events for second time"); - - ViewSnapshot modified_snapshot = ViewSnapshot::FromInitialDocuments( - snapshot.query(), snapshot.documents(), snapshot.mutated_keys(), - snapshot.from_cache(), snapshot.excludes_metadata_changes()); - raised_initial_event_ = true; - listener_->OnEvent(std::move(modified_snapshot)); -} - -} // namespace core -} // namespace firestore -} // namespace firebase - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/relation_filter.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/relation_filter.cc deleted file mode 100644 index 07087e6..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/relation_filter.cc +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/core/relation_filter.h" - -#include - -#include "absl/types/optional.h" - -namespace firebase { -namespace firestore { -namespace core { - -using model::FieldPath; -using model::FieldValue; - -RelationFilter::RelationFilter(FieldPath field, - Operator op, - FieldValue value_rhs) - : field_(std::move(field)), op_(op), value_rhs_(std::move(value_rhs)) { -} - -const FieldPath& RelationFilter::field() const { - return field_; -} - -bool RelationFilter::Matches(const model::Document& doc) const { - if (field_.IsKeyFieldPath()) { - // TODO(rsgowman): Port this case - abort(); - } else { - absl::optional doc_field_value = doc.field(field_); - return doc_field_value && MatchesValue(doc_field_value.value()); - } -} - -bool RelationFilter::MatchesValue(const FieldValue& other) const { - // Only compare types with matching backend order (such as double and int). - return FieldValue::Comparable(other.type(), value_rhs_.type()) && - MatchesComparison(other); -} - -bool RelationFilter::MatchesComparison(const FieldValue& other) const { - switch (op_) { - case Operator::LessThan: - return other < value_rhs_; - case Operator::LessThanOrEqual: - return other <= value_rhs_; - case Operator::Equal: - return other == value_rhs_; - case Operator::GreaterThan: - return other > value_rhs_; - case Operator::GreaterThanOrEqual: - return other >= value_rhs_; - } - UNREACHABLE(); -} - -std::string RelationFilter::CanonicalId() const { - // TODO(rsgowman): Port this - abort(); -} - -} // namespace core -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/relation_filter.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/relation_filter.h deleted file mode 100644 index 8110ac1..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/relation_filter.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_RELATION_FILTER_H_ -#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_RELATION_FILTER_H_ - -#include - -#include "Firestore/core/src/firebase/firestore/core/filter.h" -#include "Firestore/core/src/firebase/firestore/model/document.h" -#include "Firestore/core/src/firebase/firestore/model/field_path.h" -#include "Firestore/core/src/firebase/firestore/model/field_value.h" - -namespace firebase { -namespace firestore { -namespace core { - -/** Represents a filter to be applied to the query. */ -class RelationFilter : public Filter { - public: - /** - * Creates a new filter that compares fields and values. Only intended to be - * called from Filter::Create(). - */ - RelationFilter(model::FieldPath field, - Operator op, - model::FieldValue value_rhs); - - const model::FieldPath& field() const override; - - bool Matches(const model::Document& doc) const override; - - std::string CanonicalId() const override; - - private: - bool MatchesValue(const model::FieldValue& other) const; - bool MatchesComparison(const model::FieldValue& other) const; - - const model::FieldPath field_; - const Operator op_; - const model::FieldValue value_rhs_; -}; - -} // namespace core -} // namespace firestore -} // namespace firebase - -#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_RELATION_FILTER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/sync_engine.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/sync_engine.cc new file mode 100644 index 0000000..fa98946 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/sync_engine.cc @@ -0,0 +1,555 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/sync_engine.h" + +#include "Firestore/core/include/firebase/firestore/firestore_errors.h" +#include "Firestore/core/src/firebase/firestore/core/transaction.h" +#include "Firestore/core/src/firebase/firestore/core/transaction_runner.h" +#include "Firestore/core/src/firebase/firestore/local/query_result.h" +#include "Firestore/core/src/firebase/firestore/local/target_data.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/document_map.h" +#include "Firestore/core/src/firebase/firestore/model/document_set.h" +#include "Firestore/core/src/firebase/firestore/model/no_document.h" +#include "Firestore/core/src/firebase/firestore/util/async_queue.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" + +namespace firebase { +namespace firestore { +namespace core { + +namespace { + +using auth::User; +using firestore::Error; +using local::LocalStore; +using local::LocalViewChanges; +using local::LocalWriteResult; +using local::QueryPurpose; +using local::QueryResult; +using local::TargetData; +using model::BatchId; +using model::DocumentKey; +using model::DocumentKeySet; +using model::DocumentMap; +using model::kBatchIdUnknown; +using model::ListenSequenceNumber; +using model::MaybeDocumentMap; +using model::NoDocument; +using model::SnapshotVersion; +using model::TargetId; +using remote::RemoteEvent; +using remote::TargetChange; +using util::AsyncQueue; +using util::Status; +using util::StatusCallback; + +// Limbo documents don't use persistence, and are eagerly GC'd. So, listens for +// them don't need real sequence numbers. +const ListenSequenceNumber kIrrelevantSequenceNumber = -1; + +bool ErrorIsInteresting(const Status& error) { + bool missing_index = + (error.code() == Error::FailedPrecondition && + error.error_message().find("requires an index") != std::string::npos); + bool no_permission = (error.code() == Error::PermissionDenied); + return missing_index || no_permission; +} + +} // namespace + +SyncEngine::SyncEngine(LocalStore* local_store, + remote::RemoteStore* remote_store, + const auth::User& initial_user) + : local_store_(local_store), + remote_store_(remote_store), + current_user_(initial_user), + target_id_generator_(TargetIdGenerator::SyncEngineTargetIdGenerator()) { +} + +void SyncEngine::AssertCallbackExists(absl::string_view source) { + HARD_ASSERT(sync_engine_callback_, + "Tried to call '%s' before callback was registered.", source); +} + +TargetId SyncEngine::Listen(Query query) { + AssertCallbackExists("Listen"); + + HARD_ASSERT(query_views_by_query_.find(query) == query_views_by_query_.end(), + "We already listen to query: %s", query.ToString()); + + TargetData target_data = local_store_->AllocateTarget(query.ToTarget()); + ViewSnapshot view_snapshot = + InitializeViewAndComputeSnapshot(query, target_data.target_id()); + std::vector snapshots; + // Not using the `std::initializer_list` constructor to avoid extra copies. + snapshots.push_back(std::move(view_snapshot)); + sync_engine_callback_->OnViewSnapshots(std::move(snapshots)); + + // TODO(wuandy): move `target_data` into `Listen`. + remote_store_->Listen(target_data); + return target_data.target_id(); +} + +ViewSnapshot SyncEngine::InitializeViewAndComputeSnapshot(const Query& query, + TargetId target_id) { + QueryResult query_result = + local_store_->ExecuteQuery(query, /* use_previous_results= */ true); + + // If there are already queries mapped to the target id, create a synthesized + // target change to apply the sync state from those queries to the new query. + auto current_sync_state = SyncState::None; + absl::optional synthesized_current_change; + if (queries_by_target_.find(target_id) != queries_by_target_.end()) { + const Query& mirror_query = queries_by_target_[target_id][0]; + current_sync_state = + query_views_by_query_[mirror_query]->view().sync_state(); + synthesized_current_change = TargetChange::CreateSynthesizedTargetChange( + current_sync_state == SyncState::Synced); + } + + View view(query, query_result.remote_keys()); + ViewDocumentChanges view_doc_changes = + view.ComputeDocumentChanges(query_result.documents().underlying_map()); + ViewChange view_change = + view.ApplyChanges(view_doc_changes, synthesized_current_change); + HARD_ASSERT(view_change.limbo_changes().empty(), + "View returned limbo docs before target ack from the server."); + + auto query_view = + std::make_shared(query, target_id, std::move(view)); + query_views_by_query_[query] = query_view; + + queries_by_target_[target_id].push_back(query); + + HARD_ASSERT( + view_change.snapshot().has_value(), + "ApplyChanges to documents for new view should always return a snapshot"); + return view_change.snapshot().value(); +} + +void SyncEngine::StopListening(const Query& query) { + AssertCallbackExists("StopListening"); + + auto query_view = query_views_by_query_[query]; + HARD_ASSERT(query_view, "Trying to stop listening to a query not found"); + + query_views_by_query_.erase(query); + + TargetId target_id = query_view->target_id(); + auto& queries = queries_by_target_[target_id]; + queries.erase(std::remove(queries.begin(), queries.end(), query)); + + if (queries.empty()) { + local_store_->ReleaseTarget(target_id); + remote_store_->StopListening(target_id); + RemoveAndCleanupTarget(target_id, Status::OK()); + } +} + +void SyncEngine::RemoveAndCleanupTarget(TargetId target_id, Status status) { + for (const Query& query : queries_by_target_.at(target_id)) { + query_views_by_query_.erase(query); + if (!status.ok()) { + sync_engine_callback_->OnError(query, status); + if (ErrorIsInteresting(status)) { + LOG_WARN("Listen for query at %s failed: %s", + query.path().CanonicalString(), status.error_message()); + } + } + } + queries_by_target_.erase(target_id); + + DocumentKeySet limbo_keys = limbo_document_refs_.ReferencedKeys(target_id); + limbo_document_refs_.RemoveReferences(target_id); + for (const DocumentKey& key : limbo_keys) { + if (!limbo_document_refs_.ContainsKey(key)) { + // We removed the last reference for this key. + RemoveLimboTarget(key); + } + } +} + +void SyncEngine::WriteMutations(std::vector&& mutations, + StatusCallback callback) { + AssertCallbackExists("WriteMutations"); + + LocalWriteResult result = local_store_->WriteLocally(std::move(mutations)); + mutation_callbacks_[current_user_].insert( + std::make_pair(result.batch_id(), std::move(callback))); + + EmitNewSnapshotsAndNotifyLocalStore(result.changes(), absl::nullopt); + remote_store_->FillWritePipeline(); +} + +void SyncEngine::RegisterPendingWritesCallback(StatusCallback callback) { + if (!remote_store_->CanUseNetwork()) { + LOG_DEBUG( + "The network is disabled. The task returned by " + "'waitForPendingWrites()' will not " + "complete until the network is enabled."); + } + + int largest_pending_batch_id = + local_store_->GetHighestUnacknowledgedBatchId(); + + if (largest_pending_batch_id == kBatchIdUnknown) { + // Trigger the callback right away if there is no pending writes at the + // moment. + callback(Status::OK()); + return; + } + + pending_writes_callbacks_[largest_pending_batch_id].push_back( + std::move(callback)); +} + +void SyncEngine::Transaction(int retries, + const std::shared_ptr& worker_queue, + TransactionUpdateCallback update_callback, + TransactionResultCallback result_callback) { + worker_queue->VerifyIsCurrentQueue(); + HARD_ASSERT(retries >= 0, "Got negative number of retries for transaction"); + + // Allocate a shared_ptr so that the TransactionRunner can outlive this frame. + auto runner = std::make_shared(worker_queue, remote_store_, + std::move(update_callback), + std::move(result_callback)); + runner->Run(); +} + +void SyncEngine::HandleCredentialChange(const auth::User& user) { + bool user_changed = (current_user_ != user); + current_user_ = user; + + if (user_changed) { + // Fails callbacks waiting for pending writes requested by previous user. + FailOutstandingPendingWriteCallbacks( + "'waitForPendingWrites' callback is cancelled due to a user change."); + // Notify local store and emit any resulting events from swapping out the + // mutation queue. + MaybeDocumentMap changes = local_store_->HandleUserChange(user); + EmitNewSnapshotsAndNotifyLocalStore(changes, absl::nullopt); + } + + // Notify remote store so it can restart its streams. + remote_store_->HandleCredentialChange(); +} + +void SyncEngine::ApplyRemoteEvent(const RemoteEvent& remote_event) { + AssertCallbackExists("HandleRemoteEvent"); + + // Update received document as appropriate for any limbo targets. + for (const auto& entry : remote_event.target_changes()) { + TargetId target_id = entry.first; + const TargetChange& change = entry.second; + auto it = limbo_resolutions_by_target_.find(target_id); + if (it == limbo_resolutions_by_target_.end()) { + continue; + } + + LimboResolution& limbo_resolution = it->second; + // Since this is a limbo resolution lookup, it's for a single document and + // it could be added, modified, or removed, but not a combination. + auto changed_documents_count = change.added_documents().size() + + change.modified_documents().size() + + change.removed_documents().size(); + HARD_ASSERT( + changed_documents_count <= 1, + "Limbo resolution for single document contains multiple changes."); + + if (!change.added_documents().empty()) { + limbo_resolution.document_received = true; + } else if (!change.modified_documents().empty()) { + HARD_ASSERT(limbo_resolution.document_received, + "Received change for limbo target document without add."); + } else if (!change.removed_documents().empty()) { + HARD_ASSERT(limbo_resolution.document_received, + "Received remove for limbo target document without add."); + limbo_resolution.document_received = false; + } else { + // This was probably just a CURRENT target change or similar. + } + } + + MaybeDocumentMap changes = local_store_->ApplyRemoteEvent(remote_event); + EmitNewSnapshotsAndNotifyLocalStore(changes, remote_event); +} + +void SyncEngine::HandleRejectedListen(TargetId target_id, Status error) { + AssertCallbackExists("HandleRejectedListen"); + + auto it = limbo_resolutions_by_target_.find(target_id); + if (it != limbo_resolutions_by_target_.end()) { + DocumentKey limbo_key = it->second.key; + // Since this query failed, we won't want to manually unlisten to it. + // So go ahead and remove it from bookkeeping. + limbo_targets_by_key_.erase(limbo_key); + limbo_resolutions_by_target_.erase(target_id); + + // TODO(dimond): Retry on transient errors? + + // It's a limbo doc. Create a synthetic event saying it was deleted. This is + // kind of a hack. Ideally, we would have a method in the local store to + // purge a document. However, it would be tricky to keep all of the local + // store's invariants with another method. + NoDocument doc(limbo_key, SnapshotVersion::None(), + /* has_committed_mutations= */ false); + + // Explicitly instantiate these to work around a bug in the default + // constructor of the std::unordered_map that comes with GCC 4.8. Without + // this GCC emits a spurious "chosen constructor is explicit in + // copy-initialization" error. + DocumentKeySet limbo_documents{limbo_key}; + RemoteEvent::TargetChangeMap target_changes; + RemoteEvent::TargetSet target_mismatches; + RemoteEvent::DocumentUpdateMap document_updates{{limbo_key, doc}}; + + RemoteEvent event{SnapshotVersion::None(), std::move(target_changes), + std::move(target_mismatches), std::move(document_updates), + std::move(limbo_documents)}; + ApplyRemoteEvent(event); + } else { + local_store_->ReleaseTarget(target_id); + RemoveAndCleanupTarget(target_id, error); + } +} + +void SyncEngine::HandleSuccessfulWrite( + const model::MutationBatchResult& batch_result) { + AssertCallbackExists("HandleSuccessfulWrite"); + + // The local store may or may not be able to apply the write result and + // raise events immediately (depending on whether the watcher is caught up), + // so we raise user callbacks first so that they consistently happen before + // listen events. + NotifyUser(batch_result.batch().batch_id(), Status::OK()); + + TriggerPendingWriteCallbacks(batch_result.batch().batch_id()); + + MaybeDocumentMap changes = local_store_->AcknowledgeBatch(batch_result); + EmitNewSnapshotsAndNotifyLocalStore(changes, absl::nullopt); +} + +void SyncEngine::HandleRejectedWrite( + firebase::firestore::model::BatchId batch_id, Status error) { + AssertCallbackExists("HandleRejectedWrite"); + + MaybeDocumentMap changes = local_store_->RejectBatch(batch_id); + + if (!changes.empty() && ErrorIsInteresting(error)) { + const DocumentKey& min_key = changes.min()->first; + LOG_WARN("Write at %s failed: %s", min_key.ToString(), + error.error_message()); + } + + // The local store may or may not be able to apply the write result and + // raise events immediately (depending on whether the watcher is caught up), + // so we raise user callbacks first so that they consistently happen before + // listen events. + NotifyUser(batch_id, std::move(error)); + + TriggerPendingWriteCallbacks(batch_id); + + EmitNewSnapshotsAndNotifyLocalStore(changes, absl::nullopt); +} + +void SyncEngine::HandleOnlineStateChange(model::OnlineState online_state) { + AssertCallbackExists("HandleOnlineStateChange"); + + std::vector new_view_snapshot; + for (const auto& entry : query_views_by_query_) { + const auto& query_view = entry.second; + ViewChange view_change = + query_view->view().ApplyOnlineStateChange(online_state); + HARD_ASSERT(view_change.limbo_changes().empty(), + "OnlineState should not affect limbo documents."); + if (view_change.snapshot().has_value()) { + new_view_snapshot.push_back(*std::move(view_change).snapshot()); + } + } + + sync_engine_callback_->OnViewSnapshots(std::move(new_view_snapshot)); + sync_engine_callback_->HandleOnlineStateChange(online_state); +} + +DocumentKeySet SyncEngine::GetRemoteKeys(TargetId target_id) const { + auto it = limbo_resolutions_by_target_.find(target_id); + if (it != limbo_resolutions_by_target_.end() && + it->second.document_received) { + return DocumentKeySet{it->second.key}; + } else { + DocumentKeySet keys; + if (queries_by_target_.count(target_id) == 0) { + return keys; + } + + for (const auto& query : queries_by_target_.at(target_id)) { + for (const auto& key : + query_views_by_query_.at(query)->view().synced_documents()) { + keys = keys.insert(key); + } + } + return keys; + } +} + +void SyncEngine::NotifyUser(BatchId batch_id, Status status) { + auto it = mutation_callbacks_.find(current_user_); + + // NOTE: Mutations restored from persistence won't have callbacks, so + // it's okay for this (or the callback below) to not exist. + if (it == mutation_callbacks_.end()) { + return; + } + + std::unordered_map& callbacks = it->second; + auto callback_it = callbacks.find(batch_id); + if (callback_it != callbacks.end()) { + callback_it->second(std::move(status)); + callbacks.erase(callback_it); + } +} + +void SyncEngine::TriggerPendingWriteCallbacks(BatchId batch_id) { + auto it = pending_writes_callbacks_.find(batch_id); + if (it != pending_writes_callbacks_.end()) { + for (const auto& callback : it->second) { + callback(Status::OK()); + } + + pending_writes_callbacks_.erase(it); + } +} + +void SyncEngine::FailOutstandingPendingWriteCallbacks( + const std::string& message) { + for (const auto& entry : pending_writes_callbacks_) { + for (const auto& callback : entry.second) { + callback(Status(Error::Cancelled, message)); + } + } + + pending_writes_callbacks_.clear(); +} + +void SyncEngine::EmitNewSnapshotsAndNotifyLocalStore( + const MaybeDocumentMap& changes, + const absl::optional& maybe_remote_event) { + std::vector new_snapshots; + std::vector document_changes_in_all_views; + + for (const auto& entry : query_views_by_query_) { + const auto& query_view = entry.second; + View& view = query_view->view(); + ViewDocumentChanges view_doc_changes = view.ComputeDocumentChanges(changes); + if (view_doc_changes.needs_refill()) { + // The query has a limit and some docs were removed/updated, so we need to + // re-run the query against the local store to make sure we didn't lose + // any good docs that had been past the limit. + QueryResult query_result = local_store_->ExecuteQuery( + query_view->query(), /* use_previous_results= */ false); + view_doc_changes = view.ComputeDocumentChanges( + query_result.documents().underlying_map(), view_doc_changes); + } + + absl::optional target_changes; + if (maybe_remote_event.has_value()) { + const RemoteEvent& remote_event = maybe_remote_event.value(); + auto it = remote_event.target_changes().find(query_view->target_id()); + if (it != remote_event.target_changes().end()) { + target_changes = it->second; + } + } + ViewChange view_change = + view.ApplyChanges(view_doc_changes, target_changes); + + UpdateTrackedLimboDocuments(view_change.limbo_changes(), + query_view->target_id()); + + if (view_change.snapshot().has_value()) { + new_snapshots.push_back(*view_change.snapshot()); + LocalViewChanges doc_changes = LocalViewChanges::FromViewSnapshot( + *view_change.snapshot(), query_view->target_id()); + document_changes_in_all_views.push_back(std::move(doc_changes)); + } + } + + sync_engine_callback_->OnViewSnapshots(std::move(new_snapshots)); + local_store_->NotifyLocalViewChanges(document_changes_in_all_views); +} + +void SyncEngine::UpdateTrackedLimboDocuments( + const std::vector& limbo_changes, TargetId target_id) { + for (const LimboDocumentChange& limbo_change : limbo_changes) { + switch (limbo_change.type()) { + case LimboDocumentChange::Type::Added: + limbo_document_refs_.AddReference(limbo_change.key(), target_id); + TrackLimboChange(limbo_change); + break; + + case LimboDocumentChange::Type::Removed: + LOG_DEBUG("Document no longer in limbo: %s", + limbo_change.key().ToString()); + limbo_document_refs_.RemoveReference(limbo_change.key(), target_id); + if (!limbo_document_refs_.ContainsKey(limbo_change.key())) { + // We removed the last reference for this key + RemoveLimboTarget(limbo_change.key()); + } + break; + + default: + HARD_FAIL("Unknown limbo change type: %s", limbo_change.type()); + } + } +} + +void SyncEngine::TrackLimboChange(const LimboDocumentChange& limbo_change) { + const DocumentKey& key = limbo_change.key(); + + if (limbo_targets_by_key_.find(key) == limbo_targets_by_key_.end()) { + LOG_DEBUG("New document in limbo: %s", key.ToString()); + + TargetId limbo_target_id = target_id_generator_.NextId(); + Query query(key.path()); + TargetData target_data(query.ToTarget(), limbo_target_id, + kIrrelevantSequenceNumber, + QueryPurpose::LimboResolution); + limbo_resolutions_by_target_.emplace(limbo_target_id, LimboResolution{key}); + remote_store_->Listen(target_data); + limbo_targets_by_key_[key] = limbo_target_id; + } +} + +void SyncEngine::RemoveLimboTarget(const DocumentKey& key) { + auto it = limbo_targets_by_key_.find(key); + if (it == limbo_targets_by_key_.end()) { + // This target already got removed, because the query failed. + return; + } + + TargetId limbo_target_id = it->second; + remote_store_->StopListening(limbo_target_id); + limbo_targets_by_key_.erase(key); + limbo_resolutions_by_target_.erase(limbo_target_id); +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/sync_engine.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/sync_engine.h new file mode 100644 index 0000000..12e0f3a --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/sync_engine.h @@ -0,0 +1,309 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_SYNC_ENGINE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_SYNC_ENGINE_H_ + +#include +#include +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/core/query.h" +#include "Firestore/core/src/firebase/firestore/core/target_id_generator.h" +#include "Firestore/core/src/firebase/firestore/core/view.h" +#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" +#include "Firestore/core/src/firebase/firestore/local/local_store.h" +#include "Firestore/core/src/firebase/firestore/local/reference_set.h" +#include "Firestore/core/src/firebase/firestore/local/target_data.h" +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_store.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "absl/strings/string_view.h" + +namespace firebase { +namespace firestore { +namespace core { + +/** + * Interface implemented by `EventManager` to handle notifications from + * `SyncEngine`. + */ +class SyncEngineCallback { + public: + virtual ~SyncEngineCallback() = default; + + /** Handles a change in online state. */ + virtual void HandleOnlineStateChange(model::OnlineState online_state) = 0; + /** Handles new view snapshots. */ + virtual void OnViewSnapshots(std::vector&& snapshots) = 0; + /** Handles the failure of a query. */ + virtual void OnError(const core::Query& query, const util::Status& error) = 0; +}; + +/** + * Interface implemented by `SyncEngine` to receive requests from + * `EventManager`. + // PORTING NOTE: This is extracted as an interface to allow gmock to mock + // sync engine. + */ +class QueryEventSource { + public: + virtual ~QueryEventSource() = default; + + virtual void SetCallback(SyncEngineCallback* callback) = 0; + + /** + * Initiates a new listen. The LocalStore will be queried for initial data + * and the listen will be sent to the `RemoteStore` to get remote data. The + * registered SyncEngineCallback will be notified of resulting view + * snapshots and/or listen errors. + * + * @return the target ID assigned to the query. + */ + virtual model::TargetId Listen(Query query) = 0; + + /** Stops listening to a query previously listened to via `Listen`. */ + virtual void StopListening(const Query& query) = 0; +}; + +/** + * SyncEngine is the central controller in the client SDK architecture. It is + * the glue code between the EventManager, LocalStore, and RemoteStore. Some of + * SyncEngine's responsibilities include: + * 1. Coordinating client requests and remote events between the EventManager + * and the local and remote data stores. + * 2. Managing a View object for each query, providing the unified view between + * the local and remote data stores. + * 3. Notifying the RemoteStore when the LocalStore has new mutations in its + * queue that need sending to the backend. + * + * The SyncEngine’s methods should only ever be called by methods running on our + * own worker queue. + */ +class SyncEngine : public remote::RemoteStoreCallback, public QueryEventSource { + public: + SyncEngine(local::LocalStore* local_store, + remote::RemoteStore* remote_store, + const auth::User& initial_user); + + // Implements `QueryEventSource`. + void SetCallback(SyncEngineCallback* callback) override { + sync_engine_callback_ = callback; + } + model::TargetId Listen(Query query) override; + void StopListening(const Query& query) override; + + /** + * Initiates the write of local mutation batch which involves adding the + * writes to the mutation queue, notifying the remote store about new + * mutations, and raising events for any changes this write caused. The + * provided callback will be called once the write has been acked or + * rejected by the backend (or failed locally for any other reason). + */ + void WriteMutations(std::vector&& mutations, + util::StatusCallback callback); + + /** + * Registers a user callback that is called when all pending mutations at the + * moment of calling are acknowledged . + */ + void RegisterPendingWritesCallback(util::StatusCallback callback); + + /** + * Runs the given transaction block up to retries times and then calls + * completion. + * + * @param retries The number of times to try before giving up. + * @param worker_queue The queue to dispatch sync engine calls to. + * @param update_callback The callback to call to execute the user's + * transaction. + * @param result_callback The callback to call when the transaction is + * finished or failed. + */ + void Transaction(int retries, + const std::shared_ptr& worker_queue, + core::TransactionUpdateCallback update_callback, + core::TransactionResultCallback result_callback); + + void HandleCredentialChange(const auth::User& user); + + // Implements `RemoteStoreCallback` + void ApplyRemoteEvent(const remote::RemoteEvent& remote_event) override; + void HandleRejectedListen(model::TargetId target_id, + util::Status error) override; + void HandleSuccessfulWrite( + const model::MutationBatchResult& batch_result) override; + void HandleRejectedWrite(model::BatchId batch_id, + util::Status error) override; + void HandleOnlineStateChange(model::OnlineState online_state) override; + model::DocumentKeySet GetRemoteKeys(model::TargetId target_id) const override; + + // For tests only + std::map GetCurrentLimboDocuments() + const { + // Return defensive copy + return limbo_targets_by_key_; + } + + private: + /** + * QueryView contains all of the info that SyncEngine needs to track for a + * particular query and view. + */ + class QueryView { + public: + QueryView(Query query, model::TargetId target_id, View view) + : query_(std::move(query)), + target_id_(target_id), + view_(std::move(view)) { + } + + const Query& query() const { + return query_; + } + + /** + * The target ID created by the client that is used in the watch stream to + * identify this query. + */ + model::TargetId target_id() const { + return target_id_; + } + + /** + * The view is responsible for computing the final merged truth of what docs + * are in the query. It gets notified of local and remote changes, and + * applies the query filters and limits to determine the most correct + * possible results. + */ + View& view() { + return view_; + } + + private: + Query query_; + model::TargetId target_id_; + View view_; + }; + + /** Tracks a limbo resolution. */ + class LimboResolution { + public: + LimboResolution() = default; + + explicit LimboResolution(const model::DocumentKey& key) : key{key} { + } + + model::DocumentKey key; + + /** + * Set to true once we've received a document. This is used in + * RemoteKeysForTarget and ultimately used by `WatchChangeAggregator` to + * decide whether it needs to manufacture a delete event for the target once + * the target is CURRENT. + */ + bool document_received = false; + }; + + void AssertCallbackExists(absl::string_view source); + + ViewSnapshot InitializeViewAndComputeSnapshot(const Query& query, + model::TargetId target_id); + + void RemoveAndCleanupTarget(model::TargetId target_id, util::Status status); + + void RemoveLimboTarget(const model::DocumentKey& key); + + void EmitNewSnapshotsAndNotifyLocalStore( + const model::MaybeDocumentMap& changes, + const absl::optional& maybe_remote_event); + + /** Updates the limbo document state for the given target_id. */ + void UpdateTrackedLimboDocuments( + const std::vector& limbo_changes, + model::TargetId target_id); + + void TrackLimboChange(const LimboDocumentChange& limbo_change); + + void NotifyUser(model::BatchId batch_id, util::Status status); + + /** + * Triggers callbacks waiting for this batch id to get acknowledged by + * server, if there are any. + */ + void TriggerPendingWriteCallbacks(model::BatchId batch_id); + void FailOutstandingPendingWriteCallbacks(const std::string& message); + + /** The local store, used to persist mutations and cached documents. */ + local::LocalStore* local_store_ = nullptr; + + /** The remote store for sending writes, watches, etc. to the backend. */ + remote::RemoteStore* remote_store_ = nullptr; + + auth::User current_user_; + SyncEngineCallback* sync_engine_callback_ = nullptr; + + /** + * Used for creating the TargetId for the listens used to resolve limbo + * documents. + */ + TargetIdGenerator target_id_generator_; + + /** Stores user completion blocks, indexed by User and BatchId. */ + std::unordered_map, + auth::HashUser> + mutation_callbacks_; + + /** Stores user callbacks waiting for pending writes to be acknowledged. */ + std::unordered_map> + pending_writes_callbacks_; + + // Shared pointers are used to avoid creating and storing two copies of the + // same `QueryView` and for consistency with other platforms. + /** QueryViews for all active queries, indexed by query. */ + std::unordered_map> query_views_by_query_; + + /** Queries mapped to Targets, indexed by target ID. */ + std::unordered_map> queries_by_target_; + + /** + * When a document is in limbo, we create a special listen to resolve it. This + * maps the DocumentKey of each limbo document to the TargetId of the listen + * resolving it. + */ + std::map limbo_targets_by_key_; + + /** + * Basically the inverse of limbo_targets_by_key_, a map of target ID to a + * LimboResolution (which includes the DocumentKey as well as whether we've + * received a document for the target). + */ + std::map limbo_resolutions_by_target_; + + /** Used to track any documents that are currently in limbo. */ + local::ReferenceSet limbo_document_refs_; +}; + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_SYNC_ENGINE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/sync_engine_callback.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/sync_engine_callback.h new file mode 100644 index 0000000..bf7d0eb --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/sync_engine_callback.h @@ -0,0 +1,51 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_SYNC_ENGINE_CALLBACK_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_SYNC_ENGINE_CALLBACK_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/core/query.h" +#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" + +namespace firebase { +namespace firestore { +namespace core { + +/** + * Interface implemented by `EventManager` to handle notifications from + * `SyncEngine`. + */ +class SyncEngineCallback { + public: + virtual ~SyncEngineCallback() = default; + + /** Handles a change in online state. */ + virtual void HandleOnlineStateChange(model::OnlineState online_state) = 0; + /** Handles new view snapshots. */ + virtual void OnViewSnapshots(std::vector&& snapshots) = 0; + /** Handles the failure of a query. */ + virtual void OnError(const core::Query& query, const util::Status& error) = 0; +}; + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_SYNC_ENGINE_CALLBACK_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/target.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/target.cc new file mode 100644 index 0000000..2d7e8fd --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/target.cc @@ -0,0 +1,107 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/target.h" + +#include + +#include "Firestore/core/src/firebase/firestore/core/field_filter.h" +#include "Firestore/core/src/firebase/firestore/core/operator.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/equality.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "absl/strings/str_cat.h" + +namespace firebase { +namespace firestore { +namespace core { + +using model::DocumentKey; +using model::FieldPath; + +// MARK: - Accessors + +bool Target::IsDocumentQuery() const { + return DocumentKey::IsDocumentKey(path_) && !collection_group_ && + filters_.empty(); +} + +const std::string& Target::CanonicalId() const { + if (!canonical_id_.empty()) return canonical_id_; + + std::string result; + absl::StrAppend(&result, path_.CanonicalString()); + + if (collection_group_) { + absl::StrAppend(&result, "|cg:", *collection_group_); + } + + // Add filters. + absl::StrAppend(&result, "|f:"); + for (const auto& filter : filters_) { + absl::StrAppend(&result, filter.CanonicalId()); + } + + // Add order by. + absl::StrAppend(&result, "|ob:"); + for (const OrderBy& order_by : order_bys()) { + absl::StrAppend(&result, order_by.CanonicalId()); + } + + // Add limit. + if (limit_ != kNoLimit) { + absl::StrAppend(&result, "|l:", limit_); + } + + if (start_at_) { + absl::StrAppend(&result, "|lb:", start_at_->CanonicalId()); + } + + if (end_at_) { + absl::StrAppend(&result, "|ub:", end_at_->CanonicalId()); + } + + canonical_id_ = std::move(result); + return canonical_id_; +} + +size_t Target::Hash() const { + return util::Hash(CanonicalId()); +} + +std::string Target::ToString() const { + return absl::StrCat("Target(canonical_id=", CanonicalId(), ")"); +} + +std::ostream& operator<<(std::ostream& os, const Target& target) { + return os << target.ToString(); +} + +bool operator==(const Target& lhs, const Target& rhs) { + return lhs.path() == rhs.path() && + util::Equals(lhs.collection_group(), rhs.collection_group()) && + lhs.filters() == rhs.filters() && lhs.order_bys() == rhs.order_bys() && + lhs.limit() == rhs.limit() && + util::Equals(lhs.start_at(), rhs.start_at()) && + util::Equals(lhs.end_at(), rhs.end_at()); +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/target.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/target.h new file mode 100644 index 0000000..4f7119a --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/target.h @@ -0,0 +1,153 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TARGET_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TARGET_H_ + +#include +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/core/bound.h" +#include "Firestore/core/src/firebase/firestore/core/filter.h" +#include "Firestore/core/src/firebase/firestore/core/order_by.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" + +namespace firebase { +namespace firestore { +namespace core { + +using CollectionGroupId = std::shared_ptr; + +/** + * A Target represents the WatchTarget representation of a Query, which is + * used by the LocalStore and the RemoteStore to keep track of and to execute + * backend queries. While multiple Queries can map to the same Target, each + * Target maps to a single WatchTarget in RemoteStore and a single TargetData + * entry in persistence. + */ +class Target { + public: + static constexpr int32_t kNoLimit = std::numeric_limits::max(); + + Target() = default; + + // MARK: - Accessors + + /** The base path of the target. */ + const model::ResourcePath& path() const { + return path_; + } + + /** The collection group of the target, if any. */ + const std::shared_ptr& collection_group() const { + return collection_group_; + } + + /** Returns true if this Target is for a specific document. */ + bool IsDocumentQuery() const; + + /** The filters on the documents returned by the target. */ + const FilterList& filters() const { + return filters_; + } + + /** Returns the list of ordering constraints by the target. */ + const OrderByList& order_bys() const { + return order_bys_; + } + + int32_t limit() const { + return limit_; + } + + const std::shared_ptr& start_at() const { + return start_at_; + } + + const std::shared_ptr& end_at() const { + return end_at_; + } + + const std::string& CanonicalId() const; + + std::string ToString() const; + + friend std::ostream& operator<<(std::ostream& os, const Target& target); + + size_t Hash() const; + + private: + /** + * Initializes a Target with a path and additional query constraints. + * Path must currently be empty if this is a collection group query. + * + * NOTE: This is made private and onlyy accessible by `Query`. You should + * always construct Target from `Query.toTarget` because Query provides + * an implicit `orderBy` property. + */ + Target(model::ResourcePath path, + CollectionGroupId collection_group, + FilterList filters, + OrderByList order_bys, + int32_t limit, + std::shared_ptr start_at, + std::shared_ptr end_at) + : path_(std::move(path)), + collection_group_(std::move(collection_group)), + filters_(std::move(filters)), + order_bys_(std::move(order_bys)), + limit_(limit), + start_at_(std::move(start_at)), + end_at_(std::move(end_at)) { + } + friend class Query; + + model::ResourcePath path_; + std::shared_ptr collection_group_; + FilterList filters_; + OrderByList order_bys_; + int32_t limit_ = kNoLimit; + std::shared_ptr start_at_; + std::shared_ptr end_at_; + + mutable std::string canonical_id_; +}; + +bool operator==(const Target& lhs, const Target& rhs); + +inline bool operator!=(const Target& lhs, const Target& rhs) { + return !(lhs == rhs); +} + +} // namespace core +} // namespace firestore +} // namespace firebase + +namespace std { + +template <> +struct hash { + size_t operator()(const firebase::firestore::core::Target& target) const { + return target.Hash(); + } +}; + +} // namespace std + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TARGET_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/target_id_generator.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/target_id_generator.h index 54c492a..412dd28 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/target_id_generator.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/target_id_generator.h @@ -24,7 +24,7 @@ namespace firestore { namespace core { /** The set of all valid generators. */ -enum class TargetIdGeneratorId { QueryCache = 0, SyncEngine = 1 }; +enum class TargetIdGeneratorId { TargetCache = 0, SyncEngine = 1 }; /** * Generates monotonically increasing target IDs for sending targets to the @@ -57,9 +57,9 @@ class TargetIdGenerator { * @param after An ID to start at. Every call to NextId returns a larger id. * @return An instance of TargetIdGenerator. */ - static TargetIdGenerator QueryCacheTargetIdGenerator(model::TargetId after) { - TargetIdGenerator generator(TargetIdGeneratorId::QueryCache, after); - // Make sure that the next call to `nextId()` returns the first value after + static TargetIdGenerator TargetCacheTargetIdGenerator(model::TargetId after) { + TargetIdGenerator generator(TargetIdGeneratorId::TargetCache, after); + // Make sure that the next call to `NextId()` returns the first value after // 'after'. generator.NextId(); return generator; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction.cc new file mode 100644 index 0000000..315c7bd --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction.cc @@ -0,0 +1,236 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/transaction.h" + +#include +#include +#include + +#include "Firestore/core/include/firebase/firestore/firestore_errors.h" +#include "Firestore/core/src/firebase/firestore/core/user_data.h" +#include "Firestore/core/src/firebase/firestore/model/delete_mutation.h" +#include "Firestore/core/src/firebase/firestore/model/verify_mutation.h" +#include "Firestore/core/src/firebase/firestore/remote/datastore.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" + +using firebase::firestore::Error; +using firebase::firestore::core::ParsedSetData; +using firebase::firestore::core::ParsedUpdateData; +using firebase::firestore::model::DeleteMutation; +using firebase::firestore::model::DocumentKey; +using firebase::firestore::model::DocumentKeyHash; +using firebase::firestore::model::MaybeDocument; +using firebase::firestore::model::Mutation; +using firebase::firestore::model::Precondition; +using firebase::firestore::model::SnapshotVersion; +using firebase::firestore::model::VerifyMutation; +using firebase::firestore::remote::Datastore; +using firebase::firestore::util::Status; +using firebase::firestore::util::StatusOr; + +namespace firebase { +namespace firestore { +namespace core { + +Transaction::Transaction(Datastore* datastore) + : datastore_{NOT_NULL(datastore)} { +} + +Status Transaction::RecordVersion(const MaybeDocument& doc) { + SnapshotVersion doc_version; + + if (doc.is_document()) { + doc_version = doc.version(); + } else if (doc.is_no_document()) { + // For deleted docs, we must record an explicit no version to build the + // right precondition when writing. + doc_version = SnapshotVersion::None(); + } else { + HARD_FAIL("Unexpected document type in transaction: %s", doc.type()); + } + + absl::optional existing_version = GetVersion(doc.key()); + if (existing_version.has_value()) { + if (doc_version != existing_version.value()) { + // This transaction will fail no matter what. + return Status{Error::Aborted, + "Document version changed between two reads."}; + } + return Status::OK(); + } else { + read_versions_[doc.key()] = doc_version; + return Status::OK(); + } +} + +void Transaction::Lookup(const std::vector& keys, + LookupCallback&& callback) { + EnsureCommitNotCalled(); + + if (!mutations_.empty()) { + Status lookup_error = Status{Error::InvalidArgument, + "Firestore transactions require all reads to " + "be executed before all writes"}; + callback(lookup_error); + return; + } + + datastore_->LookupDocuments( + keys, [this, callback]( + const StatusOr>& maybe_documents) { + if (!maybe_documents.ok()) { + callback(maybe_documents.status()); + return; + } + + const auto& documents = maybe_documents.ValueOrDie(); + for (const MaybeDocument& doc : documents) { + Status record_error = RecordVersion(doc); + if (!record_error.ok()) { + callback(record_error); + return; + } + } + + // TODO(varconst): see if `maybe_documents` can be moved into the + // callback. + callback(maybe_documents); + }); +} + +void Transaction::WriteMutations(std::vector&& mutations) { + EnsureCommitNotCalled(); + // `move` will become appropriate once `Mutation` is replaced by the C++ + // equivalent. + std::move(mutations.begin(), mutations.end(), std::back_inserter(mutations_)); +} + +Precondition Transaction::CreatePrecondition(const DocumentKey& key) { + absl::optional version = GetVersion(key); + if (written_docs_.count(key) == 0 && version.has_value()) { + return Precondition::UpdateTime(version.value()); + } else { + return Precondition::None(); + } +} + +StatusOr Transaction::CreateUpdatePrecondition( + const DocumentKey& key) { + absl::optional version = GetVersion(key); + // The first time a document is written, we want to take into account the + // read time and existence. + if (written_docs_.count(key) == 0 && version.has_value()) { + if (version.value() == SnapshotVersion::None()) { + // The document doesn't exist, so fail the transaction. + // + // This has to be validated locally because you can't send a + // precondition that a document does not exist without changing the + // semantics of the backend write to be an insert. This is the reverse + // of what we want, since we want to assert that the document doesn't + // exist but then send the update and have it fail. Since we can't + // express that to the backend, we have to validate locally. + // + // Note: this can change once we can send separate verify writes in the + // transaction. + return Status{Error::InvalidArgument, + "Can't update a document that doesn't exist."}; + } + // Document exists, just base precondition on document update time. + return Precondition::UpdateTime(version.value()); + } else { + // Document was not read, so we just use the preconditions for a blind + // update. + return Precondition::Exists(true); + } +} + +void Transaction::Set(const DocumentKey& key, ParsedSetData&& data) { + WriteMutations(std::move(data).ToMutations(key, CreatePrecondition(key))); + written_docs_.insert(key); +} + +void Transaction::Update(const DocumentKey& key, ParsedUpdateData&& data) { + StatusOr maybe_precondition = CreateUpdatePrecondition(key); + if (!maybe_precondition.ok()) { + last_write_error_ = maybe_precondition.status(); + } else { + WriteMutations( + std::move(data).ToMutations(key, maybe_precondition.ValueOrDie())); + } + written_docs_.insert(key); +} + +void Transaction::Delete(const DocumentKey& key) { + Mutation mutation = DeleteMutation(key, CreatePrecondition(key)); + WriteMutations({mutation}); + written_docs_.insert(key); +} + +void Transaction::Commit(util::StatusCallback&& callback) { + EnsureCommitNotCalled(); + + // If there was an error writing, raise that error now + if (!last_write_error_.ok()) { + callback(last_write_error_); + return; + } + + // Make a list of read documents that haven't been written. + std::unordered_set unwritten; + for (const auto& kv : read_versions_) { + unwritten.insert(kv.first); + } + // For each mutation, note that the doc was written. + for (const Mutation& mutation : mutations_) { + unwritten.erase(mutation.key()); + } + + // For each document that was read but not written to, we want to perform a + // `verify` operation. + for (const DocumentKey& key : unwritten) { + mutations_.push_back(VerifyMutation(key, CreatePrecondition(key))); + } + committed_ = true; + datastore_->CommitMutations(mutations_, std::move(callback)); +} + +void Transaction::MarkPermanentlyFailed() { + permanent_error_ = true; +} + +bool Transaction::IsPermanentlyFailed() const { + return permanent_error_; +} + +void Transaction::EnsureCommitNotCalled() { + HARD_ASSERT(!committed_, + "A transaction object cannot be used after its " + "update callback has been invoked."); +} + +absl::optional Transaction::GetVersion( + const DocumentKey& key) const { + auto found = read_versions_.find(key); + if (found != read_versions_.end()) { + return found->second; + } + return absl::nullopt; +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction.h index 37d9d66..32245dc 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction.h @@ -17,39 +17,38 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TRANSACTION_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TRANSACTION_H_ -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - #include +#include #include +#include #include -#include "Firestore/core/src/firebase/firestore/core/user_data.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/mutation.h" #include "Firestore/core/src/firebase/firestore/model/precondition.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/remote/datastore.h" #include "Firestore/core/src/firebase/firestore/util/status.h" #include "Firestore/core/src/firebase/firestore/util/statusor.h" +#include "absl/types/any.h" #include "absl/types/optional.h" -NS_ASSUME_NONNULL_BEGIN - -@class FSTMaybeDocument; -@class FSTMutation; - namespace firebase { namespace firestore { +namespace remote { + +class Datastore; + +} // namespace remote + namespace core { +class ParsedSetData; +class ParsedUpdateData; + class Transaction { public: - // TODO(varconst): once `FSTMaybeDocument` is replaced with a C++ equivalent, - // this function could take a single `StatusOr` parameter. using LookupCallback = std::function&, const util::Status&)>; - using CommitCallback = std::function; + const util::StatusOr>&)>; Transaction() = default; explicit Transaction(remote::Datastore* transaction); @@ -84,7 +83,18 @@ class Transaction { * callback when finished. Once this is called, no other mutations or * commits are allowed on the transaction. */ - void Commit(CommitCallback&& callback); + void Commit(util::StatusCallback&& callback); + + /** + * Marks the transaction as permanently failed, so the transaction will not + * retry. + */ + void MarkPermanentlyFailed(); + + /** + * Checks if the transaction is permanently failed. + */ + bool IsPermanentlyFailed() const; private: /** @@ -93,10 +103,10 @@ class Transaction { * error. When the transaction is committed, the versions recorded will be set * as preconditions on the writes sent to the backend. */ - util::Status RecordVersion(FSTMaybeDocument* doc); + util::Status RecordVersion(const model::MaybeDocument& doc); /** Stores mutations to be written when `Commit` is called. */ - void WriteMutations(std::vector&& mutations); + void WriteMutations(std::vector&& mutations); /** * Returns version of this doc when it was read in this transaction as a @@ -118,25 +128,46 @@ class Transaction { remote::Datastore* datastore_ = nullptr; - std::vector mutations_; + std::vector mutations_; bool committed_ = false; + bool permanent_error_ = false; /** - * An error that may have occurred as a consequence of a write. If set, needs - * to be raised in the completion handler instead of trying to commit. + * A deferred usage error that occurred previously in this transaction that + * will cause the transaction to fail once it actually commits. */ util::Status last_write_error_; + /** + * Set of documents that have been written in the transaction. + * + * When there's more than one write to the same key in a transaction, any + * writes after the first are handled differently. + */ + std::unordered_set written_docs_; + std::unordered_map read_versions_; }; +using TransactionResultCallback = util::StatusCallback; + +/** + * TransactionUpdateCallback is a block that wraps a user's transaction update + * block internally. + * + * The update block will be called with two parameters: + * * The transaction: an object with methods for performing reads and writes + * within the transaction. + * * The callback: to be called by the block once the user's code is finished. + */ +using TransactionUpdateCallback = std::function, TransactionResultCallback)>; + } // namespace core } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TRANSACTION_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction.mm deleted file mode 100644 index d4fa6ca..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction.mm +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/core/transaction.h" - -#include -#include -#include - -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Model/FSTMutation.h" - -#include "Firestore/core/include/firebase/firestore/firestore_errors.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" - -using firebase::firestore::FirestoreErrorCode; -using firebase::firestore::core::ParsedSetData; -using firebase::firestore::core::ParsedUpdateData; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::DocumentKeyHash; -using firebase::firestore::model::Precondition; -using firebase::firestore::model::SnapshotVersion; -using firebase::firestore::remote::Datastore; -using firebase::firestore::util::Status; -using firebase::firestore::util::StatusOr; - -namespace firebase { -namespace firestore { -namespace core { - -Transaction::Transaction(Datastore* datastore) - : datastore_{NOT_NULL(datastore)} { -} - -Status Transaction::RecordVersion(FSTMaybeDocument* doc) { - SnapshotVersion doc_version; - - if ([doc isKindOfClass:[FSTDocument class]]) { - doc_version = doc.version; - } else if ([doc isKindOfClass:[FSTDeletedDocument class]]) { - // For deleted docs, we must record an explicit no version to build the - // right precondition when writing. - doc_version = SnapshotVersion::None(); - } else { - HARD_FAIL("Unexpected document type in transaction: %s", - NSStringFromClass([doc class])); - } - - absl::optional existing_version = GetVersion(doc.key); - if (existing_version.has_value()) { - if (doc_version != existing_version.value()) { - // This transaction will fail no matter what. - return Status{FirestoreErrorCode::Aborted, - "Document version changed between two reads."}; - } - return Status::OK(); - } else { - read_versions_[doc.key] = doc_version; - return Status::OK(); - } -} - -void Transaction::Lookup(const std::vector& keys, - LookupCallback&& callback) { - EnsureCommitNotCalled(); - - HARD_ASSERT(mutations_.empty(), - "Transactions lookups are invalid after writes."); - - datastore_->LookupDocuments( - keys, [this, callback](const std::vector& documents, - const Status& status) { - if (!status.ok()) { - callback({}, status); - return; - } - - for (FSTMaybeDocument* doc : documents) { - Status record_error = RecordVersion(doc); - if (!record_error.ok()) { - callback({}, record_error); - return; - } - } - - callback(documents, Status::OK()); - }); -} - -void Transaction::WriteMutations(std::vector&& mutations) { - EnsureCommitNotCalled(); - // `move` will become appropriate once `FSTMutation` is replaced by the C++ - // equivalent. - std::move(mutations.begin(), mutations.end(), std::back_inserter(mutations_)); -} - -Precondition Transaction::CreatePrecondition(const DocumentKey& key) { - absl::optional version = GetVersion(key); - if (version.has_value()) { - return Precondition::UpdateTime(version.value()); - } else { - return Precondition::None(); - } -} - -StatusOr Transaction::CreateUpdatePrecondition( - const DocumentKey& key) { - absl::optional version = GetVersion(key); - - if (version.has_value() && version.value() == SnapshotVersion::None()) { - // The document to update doesn't exist, so fail the transaction. - return Status{FirestoreErrorCode::Aborted, - "Can't update a document that doesn't exist."}; - } else if (version.has_value()) { - // Document exists, just base precondition on document update time. - return Precondition::UpdateTime(version.value()); - } else { - // Document was not read, so we just use the preconditions for a blind - // update. - return Precondition::Exists(true); - } -} - -void Transaction::Set(const DocumentKey& key, ParsedSetData&& data) { - WriteMutations(std::move(data).ToMutations(key, CreatePrecondition(key))); -} - -void Transaction::Update(const DocumentKey& key, ParsedUpdateData&& data) { - StatusOr maybe_precondition = CreateUpdatePrecondition(key); - if (!maybe_precondition.ok()) { - last_write_error_ = maybe_precondition.status(); - } else { - WriteMutations( - std::move(data).ToMutations(key, maybe_precondition.ValueOrDie())); - } -} - -void Transaction::Delete(const DocumentKey& key) { - FSTMutation* mutation = - [[FSTDeleteMutation alloc] initWithKey:key - precondition:CreatePrecondition(key)]; - WriteMutations({mutation}); - - // Since the delete will be applied before all following writes, we need to - // ensure that the precondition for the next write will be exists: false. - read_versions_[key] = SnapshotVersion::None(); -} - -void Transaction::Commit(CommitCallback&& callback) { - EnsureCommitNotCalled(); - - // If there was an error writing, raise that error now - if (!last_write_error_.ok()) { - callback(last_write_error_); - return; - } - - // Make a list of read documents that haven't been written. - std::unordered_set unwritten; - for (const auto& kv : read_versions_) { - unwritten.insert(kv.first); - }; - // For each mutation, note that the doc was written. - for (FSTMutation* mutation : mutations_) { - unwritten.erase(mutation.key); - } - - if (!unwritten.empty()) { - // TODO(klimt): This is a temporary restriction, until "verify" is supported - // on the backend. - callback( - Status{FirestoreErrorCode::FailedPrecondition, - "Every document read in a transaction must also be written in " - "that transaction."}); - } else { - committed_ = true; - datastore_->CommitMutations(mutations_, std::move(callback)); - } -} - -void Transaction::EnsureCommitNotCalled() { - HARD_ASSERT(!committed_, "A transaction object cannot be used after its " - "update callback has been invoked."); -} - -absl::optional Transaction::GetVersion( - const DocumentKey& key) const { - auto found = read_versions_.find(key); - if (found != read_versions_.end()) { - return found->second; - } - return absl::nullopt; -} - -} // namespace core -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction_runner.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction_runner.cc new file mode 100644 index 0000000..2796c7e --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction_runner.cc @@ -0,0 +1,108 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include + +#include "Firestore/core/src/firebase/firestore/core/transaction_runner.h" +#include "Firestore/core/src/firebase/firestore/remote/exponential_backoff.h" +#include "absl/algorithm/container.h" + +namespace firebase { +namespace firestore { +namespace core { +namespace { + +using remote::RemoteStore; +using util::AsyncQueue; +using util::Status; +using util::TimerId; + +/** Maximum number of times a transaction can be retried before failing. */ +constexpr int kRetryCount = 5; + +bool IsRetryableTransactionError(const util::Status& error) { + // In transactions, the backend will fail outdated reads with + // FAILED_PRECONDITION and non-matching document versions with ABORTED. These + // errors should be retried. + Error code = error.code(); + return code == Error::Aborted || code == Error::FailedPrecondition || + !remote::Datastore::IsPermanentError(error); +} +} // namespace + +TransactionRunner::TransactionRunner(const std::shared_ptr& queue, + RemoteStore* remote_store, + TransactionUpdateCallback update_callback, + TransactionResultCallback result_callback) + : queue_{queue}, + remote_store_{remote_store}, + update_callback_{std::move(update_callback)}, + result_callback_{std::move(result_callback)}, + backoff_{queue_, TimerId::RetryTransaction}, + retries_left_{kRetryCount} { +} + +void TransactionRunner::Run() { + queue_->VerifyIsCurrentQueue(); + + auto shared_this = this->shared_from_this(); + backoff_.BackoffAndRun([shared_this] { + std::shared_ptr transaction = + shared_this->remote_store_->CreateTransaction(); + shared_this->update_callback_( + transaction, [transaction, shared_this](const util::Status& status) { + shared_this->queue_->Enqueue([transaction, shared_this, status] { + shared_this->ContinueCommit(transaction, status); + }); + }); + }); +} + +void TransactionRunner::ContinueCommit( + const std::shared_ptr& transaction, util::Status status) { + if (!status.ok()) { + HandleTransactionError(transaction, std::move(status)); + } else { + auto shared_this = this->shared_from_this(); + transaction->Commit([shared_this, transaction](Status commit_status) { + shared_this->DispatchResult(transaction, std::move(commit_status)); + }); + } +} + +void TransactionRunner::DispatchResult( + const std::shared_ptr& transaction, Status status) { + if (status.ok()) { + result_callback_(std::move(status)); + } else { + HandleTransactionError(transaction, std::move(status)); + } +} + +void TransactionRunner::HandleTransactionError( + const std::shared_ptr& transaction, Status status) { + if (retries_left_ > 0 && IsRetryableTransactionError(status) && + !transaction->IsPermanentlyFailed()) { + retries_left_ -= 1; + Run(); + } else { + result_callback_(std::move(status)); + } +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction_runner.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction_runner.h new file mode 100644 index 0000000..f17a259 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction_runner.h @@ -0,0 +1,77 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TRANSACTION_RUNNER_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TRANSACTION_RUNNER_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/core/transaction.h" +#include "Firestore/core/src/firebase/firestore/remote/exponential_backoff.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_store.h" +#include "Firestore/core/src/firebase/firestore/util/async_queue.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" + +namespace firebase { +namespace firestore { +namespace core { + +/** + * TransactionRunner encapsulates the logic needed to run and retry transactions + * with backoff. + * + * TransactionRunner manages its own lifetime by keeping itself alive until all + * retries are completed. It must be allocated via + * std::make_shared because the implementation expects to be + * able to call std::shared_from_this to create additional references that will + * keep it alive. + */ +class TransactionRunner + : public std::enable_shared_from_this { + public: + TransactionRunner(const std::shared_ptr& queue, + remote::RemoteStore* remote_store, + core::TransactionUpdateCallback update_callback, + core::TransactionResultCallback result_callback); + + /** + * Runs the transaction and calls the result_callback_ with the result. + */ + void Run(); + + private: + void ContinueCommit(const std::shared_ptr& transaction, + util::Status maybe_result); + + void DispatchResult(const std::shared_ptr& transaction, + util::Status status); + + void HandleTransactionError(const std::shared_ptr& transaction, + util::Status status); + + std::shared_ptr queue_; + remote::RemoteStore* remote_store_; + core::TransactionUpdateCallback update_callback_; + core::TransactionResultCallback result_callback_; + remote::ExponentialBackoff backoff_; + int retries_left_; +}; + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_TRANSACTION_RUNNER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/user_data.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/user_data.cc new file mode 100644 index 0000000..69c34fe --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/user_data.cc @@ -0,0 +1,275 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/user_data.h" + +#include + +#include "Firestore/core/src/firebase/firestore/model/mutation.h" +#include "Firestore/core/src/firebase/firestore/model/patch_mutation.h" +#include "Firestore/core/src/firebase/firestore/model/set_mutation.h" +#include "Firestore/core/src/firebase/firestore/model/transform_mutation.h" +#include "Firestore/core/src/firebase/firestore/model/transform_operation.h" +#include "Firestore/core/src/firebase/firestore/util/exception.h" +#include "absl/memory/memory.h" +#include "absl/strings/match.h" + +namespace firebase { +namespace firestore { +namespace core { + +using model::DocumentKey; +using model::FieldMask; +using model::FieldPath; +using model::FieldTransform; +using model::Mutation; +using model::ObjectValue; +using model::PatchMutation; +using model::Precondition; +using model::SetMutation; +using model::TransformMutation; +using model::TransformOperation; +using util::ThrowInvalidArgument; + +// MARK: - ParseAccumulator + +ParseContext ParseAccumulator::RootContext() { + return ParseContext{ + this, absl::make_unique(FieldPath::EmptyPath()), false}; +} + +bool ParseAccumulator::Contains(const FieldPath& field_path) const { + for (const FieldPath& field : field_mask_) { + if (field_path.IsPrefixOf(field)) { + return true; + } + } + + for (const FieldTransform& field_transform : field_transforms_) { + if (field_path.IsPrefixOf(field_transform.path())) { + return true; + } + } + + return false; +} + +void ParseAccumulator::AddToFieldMask(FieldPath field_path) { + field_mask_.insert(std::move(field_path)); +} + +void ParseAccumulator::AddToFieldTransforms( + FieldPath field_path, TransformOperation transform_operation) { + field_transforms_.emplace_back(std::move(field_path), + std::move(transform_operation)); +} + +ParsedSetData ParseAccumulator::MergeData(ObjectValue data) && { + return ParsedSetData{std::move(data), FieldMask{std::move(field_mask_)}, + std::move(field_transforms_)}; +} + +ParsedSetData ParseAccumulator::MergeData(ObjectValue data, + model::FieldMask user_field_mask) && { + std::vector covered_field_transforms; + + for (FieldTransform& field_transform : field_transforms_) { + if (user_field_mask.covers(field_transform.path())) { + covered_field_transforms.push_back(std::move(field_transform)); + } + } + + return ParsedSetData{std::move(data), std::move(user_field_mask), + std::move(covered_field_transforms)}; +} + +ParsedSetData ParseAccumulator::SetData(ObjectValue data) && { + return ParsedSetData{std::move(data), std::move(field_transforms_)}; +} + +ParsedUpdateData ParseAccumulator::UpdateData(ObjectValue data) && { + return ParsedUpdateData{data, FieldMask{std::move(field_mask_)}, + std::move(field_transforms_)}; +} + +// MARK: - ParseContext + +namespace { + +const char* RESERVED_FIELD_DESIGNATOR = "__"; + +} // namespace + +ParseContext ParseContext::ChildContext(const std::string& field_name) { + std::unique_ptr path; + if (path_) { + path = absl::make_unique(path_->Append(field_name)); + } + + ParseContext context{accumulator_, std::move(path), false}; + context.ValidatePathSegment(field_name); + return context; +} + +ParseContext ParseContext::ChildContext(const FieldPath& field_path) { + std::unique_ptr path; + if (path_) { + path = absl::make_unique(path_->Append(field_path)); + } + + ParseContext context{accumulator_, std::move(path), false}; + context.ValidatePath(); + return context; +} + +ParseContext ParseContext::ChildContext(size_t array_index) { + // TODO(b/34871131): We don't support array paths right now; make path null. + (void)array_index; + return {accumulator_, /* path= */ nullptr, /* array_element= */ true}; +} + +/** + * Returns a string that can be appended to error messages indicating what field + * caused the error. + */ +std::string ParseContext::FieldDescription() const { + // TODO(b/34871131): Remove nullptr check once we have proper paths for fields + // within arrays. + if (!path_ || path_->empty()) { + return ""; + } else { + return util::StringFormat(" (found in field %s)", path_->CanonicalString()); + } +} + +bool ParseContext::write() const { + switch (accumulator_->data_source()) { + case UserDataSource::Set: // Falls through. + case UserDataSource::MergeSet: // Falls through. + case UserDataSource::Update: + return true; + case UserDataSource::Argument: + case UserDataSource::ArrayArgument: + return false; + default: + ThrowInvalidArgument("Unexpected case for UserDataSource: %s", + accumulator_->data_source()); + } +} + +void ParseContext::ValidatePath() const { + // TODO(b/34871131): Remove nullptr check once we have proper paths for fields + // within arrays. + if (!path_) { + return; + } + for (const std::string& segment : *path_) { + ValidatePathSegment(segment); + } +} + +void ParseContext::ValidatePathSegment(absl::string_view segment) const { + absl::string_view designator{RESERVED_FIELD_DESIGNATOR}; + if (segment.empty()) { + ThrowInvalidArgument("Invalid data. Document fields must not be empty%s", + FieldDescription()); + } + if (write() && absl::StartsWith(segment, designator) && + absl::EndsWith(segment, designator)) { + ThrowInvalidArgument( + "Invalid data. Document fields cannot begin and end with \"%s\"%s", + RESERVED_FIELD_DESIGNATOR, FieldDescription()); + } +} + +void ParseContext::AddToFieldMask(FieldPath field_path) { + accumulator_->AddToFieldMask(std::move(field_path)); +} + +void ParseContext::AddToFieldTransforms( + FieldPath field_path, TransformOperation transform_operation) { + accumulator_->AddToFieldTransforms(std::move(field_path), + std::move(transform_operation)); +} + +// MARK: - ParsedSetData + +ParsedSetData::ParsedSetData(ObjectValue data, + std::vector field_transforms) + : data_{std::move(data)}, + field_transforms_{std::move(field_transforms)}, + patch_{false} { +} + +ParsedSetData::ParsedSetData(ObjectValue data, + FieldMask field_mask, + std::vector field_transforms) + : data_{std::move(data)}, + field_mask_{std::move(field_mask)}, + field_transforms_{std::move(field_transforms)}, + patch_{true} { +} + +std::vector ParsedSetData::ToMutations( + const DocumentKey& key, const Precondition& precondition) && { + std::vector mutations; + if (patch_) { + PatchMutation mutation(key, std::move(data_), std::move(field_mask_), + precondition); + mutations.push_back(mutation); + } else { + SetMutation mutation(key, std::move(data_), precondition); + mutations.push_back(mutation); + } + + if (!field_transforms_.empty()) { + TransformMutation mutation(key, std::move(field_transforms_)); + mutations.push_back(mutation); + } + + return mutations; +} + +// MARK: - ParsedUpdateData + +ParsedUpdateData::ParsedUpdateData( + ObjectValue data, + model::FieldMask field_mask, + std::vector field_transforms) + : data_{std::move(data)}, + field_mask_{std::move(field_mask)}, + field_transforms_{std::move(field_transforms)} { +} + +std::vector ParsedUpdateData::ToMutations( + const DocumentKey& key, const Precondition& precondition) && { + std::vector mutations; + + PatchMutation mutation(key, std::move(data_), std::move(field_mask_), + precondition); + mutations.push_back(mutation); + + if (!field_transforms_.empty()) { + TransformMutation mutation(key, std::move(field_transforms_)); + mutations.push_back(mutation); + } + + return mutations; +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/user_data.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/user_data.h index d3c3bf9..2968191 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/user_data.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/user_data.h @@ -23,19 +23,26 @@ #include #include -#include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/field_mask.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" #include "Firestore/core/src/firebase/firestore/model/field_transform.h" -#include "Firestore/core/src/firebase/firestore/model/precondition.h" - -@class FSTMutation; -@class FSTObjectValue; +#include "Firestore/core/src/firebase/firestore/model/field_value.h" namespace firebase { namespace firestore { +namespace model { + +class Precondition; +class Mutation; + +} // namespace model + namespace core { +class ParseContext; +class ParsedSetData; +class ParsedUpdateData; + /** * Represents what type of API method provided the data being parsed; useful for * determining which error conditions apply during parsing and providing better @@ -54,12 +61,13 @@ enum class UserDataSource { * false. */ Argument, + /** + * Indicates that the source is an Argument that may directly contain nested + * arrays (e.g. the operand of a `in` query). + */ + ArrayArgument }; -class ParseContext; -class ParsedSetData; -class ParsedUpdateData; - /** * Accumulates the side-effect results of parsing user input. These include: * @@ -112,9 +120,8 @@ class ParseAccumulator { /** * Adds a transformation for the given field path. */ - void AddToFieldTransforms( - model::FieldPath field_path, - std::unique_ptr transform_operation); + void AddToFieldTransforms(model::FieldPath field_path, + model::TransformOperation transform_operation); /** * Wraps the given `data` along with any accumulated field mask and transforms @@ -123,7 +130,7 @@ class ParseAccumulator { * @return ParsedSetData that has consumed the contents of this * ParseAccumulator. */ - ParsedSetData MergeData(FSTObjectValue* data) &&; + ParsedSetData MergeData(model::ObjectValue data) &&; /** * Wraps the given `data` and `user_field_mask` along with any accumulated @@ -138,7 +145,7 @@ class ParseAccumulator { * ParseAccumulator. The field mask in the result will be the user_field_mask * and only transforms that are covered by the mask will be included. */ - ParsedSetData MergeData(FSTObjectValue* data, + ParsedSetData MergeData(model::ObjectValue data, model::FieldMask user_field_mask) &&; /** @@ -148,7 +155,7 @@ class ParseAccumulator { * @return ParsedSetData that has consumed the contents of this * ParseAccumulator. */ - ParsedSetData SetData(FSTObjectValue* data) &&; + ParsedSetData SetData(model::ObjectValue data) &&; /** * Wraps the given `data` along with any accumulated field mask and transforms @@ -157,7 +164,7 @@ class ParseAccumulator { * @return ParsedSetData that has consumed the contents of this * ParseAccumulator. */ - ParsedUpdateData UpdateData(FSTObjectValue* data) &&; + ParsedUpdateData UpdateData(model::ObjectValue data) &&; private: friend class ParseContext; @@ -180,7 +187,7 @@ class ParseAccumulator { class ParseContext { public: /** - * Initializes a FSTParseContext with the given source and path. + * Initializes a ParseContext with the given source and path. * * @param path A path within the object being parsed. This could be an empty * path (in which case the context represents the root of the data being @@ -225,16 +232,15 @@ class ParseContext { std::string FieldDescription() const; - // Helpers to get a FSTParseContext for a child field. + // Helpers to get a ParseContext for a child field. ParseContext ChildContext(const std::string& field_name); ParseContext ChildContext(const model::FieldPath& field_path); ParseContext ChildContext(size_t array_index); void AddToFieldMask(model::FieldPath field_path); - void AddToFieldTransforms( - model::FieldPath field_path, - std::unique_ptr transform_operation); + void AddToFieldTransforms(model::FieldPath field_path, + model::TransformOperation transform_operation); private: void ValidatePath() const; @@ -253,9 +259,9 @@ class ParseContext { /** The result of parsing document data (e.g. for a SetData call). */ class ParsedSetData { public: - ParsedSetData(FSTObjectValue* data, + ParsedSetData(model::ObjectValue data, std::vector field_transforms); - ParsedSetData(FSTObjectValue* data, + ParsedSetData(model::ObjectValue data, model::FieldMask field_mask, std::vector field_transforms); @@ -266,12 +272,12 @@ class ParsedSetData { * * This method consumes the values stored in the ParsedSetData */ - std::vector ToMutations( + std::vector ToMutations( const model::DocumentKey& key, const model::Precondition& precondition) &&; private: - FSTObjectValue* data_; + model::ObjectValue data_; model::FieldMask field_mask_; std::vector field_transforms_; bool patch_; @@ -280,11 +286,11 @@ class ParsedSetData { /** The result of parsing "update" data (i.e. for an UpdateData call). */ class ParsedUpdateData { public: - ParsedUpdateData(FSTObjectValue* data, + ParsedUpdateData(model::ObjectValue data, model::FieldMask field_mask, - std::vector fieldTransforms); + std::vector field_transforms); - FSTObjectValue* data() const { + const model::ObjectValue& data() const { return data_; } @@ -299,12 +305,12 @@ class ParsedUpdateData { * * This method consumes the values stored in the ParsedUpdateData */ - std::vector ToMutations( + std::vector ToMutations( const model::DocumentKey& key, const model::Precondition& precondition) &&; private: - FSTObjectValue* data_; + model::ObjectValue data_; model::FieldMask field_mask_; std::vector field_transforms_; }; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/user_data.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/user_data.mm deleted file mode 100644 index 237e49f..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/user_data.mm +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/core/user_data.h" - -#include - -#import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" - -#include "absl/strings/match.h" - -namespace firebase { -namespace firestore { -namespace core { - -using model::DocumentKey; -using model::FieldMask; -using model::FieldPath; -using model::FieldTransform; -using model::Precondition; -using model::TransformOperation; - -#pragma mark - ParseAccumulator - -ParseContext ParseAccumulator::RootContext() { - return ParseContext{ - this, absl::make_unique(FieldPath::EmptyPath()), false}; -} - -bool ParseAccumulator::Contains(const FieldPath& field_path) const { - for (const FieldPath& field : field_mask_) { - if (field_path.IsPrefixOf(field)) { - return true; - } - } - - for (const FieldTransform& field_transform : field_transforms_) { - if (field_path.IsPrefixOf(field_transform.path())) { - return true; - } - } - - return false; -} - -void ParseAccumulator::AddToFieldMask(FieldPath field_path) { - field_mask_.insert(std::move(field_path)); -} - -void ParseAccumulator::AddToFieldTransforms( - FieldPath field_path, - std::unique_ptr transform_operation) { - field_transforms_.emplace_back(std::move(field_path), - std::move(transform_operation)); -} - -ParsedSetData ParseAccumulator::MergeData(FSTObjectValue* data) && { - return ParsedSetData{data, FieldMask{std::move(field_mask_)}, - std::move(field_transforms_)}; -} - -ParsedSetData ParseAccumulator::MergeData(FSTObjectValue* data, - model::FieldMask user_field_mask) && { - std::vector covered_field_transforms; - - for (FieldTransform& field_transform : field_transforms_) { - if (user_field_mask.covers(field_transform.path())) { - covered_field_transforms.push_back(std::move(field_transform)); - } - } - - return ParsedSetData{data, std::move(user_field_mask), - std::move(covered_field_transforms)}; -} - -ParsedSetData ParseAccumulator::SetData(FSTObjectValue* data) && { - return ParsedSetData{data, std::move(field_transforms_)}; -} - -ParsedUpdateData ParseAccumulator::UpdateData(FSTObjectValue* data) && { - return ParsedUpdateData{data, FieldMask{std::move(field_mask_)}, - std::move(field_transforms_)}; -} - -#pragma mark - ParseContext - -namespace { - -const char* RESERVED_FIELD_DESIGNATOR = "__"; - -} // namespace - -ParseContext ParseContext::ChildContext(const std::string& field_name) { - std::unique_ptr path; - if (path_) { - path = absl::make_unique(path_->Append(field_name)); - } - - ParseContext context{accumulator_, std::move(path), false}; - context.ValidatePathSegment(field_name); - return context; -} - -ParseContext ParseContext::ChildContext(const FieldPath& fieldPath) { - std::unique_ptr path; - if (path_) { - path = absl::make_unique(path_->Append(fieldPath)); - } - - ParseContext context{accumulator_, std::move(path), false}; - context.ValidatePath(); - return context; -} - -ParseContext ParseContext::ChildContext(size_t array_index) { - // TODO(b/34871131): We don't support array paths right now; make path null. - (void)array_index; - return {accumulator_, /* path= */ nullptr, /* array_element= */ true}; -} - -/** - * Returns a string that can be appended to error messages indicating what field - * caused the error. - */ -std::string ParseContext::FieldDescription() const { - // TODO(b/34871131): Remove nullptr check once we have proper paths for fields - // within arrays. - if (!path_ || path_->empty()) { - return ""; - } else { - return util::StringFormat(" (found in field %s)", path_->CanonicalString()); - } -} - -bool ParseContext::write() const { - switch (accumulator_->data_source()) { - case UserDataSource::Set: // Falls through. - case UserDataSource::MergeSet: // Falls through. - case UserDataSource::Update: - return true; - case UserDataSource::Argument: - return false; - default: - FSTThrowInvalidArgument(@"Unexpected case for UserDataSource: %d", - accumulator_->data_source()); - } -} - -void ParseContext::ValidatePath() const { - // TODO(b/34871131): Remove nullptr check once we have proper paths for fields - // within arrays. - if (!path_) { - return; - } - for (const std::string& segment : *path_) { - ValidatePathSegment(segment); - } -} - -void ParseContext::ValidatePathSegment(absl::string_view segment) const { - absl::string_view designator{RESERVED_FIELD_DESIGNATOR}; - if (write() && absl::StartsWith(segment, designator) && - absl::EndsWith(segment, designator)) { - FSTThrowInvalidArgument(@"Document fields cannot begin and end with %s%s", - RESERVED_FIELD_DESIGNATOR, - FieldDescription().c_str()); - } -} - -void ParseContext::AddToFieldMask(FieldPath field_path) { - accumulator_->AddToFieldMask(std::move(field_path)); -} - -void ParseContext::AddToFieldTransforms( - FieldPath field_path, - std::unique_ptr transform_operation) { - accumulator_->AddToFieldTransforms(std::move(field_path), - std::move(transform_operation)); -} - -#pragma mark - ParsedSetData - -ParsedSetData::ParsedSetData(FSTObjectValue* data, - std::vector field_transforms) - : data_{data}, - field_transforms_{std::move(field_transforms)}, - patch_{false} { -} - -ParsedSetData::ParsedSetData(FSTObjectValue* data, - FieldMask field_mask, - std::vector field_transforms) - : data_{data}, - field_mask_{std::move(field_mask)}, - field_transforms_{std::move(field_transforms)}, - patch_{true} { -} - -std::vector ParsedSetData::ToMutations( - const DocumentKey& key, const Precondition& precondition) && { - std::vector mutations; - if (patch_) { - FSTMutation* mutation = - [[FSTPatchMutation alloc] initWithKey:key - fieldMask:std::move(field_mask_) - value:data_ - precondition:precondition]; - mutations.push_back(mutation); - } else { - FSTMutation* mutation = [[FSTSetMutation alloc] initWithKey:key - value:data_ - precondition:precondition]; - mutations.push_back(mutation); - } - - if (!field_transforms_.empty()) { - FSTMutation* mutation = - [[FSTTransformMutation alloc] initWithKey:key - fieldTransforms:field_transforms_]; - mutations.push_back(mutation); - } - - return mutations; -} - -#pragma mark - ParsedUpdateData - -ParsedUpdateData::ParsedUpdateData( - FSTObjectValue* data, - model::FieldMask field_mask, - std::vector field_transforms) - : data_{data}, - field_mask_{std::move(field_mask)}, - field_transforms_{std::move(field_transforms)} { -} - -std::vector ParsedUpdateData::ToMutations( - const DocumentKey& key, const Precondition& precondition) && { - std::vector mutations; - - FSTMutation* mutation = - [[FSTPatchMutation alloc] initWithKey:key - fieldMask:std::move(field_mask_) - value:data_ - precondition:precondition]; - mutations.push_back(mutation); - - if (!field_transforms_.empty()) { - FSTMutation* mutation = - [[FSTTransformMutation alloc] initWithKey:key - fieldTransforms:std::move(field_transforms_)]; - mutations.push_back(mutation); - } - - return mutations; -} - -} // namespace core -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view.cc new file mode 100644 index 0000000..34fd770 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view.cc @@ -0,0 +1,409 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/view.h" + +#include + +#include "Firestore/core/src/firebase/firestore/core/target.h" +#include "Firestore/core/src/firebase/firestore/model/document_set.h" + +namespace firebase { +namespace firestore { +namespace core { + +using model::Document; +using model::DocumentKey; +using model::DocumentKeySet; +using model::DocumentSet; +using model::MaybeDocument; +using model::MaybeDocumentMap; +using model::OnlineState; +using remote::TargetChange; +using util::ComparisonResult; + +// MARK: - LimboDocumentChange + +LimboDocumentChange::LimboDocumentChange( + firebase::firestore::core::LimboDocumentChange::Type type, + firebase::firestore::model::DocumentKey key) + : type_(type), key_(std::move(key)) { +} + +bool operator==(const LimboDocumentChange& lhs, + const LimboDocumentChange& rhs) { + return lhs.type() == rhs.type() && lhs.key() == rhs.key(); +} + +// MARK: - ViewDocumentChanges + +ViewDocumentChanges::ViewDocumentChanges(model::DocumentSet new_documents, + DocumentViewChangeSet changes, + model::DocumentKeySet mutated_keys, + bool needs_refill) + : document_set_(std::move(new_documents)), + change_set_(std::move(changes)), + mutated_keys_(std::move(mutated_keys)), + needs_refill_(needs_refill) { +} + +// MARK: - View + +namespace { + +int GetDocumentViewChangeTypePosition(DocumentViewChange::Type change_type) { + switch (change_type) { + case DocumentViewChange::Type::Removed: + return 0; + case DocumentViewChange::Type::Added: + return 1; + case DocumentViewChange::Type::Modified: + return 2; + case DocumentViewChange::Type::Metadata: + // A metadata change is converted to a modified change at the public API + // layer. Since we sort by document key and then change type, metadata and + // modified changes must be sorted equivalently. + return 2; + } + HARD_FAIL("Unknown DocumentViewChange::Type %s", change_type); +} + +} // namespace + +View::View(Query query, DocumentKeySet remote_documents) + : query_(std::move(query)), + document_set_(query_.Comparator()), + synced_documents_(std::move(remote_documents)) { +} + +ComparisonResult View::Compare(const Document& lhs, const Document& rhs) const { + return document_set_.comparator().Compare(lhs, rhs); +} + +ViewDocumentChanges View::ComputeDocumentChanges( + const MaybeDocumentMap& doc_changes, + const absl::optional& previous_changes) const { + DocumentViewChangeSet change_set; + if (previous_changes) { + change_set = previous_changes->change_set(); + } + DocumentSet old_document_set = + previous_changes ? previous_changes->document_set() : document_set_; + + DocumentKeySet new_mutated_keys = + previous_changes ? previous_changes->mutated_keys() : mutated_keys_; + DocumentKeySet old_mutated_keys = mutated_keys_; + DocumentSet new_document_set = old_document_set; + bool needs_refill = false; + + // Track the last doc in a (full) limit. This is necessary, because some + // update (a delete, or an update moving a doc past the old limit) might mean + // there is some other document in the local cache that either should come (1) + // between the old last limit doc and the new last document, in the case of + // updates, or (2) after the new last document, in the case of deletes. So we + // keep this doc at the old limit to compare the updates to. + // + // Note that this should never get used in a refill (when previous_changes is + // set), because there will only be adds -- no deletes or updates. + absl::optional last_doc_in_limit; + if (query_.has_limit_to_first() && + old_document_set.size() == static_cast(query_.limit())) { + last_doc_in_limit = old_document_set.GetLastDocument(); + } + absl::optional first_doc_in_limit; + if (query_.has_limit_to_last() && + old_document_set.size() == static_cast(query_.limit())) { + first_doc_in_limit = old_document_set.GetFirstDocument(); + } + + for (const auto& kv : doc_changes) { + const DocumentKey& key = kv.first; + const MaybeDocument& maybe_new_doc = kv.second; + + absl::optional old_doc = old_document_set.GetDocument(key); + absl::optional new_doc; + if (maybe_new_doc.is_document()) { + new_doc = Document(maybe_new_doc); + } + if (new_doc) { + HARD_ASSERT(key == new_doc->key(), + "Mismatching key in document changes: %s != %s", + key.ToString(), new_doc->key().ToString()); + if (!query_.Matches(*new_doc)) { + new_doc = absl::nullopt; + } + } + + bool old_doc_had_pending_mutations = + old_doc && old_mutated_keys.contains(key); + + // We only consider committed mutations for documents that were mutated + // during the lifetime of the view. + bool new_doc_has_pending_mutations = + new_doc && (new_doc->has_local_mutations() || + (old_mutated_keys.contains(key) && + new_doc->has_committed_mutations())); + + bool change_applied = false; + // Calculate change + if (old_doc && new_doc) { + bool docs_equal = old_doc->data() == new_doc->data(); + if (!docs_equal) { + if (!ShouldWaitForSyncedDocument(*new_doc, *old_doc)) { + change_set.AddChange( + DocumentViewChange{*new_doc, DocumentViewChange::Type::Modified}); + change_applied = true; + + bool outside_limit = + last_doc_in_limit && + util::Descending(Compare(*new_doc, *last_doc_in_limit)); + bool outside_limit_to_last = + first_doc_in_limit && + util::Ascending(Compare(*new_doc, *first_doc_in_limit)); + if (outside_limit || outside_limit_to_last) { + // This doc moved from inside the limit to after the limit. That + // means there may be some doc in the local cache that's actually + // less than this one. + needs_refill = true; + } + } + } else if (old_doc_had_pending_mutations != + new_doc_has_pending_mutations) { + change_set.AddChange( + DocumentViewChange{*new_doc, DocumentViewChange::Type::Metadata}); + change_applied = true; + } + + } else if (!old_doc && new_doc) { + change_set.AddChange( + DocumentViewChange{*new_doc, DocumentViewChange::Type::Added}); + change_applied = true; + } else if (old_doc && !new_doc) { + change_set.AddChange( + DocumentViewChange{*old_doc, DocumentViewChange::Type::Removed}); + change_applied = true; + + if (last_doc_in_limit || first_doc_in_limit) { + // A doc was removed from a full limit query. We'll need to re-query + // from the local cache to see if we know about some other doc that + // should be in the results. + needs_refill = true; + } + } + + if (change_applied) { + if (new_doc) { + new_document_set = new_document_set.insert(new_doc); + if (new_doc->has_local_mutations()) { + new_mutated_keys = new_mutated_keys.insert(key); + } else { + new_mutated_keys = new_mutated_keys.erase(key); + } + } else { + new_document_set = new_document_set.erase(key); + new_mutated_keys = new_mutated_keys.erase(key); + } + } + } + + // Drop documents out to meet limitToFirst/limitToLast requirement. + if (query_.limit_type() != LimitType::None) { + auto limit = static_cast(query_.limit()); + if (limit < new_document_set.size()) { + for (size_t i = new_document_set.size() - limit; i > 0; --i) { + absl::optional found = + query_.has_limit_to_first() ? new_document_set.GetLastDocument() + : new_document_set.GetFirstDocument(); + const Document& old_doc = *found; + new_document_set = new_document_set.erase(old_doc.key()); + new_mutated_keys = new_mutated_keys.erase(old_doc.key()); + change_set.AddChange( + DocumentViewChange{old_doc, DocumentViewChange::Type::Removed}); + } + } + } + + HARD_ASSERT(!needs_refill || !previous_changes, + "View was refilled using docs that themselves needed refilling."); + + return ViewDocumentChanges(std::move(new_document_set), std::move(change_set), + new_mutated_keys, needs_refill); +} + +bool View::ShouldWaitForSyncedDocument(const Document& new_doc, + const Document& old_doc) const { + // We suppress the initial change event for documents that were modified as + // part of a write acknowledgment (e.g. when the value of a server transform + // is applied) as Watch will send us the same document again. By suppressing + // the event, we only raise two user visible events (one with + // `has_pending_writes` and the final state of the document) instead of three + // (one with `has_pending_writes`, the modified document with + // `has_pending_writes` and the final state of the document). + return (old_doc.has_local_mutations() && new_doc.has_committed_mutations() && + !new_doc.has_local_mutations()); +} + +ViewChange View::ApplyChanges(const ViewDocumentChanges& doc_changes) { + return ApplyChanges(doc_changes, {}); +} + +ViewChange View::ApplyChanges( + const ViewDocumentChanges& doc_changes, + const absl::optional& target_change) { + HARD_ASSERT(!doc_changes.needs_refill(), + "Cannot apply changes that need a refill"); + + DocumentSet old_documents = document_set_; + document_set_ = doc_changes.document_set(); + mutated_keys_ = doc_changes.mutated_keys(); + + // Sort changes based on type and query comparator. + std::vector changes = + doc_changes.change_set().GetChanges(); + std::sort( + changes.begin(), changes.end(), + [this](const DocumentViewChange& lhs, const DocumentViewChange& rhs) { + int pos1 = GetDocumentViewChangeTypePosition(lhs.type()); + int pos2 = GetDocumentViewChangeTypePosition(rhs.type()); + if (pos1 != pos2) { + return pos1 < pos2; + } + return util::Ascending(Compare(lhs.document(), rhs.document())); + }); + + ApplyTargetChange(target_change); + std::vector limbo_changes = UpdateLimboDocuments(); + bool synced = limbo_documents_.empty() && current_; + SyncState new_sync_state = synced ? SyncState::Synced : SyncState::Local; + bool sync_state_changed = new_sync_state != sync_state_; + sync_state_ = new_sync_state; + + if (changes.empty() && !sync_state_changed) { + // No changes. + return ViewChange(absl::nullopt, std::move(limbo_changes)); + } else { + ViewSnapshot snapshot{query_, + doc_changes.document_set(), + old_documents, + std::move(changes), + doc_changes.mutated_keys(), + /*from_cache=*/new_sync_state == SyncState::Local, + sync_state_changed, + /*excludes_metadata_changes=*/false}; + + return ViewChange(std::move(snapshot), std::move(limbo_changes)); + } +} + +ViewChange View::ApplyOnlineStateChange(OnlineState online_state) { + if (current_ && online_state == OnlineState::Offline) { + // If we're offline, set `current_` to false and then call ApplyChanges to + // refresh our sync state and generate a ViewChange as appropriate. We are + // guaranteed to get a new `TargetChange` that sets `current_` back to true + // once the client is back online. + current_ = false; + return ApplyChanges( + ViewDocumentChanges(document_set_, DocumentViewChangeSet{}, + mutated_keys_, /* needs_refill= */ false)); + } else { + // No effect, just return a no-op ViewChange. + return ViewChange(absl::nullopt, {}); + } +} + +// MARK: Private Methods + +/** Returns whether the doc for the given key should be in limbo. */ +bool View::ShouldBeInLimbo(const DocumentKey& key) const { + // If the remote end says it's part of this query, it's not in limbo. + if (synced_documents_.contains(key)) { + return false; + } + // The local store doesn't think it's a result, so it shouldn't be in limbo. + if (!document_set_.ContainsKey(key)) { + return false; + } + // If there are local changes to the doc, they might explain why the server + // doesn't know that it's part of the query. So don't put it in limbo. + // TODO(klimt): Ideally, we would only consider changes that might actually + // affect this specific query. + if (document_set_.GetDocument(key)->has_local_mutations()) { + return false; + } + // Everything else is in limbo. + return true; +} + +/** + * Updates synced_documents_ and current based on the given change. + */ +void View::ApplyTargetChange( + const absl::optional& maybe_target_change) { + if (maybe_target_change.has_value()) { + const TargetChange& target_change = maybe_target_change.value(); + + for (const DocumentKey& key : target_change.added_documents()) { + synced_documents_ = synced_documents_.insert(key); + } + for (const DocumentKey& key : target_change.modified_documents()) { + HARD_ASSERT(synced_documents_.find(key) != synced_documents_.end(), + "Modified document %s not found in view.", key.ToString()); + } + for (const DocumentKey& key : target_change.removed_documents()) { + synced_documents_ = synced_documents_.erase(key); + } + + current_ = target_change.current(); + } +} + +/** Updates limbo_documents_ and returns any changes as LimboDocumentChanges. */ +std::vector View::UpdateLimboDocuments() { + // We can only determine limbo documents when we're in-sync with the server. + if (!current_) { + return {}; + } + + // TODO(klimt): Do this incrementally so that it's not quadratic when updating + // many documents. + DocumentKeySet old_limbo_documents = std::move(limbo_documents_); + limbo_documents_ = DocumentKeySet{}; + for (const Document& doc : document_set_) { + if (ShouldBeInLimbo(doc.key())) { + limbo_documents_ = limbo_documents_.insert(doc.key()); + } + } + + // Diff the new limbo docs with the old limbo docs. + std::vector changes; + changes.reserve(old_limbo_documents.size() + limbo_documents_.size()); + + for (const DocumentKey& key : old_limbo_documents) { + if (!limbo_documents_.contains(key)) { + changes.push_back(LimboDocumentChange::Removed(key)); + } + } + for (const DocumentKey& key : limbo_documents_) { + if (!old_limbo_documents.contains(key)) { + changes.push_back(LimboDocumentChange::Added(key)); + } + } + return changes; +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view.h new file mode 100644 index 0000000..74c9ffe --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view.h @@ -0,0 +1,237 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_VIEW_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_VIEW_H_ + +#include +#include + +#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/document_set.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" + +namespace firebase { +namespace firestore { +namespace core { + +/** A change to a particular document wrt whether it is in "limbo". */ +class LimboDocumentChange { + public: + enum class Type { + Added, + Removed, + }; + + static LimboDocumentChange Added(model::DocumentKey key) { + return {Type::Added, std::move(key)}; + } + + static LimboDocumentChange Removed(model::DocumentKey key) { + return {Type::Removed, std::move(key)}; + } + + LimboDocumentChange(Type type, model::DocumentKey key); + + Type type() const { + return type_; + } + + const model::DocumentKey& key() const { + return key_; + } + + friend bool operator==(const LimboDocumentChange& lhs, + const LimboDocumentChange& rhs); + + private: + Type type_; + model::DocumentKey key_; +}; + +/** The result of applying a set of doc changes to a view. */ +class ViewDocumentChanges { + public: + ViewDocumentChanges(model::DocumentSet new_documents, + DocumentViewChangeSet changes, + model::DocumentKeySet mutated_keys, + bool needs_refill); + + /** The new set of docs that should be in the view. */ + const model::DocumentSet& document_set() const { + return document_set_; + } + + /** The diff of these docs with the previous set of docs. */ + const core::DocumentViewChangeSet& change_set() const { + return change_set_; + } + + const model::DocumentKeySet& mutated_keys() const { + return mutated_keys_; + } + + /** + * Whether the set of documents passed in was not sufficient to calculate the + * new state of the view and there needs to be another pass based on the local + * cache. + */ + bool needs_refill() const { + return needs_refill_; + } + + private: + model::DocumentSet document_set_; + core::DocumentViewChangeSet change_set_; + model::DocumentKeySet mutated_keys_; + bool needs_refill_ = false; +}; + +/** A set of changes to a view. */ +class ViewChange { + public: + ViewChange(absl::optional snapshot, + std::vector limbo_changes) + : snapshot_(std::move(snapshot)), + limbo_changes_(std::move(limbo_changes)) { + } + + const absl::optional snapshot() const& { + return snapshot_; + } + + absl::optional&& snapshot() && { + return std::move(snapshot_); + } + + const std::vector limbo_changes() const { + return limbo_changes_; + } + + private: + absl::optional snapshot_; + std::vector limbo_changes_; +}; + +/** + * View is responsible for computing the final merged truth of what docs are in + * a query. It gets notified of local and remote changes to docs, and applies + * the query filters and limits to determine the most correct possible results. + */ +class View { + public: + View(Query query, model::DocumentKeySet remote_documents); + + /** + * The set of remote documents that the server has told us belongs to the + * target associated with this view. + */ + const model::DocumentKeySet& synced_documents() const { + return synced_documents_; + } + + /** + * Iterates over a set of doc changes, applies the query limit, and computes + * what the new results should be, what the changes were, and whether we may + * need to go back to the local cache for more results. Does not make any + * changes to the view. + * + * @param doc_changes The doc changes to apply to this view. + * @param previous_changes If this is being called with a refill, then start + * with this set of docs and changes instead of the current view. + * @return a new set of docs, changes, and refill flag. + */ + core::ViewDocumentChanges ComputeDocumentChanges( + const model::MaybeDocumentMap& doc_changes, + const absl::optional& previous_changes = + absl::nullopt) const; + + /** + * Updates the view with the given ViewDocumentChanges. + * + * @param doc_changes The set of changes to make to the view's docs. + * @return A new ViewChange with the given docs, changes, and sync state. + */ + ViewChange ApplyChanges(const core::ViewDocumentChanges& doc_changes); + + /** + * Updates the view with the given ViewDocumentChanges and updates limbo docs + * and sync state from the given (optional) target change. + * + * @param doc_changes The set of changes to make to the view's docs. + * @param target_change A target change to apply for computing limbo docs and + * sync state. + * @return A new ViewChange with the given docs, changes, and sync state. + */ + ViewChange ApplyChanges( + const core::ViewDocumentChanges& doc_changes, + const absl::optional& target_change); + + /** + * Applies an OnlineState change to the view, potentially generating an + * ViewChange if the view's sync_state_ changes as a result. + */ + core::ViewChange ApplyOnlineStateChange(model::OnlineState online_state); + + core::SyncState sync_state() const { + return sync_state_; + } + + private: + util::ComparisonResult Compare(const model::Document& lhs, + const model::Document& rhs) const; + + bool ShouldBeInLimbo(const model::DocumentKey& key) const; + + bool ShouldWaitForSyncedDocument(const model::Document& new_doc, + const model::Document& old_doc) const; + + void ApplyTargetChange( + const absl::optional& maybe_target_change); + + std::vector UpdateLimboDocuments(); + + Query query_; + + model::DocumentSet document_set_; + + /** Documents included in the remote target. */ + model::DocumentKeySet synced_documents_; + + /** Documents in the view but not in the remote target */ + model::DocumentKeySet limbo_documents_; + + /** Document Keys that have local changes. */ + model::DocumentKeySet mutated_keys_; + + SyncState sync_state_ = SyncState::None; + + /** + * A flag whether the view is current with the backend. A view is considered + * current after it has seen the current flag from the backend and did not + * lose consistency within the watch stream (e.g. because of an existence + * filter mismatch). + */ + bool current_ = false; +}; + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_VIEW_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view_snapshot.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view_snapshot.cc new file mode 100644 index 0000000..d148cbb --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view_snapshot.cc @@ -0,0 +1,219 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" + +#include + +#include "Firestore/core/src/firebase/firestore/model/document_set.h" +#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "Firestore/core/src/firebase/firestore/util/string_format.h" +#include "Firestore/core/src/firebase/firestore/util/to_string.h" + +namespace firebase { +namespace firestore { +namespace core { + +using model::Document; +using model::DocumentKey; +using model::DocumentKeySet; +using model::DocumentSet; +using util::StringFormat; + +// DocumentViewChange + +DocumentViewChange::DocumentViewChange(Document document, Type type) + : document_{std::move(document)}, type_{type} { +} + +const Document& DocumentViewChange::document() const { + return document_; +} + +std::string DocumentViewChange::ToString() const { + return StringFormat("", + util::ToString(document()), type()); +} + +size_t DocumentViewChange::Hash() const { + return util::Hash(document(), type()); +} + +bool operator==(const DocumentViewChange& lhs, const DocumentViewChange& rhs) { + return lhs.document() == rhs.document() && lhs.type() == rhs.type(); +} + +// DocumentViewChangeSet + +void DocumentViewChangeSet::AddChange(DocumentViewChange&& change) { + const DocumentKey& key = change.document().key(); + auto old_change_iter = change_map_.find(key); + if (old_change_iter == change_map_.end()) { + change_map_ = change_map_.insert(key, change); + return; + } + + const DocumentViewChange& old = old_change_iter->second; + DocumentViewChange::Type old_type = old.type(); + DocumentViewChange::Type new_type = change.type(); + + // Merge the new change with the existing change. + if (new_type != DocumentViewChange::Type::Added && + old_type == DocumentViewChange::Type::Metadata) { + change_map_ = change_map_.insert(key, change); + + } else if (new_type == DocumentViewChange::Type::Metadata && + old_type != DocumentViewChange::Type::Removed) { + DocumentViewChange new_change{change.document(), old_type}; + change_map_ = change_map_.insert(key, new_change); + + } else if (new_type == DocumentViewChange::Type::Modified && + old_type == DocumentViewChange::Type::Modified) { + DocumentViewChange new_change{change.document(), + DocumentViewChange::Type::Modified}; + change_map_ = change_map_.insert(key, new_change); + + } else if (new_type == DocumentViewChange::Type::Modified && + old_type == DocumentViewChange::Type::Added) { + DocumentViewChange new_change{change.document(), + DocumentViewChange::Type::Added}; + change_map_ = change_map_.insert(key, new_change); + + } else if (new_type == DocumentViewChange::Type::Removed && + old_type == DocumentViewChange::Type::Added) { + change_map_ = change_map_.erase(key); + + } else if (new_type == DocumentViewChange::Type::Removed && + old_type == DocumentViewChange::Type::Modified) { + DocumentViewChange new_change{old.document(), + DocumentViewChange::Type::Removed}; + change_map_ = change_map_.insert(key, new_change); + + } else if (new_type == DocumentViewChange::Type::Added && + old_type == DocumentViewChange::Type::Removed) { + DocumentViewChange new_change{change.document(), + DocumentViewChange::Type::Modified}; + change_map_ = change_map_.insert(key, new_change); + + } else { + // This includes these cases, which don't make sense: + // Added -> Added + // Removed -> Removed + // Modified -> Added + // Removed -> Modified + // Metadata -> Added + // Removed -> Metadata + HARD_FAIL("Unsupported combination of changes: %s after %s", new_type, + old_type); + } +} + +std::vector DocumentViewChangeSet::GetChanges() const { + std::vector changes; + for (const auto& kv : change_map_) { + const DocumentViewChange& change = kv.second; + changes.push_back(change); + } + return changes; +} + +std::string DocumentViewChangeSet::ToString() const { + return util::ToString(change_map_); +} + +// ViewSnapshot + +ViewSnapshot::ViewSnapshot(Query query, + DocumentSet documents, + DocumentSet old_documents, + std::vector document_changes, + model::DocumentKeySet mutated_keys, + bool from_cache, + bool sync_state_changed, + bool excludes_metadata_changes) + : query_{std::move(query)}, + documents_{std::move(documents)}, + old_documents_{std::move(old_documents)}, + document_changes_{std::move(document_changes)}, + mutated_keys_{std::move(mutated_keys)}, + from_cache_{from_cache}, + sync_state_changed_{sync_state_changed}, + excludes_metadata_changes_{excludes_metadata_changes} { +} + +ViewSnapshot ViewSnapshot::FromInitialDocuments( + Query query, + DocumentSet documents, + DocumentKeySet mutated_keys, + bool from_cache, + bool excludes_metadata_changes) { + std::vector view_changes; + for (const Document& doc : documents) { + view_changes.emplace_back(doc, DocumentViewChange::Type::Added); + } + + DocumentSet old_documents(query.Comparator()); + return ViewSnapshot{std::move(query), + documents, + old_documents, + std::move(view_changes), + std::move(mutated_keys), + from_cache, + /*sync_state_changed=*/true, + excludes_metadata_changes}; +} + +const Query& ViewSnapshot::query() const { + return query_; +} + +std::string ViewSnapshot::ToString() const { + return StringFormat( + "", + query_.ToString(), documents_.ToString(), old_documents_.ToString(), + util::ToString(document_changes()), from_cache(), mutated_keys().size(), + sync_state_changed(), excludes_metadata_changes()); +} + +std::ostream& operator<<(std::ostream& out, const ViewSnapshot& value) { + return out << value.ToString(); +} + +size_t ViewSnapshot::Hash() const { + // Note: We are omitting `mutated_keys_` from the hash, since we don't have a + // straightforward way to compute its hash value. Since `ViewSnapshot` is + // currently not stored in any dictionaries, this has no side effects. + + return util::Hash(query(), documents(), old_documents(), document_changes(), + from_cache(), sync_state_changed(), + excludes_metadata_changes()); +} + +bool operator==(const ViewSnapshot& lhs, const ViewSnapshot& rhs) { + return lhs.query() == rhs.query() && lhs.documents() == rhs.documents() && + lhs.old_documents() == rhs.old_documents() && + lhs.document_changes() == rhs.document_changes() && + lhs.from_cache() == rhs.from_cache() && + lhs.mutated_keys() == rhs.mutated_keys() && + lhs.sync_state_changed() == rhs.sync_state_changed() && + lhs.excludes_metadata_changes() == rhs.excludes_metadata_changes(); +} + +} // namespace core +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view_snapshot.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view_snapshot.h index 5e4c7de..bd088c4 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view_snapshot.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view_snapshot.h @@ -17,10 +17,6 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_VIEW_SNAPSHOT_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_VIEW_SNAPSHOT_H_ -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - #include #include #include @@ -29,17 +25,14 @@ #include #include "Firestore/core/src/firebase/firestore/core/event_listener.h" +#include "Firestore/core/src/firebase/firestore/core/query.h" #include "Firestore/core/src/firebase/firestore/immutable/sorted_map.h" +#include "Firestore/core/src/firebase/firestore/model/document.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/document_set.h" #include "Firestore/core/src/firebase/firestore/util/statusor.h" -NS_ASSUME_NONNULL_BEGIN - -@class FSTDocument; -@class FSTQuery; - namespace firebase { namespace firestore { namespace core { @@ -52,17 +45,13 @@ class DocumentViewChange { * NOTE: We sort document changes by their type, so the ordering of this enum * is significant. */ - enum class Type { kRemoved = 0, kAdded, kModified, kMetadata }; + enum class Type { Removed = 0, Added, Modified, Metadata }; DocumentViewChange() = default; - DocumentViewChange(FSTDocument* document, Type type) - : document_{document}, type_{type} { - } + DocumentViewChange(model::Document document, Type type); - FSTDocument* document() const { - return document_; - } + const model::Document& document() const; DocumentViewChange::Type type() const { return type_; } @@ -71,7 +60,7 @@ class DocumentViewChange { size_t Hash() const; private: - FSTDocument* document_ = nullptr; + model::Document document_; Type type_{}; }; @@ -111,7 +100,7 @@ class ViewSnapshot { using Listener = std::unique_ptr>; using SharedListener = std::shared_ptr>; - ViewSnapshot(FSTQuery* query, + ViewSnapshot(Query query, model::DocumentSet documents, model::DocumentSet old_documents, std::vector document_changes, @@ -124,16 +113,14 @@ class ViewSnapshot { * Returns a view snapshot as if all documents in the snapshot were * added. */ - static ViewSnapshot FromInitialDocuments(FSTQuery* query, + static ViewSnapshot FromInitialDocuments(Query query, model::DocumentSet documents, model::DocumentKeySet mutated_keys, bool from_cache, bool excludes_metadata_changes); /** The query this view is tracking the results for. */ - FSTQuery* query() const { - return query_; - } + const Query& query() const; /** The documents currently known to be results of the query. */ const model::DocumentSet& documents() const { @@ -180,7 +167,7 @@ class ViewSnapshot { size_t Hash() const; private: - FSTQuery* query_ = nil; + Query query_; model::DocumentSet documents_; model::DocumentSet old_documents_; @@ -198,6 +185,4 @@ bool operator==(const ViewSnapshot& lhs, const ViewSnapshot& rhs); } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_VIEW_SNAPSHOT_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view_snapshot.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view_snapshot.mm deleted file mode 100644 index 6663063..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/view_snapshot.mm +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" - -#include - -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Model/FSTDocument.h" - -#include "Firestore/core/src/firebase/firestore/model/document_set.h" -#include "Firestore/core/src/firebase/firestore/util/hashing.h" -#include "Firestore/core/src/firebase/firestore/util/objc_compatibility.h" -#include "Firestore/core/src/firebase/firestore/util/string_format.h" -#include "Firestore/core/src/firebase/firestore/util/to_string.h" - -namespace firebase { -namespace firestore { -namespace core { - -namespace objc = util::objc; -using model::DocumentKey; -using model::DocumentKeySet; -using model::DocumentSet; -using util::StringFormat; - -// DocumentViewChange - -std::string DocumentViewChange::ToString() const { - return StringFormat("", - util::ToString(document()), type()); -} - -size_t DocumentViewChange::Hash() const { - size_t document_hash = static_cast([document() hash]); - return util::Hash(document_hash, static_cast(type())); -} - -bool operator==(const DocumentViewChange& lhs, const DocumentViewChange& rhs) { - return objc::Equals(lhs.document(), rhs.document()) && - lhs.type() == rhs.type(); -} - -// DocumentViewChangeSet - -void DocumentViewChangeSet::AddChange(DocumentViewChange&& change) { - const DocumentKey& key = change.document().key; - auto old_change_iter = change_map_.find(key); - if (old_change_iter == change_map_.end()) { - change_map_ = change_map_.insert(key, change); - return; - } - - const DocumentViewChange& old = old_change_iter->second; - DocumentViewChange::Type old_type = old.type(); - DocumentViewChange::Type new_type = change.type(); - - // Merge the new change with the existing change. - if (new_type != DocumentViewChange::Type::kAdded && - old_type == DocumentViewChange::Type::kMetadata) { - change_map_ = change_map_.insert(key, change); - - } else if (new_type == DocumentViewChange::Type::kMetadata && - old_type != DocumentViewChange::Type::kRemoved) { - DocumentViewChange new_change{change.document(), old_type}; - change_map_ = change_map_.insert(key, new_change); - - } else if (new_type == DocumentViewChange::Type::kModified && - old_type == DocumentViewChange::Type::kModified) { - DocumentViewChange new_change{change.document(), - DocumentViewChange::Type::kModified}; - change_map_ = change_map_.insert(key, new_change); - - } else if (new_type == DocumentViewChange::Type::kModified && - old_type == DocumentViewChange::Type::kAdded) { - DocumentViewChange new_change{change.document(), - DocumentViewChange::Type::kAdded}; - change_map_ = change_map_.insert(key, new_change); - - } else if (new_type == DocumentViewChange::Type::kRemoved && - old_type == DocumentViewChange::Type::kAdded) { - change_map_ = change_map_.erase(key); - - } else if (new_type == DocumentViewChange::Type::kRemoved && - old_type == DocumentViewChange::Type::kModified) { - DocumentViewChange new_change{old.document(), - DocumentViewChange::Type::kRemoved}; - change_map_ = change_map_.insert(key, new_change); - - } else if (new_type == DocumentViewChange::Type::kAdded && - old_type == DocumentViewChange::Type::kRemoved) { - DocumentViewChange new_change{change.document(), - DocumentViewChange::Type::kModified}; - change_map_ = change_map_.insert(key, new_change); - - } else { - // This includes these cases, which don't make sense: - // Added -> Added - // Removed -> Removed - // Modified -> Added - // Removed -> Modified - // Metadata -> Added - // Removed -> Metadata - HARD_FAIL("Unsupported combination of changes: %s after %s", new_type, - old_type); - } -} - -std::vector DocumentViewChangeSet::GetChanges() const { - std::vector changes; - for (const auto& kv : change_map_) { - const DocumentViewChange& change = kv.second; - changes.push_back(change); - } - return changes; -} - -std::string DocumentViewChangeSet::ToString() const { - return util::ToString(change_map_); -} - -// ViewSnapshot - -ViewSnapshot::ViewSnapshot(FSTQuery* query, - DocumentSet documents, - DocumentSet old_documents, - std::vector document_changes, - model::DocumentKeySet mutated_keys, - bool from_cache, - bool sync_state_changed, - bool excludes_metadata_changes) - : query_{query}, - documents_{std::move(documents)}, - old_documents_{std::move(old_documents)}, - document_changes_{std::move(document_changes)}, - mutated_keys_{std::move(mutated_keys)}, - from_cache_{from_cache}, - sync_state_changed_{sync_state_changed}, - excludes_metadata_changes_{excludes_metadata_changes} { -} - -ViewSnapshot ViewSnapshot::FromInitialDocuments( - FSTQuery* query, - DocumentSet documents, - DocumentKeySet mutated_keys, - bool from_cache, - bool excludes_metadata_changes) { - std::vector view_changes; - for (FSTDocument* doc : documents) { - view_changes.emplace_back(doc, DocumentViewChange::Type::kAdded); - } - - return ViewSnapshot{query, documents, - /*old_documents=*/ - DocumentSet{query.comparator}, std::move(view_changes), - std::move(mutated_keys), from_cache, - /*sync_state_changed=*/true, excludes_metadata_changes}; -} - -std::string ViewSnapshot::ToString() const { - return StringFormat( - "", - query(), documents_.ToString(), old_documents_.ToString(), - objc::Description(document_changes()), from_cache(), - mutated_keys().size(), sync_state_changed(), excludes_metadata_changes()); -} - -std::ostream& operator<<(std::ostream& out, const ViewSnapshot& value) { - return out << value.ToString(); -} - -size_t ViewSnapshot::Hash() const { - // Note: We are omitting `mutated_keys_` from the hash, since we don't have a - // straightforward way to compute its hash value. Since `ViewSnapshot` is - // currently not stored in any dictionaries, this has no side effects. - - return util::Hash([query() hash], documents(), old_documents(), - document_changes(), from_cache(), sync_state_changed(), - excludes_metadata_changes()); -} - -bool operator==(const ViewSnapshot& lhs, const ViewSnapshot& rhs) { - return objc::Equals(lhs.query(), rhs.query()) && - lhs.documents() == rhs.documents() && - lhs.old_documents() == rhs.old_documents() && - lhs.document_changes() == rhs.document_changes() && - lhs.from_cache() == rhs.from_cache() && - lhs.mutated_keys() == rhs.mutated_keys() && - lhs.sync_state_changed() == rhs.sync_state_changed() && - lhs.excludes_metadata_changes() == rhs.excludes_metadata_changes(); -} - -} // namespace core -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/geo_point.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/geo_point.cc index 393b8f2..08825da 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/geo_point.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/geo_point.cc @@ -17,15 +17,14 @@ #include "Firestore/core/include/firebase/firestore/geo_point.h" #include +#include #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "absl/strings/str_cat.h" namespace firebase { namespace firestore { -GeoPoint::GeoPoint() : GeoPoint(0, 0) { -} - GeoPoint::GeoPoint(double latitude, double longitude) : latitude_(latitude), longitude_(longitude) { HARD_ASSERT(!std::isnan(latitude) && -90 <= latitude && latitude <= 90, @@ -34,6 +33,15 @@ GeoPoint::GeoPoint(double latitude, double longitude) "Latitude must be in the range of [-180, 180]"); } +std::string GeoPoint::ToString() const { + return absl::StrCat("GeoPoint(latitude=", latitude_, + ", longitude=", longitude_, ")"); +} + +std::ostream& operator<<(std::ostream& out, const GeoPoint& geo_point) { + return out << geo_point.ToString(); +} + bool operator<(const GeoPoint& lhs, const GeoPoint& rhs) { if (lhs.latitude() == rhs.latitude()) { return lhs.longitude() < rhs.longitude(); diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/append_only_list.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/append_only_list.h new file mode 100644 index 0000000..ad59fbd --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/append_only_list.h @@ -0,0 +1,253 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_APPEND_ONLY_LIST_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_APPEND_ONLY_LIST_H_ + +#include +#include +#include +#include +#include + +#include "absl/algorithm/container.h" +#include "absl/base/attributes.h" + +namespace firebase { +namespace firestore { +namespace immutable { + +/** + * An immutable list, optimized for appending. + * + * Each `push_back` creates a new instance and does not modify any that come + * before. If `push_back` is called on the last such instance, it will share + * the backing vector with the prior instance (though the prior instance will + * not perceive any change). + * + * This "chaining" behavior is what makes AppendOnlyList efficient, but it only + * applies when applied to the last link in the chain. When applied any instance + * that is not at the end, most operations will copy instead of chaining. + * + * Iterators over an AppendOnlyList are never invalidated. + */ +template +class AppendOnlyList { + public: + using iterator = const T*; + using const_iterator = const T*; + using value_type = T; + + AppendOnlyList() = default; + + AppendOnlyList(std::initializer_list initializer_list) + : contents_(std::make_shared>(initializer_list)), + size_(initializer_list.size()) { + } + + /** + * Returns a new AppendOnlyList that has reserved the given capacity in its + * backing vector, without actually lengthening the chain. + * + * This has a similar effect to std::vector::reserve, except that *this is + * not actually modified. Successive `push_back` operations until `size()` + * is equal to `capacity` are guaranteed to be O(1). + * + * Note that if this instance is not the end of the chain, then this forces + * a copy. + */ + ABSL_MUST_USE_RESULT AppendOnlyList reserve(size_t capacity) const { + if (capacity <= size_) { + return *this; + } + + // Create a the underlying vector with capacity reserved, but return the + // result with the current size. Reserving does not actually append anything + // to the underlying vector so size() shouldn't change. + std::shared_ptr> new_contents = PrepareForAppend(capacity); + return AppendOnlyList(std::move(new_contents), size_); + } + + /** + * Creates a new AppendOnlyList with the given value appended to the end. + * + * Each `push_back` creates a new instance and appears not to modify any that + * come. If `push_back` is called on the last instance in a chain, it will + * share the backing vector with the prior instance. + * + * If `push_back` is called when this instance isn't the last instance in the + * chain, it will make a copy of all preceding elements in the chain and + * return a new chain suitable for further chained `push_back` operations. + */ + ABSL_MUST_USE_RESULT AppendOnlyList push_back(const T& value) const { + size_t new_size = size_ + 1; + std::shared_ptr> new_contents = PrepareForAppend(new_size); + + new_contents->push_back(value); + return AppendOnlyList(std::move(new_contents), new_size); + } + + /** + * Creates a new AppendOnlyList with the given value appended to the end. + * + * @see `push_back(const T&)` for detailed discussion. + */ + ABSL_MUST_USE_RESULT AppendOnlyList push_back(T&& value) const { + size_t new_size = size_ + 1; + std::shared_ptr> new_contents = PrepareForAppend(new_size); + + new_contents->push_back(std::move(value)); + return AppendOnlyList(std::move(new_contents), new_size); + } + + /** + * Creates a new AppendOnlyList constructing a new value appended to the end. + * + * @see `push_back(const T&)` for detailed discussion. + */ + template + ABSL_MUST_USE_RESULT AppendOnlyList emplace_back(Args&&... args) const { + size_t new_size = size_ + 1; + std::shared_ptr> new_contents = PrepareForAppend(new_size); + + new_contents->emplace_back(std::forward(args)...); + return AppendOnlyList(std::move(new_contents), new_size); + } + + /** + * Creates a new AppendOnlyList with the final link in the chain removed. + * + * Note that the element isn't actually removed from the backing vector and + * it still constitutes the end of the chain. This means that any `push_back` + * on the resulting AppendOnlyList will result in a full copy. + * + * Calling pop_back() on an empty AppendOnlyList returns an empty + * AppendOnlyList. + */ + ABSL_MUST_USE_RESULT AppendOnlyList pop_back() const { + if (size_ <= 1) { + return AppendOnlyList(nullptr, 0); + } + + return AppendOnlyList(contents_, size_ - 1); + } + + size_t size() const { + return size_; + } + + size_t capacity() const { + return contents_ ? contents_->capacity() : 0; + } + + bool empty() const { + return size_ == 0; + } + + /** + * Returns an iterator to the beginning of the list. Iterators are never + * invalidated (so long as the container itself is valid). + */ + const_iterator begin() const { + if (size_ == 0) { + return nullptr; + } else { + return contents_->data(); + } + } + + /** + * Returns an iterator that points to one past the end of the list. Iterators + * are never invalidated (so long as the container itself is valid). + */ + const_iterator end() const { + if (size_ == 0) { + return nullptr; + } else { + return contents_->data() + size_; + } + } + + /** + * Returns the first element of the list. Only valid when the list is not + * empty. + */ + const T& front() const { + return *begin(); + } + + /** + * Returns the last element of the list. Only valid when the list is not + * empty. + */ + const T& back() const { + return *(end() - 1); + } + + const T& operator[](size_t pos) const { + return (*contents_)[pos]; + } + + friend bool operator==(const AppendOnlyList& lhs, const AppendOnlyList& rhs) { + return absl::c_equal(lhs, rhs); + } + + friend bool operator!=(const AppendOnlyList& lhs, const AppendOnlyList& rhs) { + return !(lhs == rhs); + } + + private: + AppendOnlyList(std::shared_ptr> contents, size_t size) + : contents_(std::move(contents)), size_(size) { + } + + std::shared_ptr> PrepareForAppend(size_t new_size) const { + if (contents_ && size_ == contents_->size() && + new_size <= contents_->capacity()) { + // If there's an existing vector, this instance points to the end, and + // can already accommodate what's required, there's nothing to do. + return contents_; + } + + size_t min_capacity = new_size; + if (contents_) { + // if contents_->capacity() * 2 overflows, min_capacity will be larger. + min_capacity = std::max(min_capacity, contents_->capacity() * 2); + } + + // min_capacity will be larger than the existing contents of this list so + // reserve that capacity copying in the current values. Copying from this + // and then reserving would cause two allocations, the first for exactly + // the current size and then another for min_capacity. + auto new_contents = std::make_shared>(); + new_contents->reserve(min_capacity); + new_contents->insert(new_contents->begin(), begin(), end()); + return new_contents; + } + + // A shared vector. Sequential push_back operations will share the vector. May + // be nullptr when size_ == 0, but is not required to be null. + std::shared_ptr> contents_; + + // size_ is not shared. + size_t size_ = 0; +}; + +} // namespace immutable +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_APPEND_ONLY_LIST_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h index 1a7076d..0e9bafc 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h @@ -26,7 +26,6 @@ #include #include "Firestore/core/src/firebase/firestore/immutable/keys_view.h" -#include "Firestore/core/src/firebase/firestore/immutable/map_entry.h" #include "Firestore/core/src/firebase/firestore/immutable/sorted_container.h" #include "Firestore/core/src/firebase/firestore/util/comparison.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" @@ -124,8 +123,6 @@ class FixedArray { template > class ArraySortedMap : public SortedMapBase { public: - using key_comparator_type = KeyComparator; - /** * The type of the entries stored in the map. */ @@ -144,7 +141,7 @@ class ArraySortedMap : public SortedMapBase { * Creates an empty ArraySortedMap. */ explicit ArraySortedMap(const C& comparator = C()) - : array_{EmptyArray()}, key_comparator_{comparator} { + : array_{EmptyArray()}, comparator_{comparator} { } /** @@ -152,7 +149,7 @@ class ArraySortedMap : public SortedMapBase { */ ArraySortedMap(std::initializer_list entries, const C& comparator = C()) - : array_{SortedArray(entries, comparator)}, key_comparator_{comparator} { + : array_{SortedArray(entries, comparator)}, comparator_{comparator} { } /** Returns true if the map contains no elements. */ @@ -166,7 +163,7 @@ class ArraySortedMap : public SortedMapBase { } const C& comparator() const { - return key_comparator_.comparator(); + return comparator_; } /** @@ -185,7 +182,8 @@ class ArraySortedMap : public SortedMapBase { if (pos != current_end) { // lower_bound found an entry where pos->first >= pair.first. Reversing // the argument order here tests pair.first < pos->first. - replacing_entry = !key_comparator_(key, *pos); + auto cmp = comparator_.Compare(key, pos->first); + replacing_entry = cmp == util::ComparisonResult::Same; if (replacing_entry && value == pos->second) { return *this; } @@ -241,13 +239,9 @@ class ArraySortedMap : public SortedMapBase { * not found. */ const_iterator find(const K& key) const { - const_iterator not_found = end(); - const_iterator bound = lower_bound(key); - if (bound != not_found && !key_comparator_(key, *bound)) { - return bound; - } else { - return not_found; - } + return std::find_if(begin(), end(), [&](const std::pair& kv) { + return util::Same(comparator_.Compare(key, kv.first)); + }); } /** @@ -271,7 +265,10 @@ class ArraySortedMap : public SortedMapBase { * requested key. */ const_iterator lower_bound(const K& key) const { - return std::lower_bound(begin(), end(), key, key_comparator_); + return std::lower_bound( + begin(), end(), key, [&](const std::pair& el, const K& key) { + return util::Ascending(comparator_.Compare(el.first, key)); + }); } const_iterator min() const { @@ -337,24 +334,24 @@ class ArraySortedMap : public SortedMapBase { static array_pointer SortedArray(std::initializer_list entries, const C& comparator) { std::vector sorted{entries.begin(), entries.end()}; - std::sort(sorted.begin(), sorted.end(), - [&comparator](const value_type& lhs, const value_type& rhs) { - return comparator(lhs.first, rhs.first); - }); + std::sort( + sorted.begin(), sorted.end(), + [&comparator](const value_type& lhs, const value_type& rhs) { + return util::Ascending(comparator.Compare(lhs.first, rhs.first)); + }); return std::make_shared(sorted.begin(), sorted.end()); } - ArraySortedMap(const array_pointer& array, - const key_comparator_type& key_comparator) noexcept - : array_{array}, key_comparator_{key_comparator} { + ArraySortedMap(const array_pointer& array, const C& comparator) noexcept + : array_{array}, comparator_{comparator} { } ArraySortedMap wrap(const array_pointer& array) const noexcept { - return ArraySortedMap{array, key_comparator_}; + return ArraySortedMap{array, comparator_}; } array_pointer array_; - key_comparator_type key_comparator_; + C comparator_; }; } // namespace impl diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/keys_view.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/keys_view.h index 6cf04b6..ecce948 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/keys_view.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/keys_view.h @@ -19,6 +19,7 @@ #include +#include "Firestore/core/src/firebase/firestore/util/comparison.h" #include "Firestore/core/src/firebase/firestore/util/iterator_adaptors.h" #include "Firestore/core/src/firebase/firestore/util/range.h" @@ -68,7 +69,7 @@ auto KeysViewIn(const Range& range, // Forward iterators can't ever reach the end if the end is behind the start: // they just keep incrementing until address space runs out. Adjust the range // accordingly. - bool empty_range = !comparator(start_key, end_key); + bool empty_range = !util::Ascending(comparator.Compare(start_key, end_key)); if (empty_range) { return MakeKeysRange(std::end(range), std::end(range)); } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/llrb_node.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/llrb_node.h index 0046580..8c44475 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/llrb_node.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/llrb_node.h @@ -22,6 +22,7 @@ #include "Firestore/core/src/firebase/firestore/immutable/llrb_node_iterator.h" #include "Firestore/core/src/firebase/firestore/immutable/sorted_container.h" +#include "Firestore/core/src/firebase/firestore/util/comparison.h" namespace firebase { namespace firestore { @@ -263,21 +264,18 @@ LlrbNode LlrbNode::InnerInsert(const K& key, LlrbNode result = Clone(); const K& this_key = this->key(); - bool descending = comparator(key, this_key); - if (descending) { + util::ComparisonResult cmp = comparator.Compare(this_key, key); + if (cmp == util::ComparisonResult::Descending) { result.set_left(result.left().InnerInsert(key, value, comparator)); result.FixUp(); - } else { - bool ascending = comparator(this_key, key); - if (ascending) { - result.set_right(result.right().InnerInsert(key, value, comparator)); - result.FixUp(); + } else if (cmp == util::ComparisonResult::Ascending) { + result.set_right(result.right().InnerInsert(key, value, comparator)); + result.FixUp(); - } else { - // keys are equal so update the value. - result.set_value(value); - } + } else { + // keys are equal so update the value. + result.set_value(value); } return result; } @@ -302,8 +300,7 @@ LlrbNode LlrbNode::InnerErase(const K& key, LlrbNode n = Clone(); - bool descending = comparator(key, n.key()); - if (descending) { + if (util::Ascending(comparator.Compare(key, n.key()))) { if (!n.left().empty() && !n.left().red() && !n.left().left().red()) { n.MoveRedLeft(); } @@ -318,8 +315,7 @@ LlrbNode LlrbNode::InnerErase(const K& key, n.MoveRedRight(); } - if (util::Compare(key, n.key(), comparator) == - util::ComparisonResult::Same) { + if (util::Same(comparator.Compare(key, n.key()))) { if (n.right().empty()) { return LlrbNode{}; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/llrb_node_iterator.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/llrb_node_iterator.h index 3092678..b379656 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/llrb_node_iterator.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/llrb_node_iterator.h @@ -21,7 +21,6 @@ #include #include -#include "Firestore/core/src/firebase/firestore/immutable/llrb_node.h" #include "Firestore/core/src/firebase/firestore/util/comparison.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" @@ -117,7 +116,7 @@ class LlrbNodeIterator { const node_type* node = root; while (!node->empty()) { - util::ComparisonResult cmp = util::Compare(key, node->key(), comparator); + util::ComparisonResult cmp = comparator.Compare(key, node->key()); if (cmp == util::ComparisonResult::Same) { // Found exactly what we're looking for so we're done. stack.push(node); diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/map_entry.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/map_entry.h deleted file mode 100644 index b2b3c97..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/map_entry.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_MAP_ENTRY_H_ -#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_MAP_ENTRY_H_ - -#include -#include - -namespace firebase { -namespace firestore { -namespace immutable { - -/** - * Compares two keys out of a map entry. - * - * @tparam K The type of the first value in the pair. - * @tparam V The type of the second value in the pair. - * @tparam C The comparator for use for values of type K - */ -template > -struct KeyComparator { - using pair_type = std::pair; - - explicit KeyComparator(const C& comparator = C()) - : key_comparator_(comparator) { - } - - bool operator()(const K& lhs, const pair_type& rhs) const noexcept { - return key_comparator_(lhs, rhs.first); - } - - bool operator()(const pair_type& lhs, const K& rhs) const noexcept { - return key_comparator_(lhs.first, rhs); - } - - bool operator()(const pair_type& lhs, const pair_type& rhs) const noexcept { - return key_comparator_(lhs.first, rhs.first); - } - - const C& comparator() const { - return key_comparator_; - } - - private: - C key_comparator_; -}; - -} // namespace immutable -} // namespace firestore -} // namespace firebase - -#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_MAP_ENTRY_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/sorted_map.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/sorted_map.h index f3c998b..50580c4 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/sorted_map.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/sorted_map.h @@ -26,6 +26,7 @@ #include "Firestore/core/src/firebase/firestore/immutable/tree_sorted_map.h" #include "Firestore/core/src/firebase/firestore/util/comparison.h" #include "absl/base/attributes.h" +#include "absl/types/optional.h" namespace firebase { namespace firestore { @@ -161,6 +162,16 @@ class SortedMap : public SortedMapBase { UNREACHABLE(); } + const C& comparator() const { + switch (tag_) { + case Tag::Array: + return array_.comparator(); + case Tag::Tree: + return tree_.comparator(); + } + UNREACHABLE(); + } + /** * Creates a new map identical to this one, but with a key-value pair added or * updated. @@ -254,6 +265,15 @@ class SortedMap : public SortedMapBase { UNREACHABLE(); } + absl::optional get(const K& key) const { + auto found = find(key); + if (found != end()) { + return found->second; + } else { + return absl::nullopt; + } + } + /** * Finds the first entry in the map containing a key greater than or equal * to the given key. @@ -355,16 +375,6 @@ class SortedMap : public SortedMapBase { : tag_{Tag::Tree}, tree_{std::move(tree)} { } - const C& comparator() const { - switch (tag_) { - case Tag::Array: - return array_.comparator(); - case Tag::Tree: - return tree_.comparator(); - } - UNREACHABLE(); - } - enum class Tag { Array, Tree, diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/sorted_map_iterator.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/sorted_map_iterator.h index 20c11a7..264172c 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/sorted_map_iterator.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/sorted_map_iterator.h @@ -60,7 +60,7 @@ class SortedMapIterator { } } - SortedMapIterator(SortedMapIterator&& other) : tag_(other.tag_) { + SortedMapIterator(SortedMapIterator&& other) noexcept : tag_(other.tag_) { switch (tag_) { case Tag::Array: new (&array_iter_) ArrayIter{std::move(other.array_iter_)}; @@ -99,7 +99,7 @@ class SortedMapIterator { return *this; } - SortedMapIterator& operator=(SortedMapIterator&& other) { + SortedMapIterator& operator=(SortedMapIterator&& other) noexcept { if (tag_ == other.tag_) { switch (tag_) { case Tag::Array: diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/sorted_set.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/sorted_set.h index 36b6e16..7907a3b 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/sorted_set.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/sorted_set.h @@ -23,6 +23,7 @@ #include "Firestore/core/src/firebase/firestore/immutable/sorted_container.h" #include "Firestore/core/src/firebase/firestore/immutable/sorted_map.h" #include "Firestore/core/src/firebase/firestore/util/comparison.h" +#include "Firestore/core/src/firebase/firestore/util/empty.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/hashing.h" #include "absl/base/attributes.h" @@ -31,20 +32,9 @@ namespace firebase { namespace firestore { namespace immutable { -namespace impl { - -// An empty value to associate with keys in the underlying map. -struct Empty { - friend bool operator==(Empty /* left */, Empty /* right */) { - return true; - } -}; - -} // namespace impl - template , - typename V = impl::Empty, + typename V = util::Empty, typename M = SortedMap> class SortedSet : public SortedContainer { public: @@ -77,6 +67,10 @@ class SortedSet : public SortedContainer { return map_.size(); } + const C& comparator() const { + return map_.comparator(); + } + ABSL_MUST_USE_RESULT SortedSet insert(const K& key) const { return SortedSet{map_.insert(key, {})}; } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/tree_sorted_map.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/tree_sorted_map.h index 9a1635c..43a4cc0 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/tree_sorted_map.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/immutable/tree_sorted_map.h @@ -25,10 +25,9 @@ #include "Firestore/core/src/firebase/firestore/immutable/keys_view.h" #include "Firestore/core/src/firebase/firestore/immutable/llrb_node.h" -#include "Firestore/core/src/firebase/firestore/immutable/map_entry.h" #include "Firestore/core/src/firebase/firestore/immutable/sorted_container.h" -#include "Firestore/core/src/firebase/firestore/util/comparator_holder.h" #include "Firestore/core/src/firebase/firestore/util/comparison.h" +#include "Firestore/core/src/firebase/firestore/util/compressed_member.h" namespace firebase { namespace firestore { @@ -40,7 +39,9 @@ namespace impl { * methods to efficiently create new maps that are mutations of it. */ template > -class TreeSortedMap : public SortedMapBase, public util::ComparatorHolder { +class TreeSortedMap : public SortedMapBase, private util::CompressedMember { + using ComparatorMember = util::CompressedMember; + public: /** * The type of the entries stored in the map. @@ -58,7 +59,7 @@ class TreeSortedMap : public SortedMapBase, public util::ComparatorHolder { * Creates an empty TreeSortedMap. */ explicit TreeSortedMap(const C& comparator = {}) - : util::ComparatorHolder{comparator} { + : ComparatorMember{comparator} { } /** @@ -87,6 +88,10 @@ class TreeSortedMap : public SortedMapBase, public util::ComparatorHolder { return root_; } + const C& comparator() const { + return ComparatorMember::get(); + } + /** * Creates a new map identical to this one, but with a key-value pair added or * updated. @@ -117,7 +122,7 @@ class TreeSortedMap : public SortedMapBase, public util::ComparatorHolder { const C& comparator = this->comparator(); const node_type* node = &root(); while (!node->empty()) { - util::ComparisonResult cmp = util::Compare(key, node->key(), comparator); + util::ComparisonResult cmp = comparator.Compare(key, node->key()); if (cmp == util::ComparisonResult::Same) { return true; } else if (cmp == util::ComparisonResult::Ascending) { @@ -138,7 +143,8 @@ class TreeSortedMap : public SortedMapBase, public util::ComparatorHolder { */ const_iterator find(const K& key) const { const_iterator found = lower_bound(key); - if (!found.is_end() && !this->comparator()(key, found->first)) { + if (!found.is_end() && + util::Same(this->comparator().Compare(key, found->first))) { return found; } else { return end(); @@ -157,7 +163,7 @@ class TreeSortedMap : public SortedMapBase, public util::ComparatorHolder { size_type pruned_nodes = 0; const node_type* node = &root_; while (!node->empty()) { - util::ComparisonResult cmp = util::Compare(key, node->key(), comparator); + util::ComparisonResult cmp = comparator.Compare(key, node->key()); if (cmp == util::ComparisonResult::Same) { return pruned_nodes + node->left().size(); @@ -245,7 +251,7 @@ class TreeSortedMap : public SortedMapBase, public util::ComparatorHolder { private: TreeSortedMap(node_type&& root, const C& comparator) noexcept - : util::ComparatorHolder{comparator}, root_{std::move(root)} { + : ComparatorMember{comparator}, root_{std::move(root)} { } TreeSortedMap Wrap(node_type&& root) noexcept { diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/document_key_reference.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/document_key_reference.cc index 61c1b71..82bdeb2 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/document_key_reference.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/document_key_reference.cc @@ -45,25 +45,21 @@ std::string DocumentKeyReference::ToString() const { } /** Sorts document references by key then ID. */ -bool DocumentKeyReference::ByKey::operator()( +ComparisonResult DocumentKeyReference::ByKey::Compare( const DocumentKeyReference& lhs, const DocumentKeyReference& rhs) const { - util::Comparator key_less; - if (key_less(lhs.key_, rhs.key_)) return true; - if (key_less(rhs.key_, lhs.key_)) return false; + ComparisonResult result = util::Compare(lhs.key_, rhs.key_); + if (!util::Same(result)) return result; - util::Comparator id_less; - return id_less(lhs.ref_id_, rhs.ref_id_); + return util::Compare(lhs.ref_id_, rhs.ref_id_); } /** Sorts document references by ID then key. */ -bool DocumentKeyReference::ById::operator()( +ComparisonResult DocumentKeyReference::ById::Compare( const DocumentKeyReference& lhs, const DocumentKeyReference& rhs) const { - util::Comparator id_less; - if (id_less(lhs.ref_id_, rhs.ref_id_)) return true; - if (id_less(rhs.ref_id_, lhs.ref_id_)) return false; + ComparisonResult result = util::Compare(lhs.ref_id_, rhs.ref_id_); + if (!util::Same(result)) return result; - util::Comparator key_less; - return key_less(lhs.key_, rhs.key_); + return util::Compare(lhs.key_, rhs.key_); } } // namespace local diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/document_key_reference.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/document_key_reference.h index 257971b..59b1293 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/document_key_reference.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/document_key_reference.h @@ -34,7 +34,7 @@ namespace local { * references. * * A reference can be from either listen targets (identified by their TargetId) - * or mutation batches (identified by their BatchId). See FSTGarbageCollector + * or mutation batches (identified by their BatchId). See GarbageCollector * for more details. * * Not to be confused with FIRDocumentReference. @@ -55,8 +55,8 @@ class DocumentKeyReference { } /** - * The targetId of a referring target or the batchId of a referring mutation - * batch. (Which this is depends upon which FSTReferenceSet this reference is + * The TargetId of a referring target or the BatchId of a referring mutation + * batch. (Which this is depends upon which ReferenceSet this reference is * a part of.) */ int32_t ref_id() const { @@ -71,15 +71,15 @@ class DocumentKeyReference { std::string ToString() const; /** Sorts document references by key then Id. */ - struct ByKey : public util::Comparator { - bool operator()(const DocumentKeyReference& lhs, - const DocumentKeyReference& rhs) const; + struct ByKey { + util::ComparisonResult Compare(const DocumentKeyReference& lhs, + const DocumentKeyReference& rhs) const; }; /** Sorts document references by Id then key. */ - struct ById : public util::Comparator { - bool operator()(const DocumentKeyReference& lhs, - const DocumentKeyReference& rhs) const; + struct ById { + util::ComparisonResult Compare(const DocumentKeyReference& lhs, + const DocumentKeyReference& rhs) const; }; private: diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/index_free_query_engine.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/index_free_query_engine.cc new file mode 100644 index 0000000..b8568fb --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/index_free_query_engine.cc @@ -0,0 +1,150 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/index_free_query_engine.h" + +#include + +#include "Firestore/core/src/firebase/firestore/core/query.h" +#include "Firestore/core/src/firebase/firestore/core/target.h" +#include "Firestore/core/src/firebase/firestore/local/local_documents_view.h" +#include "Firestore/core/src/firebase/firestore/model/document.h" +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" + +namespace firebase { +namespace firestore { +namespace local { + +using core::LimitType; +using core::Query; +using core::Target; +using model::Document; +using model::DocumentKeySet; +using model::DocumentMap; +using model::DocumentSet; +using model::MaybeDocument; +using model::MaybeDocumentMap; +using model::SnapshotVersion; + +DocumentMap IndexFreeQueryEngine::GetDocumentsMatchingQuery( + const Query& query, + const SnapshotVersion& last_limbo_free_snapshot_version, + const DocumentKeySet& remote_keys) { + HARD_ASSERT(local_documents_view_, "SetLocalDocumentsView() not called"); + + // Queries that match all documents don't benefit from using IndexFreeQueries. + // It is more efficient to scan all documents in a collection, rather than to + // perform individual lookups. + if (query.MatchesAllDocuments()) { + return ExecuteFullCollectionScan(query); + } + + // Queries that have never seen a snapshot without limbo free documents should + // also be run as a full collection scan. + if (last_limbo_free_snapshot_version == SnapshotVersion::None()) { + return ExecuteFullCollectionScan(query); + } + + MaybeDocumentMap documents = local_documents_view_->GetDocuments(remote_keys); + DocumentSet previous_results = ApplyQuery(query, documents); + + if (query.limit_type() != LimitType::None && + NeedsRefill(query.limit_type(), previous_results, remote_keys, + last_limbo_free_snapshot_version)) { + return ExecuteFullCollectionScan(query); + } + + LOG_DEBUG("Re-using previous result from %s to execute query: %s", + last_limbo_free_snapshot_version.ToString(), query.ToString()); + + // Retrieve all results for documents that were updated since the last + // remote snapshot that did not contain any Limbo documents. + DocumentMap updated_results = + local_documents_view_->GetDocumentsMatchingQuery( + query, last_limbo_free_snapshot_version); + + // We merge `previous_results` into `update_results`, since `update_results` + // is already a DocumentMap. If a document is contained in both lists, then + // its contents are the same. + for (const Document& result : previous_results) { + updated_results = updated_results.insert(result.key(), result); + } + + return updated_results; +} + +DocumentSet IndexFreeQueryEngine::ApplyQuery( + const Query& query, const MaybeDocumentMap& documents) const { + // Sort the documents and re-apply the query filter since previously matching + // documents do not necessarily still match the query. + DocumentSet query_results(query.Comparator()); + + for (const auto& document_entry : documents) { + const MaybeDocument& maybe_doc = document_entry.second; + if (maybe_doc.is_document()) { + Document doc(maybe_doc); + if (query.Matches(doc)) { + query_results = query_results.insert(std::move(doc)); + } + } + } + return query_results; +} + +bool IndexFreeQueryEngine::NeedsRefill( + LimitType limit_type, + const DocumentSet& sorted_previous_results, + const DocumentKeySet& remote_keys, + const SnapshotVersion& limbo_free_snapshot_version) const { + // The query needs to be refilled if a previously matching document no longer + // matches. + if (remote_keys.size() != sorted_previous_results.size()) { + return true; + } + + // Limit queries are not eligible for index-free query execution if there is a + // potential that an older document from cache now sorts before a document + // that was previously part of the limit. + // This, however, can only happen if the document at the edge of the limit + // goes out of limit. If a document that is not the limit boundary sorts + // differently, the boundary of the limit itself did not change and documents + // from cache will continue to be "rejected" by this boundary. Therefore, we + // can ignore any modifications that don't affect the last document. + absl::optional document_at_limit_edge = + (limit_type == LimitType::First) + ? sorted_previous_results.GetLastDocument() + : sorted_previous_results.GetFirstDocument(); + if (!document_at_limit_edge) { + // We don't need to refill the query if there were already no documents. + return false; + } + return document_at_limit_edge->has_pending_writes() || + document_at_limit_edge->version() > limbo_free_snapshot_version; +} + +DocumentMap IndexFreeQueryEngine::ExecuteFullCollectionScan( + const Query& query) { + LOG_DEBUG("Using full collection scan to execute query: %s", + query.ToString()); + return local_documents_view_->GetDocumentsMatchingQuery( + query, SnapshotVersion::None()); +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/index_free_query_engine.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/index_free_query_engine.h new file mode 100644 index 0000000..f3acb1d --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/index_free_query_engine.h @@ -0,0 +1,100 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_INDEX_FREE_QUERY_ENGINE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_INDEX_FREE_QUERY_ENGINE_H_ + +#include "Firestore/core/src/firebase/firestore/local/query_engine.h" + +#include "Firestore/core/src/firebase/firestore/core/query.h" +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/document_map.h" + +namespace firebase { +namespace firestore { + +namespace model { + +class DocumentSet; + +} // namespace model + +namespace local { + +/** + * A query engine that takes advantage of the target document mapping in the + * TargetCache. The IndexFreeQueryEngine optimizes query execution by only + * reading the documents that previously matched a query plus any documents that + * were edited after the query was last listened to. + * + * There are some cases where Index-Free queries are not guaranteed to + * produce the same results as full collection scans. In these cases, the + * IndexFreeQueryEngine falls back to full query processing. These cases are: + * + * - Limit queries where a document that matched the query previously no + * longer matches the query. + * - Limit queries where a document edit may cause the document to sort below + * another document that is in the local cache. + * - Queries that have never been CURRENT or free of Limbo documents. + */ +class IndexFreeQueryEngine : public QueryEngine { + public: + void SetLocalDocumentsView(LocalDocumentsView* local_documents) override { + local_documents_view_ = local_documents; + } + + model::DocumentMap GetDocumentsMatchingQuery( + const core::Query& query, + const model::SnapshotVersion& last_limbo_free_snapshot_version, + const model::DocumentKeySet& remote_keys) override; + + Type type() const override { + return Type::IndexFree; + } + + private: + /** Applies the query filter and sorting to the provided documents. */ + model::DocumentSet ApplyQuery(const core::Query& query, + const model::MaybeDocumentMap& documents) const; + + /** + * Determines if a limit query needs to be refilled from cache, making it + * ineligible for index-free execution. + * + * @param limit_type The type of limit query for refill calculation. + * @param sorted_previous_results The documents that matched the query when it + * was last synchronized, sorted by the query's comparator. + * @param remote_keys The document keys that matched the query at the last + * snapshot. + * @param limbo_free_snapshot_version The version of the snapshot when the + * query was last synchronized. + */ + bool NeedsRefill( + core::LimitType limit_type, + const model::DocumentSet& sorted_previous_results, + const model::DocumentKeySet& remote_keys, + const model::SnapshotVersion& limbo_free_snapshot_version) const; + + model::DocumentMap ExecuteFullCollectionScan(const core::Query& query); + + LocalDocumentsView* local_documents_view_ = nullptr; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_INDEX_FREE_QUERY_ENGINE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/index_manager.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/index_manager.h index c4bad32..d4958f2 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/index_manager.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/index_manager.h @@ -38,7 +38,7 @@ class IndexManager { } /** - * Creates an index entry mapping the collectionId (last segment of the path) + * Creates an index entry mapping the collection_id (last segment of the path) * to the parent path (either the containing document location or the empty * path for root-level collections). Index entries can be retrieved via * GetCollectionParents(). @@ -50,7 +50,7 @@ class IndexManager { const model::ResourcePath& collection_path) = 0; /** - * Retrieves all parent locations containing the given collectionId, as a set + * Retrieves all parent locations containing the given collection_id, as a set * of paths (each path being either a document location or the empty path for * a root-level collection). */ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_index_manager.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_index_manager.cc new file mode 100644 index 0000000..0e3fe7d --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_index_manager.cc @@ -0,0 +1,76 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/leveldb_index_manager.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/local/leveldb_key.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_persistence.h" +#include "Firestore/core/src/firebase/firestore/local/memory_index_manager.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "absl/strings/match.h" + +namespace firebase { +namespace firestore { +namespace local { + +using model::ResourcePath; + +LevelDbIndexManager::LevelDbIndexManager(LevelDbPersistence* db) : db_(db) { +} + +void LevelDbIndexManager::AddToCollectionParentIndex( + const ResourcePath& collection_path) { + HARD_ASSERT(collection_path.size() % 2 == 1, "Expected a collection path."); + + if (collection_parents_cache_.Add(collection_path)) { + std::string collection_id = collection_path.last_segment(); + ResourcePath parent_path = collection_path.PopLast(); + + std::string key = + LevelDbCollectionParentKey::Key(collection_id, parent_path); + std::string empty_buffer; + db_->current_transaction()->Put(key, empty_buffer); + } +} + +std::vector LevelDbIndexManager::GetCollectionParents( + const std::string& collection_id) { + std::vector results; + + auto index_iterator = db_->current_transaction()->NewIterator(); + std::string index_prefix = + LevelDbCollectionParentKey::KeyPrefix(collection_id); + LevelDbCollectionParentKey row_key; + for (index_iterator->Seek(index_prefix); index_iterator->Valid(); + index_iterator->Next()) { + if (!absl::StartsWith(index_iterator->key(), index_prefix) || + !row_key.Decode(index_iterator->key()) || + row_key.collection_id() != collection_id) { + break; + } + + results.push_back(row_key.parent()); + } + return results; +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_index_manager.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_index_manager.h index 3b44cbd..7e6ff37 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_index_manager.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_index_manager.h @@ -17,10 +17,6 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_INDEX_MANAGER_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_INDEX_MANAGER_H_ -#if !defined(__OBJC__) -#error "For now, this file must only be included by ObjC source files." -#endif // !defined(__OBJC__) - #include #include @@ -28,18 +24,16 @@ #include "Firestore/core/src/firebase/firestore/local/memory_index_manager.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" -@class FSTLevelDB; - -NS_ASSUME_NONNULL_BEGIN - namespace firebase { namespace firestore { namespace local { +class LevelDbPersistence; + /** A persisted implementation of IndexManager. */ class LevelDbIndexManager : public IndexManager { public: - explicit LevelDbIndexManager(FSTLevelDB* db); + explicit LevelDbIndexManager(LevelDbPersistence* db); void AddToCollectionParentIndex( const model::ResourcePath& collection_path) override; @@ -48,8 +42,8 @@ class LevelDbIndexManager : public IndexManager { const std::string& collection_id) override; private: - // This instance is owned by FSTLevelDB; avoid a retain cycle. - __weak FSTLevelDB* db_; + // The LevelDbIndexManager is owned by LevelDbPersistence. + LevelDbPersistence* db_; /** * An in-memory copy of the index entries we've already written since the SDK @@ -65,6 +59,4 @@ class LevelDbIndexManager : public IndexManager { } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_INDEX_MANAGER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_index_manager.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_index_manager.mm deleted file mode 100644 index ef7773b..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_index_manager.mm +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/local/leveldb_index_manager.h" - -#include -#include - -#include "Firestore/core/src/firebase/firestore/local/leveldb_key.h" -#include "Firestore/core/src/firebase/firestore/local/memory_index_manager.h" -#include "Firestore/core/src/firebase/firestore/model/resource_path.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "absl/strings/match.h" - -#import "Firestore/Source/Local/FSTLevelDB.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace firebase { -namespace firestore { -namespace local { - -using model::ResourcePath; - -LevelDbIndexManager::LevelDbIndexManager(FSTLevelDB* db) : db_(db) { -} - -void LevelDbIndexManager::AddToCollectionParentIndex( - const ResourcePath& collection_path) { - HARD_ASSERT(collection_path.size() % 2 == 1, "Expected a collection path."); - - if (collection_parents_cache_.Add(collection_path)) { - std::string collection_id = collection_path.last_segment(); - ResourcePath parent_path = collection_path.PopLast(); - - std::string key = - LevelDbCollectionParentKey::Key(collection_id, parent_path); - std::string empty_buffer; - db_.currentTransaction->Put(key, empty_buffer); - } -} - -std::vector LevelDbIndexManager::GetCollectionParents( - const std::string& collection_id) { - std::vector results; - - auto index_iterator = db_.currentTransaction->NewIterator(); - std::string index_prefix = - LevelDbCollectionParentKey::KeyPrefix(collection_id); - LevelDbCollectionParentKey row_key; - for (index_iterator->Seek(index_prefix); index_iterator->Valid(); - index_iterator->Next()) { - if (!absl::StartsWith(index_iterator->key(), index_prefix) || - !row_key.Decode(index_iterator->key()) || - row_key.collection_id() != collection_id) { - break; - } - - results.push_back(row_key.parent()); - } - return results; -} - -} // namespace local -} // namespace firestore -} // namespace firebase - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_key.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_key.cc index e0f6328..ed73466 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_key.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_key.cc @@ -46,6 +46,7 @@ const char* kTargetDocumentsTable = "target_document"; const char* kDocumentTargetsTable = "document_target"; const char* kRemoteDocumentsTable = "remote_document"; const char* kCollectionParentsTable = "collection_parent"; +const char* kRemoteDocumentReadTimeTable = "remote_document_read_time"; /** * Labels for the components of keys. These serve to make keys self-describing. @@ -96,6 +97,15 @@ enum ComponentLabel { */ CollectionId = 14, + /** + * A component containing a standalone document ID (as used by the + * remote_document_read_time table). + */ + DocumentId = 15, + + /** A component containing a snapshot version. */ + SnapshotVersion = 16, + /** * A path segment describes just a single segment in a resource path. Path * segments that occur sequentially in a key represent successive segments in @@ -170,6 +180,16 @@ class Reader { return ReadLabeledString(ComponentLabel::CollectionId); } + std::string ReadDocumentId() { + return ReadLabeledString(ComponentLabel::DocumentId); + } + + /** + * Reads a snapshot version, encoded as a component label and a pair of + * seconds (int64) and nanoseconds (int32). + */ + model::SnapshotVersion ReadSnapshotVersion(); + /** * Reads component labels and strings from the key until it finds a component * label other than ComponentLabel::PathSegment (or the key is exhausted). @@ -322,6 +342,18 @@ class Reader { return ReadInt32(); } + /** + * Reads a signed number from the key. + * + * If the read is unsuccessful, returns 0 and fails the Reader. + * + * Otherwise, returns the number and advances the Reader to the next unread + * byte. + */ + int64_t ReadInt64() { + return ReadSignedNumIncreasing(); + } + /** * Reads a component label and a string from the key verifies that the label * matches the expected_label. @@ -408,6 +440,17 @@ DocumentKey Reader::ReadDocumentKey() { return DocumentKey{}; } +model::SnapshotVersion Reader::ReadSnapshotVersion() { + if (!ReadComponentLabelMatching(ComponentLabel::SnapshotVersion)) { + Fail(); + } + + int64_t seconds = ReadInt64(); + int32_t nanos = ReadInt32(); + + return model::SnapshotVersion({seconds, nanos}); +} + /** * Returns a base64-encoded string for an invalid key, used for debug-friendly * description text. @@ -485,6 +528,18 @@ std::string Reader::Describe() { absl::StrAppend(&description, " collection_id=", collection_id); } + } else if (label == ComponentLabel::DocumentId) { + std::string document_id = ReadDocumentId(); + if (ok_) { + absl::StrAppend(&description, " document_id=", document_id); + } + + } else if (label == ComponentLabel::SnapshotVersion) { + model::SnapshotVersion snapshot_version = ReadSnapshotVersion(); + if (ok_) { + absl::StrAppend(&description, + " snapshot_version=", snapshot_version.ToString()); + } } else { absl::StrAppend(&description, " unknown label=", static_cast(label)); Fail(); @@ -536,6 +591,18 @@ class Writer { WriteLabeledString(ComponentLabel::CollectionId, collection_id); } + void WriteDocumentId(absl::string_view document_id) { + WriteLabeledString(ComponentLabel::DocumentId, document_id); + } + + void WriteSnapshotVersion(model::SnapshotVersion snapshot_version) { + WriteComponentLabel(ComponentLabel::SnapshotVersion); + OrderedCode::WriteSignedNumIncreasing( + &dest_, snapshot_version.timestamp().seconds()); + OrderedCode::WriteSignedNumIncreasing( + &dest_, snapshot_version.timestamp().nanoseconds()); + } + /** * For each segment in the given resource path writes a * ComponentLabel::PathSegment component label and a string containing the @@ -915,6 +982,39 @@ bool LevelDbCollectionParentKey::Decode(absl::string_view key) { return reader.ok(); } +std::string LevelDbRemoteDocumentReadTimeKey::KeyPrefix( + const model::ResourcePath& collection_path, + model::SnapshotVersion read_time) { + Writer writer; + writer.WriteTableName(kRemoteDocumentReadTimeTable); + writer.WriteResourcePath(collection_path); + writer.WriteSnapshotVersion(read_time); + return writer.result(); +} + +std::string LevelDbRemoteDocumentReadTimeKey::Key( + const model::ResourcePath& collection_path, + model::SnapshotVersion read_time, + absl::string_view document_id) { + Writer writer; + writer.WriteTableName(kRemoteDocumentReadTimeTable); + writer.WriteResourcePath(collection_path); + writer.WriteSnapshotVersion(read_time); + writer.WriteDocumentId(document_id); + writer.WriteTerminator(); + return writer.result(); +} + +bool LevelDbRemoteDocumentReadTimeKey::Decode(absl::string_view key) { + Reader reader{key}; + reader.ReadTableNameMatching(kRemoteDocumentReadTimeTable); + collection_path_ = reader.ReadResourcePath(); + read_time_ = reader.ReadSnapshotVersion(); + document_id_ = reader.ReadDocumentId(); + reader.ReadTerminator(); + return reader.ok(); +} + } // namespace local } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_key.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_key.h index 505cb87..43117a6 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_key.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_key.h @@ -20,6 +20,7 @@ #include #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/model/types.h" #include "absl/strings/string_view.h" @@ -82,6 +83,12 @@ namespace local { // - table_name: string = "collection_parent" // - collectionId: string // - parent: ResourcePath +// +// remote_document_read_time: +// - table_name: string = "remote_document_read_time" +// - collection: ResourcePath +// - read_time: SnapshotVersion +// - document_id: string /** * Parses the given key and returns a human readable description of its @@ -140,9 +147,8 @@ class LevelDbMutationKey { } private: - // Deliberately uninitialized: will be assigned in Decode std::string user_id_; - model::BatchId batch_id_; + model::BatchId batch_id_ = model::kBatchIdUnknown; }; /** @@ -209,10 +215,9 @@ class LevelDbDocumentMutationKey { } private: - // Deliberately uninitialized: will be assigned in Decode std::string user_id_; model::DocumentKey document_key_; - model::BatchId batch_id_; + model::BatchId batch_id_ = model::kBatchIdUnknown; }; /** @@ -348,7 +353,7 @@ class LevelDbQueryTargetKey { private: // Deliberately uninitialized: will be assigned in Decode std::string canonical_id_; - model::TargetId target_id_; + model::TargetId target_id_ = 0; }; /** @@ -396,7 +401,7 @@ class LevelDbTargetDocumentKey { private: // Deliberately uninitialized: will be assigned in Decode - model::TargetId target_id_; + model::TargetId target_id_ = 0; model::DocumentKey document_key_; }; @@ -578,6 +583,58 @@ class LevelDbCollectionParentKey { model::ResourcePath parent_; }; +/** + * A key in the remote documents read time table, storing the collection path, + * read time and document ID for each entry. + */ +class LevelDbRemoteDocumentReadTimeKey { + public: + /** + * Creates a key prefix that points just before the first key for the given + * collection_path and read_time. + */ + static std::string KeyPrefix(const model::ResourcePath& collection_path, + model::SnapshotVersion read_time); + + /** + * Creates a key that points to the key for the given collection_path, + * read_time and document_id. + */ + static std::string Key(const model::ResourcePath& collection_path, + model::SnapshotVersion read_time, + absl::string_view document_id); + /** + * Decodes the given complete key, storing the decoded values in this + * instance. + * + * @return true if the key successfully decoded, false otherwise. If false is + * returned, this instance is in an undefined state until the next call to + * `Decode()`. + */ + ABSL_MUST_USE_RESULT + bool Decode(absl::string_view key); + + /** The collection path for this entry. */ + const model::ResourcePath& collection_path() const { + return collection_path_; + } + + /** The read time for for this entry. */ + model::SnapshotVersion read_time() const { + return read_time_; + } + + /** The document ID for this entry. */ + const std::string& document_id() const { + return document_id_; + } + + private: + std::string document_id_; + model::ResourcePath collection_path_; + model::SnapshotVersion read_time_; +}; + } // namespace local } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_lru_reference_delegate.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_lru_reference_delegate.cc new file mode 100644 index 0000000..ccc2601 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_lru_reference_delegate.cc @@ -0,0 +1,189 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/leveldb_lru_reference_delegate.h" + +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/local/leveldb_persistence.h" +#include "Firestore/core/src/firebase/firestore/local/listen_sequence.h" +#include "Firestore/core/src/firebase/firestore/local/reference_set.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" +#include "absl/memory/memory.h" +#include "absl/strings/match.h" + +namespace firebase { +namespace firestore { +namespace local { + +using model::DocumentKey; +using model::ListenSequenceNumber; +using model::ResourcePath; + +LevelDbLruReferenceDelegate::LevelDbLruReferenceDelegate( + LevelDbPersistence* persistence, LruParams lru_params) + : db_(persistence) { + gc_ = absl::make_unique(this, lru_params); +} + +// Explicit default the destructor after all forward declared types have been +// fully declared. +LevelDbLruReferenceDelegate::~LevelDbLruReferenceDelegate() = default; + +void LevelDbLruReferenceDelegate::Start() { + ListenSequenceNumber highest_sequence_number = + db_->target_cache()->highest_listen_sequence_number(); + listen_sequence_ = absl::make_unique(highest_sequence_number); +} + +void LevelDbLruReferenceDelegate::AddInMemoryPins(ReferenceSet* set) { + // We should be able to assert that additional_references_ is nullptr, but + // due to restarts in spec tests it would fail. + additional_references_ = set; +} + +void LevelDbLruReferenceDelegate::AddReference(const DocumentKey& key) { + WriteSentinel(key); +} + +void LevelDbLruReferenceDelegate::RemoveReference(const DocumentKey& key) { + WriteSentinel(key); +} + +void LevelDbLruReferenceDelegate::RemoveMutationReference( + const DocumentKey& key) { + WriteSentinel(key); +} + +void LevelDbLruReferenceDelegate::RemoveTarget(const TargetData& target_data) { + TargetData updated = + target_data.WithSequenceNumber(current_sequence_number()); + db_->target_cache()->UpdateTarget(std::move(updated)); +} + +void LevelDbLruReferenceDelegate::UpdateLimboDocument(const DocumentKey& key) { + WriteSentinel(key); +} + +ListenSequenceNumber LevelDbLruReferenceDelegate::current_sequence_number() + const { + HARD_ASSERT(current_sequence_number_ != kListenSequenceNumberInvalid, + "Asking for a sequence number outside of a transaction"); + return current_sequence_number_; +} + +void LevelDbLruReferenceDelegate::OnTransactionStarted(absl::string_view) { + HARD_ASSERT(current_sequence_number_ == kListenSequenceNumberInvalid, + "Previous sequence number is still in effect"); + current_sequence_number_ = listen_sequence_->Next(); +} + +void LevelDbLruReferenceDelegate::OnTransactionCommitted() { + current_sequence_number_ = kListenSequenceNumberInvalid; +} + +LruGarbageCollector* LevelDbLruReferenceDelegate::garbage_collector() { + return gc_.get(); +} + +int64_t LevelDbLruReferenceDelegate::CalculateByteSize() { + return db_->CalculateByteSize(); +} + +size_t LevelDbLruReferenceDelegate::GetSequenceNumberCount() { + size_t total_count = db_->target_cache()->size(); + EnumerateOrphanedDocuments( + [&total_count](const DocumentKey&, ListenSequenceNumber) { + total_count++; + }); + return total_count; +} + +void LevelDbLruReferenceDelegate::EnumerateTargets( + const TargetCallback& callback) { + db_->target_cache()->EnumerateTargets(callback); +} + +void LevelDbLruReferenceDelegate::EnumerateOrphanedDocuments( + const OrphanedDocumentCallback& callback) { + db_->target_cache()->EnumerateOrphanedDocuments(callback); +} + +int LevelDbLruReferenceDelegate::RemoveOrphanedDocuments( + ListenSequenceNumber upper_bound) { + int count = 0; + db_->target_cache()->EnumerateOrphanedDocuments( + [&](const DocumentKey& key, ListenSequenceNumber sequence_number) { + if (sequence_number <= upper_bound) { + if (!IsPinned(key)) { + count++; + db_->remote_document_cache()->Remove(key); + RemoveSentinel(key); + } + } + }); + return count; +} + +int LevelDbLruReferenceDelegate::RemoveTargets( + ListenSequenceNumber sequence_number, const LiveQueryMap& live_queries) { + return db_->target_cache()->RemoveTargets(sequence_number, live_queries); +} + +bool LevelDbLruReferenceDelegate::IsPinned(const DocumentKey& key) { + if (additional_references_->ContainsKey(key)) { + return true; + } + return MutationQueuesContainKey(key); +} + +bool LevelDbLruReferenceDelegate::MutationQueuesContainKey( + const DocumentKey& key) { + const std::set& users = db_->users(); + const ResourcePath& path = key.path(); + std::string buffer; + auto it = db_->current_transaction()->NewIterator(); + // For each user, if there is any batch that contains this document in any + // batch, we know it's pinned. + for (const std::string& user : users) { + std::string mutation_key = + LevelDbDocumentMutationKey::KeyPrefix(user, path); + it->Seek(mutation_key); + if (it->Valid() && absl::StartsWith(it->key(), mutation_key)) { + return true; + } + } + return false; +} + +void LevelDbLruReferenceDelegate::RemoveSentinel(const DocumentKey& key) { + db_->current_transaction()->Delete( + LevelDbDocumentTargetKey::SentinelKey(key)); +} + +void LevelDbLruReferenceDelegate::WriteSentinel(const DocumentKey& key) { + std::string sentinel_key = LevelDbDocumentTargetKey::SentinelKey(key); + std::string encoded_sequence_number = + LevelDbDocumentTargetKey::EncodeSentinelValue(current_sequence_number()); + db_->current_transaction()->Put(sentinel_key, encoded_sequence_number); +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_lru_reference_delegate.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_lru_reference_delegate.h new file mode 100644 index 0000000..778020d --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_lru_reference_delegate.h @@ -0,0 +1,101 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_LRU_REFERENCE_DELEGATE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_LRU_REFERENCE_DELEGATE_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/local/lru_garbage_collector.h" + +namespace firebase { +namespace firestore { +namespace local { + +class LevelDbPersistence; +class ListenSequence; + +class LevelDbLruReferenceDelegate : public LruDelegate { + public: + LevelDbLruReferenceDelegate(LevelDbPersistence* persistence, + LruParams lru_params); + + ~LevelDbLruReferenceDelegate(); + + void Start(); + + // MARK: ReferenceDelegate methods + + model::ListenSequenceNumber current_sequence_number() const override; + + void AddInMemoryPins(ReferenceSet* set) override; + + void AddReference(const model::DocumentKey& key) override; + void RemoveReference(const model::DocumentKey& key) override; + void RemoveMutationReference(const model::DocumentKey& key) override; + void RemoveTarget(const local::TargetData& target_data) override; + + void UpdateLimboDocument(const model::DocumentKey& key) override; + + void OnTransactionStarted(absl::string_view label) override; + void OnTransactionCommitted() override; + + // MARK: LruDelegate methods + + LruGarbageCollector* garbage_collector() override; + + int64_t CalculateByteSize() override; + size_t GetSequenceNumberCount() override; + + void EnumerateTargets(const TargetCallback& callback) override; + void EnumerateOrphanedDocuments( + const OrphanedDocumentCallback& callback) override; + + int RemoveOrphanedDocuments(model::ListenSequenceNumber upper_bound) override; + int RemoveTargets(model::ListenSequenceNumber sequence_number, + const LiveQueryMap& live_queries) override; + + private: + bool IsPinned(const model::DocumentKey& key); + + bool MutationQueuesContainKey(const model::DocumentKey& key); + + void RemoveSentinel(const model::DocumentKey& key); + void WriteSentinel(const model::DocumentKey& key); + + std::unique_ptr gc_; + + // Persistence instances are owned by FirestoreClient + LevelDbPersistence* db_; + + // Additional references are owned by LocalStore + ReferenceSet* additional_references_; + + // This needs to be a pointer because initialization is delayed until after + // we read from the target cache. + std::unique_ptr listen_sequence_; + + // The current sequence number for the currently active transaction. If no + // transaction is active, resets back to kListenSequenceNumberInvalid. + model::ListenSequenceNumber current_sequence_number_ = + kListenSequenceNumberInvalid; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_LRU_REFERENCE_DELEGATE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_migrations.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_migrations.cc index dda29e7..640b37f 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_migrations.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_migrations.cc @@ -25,6 +25,7 @@ #include "Firestore/core/src/firebase/firestore/local/memory_index_manager.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/nanopb/message.h" #include "Firestore/core/src/firebase/firestore/nanopb/reader.h" #include "Firestore/core/src/firebase/firestore/nanopb/writer.h" #include "absl/strings/match.h" @@ -39,7 +40,8 @@ using leveldb::Status; using leveldb::WriteOptions; using model::DocumentKey; using model::ResourcePath; -using nanopb::Reader; +using nanopb::Message; +using nanopb::StringReader; using nanopb::Writer; namespace { @@ -112,11 +114,9 @@ void ClearQueryCache(leveldb::DB* db) { // Reset the target global entry too (to reset the target count). firestore_client_TargetGlobal target_global{}; - std::string bytes; - Writer writer = Writer::Wrap(&bytes); - writer.WriteNanopbMessage(firestore_client_TargetGlobal_fields, - &target_global); - transaction.Put(LevelDbTargetGlobalKey::Key(), std::move(bytes)); + nanopb::StringWriter writer; + writer.Write(firestore_client_TargetGlobal_fields, &target_global); + transaction.Put(LevelDbTargetGlobalKey::Key(), writer.Release()); SaveVersion(3, &transaction); transaction.Commit(); @@ -173,15 +173,14 @@ void RemoveAcknowledgedMutations(leveldb::DB* db) { for (; it->Valid() && absl::StartsWith(it->key(), mutation_queue_start); it->Next()) { HARD_ASSERT(key.Decode(it->key()), "Failed to decode mutation queue key"); - firestore_client_MutationQueue mutation_queue{}; - Reader reader = Reader::Wrap(it->value()); - reader.ReadNanopbMessage(firestore_client_MutationQueue_fields, - &mutation_queue); + StringReader reader(it->value()); + auto mutation_queue = + Message::TryParse(&reader); HARD_ASSERT(reader.status().ok(), "Failed to deserialize MutationQueue"); RemoveMutationBatches(&transaction, key.user_id(), - mutation_queue.last_acknowledged_batch_id); + mutation_queue->last_acknowledged_batch_id); RemoveMutationDocuments(&transaction, key.user_id(), - mutation_queue.last_acknowledged_batch_id); + mutation_queue->last_acknowledged_batch_id); } SaveVersion(5, &transaction); @@ -196,11 +195,10 @@ model::ListenSequenceNumber GetHighestSequenceNumber( std::string bytes; transaction->Get(LevelDbTargetGlobalKey::Key(), &bytes); - firestore_client_TargetGlobal target_global{}; - Reader reader = Reader::Wrap(bytes); - reader.ReadNanopbMessage(firestore_client_TargetGlobal_fields, - &target_global); - return target_global.highest_listen_sequence_number; + StringReader reader(bytes); + auto target_global = + Message::TryParse(&reader); + return target_global->highest_listen_sequence_number; } /** @@ -317,6 +315,9 @@ LevelDbMigrations::SchemaVersion LevelDbMigrations::ReadSchemaVersion( if (status.IsNotFound()) { return 0; } else { + HARD_ASSERT(status.ok(), + "Failed to read version string from LevelDB, error: '%s'", + status.ToString()); return stoi(version_string); } } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_mutation_queue.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_mutation_queue.cc new file mode 100644 index 0000000..0c47b25 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_mutation_queue.cc @@ -0,0 +1,490 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/leveldb_mutation_queue.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/local/leveldb_persistence.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_transaction.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_util.h" +#include "Firestore/core/src/firebase/firestore/local/local_serializer.h" +#include "Firestore/core/src/firebase/firestore/local/reference_delegate.h" +#include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h" +#include "Firestore/core/src/firebase/firestore/nanopb/reader.h" +#include "Firestore/core/src/firebase/firestore/util/string_util.h" +#include "Firestore/core/src/firebase/firestore/util/to_string.h" +#include "absl/strings/match.h" + +namespace firebase { +namespace firestore { +namespace local { + +using auth::User; +using core::Query; +using leveldb::DB; +using leveldb::Iterator; +using leveldb::Status; +using model::BatchId; +using model::DocumentKey; +using model::DocumentKeySet; +using model::kBatchIdUnknown; +using model::Mutation; +using model::MutationBatch; +using model::ResourcePath; +using nanopb::ByteString; +using nanopb::Message; +using nanopb::StringReader; + +BatchId LoadNextBatchIdFromDb(DB* db) { + // TODO(gsoltis): implement Prev() and SeekToLast() on + // LevelDbTransaction::Iterator, then port this to a transaction. + std::unique_ptr it( + db->NewIterator(LevelDbTransaction::DefaultReadOptions())); + + std::string table_key = LevelDbMutationKey::KeyPrefix(); + + LevelDbMutationKey row_key; + BatchId max_batch_id = 0; + + bool more_user_ids = false; + std::string next_user_id; + + it->Seek(table_key); + if (it->Valid() && row_key.Decode(MakeStringView(it->key()))) { + more_user_ids = true; + next_user_id = row_key.user_id(); + } + + // This loop assumes that next_user_id contains the next username at the start + // of the iteration. + while (more_user_ids) { + // Compute the first key after the last mutation for next_user_id. + std::string user_end = LevelDbMutationKey::KeyPrefix(next_user_id); + user_end = util::PrefixSuccessor(user_end); + + // Seek to that key with the intent of finding the boundary between + // next_user_id's mutations and the one after that (if any). + it->Seek(user_end); + + // At this point there are three possible cases to handle differently. Each + // case must prepare the next iteration (by assigning to next_user_id or + // setting more_user_ids = false) and seek the iterator to the last row in + // the current user's mutation sequence. + if (!it->Valid()) { + // The iterator is past the last row altogether (there are no additional + // user_ids and now rows in any table after mutations). The last row will + // have the highest batch_id. + more_user_ids = false; + it->SeekToLast(); + + } else if (row_key.Decode(MakeStringView(it->key()))) { + // The iterator is valid and the key decoded successfully so the next user + // was just decoded. + next_user_id = row_key.user_id(); + it->Prev(); + + } else { + // The iterator is past the end of the mutations table but there are other + // rows. + more_user_ids = false; + it->Prev(); + } + + // In all the cases above there was at least one row for the current user + // and each case has set things up such that iterator points to it. + if (!row_key.Decode(MakeStringView(it->key()))) { + HARD_FAIL("There should have been a key previous to %s", user_end); + } + + if (row_key.batch_id() > max_batch_id) { + max_batch_id = row_key.batch_id(); + } + } + + return max_batch_id + 1; +} + +LevelDbMutationQueue::LevelDbMutationQueue(const User& user, + LevelDbPersistence* db, + LocalSerializer* serializer) + : db_(NOT_NULL(db)), + serializer_(NOT_NULL(serializer)), + user_id_(user.is_authenticated() ? user.uid() : "") { +} + +void LevelDbMutationQueue::Start() { + next_batch_id_ = LoadNextBatchIdFromDb(db_->ptr()); + metadata_ = MetadataForKey(mutation_queue_key()); +} + +bool LevelDbMutationQueue::IsEmpty() { + std::string user_key = LevelDbMutationKey::KeyPrefix(user_id_); + + auto it = db_->current_transaction()->NewIterator(); + it->Seek(user_key); + + bool empty = true; + if (it->Valid() && absl::StartsWith(it->key(), user_key)) { + empty = false; + } + return empty; +} + +void LevelDbMutationQueue::AcknowledgeBatch(const MutationBatch&, + const ByteString& stream_token) { + SetLastStreamToken(stream_token); +} + +MutationBatch LevelDbMutationQueue::AddMutationBatch( + const Timestamp& local_write_time, + std::vector&& base_mutations, + std::vector&& mutations) { + BatchId batch_id = next_batch_id_; + next_batch_id_++; + + MutationBatch batch(batch_id, local_write_time, std::move(base_mutations), + std::move(mutations)); + std::string key = mutation_batch_key(batch_id); + db_->current_transaction()->Put(key, serializer_->EncodeMutationBatch(batch)); + + // Store an empty value in the index which is equivalent to serializing a + // GPBEmpty message. In the future if we wanted to store some other kind of + // value here, we can parse these empty values as with some other protocol + // buffer (and the parser will see all default values). + std::string empty_buffer; + + for (const Mutation& mutation : batch.mutations()) { + key = LevelDbDocumentMutationKey::Key(user_id_, mutation.key(), batch_id); + db_->current_transaction()->Put(key, empty_buffer); + + db_->index_manager()->AddToCollectionParentIndex( + mutation.key().path().PopLast()); + } + + return batch; +} + +void LevelDbMutationQueue::RemoveMutationBatch(const MutationBatch& batch) { + auto check_iterator = db_->current_transaction()->NewIterator(); + + BatchId batch_id = batch.batch_id(); + std::string key = mutation_batch_key(batch_id); + + // As a sanity check, verify that the mutation batch exists before deleting + // it. + check_iterator->Seek(key); + HARD_ASSERT(check_iterator->Valid(), "Mutation batch %s did not exist", + DescribeKey(key)); + + HARD_ASSERT(key == check_iterator->key(), + "Mutation batch %s not found; found %s", DescribeKey(key), + DescribeKey(check_iterator->key())); + + db_->current_transaction()->Delete(key); + + for (const Mutation& mutation : batch.mutations()) { + key = LevelDbDocumentMutationKey::Key(user_id_, mutation.key(), batch_id); + db_->current_transaction()->Delete(key); + db_->reference_delegate()->RemoveMutationReference(mutation.key()); + } +} + +std::vector LevelDbMutationQueue::AllMutationBatches() { + std::string user_key = LevelDbMutationKey::KeyPrefix(user_id_); + + auto it = db_->current_transaction()->NewIterator(); + it->Seek(user_key); + std::vector result; + for (; it->Valid() && absl::StartsWith(it->key(), user_key); it->Next()) { + result.push_back(ParseMutationBatch(it->value())); + } + return result; +} + +std::vector +LevelDbMutationQueue::AllMutationBatchesAffectingDocumentKeys( + const DocumentKeySet& document_keys) { + // Take a pass through the document keys and collect the set of unique + // mutation batch_ids that affect them all. Some batches can affect more than + // one key. + std::set batch_ids; + + auto index_iterator = db_->current_transaction()->NewIterator(); + LevelDbDocumentMutationKey row_key; + for (const DocumentKey& document_key : document_keys) { + std::string index_prefix = + LevelDbDocumentMutationKey::KeyPrefix(user_id_, document_key.path()); + for (index_iterator->Seek(index_prefix); index_iterator->Valid(); + index_iterator->Next()) { + // Only consider rows matching exactly the specific key of interest. Index + // rows have this form (with markers in brackets): + // + // user collection doc 2 + // user collection doc 3 + // user collection doc sub doc 3 + // + // + // Note that Path markers sort after BatchId markers so this means that + // when searching for collection/doc, all the entries for it will be + // contiguous in the table, allowing a break after any mismatch. + if (!absl::StartsWith(index_iterator->key(), index_prefix) || + !row_key.Decode(index_iterator->key()) || + row_key.document_key() != document_key) { + break; + } + + batch_ids.insert(row_key.batch_id()); + } + } + + return AllMutationBatchesWithIds(batch_ids); +} + +std::vector +LevelDbMutationQueue::AllMutationBatchesAffectingDocumentKey( + const DocumentKey& key) { + return AllMutationBatchesAffectingDocumentKeys(DocumentKeySet{key}); +} + +std::vector +LevelDbMutationQueue::AllMutationBatchesAffectingQuery(const Query& query) { + HARD_ASSERT(!query.IsDocumentQuery(), + "Document queries shouldn't go down this path"); + HARD_ASSERT( + !query.IsCollectionGroupQuery(), + "CollectionGroup queries should be handled in LocalDocumentsView"); + + const ResourcePath& query_path = query.path(); + size_t immediate_children_path_length = query_path.size() + 1; + + // TODO(mcg): Actually implement a single-collection query + // + // This is actually executing an ancestor query, traversing the whole subtree + // below the collection which can be horrifically inefficient for some + // structures. The right way to solve this is to implement the full value + // index, but that's not in the cards in the near future so this is the best + // we can do for the moment. + // + // Since we don't yet index the actual properties in the mutations, our + // current approach is to just return all mutation batches that affect + // documents in the collection being queried. + // + // Unlike AllMutationBatchesAffectingDocumentKey, this iteration will scan the + // document-mutation index for more than a single document so the associated + // batch_ids will be neither necessarily unique nor in order. This means an + // efficient simultaneous scan isn't possible. + std::string index_prefix = + LevelDbDocumentMutationKey::KeyPrefix(user_id_, query_path); + auto index_iterator = db_->current_transaction()->NewIterator(); + index_iterator->Seek(index_prefix); + + LevelDbDocumentMutationKey row_key; + + // Collect up unique batch_ids encountered during a scan of the index. Use a + // set to accumulate the IDs so they can be traversed in order in a + // scan of the main table. + // + // This method is faster than performing lookups of the keys with _db->Get and + // keeping a hash of batch_ids that have already been looked up. The + // performance difference is minor for small numbers of keys but > 30% faster + // for larger numbers of keys. + std::set unique_batch_ids; + for (; index_iterator->Valid(); index_iterator->Next()) { + if (!absl::StartsWith(index_iterator->key(), index_prefix) || + !row_key.Decode(index_iterator->key())) { + break; + } + + // Rows with document keys more than one segment longer than the query path + // can't be matches. For example, a query on 'rooms' can't match the + // document /rooms/abc/messages/xyx. + // TODO(mcg): we'll need a different scanner when we implement ancestor + // queries. + if (row_key.document_key().path().size() != + immediate_children_path_length) { + continue; + } + + unique_batch_ids.insert(row_key.batch_id()); + } + + return AllMutationBatchesWithIds(unique_batch_ids); +} + +absl::optional LevelDbMutationQueue::LookupMutationBatch( + model::BatchId batch_id) { + std::string key = mutation_batch_key(batch_id); + + std::string value; + Status status = db_->current_transaction()->Get(key, &value); + if (!status.ok()) { + if (status.IsNotFound()) { + return absl::nullopt; + } + HARD_FAIL("Lookup mutation batch (%s, %s) failed with status: %s", user_id_, + batch_id, status.ToString()); + } + + return ParseMutationBatch(value); +} + +absl::optional +LevelDbMutationQueue::NextMutationBatchAfterBatchId(model::BatchId batch_id) { + BatchId next_batch_id = batch_id + 1; + + std::string key = mutation_batch_key(next_batch_id); + auto it = db_->current_transaction()->NewIterator(); + it->Seek(key); + + LevelDbMutationKey row_key; + if (!it->Valid() || !row_key.Decode(it->key())) { + // Past the last row in the DB or out of the mutations table + return absl::nullopt; + } + + if (row_key.user_id() != user_id_) { + // Jumped past the last mutation for this user + return absl::nullopt; + } + + HARD_ASSERT(row_key.batch_id() >= next_batch_id, + "Should have found mutation after %s", next_batch_id); + return ParseMutationBatch(it->value()); +} + +BatchId LevelDbMutationQueue::GetHighestUnacknowledgedBatchId() { + std::unique_ptr it( + db_->ptr()->NewIterator(LevelDbTransaction::DefaultReadOptions())); + + std::string next_user_key = + util::PrefixSuccessor(LevelDbMutationKey::KeyPrefix(user_id_)); + + LevelDbMutationKey row_key; + + it->Seek(next_user_key); + it->Prev(); + if (it->Valid() && row_key.Decode(MakeStringView(it->key())) && + row_key.user_id() == user_id_) { + return row_key.batch_id(); + } + + return kBatchIdUnknown; +} + +void LevelDbMutationQueue::PerformConsistencyCheck() { + if (!IsEmpty()) { + return; + } + + // Verify that there are no entries in the document-mutation index if the + // queue is empty. + std::string index_prefix = LevelDbDocumentMutationKey::KeyPrefix(user_id_); + auto index_iterator = db_->current_transaction()->NewIterator(); + index_iterator->Seek(index_prefix); + + std::vector dangling_mutation_references; + + for (; index_iterator->Valid(); index_iterator->Next()) { + // Only consider rows matching this index prefix for the current user. + if (!absl::StartsWith(index_iterator->key(), index_prefix)) { + break; + } + + dangling_mutation_references.push_back(DescribeKey(index_iterator)); + } + + HARD_ASSERT(dangling_mutation_references.empty(), + "Document leak -- detected dangling mutation references when " + "queue is empty. Dangling keys: %s", + util::ToString(dangling_mutation_references)); +} + +ByteString LevelDbMutationQueue::GetLastStreamToken() { + return ByteString{metadata_->last_stream_token}; +} + +void LevelDbMutationQueue::SetLastStreamToken(ByteString stream_token) { + std::free(metadata_->last_stream_token); + + metadata_->last_stream_token = stream_token.release(); + db_->current_transaction()->Put(mutation_queue_key(), metadata_); +} + +std::vector LevelDbMutationQueue::AllMutationBatchesWithIds( + const std::set& batch_ids) { + std::vector result; + + // Given an ordered set of unique batch_ids perform a skipping scan over the + // main table to find the mutation batches. + auto mutation_iterator = db_->current_transaction()->NewIterator(); + for (BatchId batch_id : batch_ids) { + std::string mutation_key = mutation_batch_key(batch_id); + mutation_iterator->Seek(mutation_key); + if (!mutation_iterator->Valid() || + mutation_iterator->key() != mutation_key) { + HARD_FAIL( + "Dangling document-mutation reference found: Missing batch %s; " + "seeking there found %s", + DescribeKey(mutation_key), DescribeKey(mutation_iterator)); + } + + result.push_back(ParseMutationBatch(mutation_iterator->value())); + } + + return result; +} + +Message LevelDbMutationQueue::MetadataForKey( + const std::string& key) { + std::string value; + Status status = db_->current_transaction()->Get(key, &value); + + StringReader reader{value}; + reader.set_status(ConvertStatus(status)); + auto result = Message::TryParse(&reader); + + if (reader.ok()) { + return result; + } else if (reader.status().code() == Error::NotFound) { + // Return a default-constructed message (`TryParse` is guaranteed to return + // a default-constructed message on failure). + return result; + } else { + HARD_FAIL("MetadataForKey: failed loading key %s with status: %s", key, + reader.status().ToString()); + } +} + +MutationBatch LevelDbMutationQueue::ParseMutationBatch( + absl::string_view encoded) { + StringReader reader{encoded}; + auto maybe_message = Message::TryParse(&reader); + auto result = serializer_->DecodeMutationBatch(&reader, *maybe_message); + if (!reader.ok()) { + HARD_FAIL("MutationBatch proto failed to parse: %s", + reader.status().ToString()); + } + + return result; +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_mutation_queue.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_mutation_queue.h index 676cc3f..2986fa3 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_mutation_queue.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_mutation_queue.h @@ -17,40 +17,30 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_MUTATION_QUEUE_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_MUTATION_QUEUE_H_ -#if !defined(__OBJC__) -#error "For now, this file must only be included by ObjC source files." -#endif // !defined(__OBJC__) - -#import - #include #include #include -#import "Firestore/Source/Public/FIRTimestamp.h" - +#include "Firestore/Protos/nanopb/firestore/local/mutation.nanopb.h" +#include "Firestore/core/include/firebase/firestore/timestamp.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/local/leveldb_key.h" #include "Firestore/core/src/firebase/firestore/local/mutation_queue.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/nanopb/message.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" #include "leveldb/db.h" -@class FSTLevelDB; -@class FSTLocalSerializer; -@class FSTMutation; -@class FSTMutationBatch; -@class FSTPBMutationQueue; -@class FSTQuery; - -NS_ASSUME_NONNULL_BEGIN - namespace firebase { namespace firestore { namespace local { +class LevelDbPersistence; +class LocalSerializer; + /** * Returns one larger than the largest batch ID that has been stored. If there * are no mutations returns 0. Note that batch IDs are global. @@ -60,55 +50,57 @@ model::BatchId LoadNextBatchIdFromDb(leveldb::DB* db); class LevelDbMutationQueue : public MutationQueue { public: LevelDbMutationQueue(const auth::User& user, - FSTLevelDB* db, - FSTLocalSerializer* serializer); + LevelDbPersistence* db, + LocalSerializer* serializer); void Start() override; bool IsEmpty() override; - void AcknowledgeBatch(FSTMutationBatch* batch, - NSData* _Nullable stream_token) override; + void AcknowledgeBatch(const model::MutationBatch& batch, + const nanopb::ByteString& stream_token) override; - FSTMutationBatch* AddMutationBatch( - FIRTimestamp* local_write_time, - std::vector&& base_mutations, - std::vector&& mutations) override; + model::MutationBatch AddMutationBatch( + const Timestamp& local_write_time, + std::vector&& base_mutations, + std::vector&& mutations) override; - void RemoveMutationBatch(FSTMutationBatch* batch) override; + void RemoveMutationBatch(const model::MutationBatch& batch) override; - std::vector AllMutationBatches() override; + std::vector AllMutationBatches() override; - std::vector AllMutationBatchesAffectingDocumentKeys( + std::vector AllMutationBatchesAffectingDocumentKeys( const model::DocumentKeySet& document_keys) override; - std::vector AllMutationBatchesAffectingDocumentKey( + std::vector AllMutationBatchesAffectingDocumentKey( const model::DocumentKey& key) override; - std::vector AllMutationBatchesAffectingQuery( - FSTQuery* query) override; + std::vector AllMutationBatchesAffectingQuery( + const core::Query& query) override; - FSTMutationBatch* _Nullable LookupMutationBatch( + absl::optional LookupMutationBatch( model::BatchId batch_id) override; - FSTMutationBatch* _Nullable NextMutationBatchAfterBatchId( + absl::optional NextMutationBatchAfterBatchId( model::BatchId batch_id) override; + model::BatchId GetHighestUnacknowledgedBatchId() override; + void PerformConsistencyCheck() override; - NSData* _Nullable GetLastStreamToken() override; + nanopb::ByteString GetLastStreamToken() override; - void SetLastStreamToken(NSData* _Nullable stream_token) override; + void SetLastStreamToken(nanopb::ByteString stream_token) override; private: /** - * Constructs a vector of matching batches, sorted by batchID to ensure that + * Constructs a vector of matching batches, sorted by batch_id to ensure that * multiple mutations affecting the same document key are applied in order. */ - std::vector AllMutationBatchesWithIds( + std::vector AllMutationBatchesWithIds( const std::set& batch_ids); - std::string mutation_queue_key() { + std::string mutation_queue_key() const { return LevelDbMutationQueueKey::Key(user_id_); } @@ -117,18 +109,20 @@ class LevelDbMutationQueue : public MutationQueue { } /** Parses the MutationQueue metadata from the given LevelDB row contents. */ - FSTPBMutationQueue* _Nullable MetadataForKey(const std::string& key); + nanopb::Message MetadataForKey( + const std::string& key); - FSTMutationBatch* ParseMutationBatch(absl::string_view encoded); + model::MutationBatch ParseMutationBatch(absl::string_view encoded); - // This instance is owned by FSTLevelDB; avoid a retain cycle. - __weak FSTLevelDB* db_; + // The LevelDbMutationQueue instance is owned by LevelDbPersistence. + LevelDbPersistence* db_; - FSTLocalSerializer* serializer_; + // Owned by LevelDbPersistence. + LocalSerializer* serializer_ = nullptr; /** - * The normalized userID (e.g. nil UID => @"" userID) used in our LevelDB - * keys. + * The normalized user_id (i.e. after converting null to empty) as used in our + * LevelDB keys. */ std::string user_id_; @@ -144,13 +138,11 @@ class LevelDbMutationQueue : public MutationQueue { /** * A write-through cache copy of the metadata describing the current queue. */ - FSTPBMutationQueue* _Nullable metadata_; + nanopb::Message metadata_; }; } // namespace local } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_MUTATION_QUEUE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_mutation_queue.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_mutation_queue.mm deleted file mode 100644 index 0abb5f1..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_mutation_queue.mm +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/local/leveldb_mutation_queue.h" - -#include -#include - -#import "Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Local/FSTLevelDB.h" -#import "Firestore/Source/Local/FSTLocalSerializer.h" -#import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Model/FSTMutationBatch.h" - -#include "Firestore/core/src/firebase/firestore/local/leveldb_util.h" -#include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" -#include "Firestore/core/src/firebase/firestore/model/resource_path.h" -#include "Firestore/core/src/firebase/firestore/util/string_util.h" -#include "Firestore/core/src/firebase/firestore/util/to_string.h" -#include "absl/strings/match.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace firebase { -namespace firestore { -namespace local { - -using auth::User; -using leveldb::DB; -using leveldb::Iterator; -using leveldb::Status; -using model::BatchId; -using model::DocumentKey; -using model::DocumentKeySet; -using model::kBatchIdUnknown; -using model::ResourcePath; - -BatchId LoadNextBatchIdFromDb(DB* db) { - // TODO(gsoltis): implement Prev() and SeekToLast() on - // LevelDbTransaction::Iterator, then port this to a transaction. - std::unique_ptr it( - db->NewIterator(LevelDbTransaction::DefaultReadOptions())); - - std::string table_key = LevelDbMutationKey::KeyPrefix(); - - LevelDbMutationKey row_key; - BatchId max_batch_id = kBatchIdUnknown; - - bool more_user_ids = false; - std::string next_user_id; - - it->Seek(table_key); - if (it->Valid() && row_key.Decode(MakeStringView(it->key()))) { - more_user_ids = true; - next_user_id = row_key.user_id(); - } - - // This loop assumes that nextUserId contains the next username at the start - // of the iteration. - while (more_user_ids) { - // Compute the first key after the last mutation for next_user_id. - std::string user_end = LevelDbMutationKey::KeyPrefix(next_user_id); - user_end = util::PrefixSuccessor(user_end); - - // Seek to that key with the intent of finding the boundary between - // next_user_id's mutations and the one after that (if any). - it->Seek(user_end); - - // At this point there are three possible cases to handle differently. Each - // case must prepare the next iteration (by assigning to next_user_id or - // setting more_user_ids = NO) and seek the iterator to the last row in the - // current user's mutation sequence. - if (!it->Valid()) { - // The iterator is past the last row altogether (there are no additional - // userIDs and now rows in any table after mutations). The last row will - // have the highest batchID. - more_user_ids = false; - it->SeekToLast(); - - } else if (row_key.Decode(MakeStringView(it->key()))) { - // The iterator is valid and the key decoded successfully so the next user - // was just decoded. - next_user_id = row_key.user_id(); - it->Prev(); - - } else { - // The iterator is past the end of the mutations table but there are other - // rows. - more_user_ids = false; - it->Prev(); - } - - // In all the cases above there was at least one row for the current user - // and each case has set things up such that iterator points to it. - if (!row_key.Decode(MakeStringView(it->key()))) { - HARD_FAIL("There should have been a key previous to %s", user_end); - } - - if (row_key.batch_id() > max_batch_id) { - max_batch_id = row_key.batch_id(); - } - } - - return max_batch_id + 1; -} - -LevelDbMutationQueue::LevelDbMutationQueue(const User& user, - FSTLevelDB* db, - FSTLocalSerializer* serializer) - : db_(db), - serializer_(serializer), - user_id_(user.is_authenticated() ? user.uid() : "") { -} - -void LevelDbMutationQueue::Start() { - next_batch_id_ = LoadNextBatchIdFromDb(db_.ptr); - - std::string key = mutation_queue_key(); - FSTPBMutationQueue* metadata = MetadataForKey(key); - if (!metadata) { - metadata = [FSTPBMutationQueue message]; - } - metadata_ = metadata; -} - -bool LevelDbMutationQueue::IsEmpty() { - std::string user_key = LevelDbMutationKey::KeyPrefix(user_id_); - - auto it = db_.currentTransaction->NewIterator(); - it->Seek(user_key); - - bool empty = true; - if (it->Valid() && absl::StartsWith(it->key(), user_key)) { - empty = false; - } - return empty; -} - -void LevelDbMutationQueue::AcknowledgeBatch(FSTMutationBatch* batch, - NSData* _Nullable stream_token) { - SetLastStreamToken(stream_token); -} - -FSTMutationBatch* LevelDbMutationQueue::AddMutationBatch( - FIRTimestamp* local_write_time, - std::vector&& base_mutations, - std::vector&& mutations) { - BatchId batch_id = next_batch_id_; - next_batch_id_++; - - FSTMutationBatch* batch = - [[FSTMutationBatch alloc] initWithBatchID:batch_id - localWriteTime:local_write_time - baseMutations:std::move(base_mutations) - mutations:std::move(mutations)]; - std::string key = mutation_batch_key(batch_id); - db_.currentTransaction->Put(key, [serializer_ encodedMutationBatch:batch]); - - // Store an empty value in the index which is equivalent to serializing a - // GPBEmpty message. In the future if we wanted to store some other kind of - // value here, we can parse these empty values as with some other protocol - // buffer (and the parser will see all default values). - std::string empty_buffer; - - for (FSTMutation* mutation : [batch mutations]) { - key = LevelDbDocumentMutationKey::Key(user_id_, mutation.key, batch_id); - db_.currentTransaction->Put(key, empty_buffer); - - db_.indexManager->AddToCollectionParentIndex(mutation.key.path().PopLast()); - } - - return batch; -} - -void LevelDbMutationQueue::RemoveMutationBatch(FSTMutationBatch* batch) { - auto check_iterator = db_.currentTransaction->NewIterator(); - - BatchId batch_id = batch.batchID; - std::string key = mutation_batch_key(batch_id); - - // As a sanity check, verify that the mutation batch exists before deleting - // it. - check_iterator->Seek(key); - HARD_ASSERT(check_iterator->Valid(), "Mutation batch %s did not exist", - DescribeKey(key)); - - HARD_ASSERT(key == check_iterator->key(), - "Mutation batch %s not found; found %s", DescribeKey(key), - DescribeKey(check_iterator->key())); - - db_.currentTransaction->Delete(key); - - for (FSTMutation* mutation : [batch mutations]) { - key = LevelDbDocumentMutationKey::Key(user_id_, mutation.key, batch_id); - db_.currentTransaction->Delete(key); - [db_.referenceDelegate removeMutationReference:mutation.key]; - } -} - -std::vector LevelDbMutationQueue::AllMutationBatches() { - std::string user_key = LevelDbMutationKey::KeyPrefix(user_id_); - - auto it = db_.currentTransaction->NewIterator(); - it->Seek(user_key); - std::vector result; - for (; it->Valid() && absl::StartsWith(it->key(), user_key); it->Next()) { - result.push_back(ParseMutationBatch(it->value())); - } - return result; -} - -std::vector -LevelDbMutationQueue::AllMutationBatchesAffectingDocumentKeys( - const DocumentKeySet& document_keys) { - // Take a pass through the document keys and collect the set of unique - // mutation batch_ids that affect them all. Some batches can affect more than - // one key. - std::set batch_ids; - - auto index_iterator = db_.currentTransaction->NewIterator(); - LevelDbDocumentMutationKey row_key; - for (const DocumentKey& document_key : document_keys) { - std::string index_prefix = - LevelDbDocumentMutationKey::KeyPrefix(user_id_, document_key.path()); - for (index_iterator->Seek(index_prefix); index_iterator->Valid(); - index_iterator->Next()) { - // Only consider rows matching exactly the specific key of interest. Index - // rows have this form (with markers in brackets): - // - // user collection doc 2 - // user collection doc 3 - // user collection doc sub doc 3 - // - // - // Note that Path markers sort after BatchId markers so this means that - // when searching for collection/doc, all the entries for it will be - // contiguous in the table, allowing a break after any mismatch. - if (!absl::StartsWith(index_iterator->key(), index_prefix) || - !row_key.Decode(index_iterator->key()) || - row_key.document_key() != document_key) { - break; - } - - batch_ids.insert(row_key.batch_id()); - } - } - - return AllMutationBatchesWithIds(batch_ids); -} - -std::vector -LevelDbMutationQueue::AllMutationBatchesAffectingDocumentKey( - const DocumentKey& key) { - return AllMutationBatchesAffectingDocumentKeys(DocumentKeySet{key}); -} - -std::vector -LevelDbMutationQueue::AllMutationBatchesAffectingQuery(FSTQuery* query) { - HARD_ASSERT(![query isDocumentQuery], - "Document queries shouldn't go down this path"); - HARD_ASSERT( - ![query isCollectionGroupQuery], - "CollectionGroup queries should be handled in LocalDocumentsView"); - - const ResourcePath& query_path = query.path; - size_t immediate_children_path_length = query_path.size() + 1; - - // TODO(mcg): Actually implement a single-collection query - // - // This is actually executing an ancestor query, traversing the whole subtree - // below the collection which can be horrifically inefficient for some - // structures. The right way to solve this is to implement the full value - // index, but that's not in the cards in the near future so this is the best - // we can do for the moment. - // - // Since we don't yet index the actual properties in the mutations, our - // current approach is to just return all mutation batches that affect - // documents in the collection being queried. - // - // Unlike allMutationBatchesAffectingDocumentKey, this iteration will scan the - // document-mutation index for more than a single document so the associated - // batchIDs will be neither necessarily unique nor in order. This means an - // efficient simultaneous scan isn't possible. - std::string index_prefix = - LevelDbDocumentMutationKey::KeyPrefix(user_id_, query_path); - auto index_iterator = db_.currentTransaction->NewIterator(); - index_iterator->Seek(index_prefix); - - LevelDbDocumentMutationKey row_key; - - // Collect up unique batchIDs encountered during a scan of the index. Use a - // set to accumulate batch IDs so they can be traversed in order in a - // scan of the main table. - // - // This method is faster than performing lookups of the keys with _db->Get and - // keeping a hash of batchIDs that have already been looked up. The - // performance difference is minor for small numbers of keys but > 30% faster - // for larger numbers of keys. - std::set unique_batch_ids; - for (; index_iterator->Valid(); index_iterator->Next()) { - if (!absl::StartsWith(index_iterator->key(), index_prefix) || - !row_key.Decode(index_iterator->key())) { - break; - } - - // Rows with document keys more than one segment longer than the query path - // can't be matches. For example, a query on 'rooms' can't match the - // document /rooms/abc/messages/xyx. - // TODO(mcg): we'll need a different scanner when we implement ancestor - // queries. - if (row_key.document_key().path().size() != - immediate_children_path_length) { - continue; - } - - unique_batch_ids.insert(row_key.batch_id()); - } - - return AllMutationBatchesWithIds(unique_batch_ids); -} - -FSTMutationBatch* _Nullable LevelDbMutationQueue::LookupMutationBatch( - model::BatchId batch_id) { - std::string key = mutation_batch_key(batch_id); - - std::string value; - Status status = db_.currentTransaction->Get(key, &value); - if (!status.ok()) { - if (status.IsNotFound()) { - return nil; - } - HARD_FAIL("Lookup mutation batch (%s, %s) failed with status: %s", user_id_, - batch_id, status.ToString()); - } - - return ParseMutationBatch(value); -} - -FSTMutationBatch* _Nullable LevelDbMutationQueue::NextMutationBatchAfterBatchId( - model::BatchId batch_id) { - BatchId next_batch_id = batch_id + 1; - - std::string key = mutation_batch_key(next_batch_id); - auto it = db_.currentTransaction->NewIterator(); - it->Seek(key); - - LevelDbMutationKey row_key; - if (!it->Valid() || !row_key.Decode(it->key())) { - // Past the last row in the DB or out of the mutations table - return nil; - } - - if (row_key.user_id() != user_id_) { - // Jumped past the last mutation for this user - return nil; - } - - HARD_ASSERT(row_key.batch_id() >= next_batch_id, - "Should have found mutation after %s", next_batch_id); - return ParseMutationBatch(it->value()); -} - -void LevelDbMutationQueue::PerformConsistencyCheck() { - if (!IsEmpty()) { - return; - } - - // Verify that there are no entries in the document-mutation index if the - // queue is empty. - std::string index_prefix = LevelDbDocumentMutationKey::KeyPrefix(user_id_); - auto index_iterator = db_.currentTransaction->NewIterator(); - index_iterator->Seek(index_prefix); - - std::vector dangling_mutation_references; - - for (; index_iterator->Valid(); index_iterator->Next()) { - // Only consider rows matching this index prefix for the current user. - if (!absl::StartsWith(index_iterator->key(), index_prefix)) { - break; - } - - dangling_mutation_references.push_back(DescribeKey(index_iterator)); - } - - HARD_ASSERT( - dangling_mutation_references.empty(), - "Document leak -- detected dangling mutation references when queue " - "is empty. Dangling keys: %s", - util::ToString(dangling_mutation_references)); -} - -NSData* _Nullable LevelDbMutationQueue::GetLastStreamToken() { - return metadata_.lastStreamToken; -} - -void LevelDbMutationQueue::SetLastStreamToken(NSData* _Nullable stream_token) { - metadata_.lastStreamToken = stream_token; - - db_.currentTransaction->Put(mutation_queue_key(), metadata_); -} - -std::vector LevelDbMutationQueue::AllMutationBatchesWithIds( - const std::set& batch_ids) { - std::vector result; - - // Given an ordered set of unique batchIDs perform a skipping scan over the - // main table to find the mutation batches. - auto mutation_iterator = db_.currentTransaction->NewIterator(); - for (BatchId batch_id : batch_ids) { - std::string mutation_key = mutation_batch_key(batch_id); - mutation_iterator->Seek(mutation_key); - if (!mutation_iterator->Valid() || - mutation_iterator->key() != mutation_key) { - HARD_FAIL("Dangling document-mutation reference found: " - "Missing batch %s; seeking there found %s", - DescribeKey(mutation_key), DescribeKey(mutation_iterator)); - } - - result.push_back(ParseMutationBatch(mutation_iterator->value())); - } - return result; -} - -FSTPBMutationQueue* _Nullable LevelDbMutationQueue::MetadataForKey( - const std::string& key) { - std::string value; - Status status = db_.currentTransaction->Get(key, &value); - if (status.ok()) { - NSData* data = [[NSData alloc] initWithBytesNoCopy:(void*)value.data() - length:value.size() - freeWhenDone:NO]; - - NSError* error; - FSTPBMutationQueue* proto = [FSTPBMutationQueue parseFromData:data - error:&error]; - if (!proto) { - HARD_FAIL("FSTPBMutationQueue failed to parse: %s", error); - } - return proto; - } else if (status.IsNotFound()) { - return nil; - } else { - HARD_FAIL("MetadataForKey: failed loading key %s with status: %s", key, - status.ToString()); - } -} - -FSTMutationBatch* LevelDbMutationQueue::ParseMutationBatch( - absl::string_view encoded) { - NSData* data = [[NSData alloc] initWithBytesNoCopy:(void*)encoded.data() - length:encoded.size() - freeWhenDone:NO]; - - NSError* error; - FSTPBWriteBatch* proto = [FSTPBWriteBatch parseFromData:data error:&error]; - if (!proto) { - HARD_FAIL("FSTPBMutationBatch failed to parse: %s", error); - } - - return [serializer_ decodedMutationBatch:proto]; -} - -} // namespace local -} // namespace firestore -} // namespace firebase - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_opener.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_opener.cc new file mode 100644 index 0000000..1fc2968 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_opener.cc @@ -0,0 +1,246 @@ +/* + * Copyright 2020 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/leveldb_opener.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/core/database_info.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_persistence.h" +#include "Firestore/core/src/firebase/firestore/local/local_serializer.h" +#include "Firestore/core/src/firebase/firestore/remote/serializer.h" +#include "Firestore/core/src/firebase/firestore/util/filesystem.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/path.h" +#include "Firestore/core/src/firebase/firestore/util/statusor.h" +#include "Firestore/core/src/firebase/firestore/util/string_format.h" +#include "absl/strings/match.h" + +namespace firebase { +namespace firestore { +namespace local { +namespace { + +using core::DatabaseInfo; +using remote::Serializer; +using util::Filesystem; +using util::Path; +using util::Status; +using util::StatusOr; +using util::StringFormat; + +constexpr const char* kReservedPathComponent = "firestore"; + +Status FromCause(const std::string& message, const Status& cause) { + if (cause.ok()) return cause; + + return Status(cause.code(), message).CausedBy(cause); +} + +} // namespace + +LevelDbOpener::LevelDbOpener(DatabaseInfo database_info, Filesystem* fs) + : database_info_(std::move(database_info)), + fs_(fs ? fs : Filesystem::Default()) { +} + +LevelDbOpener::LevelDbOpener(DatabaseInfo database_info, + Path firestore_app_data_dir) + : database_info_(std::move(database_info)), + app_data_dir_(std::move(firestore_app_data_dir)), + fs_(Filesystem::Default()) { +} + +util::StatusOr> LevelDbOpener::Create( + const LruParams& lru_params) { + auto maybe_dir = PrepareDataDir(); + if (!maybe_dir.ok()) return maybe_dir.status(); + Path db_data_dir = maybe_dir.ValueOrDie(); + + LOG_DEBUG("Using %s for LevelDB storage", db_data_dir.ToUtf8String()); + + Serializer remote_serializer(database_info_.database_id()); + LocalSerializer local_serializer(std::move(remote_serializer)); + + return LevelDbPersistence::Create(db_data_dir, std::move(local_serializer), + lru_params); +} + +StatusOr LevelDbOpener::LevelDbDataDir() { + StatusOr maybe_dir = FirestoreAppDataDir(); + if (!maybe_dir.ok()) return maybe_dir; + return StorageDir(maybe_dir.ValueOrDie()); +} + +StatusOr LevelDbOpener::PrepareDataDir() { + StatusOr maybe_dir = LevelDbDataDir(); + if (!maybe_dir.ok()) return maybe_dir; + Path db_data_dir = std::move(maybe_dir).ValueOrDie(); + + // Check for the preferred location. If it exists, we're done. + Status dir_status = fs_->IsDirectory(db_data_dir); + if (dir_status.ok()) { + return db_data_dir; + } else if (dir_status.code() != Error::NotFound) { + return dir_status; + } + + // The preferred dir doesn't exist so check for the legacy location. If it + // exists, migrate. + maybe_dir = FirestoreLegacyAppDataDir(); + Path legacy_db_data_dir; + if (maybe_dir.ok()) { + legacy_db_data_dir = StorageDir(std::move(maybe_dir).ValueOrDie()); + dir_status = fs_->IsDirectory(legacy_db_data_dir); + } else { + dir_status = maybe_dir.status(); + } + + if (dir_status.ok()) { + // The legacy directory does exist, so migrate + return MigrateDataDir(legacy_db_data_dir, db_data_dir); + + } else if (dir_status.code() != Error::NotFound && + dir_status.code() != Error::Unimplemented) { + return dir_status; + } + + // Either we couldn't find the legacy directory or this platform has no legacy + // directory so create the new directory. + Status created = fs_->RecursivelyCreateDir(db_data_dir); + if (!created.ok()) { + std::string message = + StringFormat("Could not create LevelDB data directory %s", + db_data_dir.ToUtf8String()); + + return FromCause(message, created); + } + + return db_data_dir; +} + +StatusOr LevelDbOpener::FirestoreAppDataDir() { + if (app_data_dir_.empty()) { + auto maybe_dir = fs_->AppDataDir(kReservedPathComponent); + if (!maybe_dir.ok()) { + return FromCause( + "Failed to find the App data directory for the current user", + maybe_dir.status()); + } + app_data_dir_ = std::move(maybe_dir).ValueOrDie(); + } + return app_data_dir_; +} + +StatusOr LevelDbOpener::FirestoreLegacyAppDataDir() { + if (legacy_app_data_dir_.empty()) { + auto maybe_dir = fs_->LegacyDocumentsDir(kReservedPathComponent); + if (!maybe_dir.ok()) { + return FromCause( + "Failed to find the Documents directory for the current user", + maybe_dir.status()); + } + legacy_app_data_dir_ = std::move(maybe_dir).ValueOrDie(); + } + return legacy_app_data_dir_; +} + +Path LevelDbOpener::StorageDir(const Path& base_path) { + // Use two different path formats: + // + // * persistence_key / project_id . database_id / name + // * persistence_key / project_id / name + // + // project_ids are DNS-compatible names and cannot contain dots so there's + // no danger of collisions. + std::string project_key = database_info_.database_id().project_id(); + if (!database_info_.database_id().IsDefaultDatabase()) { + absl::StrAppend(&project_key, ".", + database_info_.database_id().database_id()); + } + + // Reserve one additional path component to allow multiple physical databases + return Path::JoinUtf8(base_path, database_info_.persistence_key(), + project_key, "main"); +} + +StatusOr LevelDbOpener::MigrateDataDir( + const firebase::firestore::util::Path& legacy_db_data_dir, + const firebase::firestore::util::Path& db_data_dir) { + // At this point the legacy location exists and the preferred location doesn't + // so just move into place. + LOG_DEBUG( + "Migrating LevelDB storage from legacy location: %s\nMigrating to: %s", + legacy_db_data_dir.ToUtf8String(), db_data_dir.ToUtf8String()); + + Path db_data_parent = db_data_dir.Dirname(); + Status created = fs_->RecursivelyCreateDir(db_data_parent); + if (!created.ok()) { + std::string message = + StringFormat("Could not create LevelDB data directory %s", + db_data_parent.ToUtf8String()); + LOG_ERROR("Migration failed: %s. Existing data unchanged.", message); + return FromCause(message, created); + } + + Status renamed = fs_->Rename(legacy_db_data_dir, db_data_dir); + if (!renamed.ok()) { + std::string message = StringFormat( + "Failed to migrate LevelDB data from %s to %s", + legacy_db_data_dir.ToUtf8String(), db_data_dir.ToUtf8String()); + LOG_ERROR("Migration failed: %s. Existing data unchanged.", message); + return FromCause(message, renamed); + } + + RecursivelyCleanupLegacyDirs(legacy_db_data_dir); + return db_data_dir; +} + +void LevelDbOpener::RecursivelyCleanupLegacyDirs(Path legacy_dir) { + // The legacy_dir must be within the container_dir. + HARD_ASSERT(!legacy_app_data_dir_.empty()); + HARD_ASSERT(absl::StartsWith(legacy_dir.ToUtf8String(), + legacy_app_data_dir_.ToUtf8String())); + + // The container directory contains a trailing "firestore" component + HARD_ASSERT(absl::EndsWith(legacy_app_data_dir_.ToUtf8String(), + kReservedPathComponent)); + + Path parent_most = legacy_app_data_dir_.Dirname(); + for (; legacy_dir != parent_most; legacy_dir = legacy_dir.Dirname()) { + Status is_dir = fs_->IsDirectory(legacy_dir); + if (is_dir.ok()) { + if (util::IsEmptyDir(legacy_dir)) { + Status removed = fs_->RemoveDir(legacy_dir); + if (!removed.ok()) { + LOG_WARN("Could not remove directory %s: %s", + legacy_dir.ToUtf8String(), removed.ToString()); + break; + } + } + + } else if (is_dir.code() != Error::NotFound) { + LOG_WARN("Could not remove directory %s: %s", legacy_dir.ToUtf8String(), + is_dir.ToString()); + break; + } + } +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_opener.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_opener.h new file mode 100644 index 0000000..cb3e4b0 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_opener.h @@ -0,0 +1,132 @@ +/* + * Copyright 2020 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_OPENER_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_OPENER_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/core/database_info.h" +#include "Firestore/core/src/firebase/firestore/util/path.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { + +namespace util { +class Filesystem; +class Status; + +template +class StatusOr; +} // namespace util + +namespace local { + +class LevelDbPersistence; +struct LruParams; + +class LevelDbOpener { + public: + /** + * Creates an opener that uses the given filesystem, or + * `Filesystem::Default()` if `fs` is `nullptr`. A non-default Filesystem + * should only be used in tests. + */ + explicit LevelDbOpener(core::DatabaseInfo database_info, + util::Filesystem* fs = nullptr); + + /** + * Creates an opener that uses a pre-specified storage location. This should + * only be used in tests. + * + * @param database_info The instance configuration + * @param firestore_app_data_dir The Firestore-specific application data + * directory. + */ + LevelDbOpener(core::DatabaseInfo database_info, + util::Path firestore_app_data_dir); + + /** + * Creates the LevelDbPersistence instance. + * + * This process includes: + * + * * Migrating existing data from a legacy location into the new location + * (i.e. from ~/Documents to ~/Library/Application Support on iOS); + * * Cleaning up the directory structure in the legacy location; + * * Creating the directory structure to uniquely hold the data for this + * instance. + * * Actually opening the LevelDB database. + * + * @param lru_params The LRU GC configuration to use for the instance. + * @return A pointer to the created instance or Status indicating what failed. + */ + util::StatusOr> Create( + const LruParams& lru_params); + + /** + * Finds a suitable directory to serve as the root of all Firestore local + * storage for all Firestore instances. + */ + util::StatusOr FirestoreAppDataDir(); + + /** + * Finds the location where Firestore used to keep local storage for all + * Firestore instances. + */ + util::StatusOr FirestoreLegacyAppDataDir(); + + /** + * Returns the location of the data for the single Firestore instance named + * by the DatabaseInfo passed to the `LevelDbOpener` constructor. + */ + util::StatusOr LevelDbDataDir(); + + private: + /** + * Prepares the directory that contains the instance's data. + */ + util::StatusOr PrepareDataDir(); + + /** + * Computes a unique storage directory for the given identifying components of + * local storage. + * + * @param base_path The root application data directory relative to which + * the instance-specific storage directory will be created. Usually just + * `FirestoreAppDataDir()`. + * @return A storage directory unique to the instance identified by + * `database_info`. + */ + util::Path StorageDir(const util::Path& base_path); + + util::StatusOr MigrateDataDir( + const util::Path& legacy_db_data_dir, const util::Path& db_data_dir); + + void RecursivelyCleanupLegacyDirs(util::Path legacy_dir); + + core::DatabaseInfo database_info_; + util::Path app_data_dir_; + util::Path legacy_app_data_dir_; + util::Filesystem* fs_ = nullptr; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_OPENER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_persistence.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_persistence.cc new file mode 100644 index 0000000..9d2df78 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_persistence.cc @@ -0,0 +1,254 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/leveldb_persistence.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/auth/user.h" +#include "Firestore/core/src/firebase/firestore/core/database_info.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_lru_reference_delegate.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_migrations.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_opener.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_util.h" +#include "Firestore/core/src/firebase/firestore/local/listen_sequence.h" +#include "Firestore/core/src/firebase/firestore/local/lru_garbage_collector.h" +#include "Firestore/core/src/firebase/firestore/local/reference_delegate.h" +#include "Firestore/core/src/firebase/firestore/local/sizer.h" +#include "Firestore/core/src/firebase/firestore/util/filesystem.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/string_util.h" +#include "absl/memory/memory.h" +#include "absl/strings/match.h" + +namespace firebase { +namespace firestore { +namespace local { +namespace { + +using auth::User; +using leveldb::DB; +using model::ListenSequenceNumber; +using util::Filesystem; +using util::Path; +using util::Status; +using util::StatusOr; +using util::StringFormat; + +/** + * Finds all user ids in the database based on the existence of a mutation + * queue. + */ +std::set CollectUserSet(LevelDbTransaction* transaction) { + std::set result; + + std::string table_prefix = LevelDbMutationKey::KeyPrefix(); + auto it = transaction->NewIterator(); + it->Seek(table_prefix); + + LevelDbMutationKey row_key; + while (it->Valid() && absl::StartsWith(it->key(), table_prefix) && + row_key.Decode(it->key())) { + result.insert(row_key.user_id()); + + auto user_end = LevelDbMutationKey::KeyPrefix(row_key.user_id()); + user_end = util::PrefixSuccessor(user_end); + it->Seek(user_end); + } + return result; +} + +} // namespace + +util::StatusOr> LevelDbPersistence::Create( + util::Path dir, LocalSerializer serializer, const LruParams& lru_params) { + auto* fs = Filesystem::Default(); + Status status = EnsureDirectory(dir); + if (!status.ok()) return status; + + status = fs->ExcludeFromBackups(dir); + if (!status.ok()) return status; + + StatusOr> created = OpenDb(dir); + if (!created.ok()) return created.status(); + + std::unique_ptr db = std::move(created).ValueOrDie(); + LevelDbMigrations::RunMigrations(db.get()); + + LevelDbTransaction transaction(db.get(), "Start LevelDB"); + std::set users = CollectUserSet(&transaction); + transaction.Commit(); + + // Explicit conversion is required to allow the StatusOr to be created. + std::unique_ptr result( + new LevelDbPersistence(std::move(db), std::move(dir), std::move(users), + std::move(serializer), lru_params)); + return std::move(result); +} + +LevelDbPersistence::LevelDbPersistence(std::unique_ptr db, + util::Path directory, + std::set users, + LocalSerializer serializer, + const LruParams& lru_params) + : db_(std::move(db)), + directory_(std::move(directory)), + users_(std::move(users)), + serializer_(std::move(serializer)) { + target_cache_ = absl::make_unique(this, &serializer_); + document_cache_ = + absl::make_unique(this, &serializer_); + index_manager_ = absl::make_unique(this); + reference_delegate_ = + absl::make_unique(this, lru_params); + + // TODO(gsoltis): set up a leveldb transaction for these operations. + target_cache_->Start(); + reference_delegate_->Start(); + started_ = true; +} + +// MARK: - Startup + +Status LevelDbPersistence::EnsureDirectory(const Path& dir) { + auto* fs = Filesystem::Default(); + Status status = fs->RecursivelyCreateDir(dir); + if (!status.ok()) { + return Status{Error::Internal, "Failed to create persistence directory"} + .CausedBy(status); + } + + return Status::OK(); +} + +StatusOr> LevelDbPersistence::OpenDb(const Path& dir) { + leveldb::Options options; + options.create_if_missing = true; + + DB* database = nullptr; + leveldb::Status status = DB::Open(options, dir.ToUtf8String(), &database); + if (!status.ok()) { + return Status{Error::Internal, + StringFormat("Failed to open LevelDB database at %s", + dir.ToUtf8String())} + .CausedBy(ConvertStatus(status)); + } + + return std::unique_ptr(database); +} + +// MARK: - LevelDB utilities + +LevelDbTransaction* LevelDbPersistence::current_transaction() { + HARD_ASSERT(transaction_ != nullptr, + "Attempting to access transaction before one has started"); + return transaction_.get(); +} + +util::Status LevelDbPersistence::ClearPersistence( + const core::DatabaseInfo& database_info) { + LevelDbOpener opener(database_info); + StatusOr maybe_data_dir = opener.LevelDbDataDir(); + HARD_ASSERT(maybe_data_dir.ok(), "Failed to find local LevelDB files: %s", + maybe_data_dir.status().ToString()); + Path leveldb_dir = std::move(maybe_data_dir).ValueOrDie(); + + LOG_DEBUG("Clearing persistence for path: %s", leveldb_dir.ToUtf8String()); + auto* fs = Filesystem::Default(); + return fs->RecursivelyRemove(leveldb_dir); +} + +int64_t LevelDbPersistence::CalculateByteSize() { + auto* fs = Filesystem::Default(); + + int64_t count = 0; + auto iter = util::DirectoryIterator::Create(directory_); + for (; iter->Valid(); iter->Next()) { + int64_t file_size = fs->FileSize(iter->file()).ValueOrDie(); + count += file_size; + } + + HARD_ASSERT(iter->status().ok(), "Failed to iterate LevelDB directory: %s", + iter->status().error_message().c_str()); + HARD_ASSERT(count >= 0 && count <= std::numeric_limits::max(), + "Overflowed counting bytes cached"); + return count; +} + +// MARK: - Persistence + +model::ListenSequenceNumber LevelDbPersistence::current_sequence_number() + const { + return reference_delegate_->current_sequence_number(); +} + +void LevelDbPersistence::Shutdown() { + HARD_ASSERT(started_, "LevelDbPersistence shutdown without start!"); + started_ = false; + db_.reset(); +} + +LevelDbMutationQueue* LevelDbPersistence::GetMutationQueueForUser( + const auth::User& user) { + users_.insert(user.uid()); + current_mutation_queue_ = + absl::make_unique(user, this, &serializer_); + return current_mutation_queue_.get(); +} + +LevelDbTargetCache* LevelDbPersistence::target_cache() { + return target_cache_.get(); +} + +LevelDbRemoteDocumentCache* LevelDbPersistence::remote_document_cache() { + return document_cache_.get(); +} + +LevelDbIndexManager* LevelDbPersistence::index_manager() { + return index_manager_.get(); +} + +LevelDbLruReferenceDelegate* LevelDbPersistence::reference_delegate() { + return reference_delegate_.get(); +} + +void LevelDbPersistence::RunInternal(absl::string_view label, + std::function block) { + HARD_ASSERT(transaction_ == nullptr, + "Starting a transaction while one is already in progress"); + + transaction_ = absl::make_unique(db_.get(), label); + reference_delegate_->OnTransactionStarted(label); + + block(); + + reference_delegate_->OnTransactionCommitted(); + transaction_->Commit(); + transaction_.reset(); +} + +leveldb::ReadOptions StandardReadOptions() { + // For now this is paranoid, but perhaps disable that in production builds. + leveldb::ReadOptions options; + options.verify_checksums = true; + return options; +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_persistence.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_persistence.h new file mode 100644 index 0000000..0433760 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_persistence.h @@ -0,0 +1,133 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_PERSISTENCE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_PERSISTENCE_H_ + +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/auth/user.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_index_manager.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_lru_reference_delegate.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_mutation_queue.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_remote_document_cache.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_target_cache.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_transaction.h" +#include "Firestore/core/src/firebase/firestore/local/local_serializer.h" +#include "Firestore/core/src/firebase/firestore/local/persistence.h" +#include "Firestore/core/src/firebase/firestore/util/path.h" +#include "Firestore/core/src/firebase/firestore/util/statusor.h" + +namespace firebase { +namespace firestore { +namespace core { + +class DatabaseInfo; + +} // namespace core + +namespace local { + +class LevelDbLruReferenceDelegate; +struct LruParams; + +/** A LevelDB-backed implementation of the Persistence interface. */ +class LevelDbPersistence : public Persistence { + public: + /** + * Creates a LevelDB in the given directory and returns it or a Status object + * containing details of the failure. + */ + static util::StatusOr> Create( + util::Path dir, LocalSerializer serializer, const LruParams& lru_params); + + LevelDbTransaction* current_transaction(); + + leveldb::DB* ptr() { + return db_.get(); + } + + const std::set users() const { + return users_; + } + + static util::Status ClearPersistence(const core::DatabaseInfo& database_info); + + int64_t CalculateByteSize(); + + // MARK: Persistence overrides + + model::ListenSequenceNumber current_sequence_number() const override; + + void Shutdown() override; + + LevelDbMutationQueue* GetMutationQueueForUser( + const auth::User& user) override; + + LevelDbTargetCache* target_cache() override; + + LevelDbRemoteDocumentCache* remote_document_cache() override; + + LevelDbIndexManager* index_manager() override; + + LevelDbLruReferenceDelegate* reference_delegate() override; + + protected: + void RunInternal(absl::string_view label, + std::function block) override; + + private: + LevelDbPersistence(std::unique_ptr db, + util::Path directory, + std::set users, + LocalSerializer serializer, + const LruParams& lru_params); + + /** + * Ensures that the given directory exists. + */ + static util::Status EnsureDirectory(const util::Path& dir); + + /** Opens the database within the given directory. */ + static util::StatusOr> OpenDb( + const util::Path& dir); + + std::unique_ptr db_; + + util::Path directory_; + std::set users_; + LocalSerializer serializer_; + bool started_ = false; + + std::unique_ptr current_mutation_queue_; + std::unique_ptr target_cache_; + std::unique_ptr document_cache_; + std::unique_ptr index_manager_; + std::unique_ptr reference_delegate_; + + std::unique_ptr transaction_; +}; + +/** Returns a standard set of read options. */ +leveldb::ReadOptions StandardReadOptions(); + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_PERSISTENCE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_query_cache.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_query_cache.h deleted file mode 100644 index caf28c4..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_query_cache.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_QUERY_CACHE_H_ -#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_QUERY_CACHE_H_ - -#if !defined(__OBJC__) -#error "For now, this file must only be included by ObjC source files." -#endif // !defined(__OBJC__) - -#import - -#include - -#import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h" -#include "Firestore/core/src/firebase/firestore/local/query_cache.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" -#include "absl/strings/string_view.h" -#include "leveldb/db.h" - -@class FSTLevelDB; -@class FSTLocalSerializer; -@class FSTQuery; -@class FSTQueryData; - -NS_ASSUME_NONNULL_BEGIN - -namespace firebase { -namespace firestore { -namespace local { - -/** Cached Queries backed by LevelDB. */ -class LevelDbQueryCache : public QueryCache { - public: - /** - * Retrieves the global singleton metadata row from the given database, if it - * exists. - * TODO(gsoltis): remove this method once fully ported to transactions. - */ - static FSTPBTargetGlobal* ReadMetadata(leveldb::DB* db); - - /** - * Creates a new query cache in the given LevelDB. - * - * @param db The LevelDB in which to create the cache. - */ - LevelDbQueryCache(FSTLevelDB* db, FSTLocalSerializer* serializer); - - // Target-related methods - void AddTarget(FSTQueryData* query_data) override; - - void UpdateTarget(FSTQueryData* query_data) override; - - void RemoveTarget(FSTQueryData* query_data) override; - - FSTQueryData* _Nullable GetTarget(FSTQuery* query) override; - - void EnumerateTargets(const TargetCallback& callback) override; - - int RemoveTargets(model::ListenSequenceNumber upper_bound, - const std::unordered_map& - live_targets) override; - - // Key-related methods - - /** Adds the given document keys to cached query results of the given target - * ID. */ - void AddMatchingKeys(const model::DocumentKeySet& keys, - model::TargetId target_id) override; - - /** Removes the given document keys from the cached query results of the given - * target ID. */ - void RemoveMatchingKeys(const model::DocumentKeySet& keys, - model::TargetId target_id) override; - - /** Removes all the keys in the query results of the given target ID. */ - void RemoveAllKeysForTarget(model::TargetId target_id); - - model::DocumentKeySet GetMatchingKeys(model::TargetId target_id) override; - - /** - * Checks to see if there are any references to a document with the given key. - */ - bool Contains(const model::DocumentKey& key) override; - - // Other methods and accessors - size_t size() const override { - return metadata_.targetCount; - } - - model::TargetId highest_target_id() const override { - return metadata_.highestTargetId; - } - - model::ListenSequenceNumber highest_listen_sequence_number() const override { - return metadata_.highestListenSequenceNumber; - } - - const model::SnapshotVersion& GetLastRemoteSnapshotVersion() const override; - - void SetLastRemoteSnapshotVersion(model::SnapshotVersion version) override; - - // Non-interface methods - void Start(); - - void EnumerateOrphanedDocuments(const OrphanedDocumentCallback& callback); - - private: - void Save(FSTQueryData* query_data); - bool UpdateMetadata(FSTQueryData* query_data); - void SaveMetadata(); - /** - * Parses the given bytes as an FSTPBTarget protocol buffer and then converts - * to the equivalent query data. - */ - FSTQueryData* DecodeTarget(absl::string_view encoded); - - // This instance is owned by FSTLevelDB; avoid a retain cycle. - __weak FSTLevelDB* db_; - FSTLocalSerializer* serializer_; - /** A write-through cached copy of the metadata for the query cache. */ - FSTPBTargetGlobal* metadata_; - model::SnapshotVersion last_remote_snapshot_version_; -}; - -} // namespace local -} // namespace firestore -} // namespace firebase - -NS_ASSUME_NONNULL_END - -#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_QUERY_CACHE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_query_cache.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_query_cache.mm deleted file mode 100644 index 4412c46..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_query_cache.mm +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/local/leveldb_query_cache.h" - -#include -#include - -#import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Local/FSTLevelDB.h" -#import "Firestore/Source/Local/FSTLocalSerializer.h" -#import "Firestore/Source/Local/FSTQueryData.h" -#include "Firestore/core/src/firebase/firestore/local/leveldb_key.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" -#include "absl/strings/match.h" - -namespace firebase { -namespace firestore { -namespace local { - -using model::DocumentKey; -using model::DocumentKeySet; -using model::ListenSequenceNumber; -using model::SnapshotVersion; -using model::TargetId; -using util::MakeString; -using leveldb::Status; - -FSTPBTargetGlobal* LevelDbQueryCache::ReadMetadata(leveldb::DB* db) { - std::string key = LevelDbTargetGlobalKey::Key(); - std::string value; - Status status = db->Get([FSTLevelDB standardReadOptions], key, &value); - if (status.IsNotFound()) { - return nil; - } else if (!status.ok()) { - HARD_FAIL("metadataForKey: failed loading key %s with status: %s", key, - status.ToString()); - } - - NSData* data = [[NSData alloc] initWithBytesNoCopy:(void*)value.data() - length:value.size() - freeWhenDone:NO]; - - NSError* error; - FSTPBTargetGlobal* proto = [FSTPBTargetGlobal parseFromData:data - error:&error]; - if (!proto) { - HARD_FAIL("FSTPBTargetGlobal failed to parse: %s", error); - } - - return proto; -} - -LevelDbQueryCache::LevelDbQueryCache(FSTLevelDB* db, - FSTLocalSerializer* serializer) - : db_(db), serializer_(serializer) { -} - -// TODO(gsoltis): revisit having a Start method vs a static factory function -// that returns a started instance. -void LevelDbQueryCache::Start() { - // TODO(gsoltis): switch this usage of ptr to currentTransaction - metadata_ = ReadMetadata(db_.ptr); - HARD_ASSERT(metadata_ != nil, - "Found nil metadata, expected schema to be at version 0 which " - "ensures metadata existence"); - last_remote_snapshot_version_ = - [serializer_ decodedVersion:metadata_.lastRemoteSnapshotVersion]; -} - -void LevelDbQueryCache::AddTarget(FSTQueryData* query_data) { - Save(query_data); - - NSString* canonical_id = query_data.query.canonicalID; - std::string index_key = - LevelDbQueryTargetKey::Key(MakeString(canonical_id), query_data.targetID); - std::string empty_buffer; - db_.currentTransaction->Put(index_key, empty_buffer); - - metadata_.targetCount++; - UpdateMetadata(query_data); - SaveMetadata(); -} - -void LevelDbQueryCache::UpdateTarget(FSTQueryData* query_data) { - Save(query_data); - - if (UpdateMetadata(query_data)) { - SaveMetadata(); - } -} - -void LevelDbQueryCache::RemoveTarget(FSTQueryData* query_data) { - TargetId target_id = query_data.targetID; - - RemoveAllKeysForTarget(target_id); - - std::string key = LevelDbTargetKey::Key(target_id); - db_.currentTransaction->Delete(key); - - std::string index_key = LevelDbQueryTargetKey::Key( - MakeString(query_data.query.canonicalID), target_id); - db_.currentTransaction->Delete(index_key); - - metadata_.targetCount--; - SaveMetadata(); -} - -FSTQueryData* _Nullable LevelDbQueryCache::GetTarget(FSTQuery* query) { - // Scan the query-target index starting with a prefix starting with the given - // query's canonicalID. Note that this is a scan rather than a get because - // canonicalIDs are not required to be unique per target. - std::string canonical_id = MakeString(query.canonicalID); - auto index_iterator = db_.currentTransaction->NewIterator(); - std::string index_prefix = LevelDbQueryTargetKey::KeyPrefix(canonical_id); - index_iterator->Seek(index_prefix); - - // Simultaneously scan the targets table. This works because each - // (canonicalID, targetID) pair is unique and ordered, so when scanning a - // table prefixed by exactly one canonicalID, all the targetIDs will be unique - // and in order. - std::string target_prefix = LevelDbTargetKey::KeyPrefix(); - auto target_iterator = db_.currentTransaction->NewIterator(); - - LevelDbQueryTargetKey row_key; - for (; index_iterator->Valid(); index_iterator->Next()) { - // Only consider rows matching exactly the specific canonicalID of interest. - if (!absl::StartsWith(index_iterator->key(), index_prefix) || - !row_key.Decode(index_iterator->key()) || - canonical_id != row_key.canonical_id()) { - // End of this canonicalID's possible targets. - break; - } - - // Each row is a unique combination of canonicalID and targetID, so this - // foreign key reference can only occur once. - std::string target_key = LevelDbTargetKey::Key(row_key.target_id()); - target_iterator->Seek(target_key); - if (!target_iterator->Valid() || target_iterator->key() != target_key) { - HARD_FAIL("Dangling query-target reference found: " - "%s points to %s; seeking there found %s", - DescribeKey(index_iterator), DescribeKey(target_key), - DescribeKey(target_iterator)); - } - - // Finally after finding a potential match, check that the query is actually - // equal to the requested query. - FSTQueryData* target = DecodeTarget(target_iterator->value()); - if ([target.query isEqual:query]) { - return target; - } - } - - return nil; -} - -void LevelDbQueryCache::EnumerateTargets(const TargetCallback& callback) { - // Enumerate all targets, give their sequence numbers. - std::string target_prefix = LevelDbTargetKey::KeyPrefix(); - auto it = db_.currentTransaction->NewIterator(); - it->Seek(target_prefix); - for (; it->Valid() && absl::StartsWith(it->key(), target_prefix); - it->Next()) { - FSTQueryData* target = DecodeTarget(it->value()); - callback(target); - } -} - -int LevelDbQueryCache::RemoveTargets( - ListenSequenceNumber upper_bound, - const std::unordered_map& live_targets) { - int count = 0; - std::string target_prefix = LevelDbTargetKey::KeyPrefix(); - auto it = db_.currentTransaction->NewIterator(); - it->Seek(target_prefix); - for (; it->Valid() && absl::StartsWith(it->key(), target_prefix); - it->Next()) { - FSTQueryData* query_data = DecodeTarget(it->value()); - if (query_data.sequenceNumber <= upper_bound && - live_targets.find(query_data.targetID) == live_targets.end()) { - RemoveTarget(query_data); - count++; - } - } - return count; -} - -void LevelDbQueryCache::AddMatchingKeys(const DocumentKeySet& keys, - TargetId target_id) { - // Store an empty value in the index which is equivalent to serializing a - // GPBEmpty message. In the future if we wanted to store some other kind of - // value here, we can parse these empty values as with some other protocol - // buffer (and the parser will see all default values). - std::string empty_buffer; - - for (const DocumentKey& key : keys) { - db_.currentTransaction->Put(LevelDbTargetDocumentKey::Key(target_id, key), - empty_buffer); - db_.currentTransaction->Put(LevelDbDocumentTargetKey::Key(key, target_id), - empty_buffer); - [db_.referenceDelegate addReference:key]; - }; -} - -void LevelDbQueryCache::RemoveMatchingKeys(const DocumentKeySet& keys, - TargetId target_id) { - for (const DocumentKey& key : keys) { - db_.currentTransaction->Delete( - LevelDbTargetDocumentKey::Key(target_id, key)); - db_.currentTransaction->Delete( - LevelDbDocumentTargetKey::Key(key, target_id)); - [db_.referenceDelegate removeReference:key]; - } -} - -void LevelDbQueryCache::RemoveAllKeysForTarget(TargetId target_id) { - std::string index_prefix = LevelDbTargetDocumentKey::KeyPrefix(target_id); - auto index_iterator = db_.currentTransaction->NewIterator(); - index_iterator->Seek(index_prefix); - - LevelDbTargetDocumentKey row_key; - for (; index_iterator->Valid(); index_iterator->Next()) { - absl::string_view index_key = index_iterator->key(); - - // Only consider rows matching this specific targetID. - if (!row_key.Decode(index_key) || row_key.target_id() != target_id) { - break; - } - const DocumentKey& document_key = row_key.document_key(); - - // Delete both index rows - db_.currentTransaction->Delete(index_key); - db_.currentTransaction->Delete( - LevelDbDocumentTargetKey::Key(document_key, target_id)); - } -} - -DocumentKeySet LevelDbQueryCache::GetMatchingKeys(TargetId target_id) { - std::string index_prefix = LevelDbTargetDocumentKey::KeyPrefix(target_id); - auto index_iterator = db_.currentTransaction->NewIterator(); - index_iterator->Seek(index_prefix); - - DocumentKeySet result; - LevelDbTargetDocumentKey row_key; - for (; index_iterator->Valid(); index_iterator->Next()) { - // TODO(gsoltis): could we use a StartsWith instead? - // Only consider rows matching this specific target_id. - if (!row_key.Decode(index_iterator->key()) || - row_key.target_id() != target_id) { - break; - } - - result = result.insert(row_key.document_key()); - } - - return result; -} - -bool LevelDbQueryCache::Contains(const DocumentKey& key) { - // ignore sentinel rows when determining if a key belongs to a target. - // Sentinel row just says the document exists, not that it's a member of any - // particular target. - std::string index_prefix = LevelDbDocumentTargetKey::KeyPrefix(key.path()); - auto index_iterator = db_.currentTransaction->NewIterator(); - index_iterator->Seek(index_prefix); - - for (; index_iterator->Valid() && - absl::StartsWith(index_iterator->key(), index_prefix); - index_iterator->Next()) { - LevelDbDocumentTargetKey row_key; - if (row_key.Decode(index_iterator->key()) && !row_key.IsSentinel() && - row_key.document_key() == key) { - return true; - } - } - - return false; -} - -const SnapshotVersion& LevelDbQueryCache::GetLastRemoteSnapshotVersion() const { - return last_remote_snapshot_version_; -} - -void LevelDbQueryCache::SetLastRemoteSnapshotVersion(SnapshotVersion version) { - last_remote_snapshot_version_ = std::move(version); - metadata_.lastRemoteSnapshotVersion = - [serializer_ encodedVersion:last_remote_snapshot_version_]; - SaveMetadata(); -} - -void LevelDbQueryCache::EnumerateOrphanedDocuments( - const OrphanedDocumentCallback& callback) { - std::string document_target_prefix = LevelDbDocumentTargetKey::KeyPrefix(); - auto it = db_.currentTransaction->NewIterator(); - it->Seek(document_target_prefix); - ListenSequenceNumber next_to_report = 0; - DocumentKey key_to_report; - LevelDbDocumentTargetKey key; - - for (; it->Valid() && absl::StartsWith(it->key(), document_target_prefix); - it->Next()) { - HARD_ASSERT(key.Decode(it->key()), "Failed to decode DocumentTarget key"); - if (key.IsSentinel()) { - // if next_to_report is non-zero, report it, this is a new key so the last - // one must be not be a member of any targets. - if (next_to_report != 0) { - callback(key_to_report, next_to_report); - } - // set next_to_report to be this sequence number. It's the next one we - // might report, if we don't find any targets for this document. - next_to_report = - LevelDbDocumentTargetKey::DecodeSentinelValue(it->value()); - key_to_report = key.document_key(); - } else { - // set next_to_report to be 0, we know we don't need to report this one - // since we found a target for it. - next_to_report = 0; - } - } - // if next_to_report is non-zero, report it. We didn't find any targets for - // that document, and we weren't asked to stop. - if (next_to_report != 0) { - callback(key_to_report, next_to_report); - } -} - -void LevelDbQueryCache::Save(FSTQueryData* query_data) { - TargetId target_id = query_data.targetID; - std::string key = LevelDbTargetKey::Key(target_id); - db_.currentTransaction->Put(key, [serializer_ encodedQueryData:query_data]); -} - -bool LevelDbQueryCache::UpdateMetadata(FSTQueryData* query_data) { - bool updated = false; - if (query_data.targetID > metadata_.highestTargetId) { - metadata_.highestTargetId = query_data.targetID; - updated = true; - } - - if (query_data.sequenceNumber > metadata_.highestListenSequenceNumber) { - metadata_.highestListenSequenceNumber = query_data.sequenceNumber; - updated = true; - } - - return updated; -} - -void LevelDbQueryCache::SaveMetadata() { - db_.currentTransaction->Put(LevelDbTargetGlobalKey::Key(), metadata_); -} - -FSTQueryData* LevelDbQueryCache::DecodeTarget(absl::string_view encoded) { - NSData* data = [[NSData alloc] initWithBytesNoCopy:(void*)encoded.data() - length:encoded.size() - freeWhenDone:NO]; - - NSError* error; - FSTPBTarget* proto = [FSTPBTarget parseFromData:data error:&error]; - if (!proto) { - HARD_FAIL("FSTPBTarget failed to parse: %s", error); - } - - return [serializer_ decodedQueryData:proto]; -} - -} // namespace local -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_remote_document_cache.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_remote_document_cache.cc new file mode 100644 index 0000000..99d9af4 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_remote_document_cache.cc @@ -0,0 +1,221 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/leveldb_remote_document_cache.h" + +#include +#include + +#include "Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.h" + +#include "Firestore/core/src/firebase/firestore/local/leveldb_key.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_persistence.h" +#include "Firestore/core/src/firebase/firestore/local/local_serializer.h" +#include "Firestore/core/src/firebase/firestore/nanopb/message.h" +#include "Firestore/core/src/firebase/firestore/nanopb/reader.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/string_util.h" +#include "leveldb/db.h" + +namespace firebase { +namespace firestore { +namespace local { + +using core::Query; +using leveldb::Status; +using model::Document; +using model::DocumentKey; +using model::DocumentKeySet; +using model::DocumentMap; +using model::MaybeDocument; +using model::MaybeDocumentMap; +using model::OptionalMaybeDocumentMap; +using model::ResourcePath; +using model::SnapshotVersion; +using nanopb::ByteString; +using nanopb::Message; +using nanopb::StringReader; + +LevelDbRemoteDocumentCache::LevelDbRemoteDocumentCache( + LevelDbPersistence* db, LocalSerializer* serializer) + : db_(db), serializer_(NOT_NULL(serializer)) { +} + +void LevelDbRemoteDocumentCache::Add(const MaybeDocument& document, + const SnapshotVersion& read_time) { + const DocumentKey& key = document.key(); + const ResourcePath& path = key.path(); + + std::string ldb_document_key = LevelDbRemoteDocumentKey::Key(key); + db_->current_transaction()->Put(ldb_document_key, + serializer_->EncodeMaybeDocument(document)); + + std::string ldb_read_time_key = LevelDbRemoteDocumentReadTimeKey::Key( + path.PopLast(), read_time, path.last_segment()); + db_->current_transaction()->Put(ldb_read_time_key, ""); + + db_->index_manager()->AddToCollectionParentIndex( + document.key().path().PopLast()); +} + +void LevelDbRemoteDocumentCache::Remove(const DocumentKey& key) { + std::string ldb_key = LevelDbRemoteDocumentKey::Key(key); + db_->current_transaction()->Delete(ldb_key); +} + +absl::optional LevelDbRemoteDocumentCache::Get( + const DocumentKey& key) { + std::string ldb_key = LevelDbRemoteDocumentKey::Key(key); + std::string value; + Status status = db_->current_transaction()->Get(ldb_key, &value); + if (status.IsNotFound()) { + return absl::nullopt; + } else if (status.ok()) { + return DecodeMaybeDocument(value, key); + } else { + HARD_FAIL("Fetch document for key (%s) failed with status: %s", + key.ToString(), status.ToString()); + } +} + +OptionalMaybeDocumentMap LevelDbRemoteDocumentCache::GetAll( + const DocumentKeySet& keys) { + OptionalMaybeDocumentMap results; + + LevelDbRemoteDocumentKey current_key; + auto it = db_->current_transaction()->NewIterator(); + + for (const DocumentKey& key : keys) { + it->Seek(LevelDbRemoteDocumentKey::Key(key)); + if (!it->Valid() || !current_key.Decode(it->key()) || + current_key.document_key() != key) { + results = results.insert(key, absl::nullopt); + } else { + results = results.insert(key, DecodeMaybeDocument(it->value(), key)); + } + } + + return results; +} + +DocumentMap LevelDbRemoteDocumentCache::GetAllExisting( + const DocumentKeySet& keys) { + DocumentMap results; + + OptionalMaybeDocumentMap docs = LevelDbRemoteDocumentCache::GetAll(keys); + for (const auto& kv : docs) { + const DocumentKey& key = kv.first; + const auto& maybe_doc = kv.second; + if (maybe_doc && maybe_doc->is_document()) { + results = results.insert(key, Document(*maybe_doc)); + } + } + + return results; +} + +DocumentMap LevelDbRemoteDocumentCache::GetMatching( + const Query& query, const SnapshotVersion& since_read_time) { + HARD_ASSERT( + !query.IsCollectionGroupQuery(), + "CollectionGroup queries should be handled in LocalDocumentsView"); + + // Use the query path as a prefix for testing if a document matches the query. + const ResourcePath& query_path = query.path(); + size_t immediate_children_path_length = query_path.size() + 1; + + if (since_read_time != SnapshotVersion::None()) { + // Execute an index-free query and filter by read time. This is safe since + // all document changes to queries that have a + // last_limbo_free_snapshot_version (`since_read_time`) have a read time + // set. + std::string start_key = LevelDbRemoteDocumentReadTimeKey::KeyPrefix( + query_path, since_read_time); + auto it = db_->current_transaction()->NewIterator(); + it->Seek(util::ImmediateSuccessor(start_key)); + + DocumentKeySet remote_keys; + + LevelDbRemoteDocumentReadTimeKey current_key; + for (; it->Valid() && current_key.Decode(it->key()); it->Next()) { + const ResourcePath& collection_path = current_key.collection_path(); + if (collection_path != query_path) { + break; + } + + const SnapshotVersion& read_time = current_key.read_time(); + if (read_time > since_read_time) { + DocumentKey document_key(query_path.Append(current_key.document_id())); + remote_keys = remote_keys.insert(document_key); + } + } + + return LevelDbRemoteDocumentCache::GetAllExisting(remote_keys); + } else { + DocumentMap results; + + // Documents are ordered by key, so we can use a prefix scan to narrow down + // the documents we need to match the query against. + std::string start_key = LevelDbRemoteDocumentKey::KeyPrefix(query_path); + auto it = db_->current_transaction()->NewIterator(); + it->Seek(start_key); + + LevelDbRemoteDocumentKey current_key; + for (; it->Valid() && current_key.Decode(it->key()); it->Next()) { + // The query is actually returning any path that starts with the query + // path prefix which may include documents in subcollections. For example, + // a query on 'rooms' will return rooms/abc/messages/xyx but we shouldn't + // match it. Fix this by discarding rows with document keys more than one + // segment longer than the query path. + const DocumentKey& document_key = current_key.document_key(); + if (document_key.path().size() != immediate_children_path_length) { + continue; + } + + MaybeDocument maybe_doc = DecodeMaybeDocument(it->value(), document_key); + if (!query_path.IsPrefixOf(maybe_doc.key().path())) { + break; + } else if (maybe_doc.is_document()) { + results = results.insert(maybe_doc.key(), Document(maybe_doc)); + } + } + + return results; + } +} + +MaybeDocument LevelDbRemoteDocumentCache::DecodeMaybeDocument( + absl::string_view encoded, const DocumentKey& key) { + StringReader reader{encoded}; + + auto message = Message::TryParse(&reader); + MaybeDocument maybe_document = + serializer_->DecodeMaybeDocument(&reader, *message); + + if (!reader.ok()) { + HARD_FAIL("MaybeDocument proto failed to parse: %s", + reader.status().ToString()); + } + HARD_ASSERT(maybe_document.key() == key, + "Read document has key (%s) instead of expected key (%s).", + maybe_document.key().ToString(), key.ToString()); + + return maybe_document; +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_remote_document_cache.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_remote_document_cache.h index 99bf754..8143dc5 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_remote_document_cache.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_remote_document_cache.h @@ -17,55 +17,59 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_REMOTE_DOCUMENT_CACHE_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_REMOTE_DOCUMENT_CACHE_H_ -#if !defined(__OBJC__) -#error "For now, this file must only be included by ObjC source files." -#endif // !defined(__OBJC__) - #include #include "Firestore/core/src/firebase/firestore/local/remote_document_cache.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/document_map.h" +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" #include "Firestore/core/src/firebase/firestore/model/types.h" #include "absl/strings/string_view.h" -@class FSTLevelDB; -@class FSTLocalSerializer; -@class FSTMaybeDocument; -@class FSTQuery; - -NS_ASSUME_NONNULL_BEGIN - namespace firebase { namespace firestore { namespace local { +class LevelDbPersistence; +class LocalSerializer; + /** Cached Remote Documents backed by leveldb. */ class LevelDbRemoteDocumentCache : public RemoteDocumentCache { public: - LevelDbRemoteDocumentCache(FSTLevelDB* db, FSTLocalSerializer* serializer); + LevelDbRemoteDocumentCache(LevelDbPersistence* db, + LocalSerializer* serializer); - void Add(FSTMaybeDocument* document) override; + void Add(const model::MaybeDocument& document, + const model::SnapshotVersion& read_time) override; void Remove(const model::DocumentKey& key) override; - FSTMaybeDocument* _Nullable Get(const model::DocumentKey& key) override; - model::MaybeDocumentMap GetAll(const model::DocumentKeySet& keys) override; - model::DocumentMap GetMatching(FSTQuery* query) override; + absl::optional Get( + const model::DocumentKey& key) override; + model::OptionalMaybeDocumentMap GetAll( + const model::DocumentKeySet& keys) override; + model::DocumentMap GetMatching( + const core::Query& query, + const model::SnapshotVersion& since_read_time) override; private: - FSTMaybeDocument* DecodeMaybeDocument(absl::string_view encoded, - const model::DocumentKey& key); + /** + * Looks up a set of entries in the cache, returning only existing entries of + * Type::Document. + */ + model::DocumentMap GetAllExisting(const model::DocumentKeySet& keys); + + model::MaybeDocument DecodeMaybeDocument(absl::string_view encoded, + const model::DocumentKey& key); - // This instance is owned by FSTLevelDB; avoid a retain cycle. - __weak FSTLevelDB* db_; - FSTLocalSerializer* serializer_; + // The LevelDbRemoteDocumentCache instance is owned by LevelDbPersistence. + LevelDbPersistence* db_; + // Owned by LevelDbPersistence. + LocalSerializer* serializer_ = nullptr; }; } // namespace local } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_REMOTE_DOCUMENT_CACHE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_remote_document_cache.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_remote_document_cache.mm deleted file mode 100644 index 69002e0..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_remote_document_cache.mm +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/local/leveldb_remote_document_cache.h" - -#import - -#include - -#import "Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Local/FSTLevelDB.h" -#import "Firestore/Source/Local/FSTLocalSerializer.h" -#include "Firestore/core/src/firebase/firestore/local/leveldb_key.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" -#include "leveldb/db.h" - -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::DocumentKeySet; -using firebase::firestore::model::DocumentMap; -using firebase::firestore::model::MaybeDocumentMap; -using leveldb::Status; - -namespace firebase { -namespace firestore { -namespace local { - -LevelDbRemoteDocumentCache::LevelDbRemoteDocumentCache( - FSTLevelDB* db, FSTLocalSerializer* serializer) - : db_(db), serializer_(serializer) { -} - -void LevelDbRemoteDocumentCache::Add(FSTMaybeDocument* document) { - std::string ldb_key = LevelDbRemoteDocumentKey::Key(document.key); - db_.currentTransaction->Put(ldb_key, - [serializer_ encodedMaybeDocument:document]); - - db_.indexManager->AddToCollectionParentIndex(document.key.path().PopLast()); -} - -void LevelDbRemoteDocumentCache::Remove(const DocumentKey& key) { - std::string ldb_key = LevelDbRemoteDocumentKey::Key(key); - db_.currentTransaction->Delete(ldb_key); -} - -FSTMaybeDocument* _Nullable LevelDbRemoteDocumentCache::Get( - const DocumentKey& key) { - std::string ldb_key = LevelDbRemoteDocumentKey::Key(key); - std::string value; - Status status = db_.currentTransaction->Get(ldb_key, &value); - if (status.IsNotFound()) { - return nil; - } else if (status.ok()) { - return DecodeMaybeDocument(value, key); - } else { - HARD_FAIL("Fetch document for key (%s) failed with status: %s", - key.ToString(), status.ToString()); - } -} - -MaybeDocumentMap LevelDbRemoteDocumentCache::GetAll( - const DocumentKeySet& keys) { - MaybeDocumentMap results; - - LevelDbRemoteDocumentKey currentKey; - auto it = db_.currentTransaction->NewIterator(); - - for (const DocumentKey& key : keys) { - it->Seek(LevelDbRemoteDocumentKey::Key(key)); - if (!it->Valid() || !currentKey.Decode(it->key()) || - currentKey.document_key() != key) { - results = results.insert(key, nil); - } else { - results = results.insert(key, DecodeMaybeDocument(it->value(), key)); - } - } - - return results; -} - -DocumentMap LevelDbRemoteDocumentCache::GetMatching(FSTQuery* query) { - HARD_ASSERT( - ![query isCollectionGroupQuery], - "CollectionGroup queries should be handled in LocalDocumentsView"); - - DocumentMap results; - - // Use the query path as a prefix for testing if a document matches the query. - const model::ResourcePath& query_path = query.path; - size_t immediate_children_path_length = query_path.size() + 1; - - // Documents are ordered by key, so we can use a prefix scan to narrow down - // the documents we need to match the query against. - std::string start_key = LevelDbRemoteDocumentKey::KeyPrefix(query_path); - auto it = db_.currentTransaction->NewIterator(); - it->Seek(start_key); - - LevelDbRemoteDocumentKey current_key; - for (; it->Valid() && current_key.Decode(it->key()); it->Next()) { - // The query is actually returning any path that starts with the query path - // prefix which may include documents in subcollections. For example, a - // query on 'rooms' will return rooms/abc/messages/xyx but we shouldn't - // match it. Fix this by discarding rows with document keys more than one - // segment longer than the query path. - const DocumentKey& document_key = current_key.document_key(); - if (document_key.path().size() != immediate_children_path_length) { - continue; - } - - FSTMaybeDocument* maybe_doc = - DecodeMaybeDocument(it->value(), document_key); - if (!query_path.IsPrefixOf(maybe_doc.key.path())) { - break; - } else if ([maybe_doc isKindOfClass:[FSTDocument class]]) { - results = - results.insert(maybe_doc.key, static_cast(maybe_doc)); - } - } - - return results; -} - -FSTMaybeDocument* LevelDbRemoteDocumentCache::DecodeMaybeDocument( - absl::string_view encoded, const DocumentKey& key) { - NSData* data = [[NSData alloc] initWithBytesNoCopy:(void*)encoded.data() - length:encoded.size() - freeWhenDone:NO]; - - NSError* error; - FSTPBMaybeDocument* proto = [FSTPBMaybeDocument parseFromData:data - error:&error]; - if (!proto) { - HARD_FAIL("FSTPBMaybeDocument failed to parse: %s", error); - } - - FSTMaybeDocument* maybeDocument = [serializer_ decodedMaybeDocument:proto]; - HARD_ASSERT(maybeDocument.key == key, - "Read document has key (%s) instead of expected key (%s).", - maybeDocument.key.ToString(), key.ToString()); - return maybeDocument; -} - -} // namespace local -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_target_cache.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_target_cache.cc new file mode 100644 index 0000000..06dfb37 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_target_cache.cc @@ -0,0 +1,400 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/leveldb_target_cache.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/local/leveldb_key.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_persistence.h" +#include "Firestore/core/src/firebase/firestore/local/leveldb_util.h" +#include "Firestore/core/src/firebase/firestore/local/local_serializer.h" +#include "Firestore/core/src/firebase/firestore/local/reference_delegate.h" +#include "Firestore/core/src/firebase/firestore/local/target_data.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" +#include "Firestore/core/src/firebase/firestore/nanopb/reader.h" +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" +#include "absl/strings/match.h" + +namespace firebase { +namespace firestore { +namespace local { + +using core::Target; +using leveldb::Status; +using model::DocumentKey; +using model::DocumentKeySet; +using model::ListenSequenceNumber; +using model::SnapshotVersion; +using model::TargetId; +using nanopb::ByteString; +using nanopb::Message; +using nanopb::StringReader; + +absl::optional> +LevelDbTargetCache::TryReadMetadata(leveldb::DB* db) { + std::string key = LevelDbTargetGlobalKey::Key(); + std::string value; + Status status = db->Get(StandardReadOptions(), key, &value); + + StringReader reader{value}; + reader.set_status(ConvertStatus(status)); + + auto result = Message::TryParse(&reader); + if (!reader.ok()) { + if (reader.status().code() == Error::NotFound) { + return absl::nullopt; + } else { + HARD_FAIL("ReadMetadata: failed loading key %s with status: %s", key, + reader.status().ToString()); + } + } + + return std::move(result); +} + +Message LevelDbTargetCache::ReadMetadata( + leveldb::DB* db) { + auto maybe_metadata = TryReadMetadata(db); + if (!maybe_metadata) { + HARD_FAIL( + "Found no metadata, expected schema to be at version 0 which " + "ensures metadata existence"); + } + return std::move(maybe_metadata).value(); +} + +LevelDbTargetCache::LevelDbTargetCache(LevelDbPersistence* db, + LocalSerializer* serializer) + : db_(NOT_NULL(db)), serializer_(NOT_NULL(serializer)) { +} + +void LevelDbTargetCache::Start() { + // TODO(gsoltis): switch this usage of ptr to current_transaction() + metadata_ = ReadMetadata(db_->ptr()); + + StringReader reader; + last_remote_snapshot_version_ = serializer_->DecodeVersion( + &reader, metadata_->last_remote_snapshot_version); + if (!reader.ok()) { + HARD_FAIL("Failed to decode last remote snapshot version, reason: '%s'", + reader.status().ToString()); + } +} + +void LevelDbTargetCache::AddTarget(const TargetData& target_data) { + Save(target_data); + + const std::string& canonical_id = target_data.target().CanonicalId(); + std::string index_key = + LevelDbQueryTargetKey::Key(canonical_id, target_data.target_id()); + std::string empty_buffer; + db_->current_transaction()->Put(index_key, empty_buffer); + + metadata_->target_count++; + UpdateMetadata(target_data); + SaveMetadata(); +} + +void LevelDbTargetCache::UpdateTarget(const TargetData& target_data) { + Save(target_data); + + if (UpdateMetadata(target_data)) { + SaveMetadata(); + } +} + +void LevelDbTargetCache::RemoveTarget(const TargetData& target_data) { + TargetId target_id = target_data.target_id(); + + RemoveAllKeysForTarget(target_id); + + std::string key = LevelDbTargetKey::Key(target_id); + db_->current_transaction()->Delete(key); + + std::string index_key = + LevelDbQueryTargetKey::Key(target_data.target().CanonicalId(), target_id); + db_->current_transaction()->Delete(index_key); + + metadata_->target_count--; + SaveMetadata(); +} + +absl::optional LevelDbTargetCache::GetTarget(const Target& target) { + // Scan the query-target index starting with a prefix starting with the given + // target's canonical_id. Note that this is a scan rather than a get because + // canonical_ids are not required to be unique per target. + const std::string& canonical_id = target.CanonicalId(); + auto index_iterator = db_->current_transaction()->NewIterator(); + std::string index_prefix = LevelDbQueryTargetKey::KeyPrefix(canonical_id); + index_iterator->Seek(index_prefix); + + // Simultaneously scan the targets table. This works because each + // (canonical_id, target_id) pair is unique and ordered, so when scanning a + // table prefixed by exactly one canonical_id, all the target_ids will be + // unique and in order. + std::string target_prefix = LevelDbTargetKey::KeyPrefix(); + auto target_iterator = db_->current_transaction()->NewIterator(); + + LevelDbQueryTargetKey row_key; + for (; index_iterator->Valid(); index_iterator->Next()) { + // Only consider rows matching exactly the specific canonical_id of + // interest. + if (!absl::StartsWith(index_iterator->key(), index_prefix) || + !row_key.Decode(index_iterator->key()) || + canonical_id != row_key.canonical_id()) { + // End of this canonical_id's possible targets. + break; + } + + // Each row is a unique combination of canonical_id and target_id, so this + // foreign key reference can only occur once. + std::string target_key = LevelDbTargetKey::Key(row_key.target_id()); + target_iterator->Seek(target_key); + if (!target_iterator->Valid() || target_iterator->key() != target_key) { + HARD_FAIL( + "Dangling query-target reference found: " + "%s points to %s; seeking there found %s", + DescribeKey(index_iterator), DescribeKey(target_key), + DescribeKey(target_iterator)); + } + + // Finally after finding a potential match, check that the target is + // actually equal to the requested target. + TargetData target_data = DecodeTarget(target_iterator->value()); + if (target_data.target() == target) { + return target_data; + } + } + + return absl::nullopt; +} + +void LevelDbTargetCache::EnumerateTargets(const TargetCallback& callback) { + // Enumerate all targets, give their sequence numbers. + std::string target_prefix = LevelDbTargetKey::KeyPrefix(); + auto it = db_->current_transaction()->NewIterator(); + it->Seek(target_prefix); + for (; it->Valid() && absl::StartsWith(it->key(), target_prefix); + it->Next()) { + TargetData target = DecodeTarget(it->value()); + callback(target); + } +} + +int LevelDbTargetCache::RemoveTargets( + ListenSequenceNumber upper_bound, + const std::unordered_map& live_targets) { + int count = 0; + std::string target_prefix = LevelDbTargetKey::KeyPrefix(); + auto it = db_->current_transaction()->NewIterator(); + it->Seek(target_prefix); + for (; it->Valid() && absl::StartsWith(it->key(), target_prefix); + it->Next()) { + TargetData target_data = DecodeTarget(it->value()); + if (target_data.sequence_number() <= upper_bound && + live_targets.find(target_data.target_id()) == live_targets.end()) { + RemoveTarget(target_data); + count++; + } + } + return count; +} + +void LevelDbTargetCache::AddMatchingKeys(const DocumentKeySet& keys, + TargetId target_id) { + // Store an empty value in the index which is equivalent to serializing a + // GPBEmpty message. In the future if we wanted to store some other kind of + // value here, we can parse these empty values as with some other protocol + // buffer (and the parser will see all default values). + std::string empty_buffer; + + for (const DocumentKey& key : keys) { + db_->current_transaction()->Put( + LevelDbTargetDocumentKey::Key(target_id, key), empty_buffer); + db_->current_transaction()->Put( + LevelDbDocumentTargetKey::Key(key, target_id), empty_buffer); + db_->reference_delegate()->AddReference(key); + } +} + +void LevelDbTargetCache::RemoveMatchingKeys(const DocumentKeySet& keys, + TargetId target_id) { + for (const DocumentKey& key : keys) { + db_->current_transaction()->Delete( + LevelDbTargetDocumentKey::Key(target_id, key)); + db_->current_transaction()->Delete( + LevelDbDocumentTargetKey::Key(key, target_id)); + db_->reference_delegate()->RemoveReference(key); + } +} + +void LevelDbTargetCache::RemoveAllKeysForTarget(TargetId target_id) { + std::string index_prefix = LevelDbTargetDocumentKey::KeyPrefix(target_id); + auto index_iterator = db_->current_transaction()->NewIterator(); + index_iterator->Seek(index_prefix); + + LevelDbTargetDocumentKey row_key; + for (; index_iterator->Valid(); index_iterator->Next()) { + absl::string_view index_key = index_iterator->key(); + + // Only consider rows matching this specific target_id. + if (!row_key.Decode(index_key) || row_key.target_id() != target_id) { + break; + } + const DocumentKey& document_key = row_key.document_key(); + + // Delete both index rows + db_->current_transaction()->Delete(index_key); + db_->current_transaction()->Delete( + LevelDbDocumentTargetKey::Key(document_key, target_id)); + } +} + +DocumentKeySet LevelDbTargetCache::GetMatchingKeys(TargetId target_id) { + std::string index_prefix = LevelDbTargetDocumentKey::KeyPrefix(target_id); + auto index_iterator = db_->current_transaction()->NewIterator(); + index_iterator->Seek(index_prefix); + + DocumentKeySet result; + LevelDbTargetDocumentKey row_key; + for (; index_iterator->Valid(); index_iterator->Next()) { + // TODO(gsoltis): could we use a StartsWith instead? + // Only consider rows matching this specific target_id. + if (!row_key.Decode(index_iterator->key()) || + row_key.target_id() != target_id) { + break; + } + + result = result.insert(row_key.document_key()); + } + + return result; +} + +bool LevelDbTargetCache::Contains(const DocumentKey& key) { + // ignore sentinel rows when determining if a key belongs to a target. + // Sentinel row just says the document exists, not that it's a member of any + // particular target. + std::string index_prefix = LevelDbDocumentTargetKey::KeyPrefix(key.path()); + auto index_iterator = db_->current_transaction()->NewIterator(); + index_iterator->Seek(index_prefix); + + for (; index_iterator->Valid() && + absl::StartsWith(index_iterator->key(), index_prefix); + index_iterator->Next()) { + LevelDbDocumentTargetKey row_key; + if (row_key.Decode(index_iterator->key()) && !row_key.IsSentinel() && + row_key.document_key() == key) { + return true; + } + } + + return false; +} + +const SnapshotVersion& LevelDbTargetCache::GetLastRemoteSnapshotVersion() + const { + return last_remote_snapshot_version_; +} + +void LevelDbTargetCache::SetLastRemoteSnapshotVersion(SnapshotVersion version) { + last_remote_snapshot_version_ = std::move(version); + metadata_->last_remote_snapshot_version = + serializer_->EncodeVersion(last_remote_snapshot_version_); + SaveMetadata(); +} + +void LevelDbTargetCache::EnumerateOrphanedDocuments( + const OrphanedDocumentCallback& callback) { + std::string document_target_prefix = LevelDbDocumentTargetKey::KeyPrefix(); + auto it = db_->current_transaction()->NewIterator(); + it->Seek(document_target_prefix); + ListenSequenceNumber next_to_report = 0; + DocumentKey key_to_report; + LevelDbDocumentTargetKey key; + + for (; it->Valid() && absl::StartsWith(it->key(), document_target_prefix); + it->Next()) { + HARD_ASSERT(key.Decode(it->key()), "Failed to decode DocumentTarget key"); + if (key.IsSentinel()) { + // if next_to_report is non-zero, report it, this is a new key so the last + // one must be not be a member of any targets. + if (next_to_report != 0) { + callback(key_to_report, next_to_report); + } + // set next_to_report to be this sequence number. It's the next one we + // might report, if we don't find any targets for this document. + next_to_report = + LevelDbDocumentTargetKey::DecodeSentinelValue(it->value()); + key_to_report = key.document_key(); + } else { + // set next_to_report to be 0, we know we don't need to report this one + // since we found a target for it. + next_to_report = 0; + } + } + // if next_to_report is non-zero, report it. We didn't find any targets for + // that document, and we weren't asked to stop. + if (next_to_report != 0) { + callback(key_to_report, next_to_report); + } +} + +void LevelDbTargetCache::Save(const TargetData& target_data) { + TargetId target_id = target_data.target_id(); + std::string key = LevelDbTargetKey::Key(target_id); + db_->current_transaction()->Put(key, + serializer_->EncodeTargetData(target_data)); +} + +bool LevelDbTargetCache::UpdateMetadata(const TargetData& target_data) { + bool updated = false; + if (target_data.target_id() > metadata_->highest_target_id) { + metadata_->highest_target_id = target_data.target_id(); + updated = true; + } + + if (target_data.sequence_number() > + metadata_->highest_listen_sequence_number) { + metadata_->highest_listen_sequence_number = target_data.sequence_number(); + updated = true; + } + + return updated; +} + +void LevelDbTargetCache::SaveMetadata() { + db_->current_transaction()->Put(LevelDbTargetGlobalKey::Key(), metadata_); +} + +TargetData LevelDbTargetCache::DecodeTarget(absl::string_view encoded) { + StringReader reader{encoded}; + auto message = Message::TryParse(&reader); + auto result = serializer_->DecodeTargetData(&reader, *message); + if (!reader.ok()) { + HARD_FAIL("Target proto failed to parse: %s", reader.status().ToString()); + } + + return result; +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_target_cache.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_target_cache.h new file mode 100644 index 0000000..a86b973 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_target_cache.h @@ -0,0 +1,153 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_TARGET_CACHE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_TARGET_CACHE_H_ + +#include + +#include "Firestore/Protos/nanopb/firestore/local/target.nanopb.h" +#include "Firestore/core/src/firebase/firestore/local/target_cache.h" +#include "Firestore/core/src/firebase/firestore/local/target_data.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/nanopb/message.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "leveldb/db.h" + +namespace firebase { +namespace firestore { +namespace local { + +class LevelDbPersistence; +class LocalSerializer; + +/** Cached Queries backed by LevelDB. */ +class LevelDbTargetCache : public TargetCache { + public: + /** + * Retrieves the global singleton metadata row from the given database. If the + * metadata row doesn't exist, this will result in an assertion failure. + * + * TODO(gsoltis): remove this method once fully ported to transactions. + */ + static nanopb::Message ReadMetadata( + leveldb::DB* db); + + /** + * Test-only -- same as `ReadMetadata`, but returns an empty optional if the + * metadata row doesn't exist. + */ + static absl::optional> + TryReadMetadata(leveldb::DB* db); + + /** + * Creates a new target cache in the given LevelDB. + * + * @param db The LevelDB in which to create the cache. + */ + LevelDbTargetCache(LevelDbPersistence* db, LocalSerializer* serializer); + + // Target-related methods + void AddTarget(const TargetData& target_data) override; + + void UpdateTarget(const TargetData& target_data) override; + + void RemoveTarget(const TargetData& target_data) override; + + absl::optional GetTarget(const core::Target& target) override; + + void EnumerateTargets(const TargetCallback& callback) override; + + int RemoveTargets(model::ListenSequenceNumber upper_bound, + const std::unordered_map& + live_targets) override; + + // Key-related methods + + /** + * Adds the given document keys to cached query results of the given target + * ID. + */ + void AddMatchingKeys(const model::DocumentKeySet& keys, + model::TargetId target_id) override; + + /** Removes the given document keys from the cached query results of the given + * target ID. */ + void RemoveMatchingKeys(const model::DocumentKeySet& keys, + model::TargetId target_id) override; + + /** Removes all the keys in the query results of the given target ID. */ + void RemoveAllKeysForTarget(model::TargetId target_id); + + model::DocumentKeySet GetMatchingKeys(model::TargetId target_id) override; + + /** + * Checks to see if there are any references to a document with the given key. + */ + bool Contains(const model::DocumentKey& key) override; + + // Other methods and accessors + size_t size() const override { + return metadata_->target_count; + } + + model::TargetId highest_target_id() const override { + return metadata_->highest_target_id; + } + + model::ListenSequenceNumber highest_listen_sequence_number() const override { + return metadata_->highest_listen_sequence_number; + } + + const model::SnapshotVersion& GetLastRemoteSnapshotVersion() const override; + + void SetLastRemoteSnapshotVersion(model::SnapshotVersion version) override; + + // Non-interface methods + void Start(); + + void EnumerateOrphanedDocuments(const OrphanedDocumentCallback& callback); + + private: + void Save(const TargetData& target_data); + bool UpdateMetadata(const TargetData& target_data); + void SaveMetadata(); + + /** + * Parses the given bytes as a `firestore_client_Target` protocol buffer and + * then converts to the equivalent target data. + */ + TargetData DecodeTarget(absl::string_view encoded); + + // The LevelDbTargetCache is owned by LevelDbPersistence. + LevelDbPersistence* db_; + // Owned by LevelDbPersistence. + LocalSerializer* serializer_ = nullptr; + + /** A write-through cached copy of the metadata for the target cache. */ + nanopb::Message metadata_; + + model::SnapshotVersion last_remote_snapshot_version_; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_TARGET_CACHE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc index b1d9f5c..114df2c 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc @@ -83,12 +83,12 @@ void LevelDbTransaction::Iterator::Seek(const std::string& key) { last_version_ = txn_->version_; } -absl::string_view LevelDbTransaction::Iterator::key() { +const std::string& LevelDbTransaction::Iterator::key() const { HARD_ASSERT(Valid(), "key() called on invalid iterator"); return current_.first; } -absl::string_view LevelDbTransaction::Iterator::value() { +const std::string& LevelDbTransaction::Iterator::value() const { HARD_ASSERT(Valid(), "value() called on invalid iterator"); return current_.second; } @@ -139,21 +139,18 @@ LevelDbTransaction::LevelDbTransaction(DB* db, absl::string_view label, const ReadOptions& read_options, const WriteOptions& write_options) - : db_(db), - mutations_(), - deletions_(), + : db_(NOT_NULL(db)), read_options_(read_options), write_options_(write_options), - version_(0), - label_(std::string{label}) { + label_(label) { } const ReadOptions& LevelDbTransaction::DefaultReadOptions() { - static ReadOptions options = ([]() { + static ReadOptions options = [] { ReadOptions read_options; read_options.verify_checksums = true; return read_options; - })(); + }(); return options; } @@ -164,7 +161,7 @@ const WriteOptions& LevelDbTransaction::DefaultWriteOptions() { void LevelDbTransaction::Put(std::string key, std::string value) { deletions_.erase(key); - mutations_.emplace(std::make_pair(std::move(key), std::move(value))); + mutations_[std::move(key)] = std::move(value); version_++; } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_transaction.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_transaction.h index 3dc06fe..87d1b05 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_transaction.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_transaction.h @@ -24,13 +24,12 @@ #include #include +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" +#include "Firestore/core/src/firebase/firestore/nanopb/message.h" +#include "Firestore/core/src/firebase/firestore/nanopb/writer.h" #include "absl/strings/string_view.h" #include "leveldb/db.h" -#if __OBJC__ -#import -#endif - namespace firebase { namespace firestore { namespace local { @@ -56,7 +55,7 @@ class LevelDbTransaction { /** * Returns true if this iterator points to an entry */ - bool Valid() { + bool Valid() const { return is_valid_; } @@ -74,12 +73,12 @@ class LevelDbTransaction { /** * Returns the key of the current entry */ - absl::string_view key(); + const std::string& key() const; /** * Returns the value of the current entry */ - absl::string_view value(); + const std::string& value() const; private: /** @@ -156,25 +155,21 @@ class LevelDbTransaction { */ void Delete(absl::string_view key); -#if __OBJC__ - /** - * Schedules the row identified by `key` to be set to the given protocol - * buffer message when this transaction commits. - */ - void Put(absl::string_view key, GPBMessage* message) { - NSData* data = [message data]; - std::string key_string(key); - mutations_[key_string] = std::string((const char*)data.bytes, data.length); - version_++; - } -#endif - /** * Schedules the row identified by `key` to be set to `value` when this * transaction commits. */ void Put(std::string key, std::string value); + /** + * Schedules the row identified by `key` to be set to the given protocol + * buffer message when this transaction commits. + */ + template + void Put(std::string key, const nanopb::Message& message) { + Put(std::move(key), MakeStdString(message)); + } + /** * Sets the contents of `value` to the latest known value for the given key, * including any pending mutations and `Status::OK` is returned. If the key @@ -198,12 +193,12 @@ class LevelDbTransaction { std::string ToString(); private: - leveldb::DB* db_; + leveldb::DB* db_ = nullptr; Mutations mutations_; Deletions deletions_; leveldb::ReadOptions read_options_; leveldb::WriteOptions write_options_; - int32_t version_; + int32_t version_ = 0; std::string label_; }; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_util.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_util.cc index 3b5d14e..cad14b2 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_util.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_util.cc @@ -17,6 +17,7 @@ #include "Firestore/core/src/firebase/firestore/local/leveldb_util.h" #include "Firestore/core/include/firebase/firestore/firestore_errors.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" #include "absl/strings/str_cat.h" namespace firebase { @@ -25,14 +26,14 @@ namespace local { namespace { -FirestoreErrorCode ConvertStatusCode(const leveldb::Status& status) { - if (status.ok()) return FirestoreErrorCode::Ok; - if (status.IsNotFound()) return FirestoreErrorCode::NotFound; - if (status.IsCorruption()) return FirestoreErrorCode::DataLoss; - if (status.IsIOError()) return FirestoreErrorCode::Unavailable; - if (status.IsNotSupportedError()) return FirestoreErrorCode::Unimplemented; - if (status.IsInvalidArgument()) return FirestoreErrorCode::InvalidArgument; - return FirestoreErrorCode::Unknown; +Error ConvertStatusCode(const leveldb::Status& status) { + if (status.ok()) return Error::Ok; + if (status.IsNotFound()) return Error::NotFound; + if (status.IsCorruption()) return Error::DataLoss; + if (status.IsIOError()) return Error::Unavailable; + if (status.IsNotSupportedError()) return Error::Unimplemented; + if (status.IsInvalidArgument()) return Error::InvalidArgument; + return Error::Unknown; } } // namespace @@ -40,7 +41,7 @@ FirestoreErrorCode ConvertStatusCode(const leveldb::Status& status) { util::Status ConvertStatus(const leveldb::Status& status) { if (status.ok()) return util::Status::OK(); - FirestoreErrorCode code = ConvertStatusCode(status); + Error code = ConvertStatusCode(status); return util::Status{code, absl::StrCat("LevelDB error: ", status.ToString())}; } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_util.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_util.h index 24a7537..f2e79f6 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_util.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/leveldb_util.h @@ -19,7 +19,7 @@ #include -#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "absl/strings/string_view.h" #include "leveldb/slice.h" #include "leveldb/status.h" diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_documents_view.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_documents_view.cc new file mode 100644 index 0000000..846b382 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_documents_view.cc @@ -0,0 +1,242 @@ +/* + * Copyright 2017 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/local_documents_view.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/local/mutation_queue.h" +#include "Firestore/core/src/firebase/firestore/local/remote_document_cache.h" +#include "Firestore/core/src/firebase/firestore/model/document.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/document_map.h" +#include "Firestore/core/src/firebase/firestore/model/no_document.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" + +namespace firebase { +namespace firestore { +namespace local { + +using core::Query; +using model::Document; +using model::DocumentKey; +using model::DocumentKeySet; +using model::DocumentMap; +using model::MaybeDocument; +using model::MaybeDocumentMap; +using model::Mutation; +using model::MutationBatch; +using model::NoDocument; +using model::OptionalMaybeDocumentMap; +using model::ResourcePath; +using model::SnapshotVersion; + +absl::optional LocalDocumentsView::GetDocument( + const DocumentKey& key) { + std::vector batches = + mutation_queue_->AllMutationBatchesAffectingDocumentKey(key); + return GetDocument(key, batches); +} + +absl::optional LocalDocumentsView::GetDocument( + const DocumentKey& key, const std::vector& batches) { + absl::optional document = remote_document_cache_->Get(key); + for (const MutationBatch& batch : batches) { + document = batch.ApplyToLocalDocument(document, key); + } + + return document; +} + +OptionalMaybeDocumentMap LocalDocumentsView::ApplyLocalMutationsToDocuments( + const OptionalMaybeDocumentMap& docs, + const std::vector& batches) { + OptionalMaybeDocumentMap results; + + for (const auto& kv : docs) { + const DocumentKey& key = kv.first; + absl::optional local_view = kv.second; + for (const MutationBatch& batch : batches) { + local_view = batch.ApplyToLocalDocument(local_view, key); + } + results = results.insert(key, local_view); + } + return results; +} + +MaybeDocumentMap LocalDocumentsView::GetDocuments(const DocumentKeySet& keys) { + OptionalMaybeDocumentMap docs = remote_document_cache_->GetAll(keys); + return GetLocalViewOfDocuments(docs); +} + +MaybeDocumentMap LocalDocumentsView::GetLocalViewOfDocuments( + const OptionalMaybeDocumentMap& base_docs) { + DocumentKeySet all_keys; + for (const auto& kv : base_docs) { + all_keys = all_keys.insert(kv.first); + } + std::vector batches = + mutation_queue_->AllMutationBatchesAffectingDocumentKeys(all_keys); + + OptionalMaybeDocumentMap docs = + ApplyLocalMutationsToDocuments(base_docs, batches); + + MaybeDocumentMap results; + for (const auto& kv : docs) { + const DocumentKey& key = kv.first; + absl::optional maybe_doc = kv.second; + + // TODO(http://b/32275378): Don't conflate missing / deleted. + if (!maybe_doc) { + maybe_doc = NoDocument(key, SnapshotVersion::None(), + /* has_committed_mutations= */ false); + } + results = results.insert(key, *maybe_doc); + } + + return results; +} + +DocumentMap LocalDocumentsView::GetDocumentsMatchingQuery( + const Query& query, const model::SnapshotVersion& since_read_time) { + if (query.IsDocumentQuery()) { + return GetDocumentsMatchingDocumentQuery(query.path()); + } else if (query.IsCollectionGroupQuery()) { + return GetDocumentsMatchingCollectionGroupQuery(query, since_read_time); + } else { + return GetDocumentsMatchingCollectionQuery(query, since_read_time); + } +} + +DocumentMap LocalDocumentsView::GetDocumentsMatchingDocumentQuery( + const ResourcePath& doc_path) { + DocumentMap result; + // Just do a simple document lookup. + absl::optional doc = GetDocument(DocumentKey{doc_path}); + if (doc && doc->is_document()) { + result = result.insert(doc->key(), Document(*doc)); + } + return result; +} + +model::DocumentMap LocalDocumentsView::GetDocumentsMatchingCollectionGroupQuery( + const Query& query, const SnapshotVersion& since_read_time) { + HARD_ASSERT( + query.path().empty(), + "Currently we only support collection group queries at the root."); + + const std::string& collection_id = *query.collection_group(); + std::vector parents = + index_manager_->GetCollectionParents(collection_id); + DocumentMap results; + + // Perform a collection query against each parent that contains the + // collection_id and aggregate the results. + for (const ResourcePath& parent : parents) { + Query collection_query = + query.AsCollectionQueryAtPath(parent.Append(collection_id)); + DocumentMap collection_results = + GetDocumentsMatchingCollectionQuery(collection_query, since_read_time); + for (const auto& kv : collection_results.underlying_map()) { + const DocumentKey& key = kv.first; + results = results.insert(key, Document(kv.second)); + } + } + return results; +} + +DocumentMap LocalDocumentsView::GetDocumentsMatchingCollectionQuery( + const Query& query, const SnapshotVersion& since_read_time) { + DocumentMap results = + remote_document_cache_->GetMatching(query, since_read_time); + // Get locally persisted mutation batches. + std::vector matching_batches = + mutation_queue_->AllMutationBatchesAffectingQuery(query); + + results = AddMissingBaseDocuments(matching_batches, std::move(results)); + + for (const MutationBatch& batch : matching_batches) { + for (const Mutation& mutation : batch.mutations()) { + // Only process documents belonging to the collection. + if (!query.path().IsImmediateParentOf(mutation.key().path())) { + continue; + } + + const DocumentKey& key = mutation.key(); + // base_doc may be unset for the documents that weren't yet written to + // the backend. + absl::optional base_doc = + results.underlying_map().get(key); + + absl::optional mutated_doc = mutation.ApplyToLocalView( + base_doc, base_doc, batch.local_write_time()); + + if (mutated_doc && mutated_doc->is_document()) { + results = results.insert(key, Document(*mutated_doc)); + } else { + results = results.erase(key); + } + } + } + + // Finally, filter out any documents that don't actually match the query. Note + // that the extra reference here prevents DocumentMap's destructor from + // deallocating the initial unfiltered results while we're iterating over + // them. + DocumentMap unfiltered = results; + for (const auto& kv : unfiltered.underlying_map()) { + const DocumentKey& key = kv.first; + Document doc(kv.second); + if (!query.Matches(doc)) { + results = results.erase(key); + } + } + + return results; +} + +DocumentMap LocalDocumentsView::AddMissingBaseDocuments( + const std::vector& matching_batches, + DocumentMap existing_docs) { + DocumentKeySet missing_doc_keys; + for (const MutationBatch& batch : matching_batches) { + for (const Mutation& mutation : batch.mutations()) { + const DocumentKey& key = mutation.key(); + if (mutation.type() == Mutation::Type::Patch && + !existing_docs.underlying_map().contains(key)) { + missing_doc_keys = missing_doc_keys.insert(key); + } + } + } + + OptionalMaybeDocumentMap missing_docs = + remote_document_cache_->GetAll(missing_doc_keys); + for (const auto& kv : missing_docs) { + const absl::optional& maybe_doc = kv.second; + if (maybe_doc && maybe_doc->is_document()) { + existing_docs = existing_docs.insert(kv.first, Document(*maybe_doc)); + } + } + + return existing_docs; +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_documents_view.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_documents_view.h index b4dd650..a4a0440 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_documents_view.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_documents_view.h @@ -17,10 +17,9 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LOCAL_DOCUMENTS_VIEW_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LOCAL_DOCUMENTS_VIEW_H_ -#import - #include +#include "Firestore/core/src/firebase/firestore/core/query.h" #include "Firestore/core/src/firebase/firestore/local/index_manager.h" #include "Firestore/core/src/firebase/firestore/local/mutation_queue.h" #include "Firestore/core/src/firebase/firestore/local/remote_document_cache.h" @@ -28,21 +27,15 @@ #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/document_map.h" -NS_ASSUME_NONNULL_BEGIN - -@class FSTMaybeDocument; -@class FSTMutationBatch; -@class FSTQuery; - namespace firebase { namespace firestore { namespace local { /** * A readonly view of the local state of all documents we're tracking (i.e. we - * have a cached version in remoteDocumentCache or local mutations for the + * have a cached version in the RemoteDocumentCache or local mutations for the * document). The view is computed by applying the mutations in the - * FSTMutationQueue to the FSTRemoteDocumentCache. + * MutationQueue to the RemoteDocumentCache. */ class LocalDocumentsView { public: @@ -54,54 +47,94 @@ class LocalDocumentsView { index_manager_{index_manager} { } + virtual ~LocalDocumentsView() = default; + /** * Gets the local view of the document identified by `key`. * * @return Local view of the document or nil if we don't have any cached state * for it. */ - FSTMaybeDocument* _Nullable GetDocument(const model::DocumentKey& key); + absl::optional GetDocument( + const model::DocumentKey& key); /** * Gets the local view of the documents identified by `keys`. * - * If we don't have cached state for a document in `keys`, a - * FSTDeletedDocument will be stored for that key in the resulting set. + * If we don't have cached state for a document in `keys`, a DeletedDocument + * will be stored for that key in the resulting set. */ model::MaybeDocumentMap GetDocuments(const model::DocumentKeySet& keys); /** - * Similar to `documentsForKeys`, but creates the local view from the given - * `baseDocs` without retrieving documents from the local store. + * Similar to `GetDocuments`, but creates the local view from the given + * `base_docs` without retrieving documents from the local store. */ model::MaybeDocumentMap GetLocalViewOfDocuments( - const model::MaybeDocumentMap& base_docs); + const model::OptionalMaybeDocumentMap& base_docs); - /** Performs a query against the local view of all documents. */ - model::DocumentMap GetDocumentsMatchingQuery(FSTQuery* query); + /** + * Performs a query against the local view of all documents. + * + * @param query The query to match documents against. + * @param since_read_time If not set to SnapshotVersion::None(), return only + * documents that have been read since this snapshot version (exclusive). + */ + // Virtual for testing. + virtual model::DocumentMap GetDocumentsMatchingQuery( + const core::Query& query, const model::SnapshotVersion& since_read_time); private: + friend class CountingQueryEngine; // For testing + /** Internal version of GetDocument that allows re-using batches. */ - FSTMaybeDocument* _Nullable GetDocument( + absl::optional GetDocument( const model::DocumentKey& key, - const std::vector& batches); + const std::vector& batches); /** * Returns the view of the given `docs` as they would appear after applying * all mutations in the given `batches`. */ - model::MaybeDocumentMap ApplyLocalMutationsToDocuments( - const model::MaybeDocumentMap& docs, - const std::vector& batches); + model::OptionalMaybeDocumentMap ApplyLocalMutationsToDocuments( + const model::OptionalMaybeDocumentMap& docs, + const std::vector& batches); /** Performs a simple document lookup for the given path. */ model::DocumentMap GetDocumentsMatchingDocumentQuery( const model::ResourcePath& doc_path); - model::DocumentMap GetDocumentsMatchingCollectionGroupQuery(FSTQuery* query); + model::DocumentMap GetDocumentsMatchingCollectionGroupQuery( + const core::Query& query, const model::SnapshotVersion& since_read_time); /** Queries the remote documents and overlays mutations. */ - model::DocumentMap GetDocumentsMatchingCollectionQuery(FSTQuery* query); + model::DocumentMap GetDocumentsMatchingCollectionQuery( + const core::Query& query, const model::SnapshotVersion& since_read_time); + + /** + * It is possible that a `PatchMutation` can make a document match a query, + * even if the version in the `RemoteDocumentCache` is not a match yet + * (waiting for server to ack). To handle this, we find all document keys + * affected by the `PatchMutation`s that are not in `existing_docs` yet, and + * back fill them via `remote_document_cache_->GetAll`, otherwise those + * `PatchMutation`s will be ignored because no base document can be found, and + * lead to missing results for the query. + */ + model::DocumentMap AddMissingBaseDocuments( + const std::vector& matching_batches, + model::DocumentMap existing_docs); + + RemoteDocumentCache* remote_document_cache() { + return remote_document_cache_; + } + + MutationQueue* mutation_queue() { + return mutation_queue_; + } + + IndexManager* index_manager() { + return index_manager_; + } RemoteDocumentCache* remote_document_cache_; MutationQueue* mutation_queue_; @@ -112,6 +145,4 @@ class LocalDocumentsView { } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LOCAL_DOCUMENTS_VIEW_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_documents_view.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_documents_view.mm deleted file mode 100644 index c27692b..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_documents_view.mm +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#import "Firestore/core/src/firebase/firestore/local/local_documents_view.h" - -#include - -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Model/FSTMutationBatch.h" - -#include "Firestore/core/src/firebase/firestore/local/mutation_queue.h" -#include "Firestore/core/src/firebase/firestore/local/remote_document_cache.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/document_map.h" -#include "Firestore/core/src/firebase/firestore/model/resource_path.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace firebase { -namespace firestore { -namespace local { - -using model::DocumentKey; -using model::DocumentKeySet; -using model::DocumentMap; -using model::MaybeDocumentMap; -using model::ResourcePath; -using model::SnapshotVersion; -using util::MakeString; - -FSTMaybeDocument* _Nullable LocalDocumentsView::GetDocument( - const DocumentKey& key) { - std::vector batches = - mutation_queue_->AllMutationBatchesAffectingDocumentKey(key); - return GetDocument(key, batches); -} - -FSTMaybeDocument* _Nullable LocalDocumentsView::GetDocument( - const DocumentKey& key, const std::vector& batches) { - FSTMaybeDocument* _Nullable document = remote_document_cache_->Get(key); - for (FSTMutationBatch* batch : batches) { - document = [batch applyToLocalDocument:document documentKey:key]; - } - - return document; -} - -MaybeDocumentMap LocalDocumentsView::ApplyLocalMutationsToDocuments( - const MaybeDocumentMap& docs, - const std::vector& batches) { - MaybeDocumentMap results; - - for (const auto& kv : docs) { - const DocumentKey& key = kv.first; - FSTMaybeDocument* local_view = kv.second; - for (FSTMutationBatch* batch : batches) { - local_view = [batch applyToLocalDocument:local_view documentKey:key]; - } - results = results.insert(key, local_view); - } - return results; -} - -MaybeDocumentMap LocalDocumentsView::GetDocuments(const DocumentKeySet& keys) { - MaybeDocumentMap docs = remote_document_cache_->GetAll(keys); - return GetLocalViewOfDocuments(docs); -} - -/** - * Similar to `documentsForKeys`, but creates the local view from the given - * `baseDocs` without retrieving documents from the local store. - */ -MaybeDocumentMap LocalDocumentsView::GetLocalViewOfDocuments( - const MaybeDocumentMap& base_docs) { - MaybeDocumentMap results; - - DocumentKeySet all_keys; - for (const auto& kv : base_docs) { - all_keys = all_keys.insert(kv.first); - } - std::vector batches = - mutation_queue_->AllMutationBatchesAffectingDocumentKeys(all_keys); - - MaybeDocumentMap docs = ApplyLocalMutationsToDocuments(base_docs, batches); - - for (const auto& kv : docs) { - const DocumentKey& key = kv.first; - FSTMaybeDocument* maybe_doc = kv.second; - - // TODO(http://b/32275378): Don't conflate missing / deleted. - if (!maybe_doc) { - maybe_doc = [FSTDeletedDocument documentWithKey:key - version:SnapshotVersion::None() - hasCommittedMutations:NO]; - } - results = results.insert(key, maybe_doc); - } - - return results; -} - -DocumentMap LocalDocumentsView::GetDocumentsMatchingQuery(FSTQuery* query) { - if ([query isDocumentQuery]) { - return GetDocumentsMatchingDocumentQuery(query.path); - } else if ([query isCollectionGroupQuery]) { - return GetDocumentsMatchingCollectionGroupQuery(query); - } else { - return GetDocumentsMatchingCollectionQuery(query); - } -} - -DocumentMap LocalDocumentsView::GetDocumentsMatchingDocumentQuery( - const ResourcePath& doc_path) { - DocumentMap result; - // Just do a simple document lookup. - FSTMaybeDocument* doc = GetDocument(DocumentKey{doc_path}); - if ([doc isKindOfClass:[FSTDocument class]]) { - result = result.insert(doc.key, static_cast(doc)); - } - return result; -} - -model::DocumentMap LocalDocumentsView::GetDocumentsMatchingCollectionGroupQuery( - FSTQuery* query) { - HARD_ASSERT( - query.path.empty(), - "Currently we only support collection group queries at the root."); - - std::string collection_id = MakeString(query.collectionGroup); - std::vector parents = - index_manager_->GetCollectionParents(collection_id); - DocumentMap results; - - // Perform a collection query against each parent that contains the - // collection_id and aggregate the results. - for (const ResourcePath& parent : parents) { - FSTQuery* collection_query = - [query collectionQueryAtPath:parent.Append(collection_id)]; - DocumentMap collection_results = - GetDocumentsMatchingCollectionQuery(collection_query); - for (const auto& kv : collection_results.underlying_map()) { - const DocumentKey& key = kv.first; - FSTDocument* doc = static_cast(kv.second); - results = results.insert(key, doc); - } - } - return results; -} - -DocumentMap LocalDocumentsView::GetDocumentsMatchingCollectionQuery( - FSTQuery* query) { - DocumentMap results = remote_document_cache_->GetMatching(query); - // Get locally persisted mutation batches. - std::vector matchingBatches = - mutation_queue_->AllMutationBatchesAffectingQuery(query); - - for (FSTMutationBatch* batch : matchingBatches) { - for (FSTMutation* mutation : [batch mutations]) { - // Only process documents belonging to the collection. - if (!query.path.IsImmediateParentOf(mutation.key.path())) { - continue; - } - - const DocumentKey& key = mutation.key; - // base_doc may be nil for the documents that weren't yet written to the - // backend. - FSTMaybeDocument* base_doc = nil; - auto found = results.underlying_map().find(key); - if (found != results.underlying_map().end()) { - base_doc = found->second; - } - FSTMaybeDocument* mutated_doc = - [mutation applyToLocalDocument:base_doc - baseDocument:base_doc - localWriteTime:batch.localWriteTime]; - - if ([mutated_doc isKindOfClass:[FSTDocument class]]) { - results = results.insert(key, static_cast(mutated_doc)); - } else { - results = results.erase(key); - } - } - } - - // Finally, filter out any documents that don't actually match the query. Note - // that the extra reference here prevents DocumentMap's destructor from - // deallocating the initial unfiltered results while we're iterating over - // them. - DocumentMap unfiltered = results; - for (const auto& kv : unfiltered.underlying_map()) { - const DocumentKey& key = kv.first; - auto* doc = static_cast(kv.second); - if (![query matchesDocument:doc]) { - results = results.erase(key); - } - } - - return results; -} - -} // namespace local -} // namespace firestore -} // namespace firebase - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_serializer.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_serializer.cc index 2b7944f..4934eec 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_serializer.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_serializer.cc @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -29,6 +30,7 @@ #include "Firestore/core/src/firebase/firestore/model/no_document.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/unknown_document.h" +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" #include "Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_format.h" @@ -37,69 +39,83 @@ namespace firebase { namespace firestore { namespace local { -using core::Query; +namespace { + +using core::Target; using model::Document; +using model::DocumentState; +using model::FieldValue; using model::MaybeDocument; using model::Mutation; using model::MutationBatch; using model::NoDocument; +using model::ObjectValue; using model::SnapshotVersion; using model::UnknownDocument; +using nanopb::ByteString; using nanopb::CheckedSize; +using nanopb::MakeArray; +using nanopb::Message; using nanopb::Reader; +using nanopb::SafeReadBoolean; using nanopb::Writer; -using remote::MakeArray; using util::Status; using util::StringFormat; -firestore_client_MaybeDocument LocalSerializer::EncodeMaybeDocument( +} // namespace + +Message LocalSerializer::EncodeMaybeDocument( const MaybeDocument& maybe_doc) const { - firestore_client_MaybeDocument result{}; + Message result; switch (maybe_doc.type()) { - case MaybeDocument::Type::Document: - result.which_document_type = firestore_client_MaybeDocument_document_tag; - result.document = EncodeDocument(static_cast(maybe_doc)); - // TODO(rsgowman): heldwriteacks: - // result.has_committed_mutations = existing_doc.HasCommittedMutations(); + case MaybeDocument::Type::Document: { + result->which_document_type = firestore_client_MaybeDocument_document_tag; + Document doc(maybe_doc); + // TODO(b/142956770): other platforms check for whether the `Document` + // contains a memoized proto and use it if available instead of + // re-encoding. + result->document = EncodeDocument(doc); + result->has_committed_mutations = doc.has_committed_mutations(); return result; + } - case MaybeDocument::Type::NoDocument: - result.which_document_type = + case MaybeDocument::Type::NoDocument: { + result->which_document_type = firestore_client_MaybeDocument_no_document_tag; - result.no_document = - EncodeNoDocument(static_cast(maybe_doc)); - // TODO(rsgowman): heldwriteacks: - // result.has_committed_mutations = no_doc.HasCommittedMutations(); + NoDocument no_doc(maybe_doc); + result->no_document = EncodeNoDocument(no_doc); + result->has_committed_mutations = no_doc.has_committed_mutations(); return result; + } case MaybeDocument::Type::UnknownDocument: - result.which_document_type = + result->which_document_type = firestore_client_MaybeDocument_unknown_document_tag; - result.unknown_document = - EncodeUnknownDocument(static_cast(maybe_doc)); - // TODO(rsgowman): heldwriteacks: - // result.has_committed_mutations = true; + result->unknown_document = + EncodeUnknownDocument(UnknownDocument(maybe_doc)); + result->has_committed_mutations = true; return result; - case MaybeDocument::Type::Unknown: - // TODO(rsgowman): Error handling - abort(); + case MaybeDocument::Type::Invalid: + HARD_FAIL("Unknown document type %s", maybe_doc.type()); } UNREACHABLE(); } -std::unique_ptr LocalSerializer::DecodeMaybeDocument( +MaybeDocument LocalSerializer::DecodeMaybeDocument( Reader* reader, const firestore_client_MaybeDocument& proto) const { - if (!reader->status().ok()) return nullptr; + if (!reader->status().ok()) return {}; switch (proto.which_document_type) { case firestore_client_MaybeDocument_document_tag: - return rpc_serializer_.DecodeDocument(reader, proto.document); + return DecodeDocument(reader, proto.document, + SafeReadBoolean(proto.has_committed_mutations)); case firestore_client_MaybeDocument_no_document_tag: - return DecodeNoDocument(reader, proto.no_document); + return DecodeNoDocument(reader, proto.no_document, + SafeReadBoolean(proto.has_committed_mutations)); case firestore_client_MaybeDocument_unknown_document_tag: return DecodeUnknownDocument(reader, proto.unknown_document); @@ -111,7 +127,7 @@ std::unique_ptr LocalSerializer::DecodeMaybeDocument( proto.which_document_type, firestore_client_MaybeDocument_no_document_tag, firestore_client_MaybeDocument_document_tag)); - return nullptr; + return {}; } UNREACHABLE(); @@ -121,8 +137,7 @@ google_firestore_v1_Document LocalSerializer::EncodeDocument( const Document& doc) const { google_firestore_v1_Document result{}; - result.name = - rpc_serializer_.EncodeString(rpc_serializer_.EncodeKey(doc.key())); + result.name = rpc_serializer_.EncodeKey(doc.key()); // Encode Document.fields (unless it's empty) pb_size_t count = CheckedSize(doc.data().GetInternalValue().size()); @@ -135,138 +150,162 @@ google_firestore_v1_Document LocalSerializer::EncodeDocument( i++; } + result.has_update_time = true; result.update_time = rpc_serializer_.EncodeVersion(doc.version()); - // Ignore Document.create_time. (We don't use this in our on-disk protos.) return result; } +Document LocalSerializer::DecodeDocument( + Reader* reader, + const google_firestore_v1_Document& proto, + bool has_committed_mutations) const { + ObjectValue fields = + rpc_serializer_.DecodeFields(reader, proto.fields_count, proto.fields); + SnapshotVersion version = + rpc_serializer_.DecodeVersion(reader, proto.update_time); + + DocumentState state = has_committed_mutations + ? DocumentState::kCommittedMutations + : DocumentState::kSynced; + return Document(std::move(fields), + rpc_serializer_.DecodeKey(reader, proto.name), version, + state); +} + firestore_client_NoDocument LocalSerializer::EncodeNoDocument( const NoDocument& no_doc) const { firestore_client_NoDocument result{}; - result.name = - rpc_serializer_.EncodeString(rpc_serializer_.EncodeKey(no_doc.key())); + result.name = rpc_serializer_.EncodeKey(no_doc.key()); result.read_time = rpc_serializer_.EncodeVersion(no_doc.version()); return result; } -std::unique_ptr LocalSerializer::DecodeNoDocument( - Reader* reader, const firestore_client_NoDocument& proto) const { +NoDocument LocalSerializer::DecodeNoDocument( + Reader* reader, + const firestore_client_NoDocument& proto, + bool has_committed_mutations) const { SnapshotVersion version = - rpc_serializer_.DecodeSnapshotVersion(reader, proto.read_time); - - // TODO(rsgowman): Fix hardcoding of has_committed_mutations. - // Instead, we should grab this from the proto (see other ports). However, - // we'll defer until the nanopb-master gets merged to master. - return absl::make_unique( - rpc_serializer_.DecodeKey(reader, - rpc_serializer_.DecodeString(proto.name)), - std::move(version), - /*has_committed_mutations=*/false); + rpc_serializer_.DecodeVersion(reader, proto.read_time); + + return NoDocument(rpc_serializer_.DecodeKey(reader, proto.name), version, + has_committed_mutations); } firestore_client_UnknownDocument LocalSerializer::EncodeUnknownDocument( const UnknownDocument& unknown_doc) const { firestore_client_UnknownDocument result{}; - result.name = rpc_serializer_.EncodeString( - rpc_serializer_.EncodeKey(unknown_doc.key())); + result.name = rpc_serializer_.EncodeKey(unknown_doc.key()); result.version = rpc_serializer_.EncodeVersion(unknown_doc.version()); return result; } -std::unique_ptr LocalSerializer::DecodeUnknownDocument( +UnknownDocument LocalSerializer::DecodeUnknownDocument( Reader* reader, const firestore_client_UnknownDocument& proto) const { SnapshotVersion version = - rpc_serializer_.DecodeSnapshotVersion(reader, proto.version); + rpc_serializer_.DecodeVersion(reader, proto.version); - return absl::make_unique( - rpc_serializer_.DecodeKey(reader, - rpc_serializer_.DecodeString(proto.name)), - std::move(version)); + return UnknownDocument(rpc_serializer_.DecodeKey(reader, proto.name), + version); } -firestore_client_Target LocalSerializer::EncodeQueryData( - const QueryData& query_data) const { - firestore_client_Target result{}; - - result.target_id = query_data.target_id(); - result.last_listen_sequence_number = query_data.sequence_number(); - result.snapshot_version = rpc_serializer_.EncodeTimestamp( - query_data.snapshot_version().timestamp()); - result.resume_token = rpc_serializer_.EncodeBytes(query_data.resume_token()); - - const Query& query = query_data.query(); - if (query.IsDocumentQuery()) { - // TODO(rsgowman): Implement. Probably like this (once EncodeDocumentsTarget - // exists): - /* - result.which_target_type = firestore_client_Target_document_tag; - result.documents = rpc_serializer_.EncodeDocumentsTarget(query); - */ - abort(); +Message LocalSerializer::EncodeTargetData( + const TargetData& target_data) const { + HARD_ASSERT(target_data.purpose() == QueryPurpose::Listen, + "Only queries with purpose %s may be stored, got %s", + QueryPurpose::Listen, target_data.purpose()); + + Message result; + + result->target_id = target_data.target_id(); + result->last_listen_sequence_number = target_data.sequence_number(); + result->snapshot_version = rpc_serializer_.EncodeTimestamp( + target_data.snapshot_version().timestamp()); + result->last_limbo_free_snapshot_version = rpc_serializer_.EncodeTimestamp( + target_data.last_limbo_free_snapshot_version().timestamp()); + + // Force a copy because pb_release would otherwise double-free. + result->resume_token = + nanopb::CopyBytesArray(target_data.resume_token().get()); + + const Target& target = target_data.target(); + if (target.IsDocumentQuery()) { + result->which_target_type = firestore_client_Target_documents_tag; + result->documents = rpc_serializer_.EncodeDocumentsTarget(target); } else { - result.which_target_type = firestore_client_Target_query_tag; - result.query = rpc_serializer_.EncodeQueryTarget(query); + result->which_target_type = firestore_client_Target_query_tag; + result->query = rpc_serializer_.EncodeQueryTarget(target); } return result; } -QueryData LocalSerializer::DecodeQueryData( +TargetData LocalSerializer::DecodeTargetData( Reader* reader, const firestore_client_Target& proto) const { - if (!reader->status().ok()) return QueryData::Invalid(); + if (!reader->status().ok()) return TargetData(); model::TargetId target_id = proto.target_id; - // TODO(rgowman): How to handle truncation of integer types? model::ListenSequenceNumber sequence_number = static_cast( proto.last_listen_sequence_number); SnapshotVersion version = - rpc_serializer_.DecodeSnapshotVersion(reader, proto.snapshot_version); - std::vector resume_token = - rpc_serializer_.DecodeBytes(proto.resume_token); - Query query = Query::Invalid(); + rpc_serializer_.DecodeVersion(reader, proto.snapshot_version); + SnapshotVersion last_limbo_free_snapshot_version = + rpc_serializer_.DecodeVersion(reader, + proto.last_limbo_free_snapshot_version); + ByteString resume_token(proto.resume_token); + Target target; switch (proto.which_target_type) { case firestore_client_Target_query_tag: - query = rpc_serializer_.DecodeQueryTarget(reader, proto.query); + target = rpc_serializer_.DecodeQueryTarget(reader, proto.query); break; case firestore_client_Target_documents_tag: - // TODO(rsgowman): Implement. - abort(); + target = rpc_serializer_.DecodeDocumentsTarget(reader, proto.documents); + break; default: reader->Fail( StringFormat("Unknown target_type: %s", proto.which_target_type)); } - if (!reader->status().ok()) return QueryData::Invalid(); - return QueryData(std::move(query), target_id, sequence_number, - QueryPurpose::kListen, std::move(version), - std::move(resume_token)); + if (!reader->status().ok()) return TargetData(); + return TargetData(std::move(target), target_id, sequence_number, + QueryPurpose::Listen, version, + last_limbo_free_snapshot_version, std::move(resume_token)); } -firestore_client_WriteBatch LocalSerializer::EncodeMutationBatch( +Message LocalSerializer::EncodeMutationBatch( const MutationBatch& mutation_batch) const { - firestore_client_WriteBatch result{}; + Message result; - result.batch_id = mutation_batch.batch_id(); - pb_size_t count = CheckedSize(mutation_batch.mutations().size()); - result.writes_count = count; - result.writes = MakeArray(count); + result->batch_id = mutation_batch.batch_id(); + + pb_size_t count = CheckedSize(mutation_batch.base_mutations().size()); + result->base_writes_count = count; + result->base_writes = MakeArray(count); int i = 0; - for (const std::unique_ptr& mutation : mutation_batch.mutations()) { - HARD_ASSERT(mutation, "Null mutation encountered."); - result.writes[i] = rpc_serializer_.EncodeMutation(*mutation.get()); + for (const auto& mutation : mutation_batch.base_mutations()) { + result->base_writes[i] = rpc_serializer_.EncodeMutation(mutation); + i++; + } + + count = CheckedSize(mutation_batch.mutations().size()); + result->writes_count = count; + result->writes = MakeArray(count); + i = 0; + for (const auto& mutation : mutation_batch.mutations()) { + result->writes[i] = rpc_serializer_.EncodeMutation(mutation); i++; } - result.local_write_time = + + result->local_write_time = rpc_serializer_.EncodeTimestamp(mutation_batch.local_write_time()); return result; @@ -277,16 +316,33 @@ MutationBatch LocalSerializer::DecodeMutationBatch( int batch_id = proto.batch_id; Timestamp local_write_time = rpc_serializer_.DecodeTimestamp(reader, proto.local_write_time); - std::vector> mutations; + + std::vector base_mutations; + for (size_t i = 0; i < proto.base_writes_count; i++) { + base_mutations.push_back( + rpc_serializer_.DecodeMutation(reader, proto.base_writes[i])); + } + + std::vector mutations; for (size_t i = 0; i < proto.writes_count; i++) { mutations.push_back( rpc_serializer_.DecodeMutation(reader, proto.writes[i])); } - return MutationBatch(batch_id, std::move(local_write_time), + return MutationBatch(batch_id, local_write_time, std::move(base_mutations), std::move(mutations)); } +google_protobuf_Timestamp LocalSerializer::EncodeVersion( + const model::SnapshotVersion& version) const { + return rpc_serializer_.EncodeVersion(version); +} + +model::SnapshotVersion LocalSerializer::DecodeVersion( + nanopb::Reader* reader, const google_protobuf_Timestamp& proto) const { + return rpc_serializer_.DecodeVersion(reader, proto); +} + } // namespace local } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_serializer.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_serializer.h index f9b2864..8e1848d 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_serializer.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_serializer.h @@ -18,22 +18,24 @@ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LOCAL_SERIALIZER_H_ #include +#include #include #include "Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.h" #include "Firestore/Protos/nanopb/firestore/local/mutation.nanopb.h" #include "Firestore/Protos/nanopb/firestore/local/target.nanopb.h" -#include "Firestore/core/src/firebase/firestore/local/query_data.h" +#include "Firestore/core/src/firebase/firestore/local/target_data.h" #include "Firestore/core/src/firebase/firestore/model/document.h" #include "Firestore/core/src/firebase/firestore/model/maybe_document.h" #include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" #include "Firestore/core/src/firebase/firestore/model/no_document.h" #include "Firestore/core/src/firebase/firestore/model/types.h" #include "Firestore/core/src/firebase/firestore/model/unknown_document.h" +#include "Firestore/core/src/firebase/firestore/nanopb/message.h" #include "Firestore/core/src/firebase/firestore/nanopb/reader.h" #include "Firestore/core/src/firebase/firestore/nanopb/writer.h" #include "Firestore/core/src/firebase/firestore/remote/serializer.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" namespace firebase { namespace firestore { @@ -58,52 +60,44 @@ namespace local { */ class LocalSerializer { public: - explicit LocalSerializer(const remote::Serializer& rpc_serializer) - : rpc_serializer_(rpc_serializer) { - } - - /** - * Release memory allocated by the Encode* methods that return protos. - * - * This essentially wraps calls to nanopb's pb_release() method. - */ - static void FreeNanopbMessage(const pb_field_t fields[], void* dest_struct) { - remote::Serializer::FreeNanopbMessage(fields, dest_struct); + explicit LocalSerializer(remote::Serializer rpc_serializer) + : rpc_serializer_(std::move(rpc_serializer)) { } /** * @brief Encodes a MaybeDocument model to the equivalent nanopb proto for * local storage. */ - firestore_client_MaybeDocument EncodeMaybeDocument( + nanopb::Message EncodeMaybeDocument( const model::MaybeDocument& maybe_doc) const; /** * @brief Decodes nanopb proto representing a MaybeDocument proto to the * equivalent model. */ - std::unique_ptr DecodeMaybeDocument( + model::MaybeDocument DecodeMaybeDocument( nanopb::Reader* reader, const firestore_client_MaybeDocument& proto) const; /** - * @brief Encodes a QueryData to the equivalent nanopb proto, representing a + * @brief Encodes a TargetData to the equivalent nanopb proto, representing a * ::firestore::proto::Target, for local storage. */ - firestore_client_Target EncodeQueryData(const QueryData& query_data) const; + nanopb::Message EncodeTargetData( + const TargetData& target_data) const; /** * @brief Decodes nanopb proto representing a ::firestore::proto::Target proto - * to the equivalent QueryData. + * to the equivalent TargetData. */ - QueryData DecodeQueryData(nanopb::Reader* reader, - const firestore_client_Target& proto) const; + TargetData DecodeTargetData(nanopb::Reader* reader, + const firestore_client_Target& proto) const; /** * @brief Encodes a MutationBatch to the equivalent nanopb proto, representing * a ::firestore::client::WriteBatch, for local storage in the mutation queue. */ - firestore_client_WriteBatch EncodeMutationBatch( + nanopb::Message EncodeMutationBatch( const model::MutationBatch& mutation_batch) const; /** @@ -113,27 +107,38 @@ class LocalSerializer { model::MutationBatch DecodeMutationBatch( nanopb::Reader* reader, const firestore_client_WriteBatch& proto) const; + google_protobuf_Timestamp EncodeVersion( + const model::SnapshotVersion& version) const; + + model::SnapshotVersion DecodeVersion( + nanopb::Reader* reader, const google_protobuf_Timestamp& proto) const; + private: /** * Encodes a Document for local storage. This differs from the v1 RPC - * serializer for Documents in that it preserves the updateTime, which is + * serializer for Documents in that it preserves the update_time, which is * considered an output only value by the server. */ google_firestore_v1_Document EncodeDocument(const model::Document& doc) const; + model::Document DecodeDocument(nanopb::Reader* reader, + const google_firestore_v1_Document& proto, + bool has_committed_mutations) const; + firestore_client_NoDocument EncodeNoDocument( const model::NoDocument& no_doc) const; - std::unique_ptr DecodeNoDocument( - nanopb::Reader* reader, const firestore_client_NoDocument& proto) const; + model::NoDocument DecodeNoDocument(nanopb::Reader* reader, + const firestore_client_NoDocument& proto, + bool has_committed_mutations) const; firestore_client_UnknownDocument EncodeUnknownDocument( const model::UnknownDocument& unknown_doc) const; - std::unique_ptr DecodeUnknownDocument( + model::UnknownDocument DecodeUnknownDocument( nanopb::Reader* reader, const firestore_client_UnknownDocument& proto) const; - const remote::Serializer& rpc_serializer_; + remote::Serializer rpc_serializer_; }; } // namespace local diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_store.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_store.cc new file mode 100644 index 0000000..fe717db --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_store.cc @@ -0,0 +1,533 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/local_store.h" + +#include + +#include "Firestore/core/src/firebase/firestore/model/patch_mutation.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/to_string.h" + +namespace firebase { +namespace firestore { +namespace local { + +namespace { + +using auth::User; +using core::Query; +using core::Target; +using core::TargetIdGenerator; +using model::BatchId; +using model::DocumentKey; +using model::DocumentKeySet; +using model::DocumentMap; +using model::DocumentVersionMap; +using model::ListenSequenceNumber; +using model::MaybeDocument; +using model::MaybeDocumentMap; +using model::Mutation; +using model::MutationBatch; +using model::MutationBatchResult; +using model::ObjectValue; +using model::OptionalMaybeDocumentMap; +using model::PatchMutation; +using model::Precondition; +using model::SnapshotVersion; +using model::TargetId; +using nanopb::ByteString; +using remote::TargetChange; + +/** + * The maximum time to leave a resume token buffered without writing it out. + * This value is arbitrary: it's long enough to avoid several writes (possibly + * indefinitely if updates come more frequently than this) but short enough that + * restarting after crashing will still have a pretty recent resume token. + */ +const int64_t kResumeTokenMaxAgeSeconds = 5 * 60; // 5 minutes + +} // namespace + +LocalStore::LocalStore(Persistence* persistence, + QueryEngine* query_engine, + const User& initial_user) + : persistence_(persistence), + mutation_queue_(persistence->GetMutationQueueForUser(initial_user)), + remote_document_cache_(persistence->remote_document_cache()), + target_cache_(persistence->target_cache()), + query_engine_(query_engine), + local_documents_( + absl::make_unique(remote_document_cache_, + mutation_queue_, + persistence->index_manager())) { + persistence->reference_delegate()->AddInMemoryPins(&local_view_references_); + target_id_generator_ = TargetIdGenerator::TargetCacheTargetIdGenerator(0); + query_engine_->SetLocalDocumentsView(local_documents_.get()); +} + +void LocalStore::Start() { + StartMutationQueue(); + TargetId target_id = target_cache_->highest_target_id(); + target_id_generator_ = + TargetIdGenerator::TargetCacheTargetIdGenerator(target_id); +} + +void LocalStore::StartMutationQueue() { + persistence_->Run("Start MutationQueue", [&] { mutation_queue_->Start(); }); +} + +MaybeDocumentMap LocalStore::HandleUserChange(const User& user) { + // Swap out the mutation queue, grabbing the pending mutation batches before + // and after. + std::vector old_batches = persistence_->Run( + "OldBatches", [&] { return mutation_queue_->AllMutationBatches(); }); + + // The old one has a reference to the mutation queue, so null it out first. + local_documents_.reset(); + mutation_queue_ = persistence_->GetMutationQueueForUser(user); + + StartMutationQueue(); + + return persistence_->Run("NewBatches", [&] { + std::vector new_batches = + mutation_queue_->AllMutationBatches(); + + // Recreate our LocalDocumentsView using the new MutationQueue. + local_documents_ = absl::make_unique( + remote_document_cache_, mutation_queue_, persistence_->index_manager()); + query_engine_->SetLocalDocumentsView(local_documents_.get()); + + // Union the old/new changed keys. + DocumentKeySet changed_keys; + for (const std::vector* batches : + {&old_batches, &new_batches}) { + for (const MutationBatch& batch : *batches) { + for (const Mutation& mutation : batch.mutations()) { + changed_keys = changed_keys.insert(mutation.key()); + } + } + } + + // Return the set of all (potentially) changed documents as the result of + // the user change. + return local_documents_->GetDocuments(changed_keys); + }); +} + +LocalWriteResult LocalStore::WriteLocally(std::vector&& mutations) { + Timestamp local_write_time = Timestamp::Now(); + DocumentKeySet keys; + for (const Mutation& mutation : mutations) { + keys = keys.insert(mutation.key()); + } + + return persistence_->Run("Locally write mutations", [&] { + // Load and apply all existing mutations. This lets us compute the current + // base state for all non-idempotent transforms before applying any + // additional user-provided writes. + MaybeDocumentMap existing_documents = local_documents_->GetDocuments(keys); + + // For non-idempotent mutations (such as `FieldValue.increment()`), we + // record the base state in a separate patch mutation. This is later used to + // guarantee consistent values and prevents flicker even if the backend + // sends us an update that already includes our transform. + std::vector base_mutations; + for (const Mutation& mutation : mutations) { + absl::optional base_document = + existing_documents.get(mutation.key()); + + absl::optional base_value = + mutation.ExtractBaseValue(base_document); + if (base_value) { + // NOTE: The base state should only be applied if there's some existing + // document to override, so use a Precondition of exists=true + base_mutations.push_back(PatchMutation(mutation.key(), *base_value, + base_value->ToFieldMask(), + Precondition::Exists(true))); + } + } + + MutationBatch batch = mutation_queue_->AddMutationBatch( + local_write_time, std::move(base_mutations), std::move(mutations)); + MaybeDocumentMap changed_documents = + batch.ApplyToLocalDocumentSet(existing_documents); + return LocalWriteResult{batch.batch_id(), std::move(changed_documents)}; + }); +} + +MaybeDocumentMap LocalStore::AcknowledgeBatch( + const MutationBatchResult& batch_result) { + return persistence_->Run("Acknowledge batch", [&] { + const MutationBatch& batch = batch_result.batch(); + mutation_queue_->AcknowledgeBatch(batch, batch_result.stream_token()); + ApplyBatchResult(batch_result); + mutation_queue_->PerformConsistencyCheck(); + + return local_documents_->GetDocuments(batch.keys()); + }); +} + +void LocalStore::ApplyBatchResult(const MutationBatchResult& batch_result) { + const MutationBatch& batch = batch_result.batch(); + DocumentKeySet doc_keys = batch.keys(); + const DocumentVersionMap& versions = batch_result.doc_versions(); + + for (const DocumentKey& doc_key : doc_keys) { + absl::optional remote_doc = + remote_document_cache_->Get(doc_key); + absl::optional doc = remote_doc; + + auto ack_version_iter = versions.find(doc_key); + HARD_ASSERT(ack_version_iter != versions.end(), + "doc_versions should contain every doc in the write."); + const SnapshotVersion& ack_version = ack_version_iter->second; + + if (!doc || doc->version() < ack_version) { + doc = batch.ApplyToRemoteDocument(doc, doc_key, batch_result); + if (!doc) { + HARD_ASSERT( + !remote_doc, + "Mutation batch %s applied to document %s resulted in nullopt.", + batch.ToString(), util::ToString(remote_doc)); + } else { + remote_document_cache_->Add(*doc, batch_result.commit_version()); + } + } + } + + mutation_queue_->RemoveMutationBatch(batch); +} + +MaybeDocumentMap LocalStore::RejectBatch(BatchId batch_id) { + return persistence_->Run("Reject batch", [&] { + absl::optional to_reject = + mutation_queue_->LookupMutationBatch(batch_id); + HARD_ASSERT(to_reject.has_value(), "Attempt to reject nonexistent batch!"); + + mutation_queue_->RemoveMutationBatch(*to_reject); + mutation_queue_->PerformConsistencyCheck(); + + return local_documents_->GetDocuments(to_reject->keys()); + }); +} + +ByteString LocalStore::GetLastStreamToken() { + return mutation_queue_->GetLastStreamToken(); +} + +void LocalStore::SetLastStreamToken(const ByteString& stream_token) { + persistence_->Run("Set stream token", + [&] { mutation_queue_->SetLastStreamToken(stream_token); }); +} + +const SnapshotVersion& LocalStore::GetLastRemoteSnapshotVersion() const { + return target_cache_->GetLastRemoteSnapshotVersion(); +} + +model::MaybeDocumentMap LocalStore::ApplyRemoteEvent( + const remote::RemoteEvent& remote_event) { + const SnapshotVersion& last_remote_version = + target_cache_->GetLastRemoteSnapshotVersion(); + + return persistence_->Run("Apply remote event", [&] { + // TODO(gsoltis): move the sequence number into the reference delegate. + ListenSequenceNumber sequence_number = + persistence_->current_sequence_number(); + + for (const auto& entry : remote_event.target_changes()) { + TargetId target_id = entry.first; + const TargetChange& change = entry.second; + + auto found = target_data_by_target_.find(target_id); + if (found == target_data_by_target_.end()) { + // We don't update the remote keys if the query is not active. This + // ensures that we persist the updated target data along with the + // updated assignment. + continue; + } + + TargetData old_target_data = found->second; + + target_cache_->RemoveMatchingKeys(change.removed_documents(), target_id); + target_cache_->AddMatchingKeys(change.added_documents(), target_id); + + // Update the resume token if the change includes one. Don't clear any + // preexisting value. Bump the sequence number as well, so that documents + // being removed now are ordered later than documents that were reviously + // _removed from this target. + const ByteString& resume_token = change.resume_token(); + // Update the resume token if the change includes one. + if (!resume_token.empty()) { + TargetData new_target_data = + old_target_data + .WithResumeToken(resume_token, remote_event.snapshot_version()) + .WithSequenceNumber(sequence_number); + target_data_by_target_[target_id] = new_target_data; + + // Update the target data if there are target changes (or if sufficient + // time has passed since the last update). + if (ShouldPersistTargetData(new_target_data, old_target_data, change)) { + target_cache_->UpdateTarget(new_target_data); + } + } + } + + OptionalMaybeDocumentMap changed_docs; + const DocumentKeySet& limbo_documents = + remote_event.limbo_document_changes(); + DocumentKeySet updated_keys; + for (const auto& kv : remote_event.document_updates()) { + updated_keys = updated_keys.insert(kv.first); + } + // Each loop iteration only affects its "own" doc, so it's safe to get all + // the remote documents in advance in a single call. + OptionalMaybeDocumentMap existing_docs = + remote_document_cache_->GetAll(updated_keys); + + for (const auto& kv : remote_event.document_updates()) { + const DocumentKey& key = kv.first; + const MaybeDocument& doc = kv.second; + absl::optional existing_doc; + auto found_existing = existing_docs.get(key); + if (found_existing) { + existing_doc = *found_existing; + } + + // Note: The order of the steps below is important, since we want to + // ensure that rejected limbo resolutions (which fabricate NoDocuments + // with SnapshotVersion::None) never add documents to cache. + if (doc.type() == MaybeDocument::Type::NoDocument && + doc.version() == SnapshotVersion::None()) { + // NoDocuments with SnapshotVersion::None are used in manufactured + // events. We remove these documents from cache since we lost access. + remote_document_cache_->Remove(key); + changed_docs = changed_docs.insert(key, doc); + } else if (!existing_doc || doc.version() > existing_doc->version() || + (doc.version() == existing_doc->version() && + existing_doc->has_pending_writes())) { + HARD_ASSERT(remote_event.snapshot_version() != SnapshotVersion::None(), + "Cannot add a document when the remote version is zero"); + remote_document_cache_->Add(doc, remote_event.snapshot_version()); + changed_docs = changed_docs.insert(key, doc); + } else { + LOG_DEBUG( + "LocalStore Ignoring outdated watch update for %s. " + "Current version: %s Watch version: %s", + key.ToString(), existing_doc->version().ToString(), + doc.version().ToString()); + } + + // If this was a limbo resolution, make sure we mark when it was accessed. + if (limbo_documents.contains(key)) { + persistence_->reference_delegate()->UpdateLimboDocument(key); + } + } + + // HACK: The only reason we allow omitting snapshot version is so we can + // synthesize remote events when we get permission denied errors while + // trying to resolve the state of a locally cached document that is in + // limbo. + const SnapshotVersion& remote_version = remote_event.snapshot_version(); + if (remote_version != SnapshotVersion::None()) { + HARD_ASSERT(remote_version >= last_remote_version, + "Watch stream reverted to previous snapshot?? (%s < %s)", + remote_version.ToString(), last_remote_version.ToString()); + target_cache_->SetLastRemoteSnapshotVersion(remote_version); + } + + return local_documents_->GetLocalViewOfDocuments(changed_docs); + }); +} + +bool LocalStore::ShouldPersistTargetData(const TargetData& new_target_data, + const TargetData& old_target_data, + const TargetChange& change) const { + // Avoid clearing any existing value + HARD_ASSERT(!new_target_data.resume_token().empty(), + "Attempted to persist target data with empty resume token"); + + // Always persist target data if we don't already have a resume token. + if (old_target_data.resume_token().empty()) return true; + + // Don't allow resume token changes to be buffered indefinitely. This allows + // us to be reasonably up-to-date after a crash and avoids needing to loop + // over all active queries on shutdown. Especially in the browser we may not + // get time to do anything interesting while the current tab is closing. + int64_t new_seconds = + new_target_data.snapshot_version().timestamp().seconds(); + int64_t old_seconds = + old_target_data.snapshot_version().timestamp().seconds(); + int64_t time_delta = new_seconds - old_seconds; + if (time_delta >= kResumeTokenMaxAgeSeconds) return true; + + // Otherwise if the only thing that has changed about a target is its resume + // token then it's not worth persisting. Note that the RemoteStore keeps an + // in-memory view of the currently active targets which includes the current + // resume token, so stream failure or user changes will still use an + // up-to-date resume token regardless of what we do here. + size_t changes = change.added_documents().size() + + change.modified_documents().size() + + change.removed_documents().size(); + return changes > 0; +} + +absl::optional LocalStore::GetTargetData( + const core::Target& target) { + auto target_id = target_id_by_target_.find(target); + if (target_id != target_id_by_target_.end()) { + return target_data_by_target_[target_id->second]; + } + return target_cache_->GetTarget(target); +} + +void LocalStore::NotifyLocalViewChanges( + const std::vector& view_changes) { + persistence_->Run("NotifyLocalViewChanges", [&] { + for (const LocalViewChanges& view_change : view_changes) { + int target_id = view_change.target_id(); + + for (const DocumentKey& key : view_change.removed_keys()) { + persistence_->reference_delegate()->RemoveReference(key); + } + local_view_references_.AddReferences(view_change.added_keys(), target_id); + local_view_references_.RemoveReferences(view_change.removed_keys(), + target_id); + + if (!view_change.is_from_cache()) { + const auto& entry = target_data_by_target_.find(target_id); + HARD_ASSERT( + entry != target_data_by_target_.end(), + "Can't set limbo-free snapshot version for unknown target: %s", + target_id); + const TargetData& target_data = entry->second; + + // Advance the last limbo free snapshot version + SnapshotVersion last_limbo_free_snapshot_version = + target_data.snapshot_version(); + TargetData updated_target_data = + target_data.WithLastLimboFreeSnapshotVersion( + last_limbo_free_snapshot_version); + target_data_by_target_[target_id] = updated_target_data; + } + } + }); +} + +absl::optional LocalStore::GetNextMutationBatch( + BatchId batch_id) { + return persistence_->Run("NextMutationBatchAfterBatchID", [&] { + return mutation_queue_->NextMutationBatchAfterBatchId(batch_id); + }); +} + +absl::optional LocalStore::ReadDocument(const DocumentKey& key) { + return persistence_->Run("ReadDocument", + [&] { return local_documents_->GetDocument(key); }); +} + +BatchId LocalStore::GetHighestUnacknowledgedBatchId() { + return persistence_->Run("GetHighestUnacknowledgedBatchId", [&] { + return mutation_queue_->GetHighestUnacknowledgedBatchId(); + }); +} + +TargetData LocalStore::AllocateTarget(Target target) { + TargetData target_data = persistence_->Run("Allocate target", [&] { + absl::optional cached = target_cache_->GetTarget(target); + // TODO(mcg): freshen last accessed date if cached exists? + if (!cached) { + cached = TargetData(std::move(target), target_id_generator_.NextId(), + persistence_->current_sequence_number(), + QueryPurpose::Listen); + target_cache_->AddTarget(*cached); + } + return *cached; + }); + + // Sanity check to ensure that even when resuming a query it's not currently + // active. + TargetId target_id = target_data.target_id(); + if (target_data_by_target_.find(target_id) == target_data_by_target_.end()) { + target_data_by_target_[target_id] = target_data; + target_id_by_target_[target_data.target()] = target_id; + } + + return target_data; +} + +void LocalStore::ReleaseTarget(TargetId target_id) { + persistence_->Run("Release target", [&] { + auto found = target_data_by_target_.find(target_id); + HARD_ASSERT(found != target_data_by_target_.end(), + "Tried to release a non-existent target: %s", target_id); + + TargetData target_data = found->second; + + // References for documents sent via Watch are automatically removed when we + // delete a query's target data from the reference delegate. Since this does + // not remove references for locally mutated documents, we have to remove + // the target associations for these documents manually. + DocumentKeySet removed = + local_view_references_.RemoveReferences(target_data.target_id()); + for (const DocumentKey& key : removed) { + persistence_->reference_delegate()->RemoveReference(key); + } + + // Note: This also updates the target cache. + persistence_->reference_delegate()->RemoveTarget(target_data); + target_data_by_target_.erase(target_id); + target_id_by_target_.erase(target_data.target()); + }); +} + +QueryResult LocalStore::ExecuteQuery(const Query& query, + bool use_previous_results) { + return persistence_->Run("ExecuteQuery", [&] { + absl::optional target_data = GetTargetData(query.ToTarget()); + SnapshotVersion last_limbo_free_snapshot_version; + DocumentKeySet remote_keys; + + if (target_data) { + last_limbo_free_snapshot_version = + target_data->last_limbo_free_snapshot_version(); + remote_keys = target_cache_->GetMatchingKeys(target_data->target_id()); + } + + model::DocumentMap documents = query_engine_->GetDocumentsMatchingQuery( + query, + use_previous_results ? last_limbo_free_snapshot_version + : SnapshotVersion::None(), + use_previous_results ? remote_keys : DocumentKeySet{}); + return QueryResult(std::move(documents), std::move(remote_keys)); + }); +} + +DocumentKeySet LocalStore::GetRemoteDocumentKeys(TargetId target_id) { + return persistence_->Run("RemoteDocumentKeysForTarget", [&] { + return target_cache_->GetMatchingKeys(target_id); + }); +} + +LruResults LocalStore::CollectGarbage(LruGarbageCollector* garbage_collector) { + return persistence_->Run("Collect garbage", [&] { + return garbage_collector->Collect(target_data_by_target_); + }); +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_store.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_store.h new file mode 100644 index 0000000..37b4515 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_store.h @@ -0,0 +1,298 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LOCAL_STORE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LOCAL_STORE_H_ + +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/auth/user.h" +#include "Firestore/core/src/firebase/firestore/core/query.h" +#include "Firestore/core/src/firebase/firestore/core/target_id_generator.h" +#include "Firestore/core/src/firebase/firestore/local/local_documents_view.h" +#include "Firestore/core/src/firebase/firestore/local/local_view_changes.h" +#include "Firestore/core/src/firebase/firestore/local/local_write_result.h" +#include "Firestore/core/src/firebase/firestore/local/lru_garbage_collector.h" +#include "Firestore/core/src/firebase/firestore/local/persistence.h" +#include "Firestore/core/src/firebase/firestore/local/query_engine.h" +#include "Firestore/core/src/firebase/firestore/local/query_result.h" +#include "Firestore/core/src/firebase/firestore/local/reference_set.h" +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/document_map.h" +#include "Firestore/core/src/firebase/firestore/model/mutation.h" +#include "Firestore/core/src/firebase/firestore/model/mutation_batch_result.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace local { + +/** + * Local storage in the Firestore client. Coordinates persistence components + * like the mutation queue and remote document cache to present a latency + * compensated view of stored data. + * + * The LocalStore is responsible for accepting mutations from the SyncEngine. + * Writes from the client are put into a queue as provisional Mutations until + * they are processed by the RemoteStore and confirmed as having been written to + * the server. + * + * The local store provides the local version of documents that have been + * modified locally. It maintains the constraint: + * + * LocalDocument = RemoteDocument + Active(LocalMutations) + * + * (Active mutations are those that are enqueued and have not been previously + * acknowledged or rejected). + * + * The RemoteDocument ("ground truth") state is provided via the + * ApplyChangeBatch method. It will be some version of a server-provided + * document OR will be a server-provided document PLUS acknowledged mutations: + * + * RemoteDocument' = RemoteDocument + Acknowledged(LocalMutations) + * + * Note that this "dirty" version of a RemoteDocument will not be identical to a + * server base version, since it has LocalMutations added to it pending getting + * an authoritative copy from the server. + * + * Since LocalMutations can be rejected by the server, we have to be able to + * revert a LocalMutation that has already been applied to the LocalDocument + * (typically done by replaying all remaining LocalMutations to the + * RemoteDocument to re-apply). + * + * It also maintains the persistence of mapping queries to resume tokens and + * target ids. + * + * The LocalStore must be able to efficiently execute queries against its local + * cache of the documents, to provide the initial set of results before any + * remote changes have been received. + */ +class LocalStore { + public: + LocalStore(Persistence* persistence, + QueryEngine* query_engine, + const auth::User& initial_user); + + /** Performs any initial startup actions required by the local store. */ + void Start(); + + /** + * Tells the LocalStore that the currently authenticated user has changed. + * + * In response the local store switches the mutation queue to the new user and + * returns any resulting document changes. + */ + model::MaybeDocumentMap HandleUserChange(const auth::User& user); + + /** Accepts locally generated Mutations and commits them to storage. */ + local::LocalWriteResult WriteLocally( + std::vector&& mutations); + + /** + * Returns the current value of a document with a given key, or `nullopt` if + * not found. + */ + absl::optional ReadDocument( + const model::DocumentKey& key); + + /** + * Acknowledges the given batch. + * + * On the happy path when a batch is acknowledged, the local store will: + * + * + remove the batch from the mutation queue; + * + apply the changes to the remote document cache; + * + recalculate the latency compensated view implied by those changes (there + * may be mutations in the queue that affect the documents but haven't been + * acknowledged yet); and + * + give the changed documents back the sync engine + * + * @return The resulting (modified) documents. + */ + model::MaybeDocumentMap AcknowledgeBatch( + const model::MutationBatchResult& batch_result); + + /** + * Removes mutations from the MutationQueue for the specified batch. + * LocalDocuments will be recalculated. + * + * @return The resulting (modified) documents. + */ + model::MaybeDocumentMap RejectBatch(model::BatchId batch_id); + + /** Returns the last recorded stream token for the current user. */ + nanopb::ByteString GetLastStreamToken(); + + /** + * Sets the stream token for the current user without acknowledging any + * mutation batch. This is usually only useful after a stream handshake or in + * response to an error that requires clearing the stream token. + */ + void SetLastStreamToken(const nanopb::ByteString& stream_token); + + /** + * Returns the last consistent snapshot processed (used by the RemoteStore to + * determine whether to buffer incoming snapshots from the backend). + */ + const model::SnapshotVersion& GetLastRemoteSnapshotVersion() const; + + /** + * Updates the "ground-state" (remote) documents. We assume that the remote + * event reflects any write batches that have been acknowledged or rejected + * (i.e. we do not re-apply local mutations to updates from this event). + * + * LocalDocuments are re-calculated if there are remaining mutations in the + * queue. + */ + model::MaybeDocumentMap ApplyRemoteEvent( + const remote::RemoteEvent& remote_event); + + /** + * Returns the keys of the documents that are associated with the given + * target_id in the remote table. + */ + model::DocumentKeySet GetRemoteDocumentKeys(model::TargetId target_id); + + /** + * Assigns a target an internal ID so that its results can be pinned so they + * don't get GC'd. A target must be allocated in the local store before the + * store can be used to manage its view. + * + * Allocating an already allocated target will return the existing + * `TargetData` for that target. + */ + local::TargetData AllocateTarget(core::Target target); + + /** + * Unpin all the documents associated with a target. + * + * Releasing a non-existing target is an error. + */ + void ReleaseTarget(model::TargetId target_id); + + /** + * Runs the specified query against the local store and returns the results, + * potentially taking advantage of target data from previous executions (such + * as the set of remote keys). + * + * @param use_previous_results Whether results from previous executions can be + * used to optimize this query execution. + */ + local::QueryResult ExecuteQuery(const core::Query& query, + bool use_previous_results); + + /** + * Notify the local store of the changed views to locally pin / unpin + * documents. + */ + void NotifyLocalViewChanges( + const std::vector& view_changes); + + /** + * Gets the mutation batch after the passed in batch_id in the mutation queue + * or `nullopt` if empty. + * + * @param batch_id The batch to search after, or `kBatchIdUnknown` for the + * first mutation in the queue. + * @return the next mutation or `nullopt` if there wasn't one. + */ + absl::optional GetNextMutationBatch( + model::BatchId batch_id); + + /** + * Returns the largest (latest) batch id in mutation queue that is pending + * server response. Returns `kBatchIdUnknown` if the queue is empty. + */ + model::BatchId GetHighestUnacknowledgedBatchId(); + + local::LruResults CollectGarbage( + local::LruGarbageCollector* garbage_collector); + + private: + friend class LocalStoreTest; // for `GetTargetData()` + + void StartMutationQueue(); + void ApplyBatchResult(const model::MutationBatchResult& batch_result); + + /** + * Returns true if the new_target_data should be persisted during an update of + * an active target. TargetData should always be persisted when a target is + * being released and should not call this function. + * + * While the target is active, TargetData updates can be omitted when nothing + * about the target has changed except metadata like the resume token or + * snapshot version. Occasionally it's worth the extra write to prevent these + * values from getting too stale after a crash, but this doesn't have to be + * too frequent. + */ + bool ShouldPersistTargetData(const TargetData& new_target_data, + const local::TargetData& old_target_data, + const remote::TargetChange& change) const; + + /** + * Returns the TargetData as seen by the LocalStore, including updates that + * may have not yet been persisted to the TargetCache. + */ + absl::optional GetTargetData(const core::Target& query); + + /** Manages our in-memory or durable persistence. Owned by FirestoreClient. */ + Persistence* persistence_ = nullptr; + + /** Used to generate target IDs for queries tracked locally. */ + core::TargetIdGenerator target_id_generator_; + + /** + * The set of all mutations that have been sent but not yet been applied to + * the backend. + */ + MutationQueue* mutation_queue_ = nullptr; + + /** The set of all cached remote documents. */ + RemoteDocumentCache* remote_document_cache_ = nullptr; + + /** Maps a query to the data about that query. */ + TargetCache* target_cache_ = nullptr; + + /** + * Performs queries over the localDocuments (and potentially maintains + * indexes). + */ + QueryEngine* query_engine_ = nullptr; + + /** + * The "local" view of all documents (layering mutation queue on top of + * remote_document_cache_). + */ + std::unique_ptr local_documents_; + + /** The set of document references maintained by any local views. */ + ReferenceSet local_view_references_; + + /** Maps target ids to data about their queries. */ + std::unordered_map target_data_by_target_; + + /** Maps a target to its targetID. */ + std::unordered_map target_id_by_target_; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LOCAL_STORE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_view_changes.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_view_changes.cc new file mode 100644 index 0000000..d1b1d0f --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_view_changes.cc @@ -0,0 +1,57 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/local_view_changes.h" + +#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" + +namespace firebase { +namespace firestore { +namespace local { + +using core::DocumentViewChange; +using core::ViewSnapshot; +using model::DocumentKeySet; +using model::TargetId; + +LocalViewChanges LocalViewChanges::FromViewSnapshot( + const core::ViewSnapshot& snapshot, model::TargetId target_id) { + DocumentKeySet added_keys; + DocumentKeySet removed_keys; + + for (const DocumentViewChange& doc_change : snapshot.document_changes()) { + switch (doc_change.type()) { + case DocumentViewChange::Type::Added: + added_keys = added_keys.insert(doc_change.document().key()); + break; + + case DocumentViewChange::Type::Removed: + removed_keys = removed_keys.insert(doc_change.document().key()); + break; + + default: + // Do nothing. + break; + } + } + + return LocalViewChanges(target_id, snapshot.from_cache(), + std::move(added_keys), std::move(removed_keys)); +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_view_changes.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_view_changes.h new file mode 100644 index 0000000..c490506 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_view_changes.h @@ -0,0 +1,81 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LOCAL_VIEW_CHANGES_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LOCAL_VIEW_CHANGES_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" + +namespace firebase { +namespace firestore { +namespace local { + +/** + * Represents changes applying to the local view of a given query, including + * what documents are currently in view and out of view. + * + * Example usage: these changes are sent to the LocalStore by the View (via the + * SyncEngine) and are used to pin / unpin documents as appropriate. + */ +class LocalViewChanges { + public: + static LocalViewChanges FromViewSnapshot(const core::ViewSnapshot& snapshot, + model::TargetId target_id); + + LocalViewChanges(model::TargetId target_id, + bool from_cache, + model::DocumentKeySet added_keys, + model::DocumentKeySet removed_keys) + : target_id_(target_id), + from_cache_(from_cache), + added_keys_(std::move(added_keys)), + removed_keys_(std::move(removed_keys)) { + } + + /** The batch ID of the local write. */ + model::TargetId target_id() const { + return target_id_; + } + + bool is_from_cache() const { + return from_cache_; + } + + /** The document changes resulting from the local write. */ + const model::DocumentKeySet& added_keys() const { + return added_keys_; + } + + const model::DocumentKeySet& removed_keys() const { + return removed_keys_; + } + + private: + model::TargetId target_id_ = 0; + bool from_cache_ = false; + model::DocumentKeySet added_keys_; + model::DocumentKeySet removed_keys_; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LOCAL_VIEW_CHANGES_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_write_result.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_write_result.h new file mode 100644 index 0000000..4e303a2 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/local_write_result.h @@ -0,0 +1,57 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LOCAL_WRITE_RESULT_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LOCAL_WRITE_RESULT_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/model/document_map.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" + +namespace firebase { +namespace firestore { +namespace local { + +/** The result of a write to the local store. */ +class LocalWriteResult { + public: + LocalWriteResult(model::BatchId batch_id, model::MaybeDocumentMap&& changes) + : batch_id_(batch_id), changes_(std::move(changes)) { + } + + LocalWriteResult() = default; + + /** The batch ID of the local write. */ + model::BatchId batch_id() const { + return batch_id_; + } + + /** The document changes resulting from the local write. */ + const model::MaybeDocumentMap& changes() const { + return changes_; + } + + private: + model::BatchId batch_id_; + model::MaybeDocumentMap changes_; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LOCAL_WRITE_RESULT_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/lru_garbage_collector.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/lru_garbage_collector.cc new file mode 100644 index 0000000..1b91514 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/lru_garbage_collector.cc @@ -0,0 +1,209 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/lru_garbage_collector.h" + +#include // NOLINT(build/c++11) +#include +#include +#include + +#include "Firestore/core/include/firebase/firestore/timestamp.h" +#include "Firestore/core/src/firebase/firestore/api/settings.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" + +namespace firebase { +namespace firestore { +namespace local { +namespace { + +using firebase::firestore::api::Settings; +using firebase::firestore::model::DocumentKey; +using firebase::firestore::model::ListenSequenceNumber; +using firebase::firestore::model::TargetId; + +using Millis = std::chrono::milliseconds; + +static Millis::rep MillisecondsBetween(const Timestamp& start, + const Timestamp& end) { + return std::chrono::duration_cast(end.ToTimePoint() - + start.ToTimePoint()) + .count(); +} + +/** + * RollingSequenceNumberBuffer tracks the nth sequence number in a series. + * Sequence numbers may be added out of order. + */ +class RollingSequenceNumberBuffer { + public: + explicit RollingSequenceNumberBuffer(size_t max_elements) + : queue_(std::priority_queue()), + max_elements_(max_elements) { + } + + RollingSequenceNumberBuffer(const RollingSequenceNumberBuffer& other) = + delete; + + void AddElement(ListenSequenceNumber sequence_number) { + if (queue_.size() < max_elements_) { + queue_.push(sequence_number); + } else { + ListenSequenceNumber highest_value = queue_.top(); + if (sequence_number < highest_value) { + queue_.pop(); + queue_.push(sequence_number); + } + } + } + + ListenSequenceNumber max_value() const { + return queue_.top(); + } + + size_t size() const { + return queue_.size(); + } + + private: + std::priority_queue queue_; + const size_t max_elements_; +}; + +} // namespace + +const ListenSequenceNumber kListenSequenceNumberInvalid = -1; + +LruParams LruParams::Default() { + return LruParams{100 * 1024 * 1024, 10, 1000}; +} + +LruParams LruParams::Disabled() { + return LruParams{api::Settings::CacheSizeUnlimited, 0, 0}; +} + +LruParams LruParams::WithCacheSize(int64_t cache_size) { + LruParams params = Default(); + params.min_bytes_threshold = cache_size; + return params; +} + +LruGarbageCollector::LruGarbageCollector(LruDelegate* delegate, + LruParams params) + : delegate_(delegate), params_(std::move(params)) { +} + +LruResults LruGarbageCollector::Collect(const LiveQueryMap& live_targets) { + if (params_.min_bytes_threshold == Settings::CacheSizeUnlimited) { + LOG_DEBUG("Garbage collection skipped; disabled"); + return LruResults::DidNotRun(); + } + + int64_t current_size = CalculateByteSize(); + if (current_size < params_.min_bytes_threshold) { + // Not enough on disk to warrant collection. Wait another timeout cycle. + LOG_DEBUG( + "Garbage collection skipped; Cache size %s is lower than threshold %s", + current_size, params_.min_bytes_threshold); + return LruResults::DidNotRun(); + } + + LOG_DEBUG("Running garbage collection on cache of size: %s", current_size); + return RunGarbageCollection(live_targets); +} + +LruResults LruGarbageCollector::RunGarbageCollection( + const LiveQueryMap& live_targets) { + Timestamp start = Timestamp::Now(); + + // Cap at the configured max + int sequence_numbers = QueryCountForPercentile(params_.percentile_to_collect); + if (sequence_numbers > params_.maximum_sequence_numbers_to_collect) { + sequence_numbers = params_.maximum_sequence_numbers_to_collect; + } + Timestamp counted_targets = Timestamp::Now(); + + ListenSequenceNumber upper_bound = + SequenceNumberForQueryCount(sequence_numbers); + Timestamp found_upper_bound = Timestamp::Now(); + + int num_targets_removed = RemoveTargets(upper_bound, live_targets); + Timestamp removed_targets = Timestamp::Now(); + + int num_documents_removed = RemoveOrphanedDocuments(upper_bound); + Timestamp removed_documents = Timestamp::Now(); + + std::string desc = "LRU Garbage Collection:\n"; + absl::StrAppend(&desc, "\tCounted targets in ", + MillisecondsBetween(start, counted_targets), "ms\n"); + absl::StrAppend(&desc, "\tDetermined least recently used ", sequence_numbers, + " sequence numbers in ", + MillisecondsBetween(counted_targets, found_upper_bound), + "ms\n"); + absl::StrAppend(&desc, "\tRemoved ", num_targets_removed, " targets in ", + MillisecondsBetween(found_upper_bound, removed_targets), + "ms\n"); + absl::StrAppend(&desc, "\tRemoved ", num_documents_removed, " documents in ", + MillisecondsBetween(removed_targets, removed_documents), + "ms\n"); + absl::StrAppend(&desc, "Total duration: ", + MillisecondsBetween(start, removed_documents), "ms"); + LOG_DEBUG(desc.c_str()); + + return LruResults{/* did_run= */ true, sequence_numbers, num_targets_removed, + num_documents_removed}; +} + +int LruGarbageCollector::QueryCountForPercentile(int percentile) { + size_t total_count = delegate_->GetSequenceNumberCount(); + return static_cast((percentile / 100.0f) * total_count); +} + +ListenSequenceNumber LruGarbageCollector::SequenceNumberForQueryCount( + int query_count) { + if (query_count == 0) { + return kListenSequenceNumberInvalid; + } + + RollingSequenceNumberBuffer buffer(query_count); + + delegate_->EnumerateTargets([&buffer](const TargetData& target_data) { + buffer.AddElement(target_data.sequence_number()); + }); + + delegate_->EnumerateOrphanedDocuments( + [&buffer](const DocumentKey& doc_key, + ListenSequenceNumber sequence_number) { + buffer.AddElement(sequence_number); + }); + + return buffer.max_value(); +} + +int LruGarbageCollector::RemoveTargets(ListenSequenceNumber sequence_number, + const LiveQueryMap& live_queries) { + return delegate_->RemoveTargets(sequence_number, live_queries); +} + +int LruGarbageCollector::RemoveOrphanedDocuments( + ListenSequenceNumber sequence_number) { + return delegate_->RemoveOrphanedDocuments(sequence_number); +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/lru_garbage_collector.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/lru_garbage_collector.h new file mode 100644 index 0000000..d4a64d1 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/lru_garbage_collector.h @@ -0,0 +1,162 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LRU_GARBAGE_COLLECTOR_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LRU_GARBAGE_COLLECTOR_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/local/reference_delegate.h" +#include "Firestore/core/src/firebase/firestore/local/target_cache.h" +#include "Firestore/core/src/firebase/firestore/local/target_data.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" + +namespace firebase { +namespace firestore { +namespace local { + +class LruGarbageCollector; + +ABSL_CONST_INIT extern const model::ListenSequenceNumber + kListenSequenceNumberInvalid; + +struct LruParams { + static LruParams Default(); + + static LruParams Disabled(); + + static LruParams WithCacheSize(int64_t cache_size); + + int64_t min_bytes_threshold; + int percentile_to_collect; + int maximum_sequence_numbers_to_collect; +}; + +struct LruResults { + static LruResults DidNotRun() { + return LruResults{/* did_run= */ false, 0, 0, 0}; + } + + bool did_run; + int sequence_numbers_collected; + int targets_removed; + int documents_removed; +}; + +using LiveQueryMap = std::unordered_map; + +/** + * Persistence layers intending to use LRU Garbage collection should implement + * this interface. This interface defines the operations that the LRU garbage + * collector needs from the persistence layer. + */ +class LruDelegate : public ReferenceDelegate { + public: + virtual ~LruDelegate() = default; + + /** Access to the underlying LRU Garbage collector instance. */ + virtual LruGarbageCollector* garbage_collector() = 0; + + virtual int64_t CalculateByteSize() = 0; + + /** Returns the number of targets and orphaned documents cached. */ + virtual size_t GetSequenceNumberCount() = 0; + + /** + * Enumerates all the targets that the delegate is aware of. This is typically + * all of the targets in an TargetCache. + */ + virtual void EnumerateTargets(const TargetCallback& callback) = 0; + + /** + * Enumerates all of the outstanding mutations. + */ + virtual void EnumerateOrphanedDocuments( + const OrphanedDocumentCallback& callback) = 0; + + /** + * Removes all unreferenced documents from the cache that have a sequence + * number less than or equal to the given sequence number. Returns the number + * of documents removed. + */ + virtual int RemoveOrphanedDocuments( + model::ListenSequenceNumber sequence_number) = 0; + + /** + * Removes all targets that are not currently being listened to and have a + * sequence number less than or equal to the given sequence number. Returns + * the number of targets removed. + */ + virtual int RemoveTargets(model::ListenSequenceNumber sequence_number, + const LiveQueryMap& live_queries) = 0; +}; + +/** + * LruGarbageCollector defines the LRU algorithm used to clean up old documents + * and targets. It is persistence-agnostic, as long as proper delegate is + * provided. + */ +class LruGarbageCollector { + public: + LruGarbageCollector(LruDelegate* delegate, LruParams params); + + int64_t CalculateByteSize() const { + return delegate_->CalculateByteSize(); + } + + /** + * Given a target percentile, return the number of queries that make up that + * percentage of the queries that are cached. For instance, if 20 queries are + * cached, and the percentile is 40, the result will be 8. + */ + int QueryCountForPercentile(int percentile); + + /** + * Given a number of queries n, return the nth sequence number in the cache. + */ + model::ListenSequenceNumber SequenceNumberForQueryCount(int query_count); + + /** + * Removes queries that are not currently live (as indicated by presence in + * the live_queries map) and have a sequence number less than or equal to the + * given sequence number. + */ + int RemoveTargets(model::ListenSequenceNumber sequence_number, + const LiveQueryMap& live_queries); + + /** + * Removes all unreferenced documents from the cache that have a sequence + * number less than or equal to the given sequence number. Returns the number + * of documents removed. + */ + int RemoveOrphanedDocuments(model::ListenSequenceNumber sequence_number); + + local::LruResults Collect(const LiveQueryMap& live_targets); + + private: + LruResults RunGarbageCollection(const LiveQueryMap& live_targets); + + // Delegate owns the LruGarbageCollector; this is a back pointer. + LruDelegate* delegate_; + + LruParams params_ = LruParams::Default(); +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LRU_GARBAGE_COLLECTOR_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_eager_reference_delegate.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_eager_reference_delegate.cc new file mode 100644 index 0000000..9563cf6 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_eager_reference_delegate.cc @@ -0,0 +1,118 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/memory_eager_reference_delegate.h" + +#include "Firestore/core/src/firebase/firestore/local/lru_garbage_collector.h" +#include "Firestore/core/src/firebase/firestore/local/memory_mutation_queue.h" +#include "Firestore/core/src/firebase/firestore/local/memory_persistence.h" +#include "Firestore/core/src/firebase/firestore/local/reference_set.h" +#include "Firestore/core/src/firebase/firestore/local/remote_document_cache.h" + +namespace firebase { +namespace firestore { +namespace local { + +using model::DocumentKey; +using model::DocumentKeyHash; +using model::ListenSequenceNumber; + +MemoryEagerReferenceDelegate::MemoryEagerReferenceDelegate( + MemoryPersistence* persistence) + : persistence_(persistence) { +} + +ListenSequenceNumber MemoryEagerReferenceDelegate::current_sequence_number() + const { + return kListenSequenceNumberInvalid; +} + +void MemoryEagerReferenceDelegate::AddInMemoryPins(ReferenceSet* set) { + // We should be able to assert that additional_references_ is nullptr, but due + // to restarts in spec tests it would fail. + additional_references_ = set; +} + +void MemoryEagerReferenceDelegate::RemoveTarget(const TargetData& target_data) { + for (const DocumentKey& doc_key : + persistence_->target_cache()->GetMatchingKeys(target_data.target_id())) { + orphaned_->insert(doc_key); + } + persistence_->target_cache()->RemoveTarget(target_data); +} + +void MemoryEagerReferenceDelegate::AddReference(const DocumentKey& key) { + orphaned_->erase(key); +} + +void MemoryEagerReferenceDelegate::RemoveReference(const DocumentKey& key) { + orphaned_->insert(key); +} + +void MemoryEagerReferenceDelegate::RemoveMutationReference( + const DocumentKey& key) { + orphaned_->insert(key); +} + +bool MemoryEagerReferenceDelegate::IsReferenced(const DocumentKey& key) const { + if (persistence_->target_cache()->Contains(key)) { + return true; + } + if (MutationQueuesContainKey(key)) { + return true; + } + if (additional_references_ && additional_references_->ContainsKey(key)) { + return true; + } + return false; +} + +void MemoryEagerReferenceDelegate::UpdateLimboDocument(const DocumentKey& key) { + if (IsReferenced(key)) { + orphaned_->erase(key); + } else { + orphaned_->insert(key); + } +} + +void MemoryEagerReferenceDelegate::OnTransactionStarted(absl::string_view) { + // Constructs the unordered map, in place, with no arguments. + orphaned_.emplace(); +} + +void MemoryEagerReferenceDelegate::OnTransactionCommitted() { + for (const auto& key : *orphaned_) { + if (!IsReferenced(key)) { + persistence_->remote_document_cache()->Remove(key); + } + } + orphaned_.reset(); +} + +bool MemoryEagerReferenceDelegate::MutationQueuesContainKey( + const DocumentKey& key) const { + const auto& queues = persistence_->mutation_queues(); + for (const auto& entry : queues) { + if (entry.second->ContainsKey(key)) { + return true; + } + } + return false; +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_eager_reference_delegate.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_eager_reference_delegate.h new file mode 100644 index 0000000..8590a3b --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_eager_reference_delegate.h @@ -0,0 +1,73 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_EAGER_REFERENCE_DELEGATE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_EAGER_REFERENCE_DELEGATE_H_ + +#include +#include + +#include "Firestore/core/src/firebase/firestore/local/reference_delegate.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace local { + +class MemoryPersistence; + +/** + * Provides the eager GC implementation for memory persistence. + */ +class MemoryEagerReferenceDelegate : public ReferenceDelegate { + public: + explicit MemoryEagerReferenceDelegate(MemoryPersistence* persistence); + + model::ListenSequenceNumber current_sequence_number() const override; + + void AddInMemoryPins(ReferenceSet* set) override; + + void AddReference(const model::DocumentKey& key) override; + void RemoveReference(const model::DocumentKey& key) override; + void RemoveMutationReference(const model::DocumentKey& key) override; + void RemoveTarget(const TargetData& target_data) override; + + void UpdateLimboDocument(const model::DocumentKey& key) override; + + void OnTransactionStarted(absl::string_view label) override; + void OnTransactionCommitted() override; + + private: + bool IsReferenced(const model::DocumentKey& key) const; + + bool MutationQueuesContainKey(const model::DocumentKey& key) const; + + absl::optional> + orphaned_; + + // This instance is owned by MemoryPersistence. + MemoryPersistence* persistence_ = nullptr; + + // The ReferenceSet is owned by LocalStore. + ReferenceSet* additional_references_ = nullptr; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_EAGER_REFERENCE_DELEGATE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_index_manager.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_index_manager.cc index 0827416..831df10 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_index_manager.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_index_manager.cc @@ -35,8 +35,8 @@ bool MemoryCollectionParentIndex::Add(const ResourcePath& collection_path) { std::string collection_id = collection_path.last_segment(); ResourcePath parent_path = collection_path.PopLast(); - std::set& existingParents = index_[collection_id]; - bool inserted = existingParents.insert(parent_path).second; + std::set& existing_parents = index_[collection_id]; + bool inserted = existing_parents.insert(parent_path).second; return inserted; } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_lru_reference_delegate.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_lru_reference_delegate.cc new file mode 100644 index 0000000..47e62cc --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_lru_reference_delegate.cc @@ -0,0 +1,190 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/memory_lru_reference_delegate.h" + +#include + +#include "Firestore/core/src/firebase/firestore/local/listen_sequence.h" +#include "Firestore/core/src/firebase/firestore/local/lru_garbage_collector.h" +#include "Firestore/core/src/firebase/firestore/local/memory_mutation_queue.h" +#include "Firestore/core/src/firebase/firestore/local/memory_persistence.h" +#include "Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h" +#include "Firestore/core/src/firebase/firestore/local/reference_set.h" +#include "Firestore/core/src/firebase/firestore/local/remote_document_cache.h" +#include "Firestore/core/src/firebase/firestore/local/sizer.h" +#include "absl/memory/memory.h" + +namespace firebase { +namespace firestore { +namespace local { + +using model::DocumentKey; +using model::ListenSequenceNumber; + +MemoryLruReferenceDelegate::MemoryLruReferenceDelegate( + MemoryPersistence* persistence, + LruParams lru_params, + std::unique_ptr sizer) + : persistence_(persistence), + sizer_(std::move(sizer)), + gc_(this, lru_params) { + // Theoretically this is always 0, since this is all in-memory... + ListenSequenceNumber highest_sequence_number = + persistence_->target_cache()->highest_listen_sequence_number(); + listen_sequence_ = absl::make_unique(highest_sequence_number); +} + +LruGarbageCollector* MemoryLruReferenceDelegate::garbage_collector() { + return &gc_; +} + +ListenSequenceNumber MemoryLruReferenceDelegate::current_sequence_number() + const { + HARD_ASSERT(current_sequence_number_ != kListenSequenceNumberInvalid, + "Asking for a sequence number outside of a transaction"); + return current_sequence_number_; +} + +void MemoryLruReferenceDelegate::AddInMemoryPins(ReferenceSet* set) { + // We should be able to assert that additional_references_ is nullptr, but due + // to restarts in spec tests it would fail. + additional_references_ = set; +} + +void MemoryLruReferenceDelegate::RemoveTarget(const TargetData& target_data) { + TargetData updated = target_data.WithSequenceNumber(current_sequence_number_); + persistence_->target_cache()->UpdateTarget(updated); +} + +void MemoryLruReferenceDelegate::UpdateLimboDocument( + const model::DocumentKey& key) { + sequence_numbers_[key] = current_sequence_number_; +} + +void MemoryLruReferenceDelegate::OnTransactionStarted(absl::string_view label) { + current_sequence_number_ = listen_sequence_->Next(); +} + +void MemoryLruReferenceDelegate::OnTransactionCommitted() { + current_sequence_number_ = kListenSequenceNumberInvalid; +} + +void MemoryLruReferenceDelegate::EnumerateTargets( + const TargetCallback& callback) { + return persistence_->target_cache()->EnumerateTargets(callback); +} + +void MemoryLruReferenceDelegate::EnumerateOrphanedDocuments( + const OrphanedDocumentCallback& callback) { + for (const auto& entry : sequence_numbers_) { + const DocumentKey& key = entry.first; + ListenSequenceNumber sequence_number = entry.second; + // Pass in the exact sequence number as the upper bound so we know it won't + // be pinned by being too recent. + if (!IsPinnedAtSequenceNumber(sequence_number, key)) { + callback(key, sequence_number); + } + } +} + +size_t MemoryLruReferenceDelegate::GetSequenceNumberCount() { + size_t total_count = persistence_->target_cache()->size(); + EnumerateOrphanedDocuments( + [&total_count](const DocumentKey& key, + ListenSequenceNumber sequence_number) { total_count++; }); + return total_count; +} + +int MemoryLruReferenceDelegate::RemoveTargets( + model::ListenSequenceNumber sequence_number, + const LiveQueryMap& live_queries) { + return persistence_->target_cache()->RemoveTargets(sequence_number, + live_queries); +} + +int MemoryLruReferenceDelegate::RemoveOrphanedDocuments( + model::ListenSequenceNumber upper_bound) { + std::vector removed = + persistence_->remote_document_cache()->RemoveOrphanedDocuments( + this, upper_bound); + for (const auto& key : removed) { + sequence_numbers_.erase(key); + } + return static_cast(removed.size()); +} + +void MemoryLruReferenceDelegate::AddReference(const DocumentKey& key) { + sequence_numbers_[key] = current_sequence_number_; +} + +void MemoryLruReferenceDelegate::RemoveReference(const DocumentKey& key) { + sequence_numbers_[key] = current_sequence_number_; +} + +bool MemoryLruReferenceDelegate::MutationQueuesContainKey( + const DocumentKey& key) const { + const auto& queues = persistence_->mutation_queues(); + for (const auto& entry : queues) { + if (entry.second->ContainsKey(key)) { + return true; + } + } + return false; +} + +void MemoryLruReferenceDelegate::RemoveMutationReference( + const DocumentKey& key) { + sequence_numbers_[key] = current_sequence_number_; +} + +bool MemoryLruReferenceDelegate::IsPinnedAtSequenceNumber( + ListenSequenceNumber upper_bound, const DocumentKey& key) const { + if (MutationQueuesContainKey(key)) { + return true; + } + if (additional_references_ && additional_references_->ContainsKey(key)) { + return true; + } + if (persistence_->target_cache()->Contains(key)) { + return true; + } + + auto it = sequence_numbers_.find(key); + if (it != sequence_numbers_.end() && it->second > upper_bound) { + return true; + } + return false; +} + +int64_t MemoryLruReferenceDelegate::CalculateByteSize() { + // Note that this method is only used for testing because this delegate is + // only used for testing. The algorithm here (loop through everything, + // serialize it and count bytes) is inefficient and inexact, but won't run in + // production. + int64_t count = 0; + count += persistence_->target_cache()->CalculateByteSize(*sizer_); + count += persistence_->remote_document_cache()->CalculateByteSize(*sizer_); + const auto& queues = persistence_->mutation_queues(); + for (const auto& entry : queues) { + count += entry.second->CalculateByteSize(*sizer_); + } + return count; +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_lru_reference_delegate.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_lru_reference_delegate.h new file mode 100644 index 0000000..8d5347f --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_lru_reference_delegate.h @@ -0,0 +1,112 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_LRU_REFERENCE_DELEGATE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_LRU_REFERENCE_DELEGATE_H_ + +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/local/lru_garbage_collector.h" +#include "Firestore/core/src/firebase/firestore/local/reference_delegate.h" + +namespace firebase { +namespace firestore { +namespace local { + +class ListenSequence; +class MemoryPersistence; +class Sizer; + +/** + * Provides the LRU GC implementation for memory persistence. + */ +class MemoryLruReferenceDelegate : public LruDelegate { + public: + MemoryLruReferenceDelegate(MemoryPersistence* persistence, + LruParams lru_params, + std::unique_ptr sizer); + + bool IsPinnedAtSequenceNumber(model::ListenSequenceNumber upper_bound, + const model::DocumentKey& key) const; + + // MARK: ReferenceDelegate overrides + + model::ListenSequenceNumber current_sequence_number() const override; + + void AddInMemoryPins(ReferenceSet* set) override; + + void AddReference(const model::DocumentKey& key) override; + void RemoveReference(const model::DocumentKey& key) override; + void RemoveMutationReference(const model::DocumentKey& key) override; + void RemoveTarget(const TargetData& target_data) override; + + void UpdateLimboDocument(const model::DocumentKey& key) override; + + void OnTransactionStarted(absl::string_view label) override; + void OnTransactionCommitted() override; + + // MARK: LruDelegate overrides + + LruGarbageCollector* garbage_collector() override; + + int64_t CalculateByteSize() override; + size_t GetSequenceNumberCount() override; + + void EnumerateTargets(const TargetCallback& callback) override; + void EnumerateOrphanedDocuments( + const OrphanedDocumentCallback& callback) override; + + int RemoveOrphanedDocuments(model::ListenSequenceNumber upper_bound) override; + int RemoveTargets(model::ListenSequenceNumber sequence_number, + const LiveQueryMap& live_queries) override; + + private: + bool MutationQueuesContainKey(const model::DocumentKey& key) const; + + // This instance is owned by MemoryPersistence. + MemoryPersistence* persistence_ = nullptr; + + std::unique_ptr sizer_; + + LruGarbageCollector gc_; + + // Tracks sequence numbers of when documents are used. Equivalent to sentinel + // rows in the leveldb implementation. + std::unordered_map + sequence_numbers_; + + // This ReferenceSet is owned by LocalStore. + ReferenceSet* additional_references_ = nullptr; + + // This needs to be a pointer because initialization is delayed until after + // we read from the target cache. + std::unique_ptr listen_sequence_; + + // The current sequence number for the currently active transaction. If no + // transaction is active, resets back to kListenSequenceNumberInvalid. + model::ListenSequenceNumber current_sequence_number_ = + kListenSequenceNumberInvalid; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_LRU_REFERENCE_DELEGATE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_mutation_queue.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_mutation_queue.cc new file mode 100644 index 0000000..777f125 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_mutation_queue.cc @@ -0,0 +1,303 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/memory_mutation_queue.h" + +#include + +#include "Firestore/core/src/firebase/firestore/local/document_key_reference.h" +#include "Firestore/core/src/firebase/firestore/local/index_manager.h" +#include "Firestore/core/src/firebase/firestore/local/memory_persistence.h" +#include "Firestore/core/src/firebase/firestore/local/reference_delegate.h" +#include "Firestore/core/src/firebase/firestore/local/sizer.h" +#include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" + +namespace firebase { +namespace firestore { +namespace local { + +using core::Query; +using model::BatchId; +using model::DocumentKey; +using model::DocumentKeySet; +using model::kBatchIdUnknown; +using model::Mutation; +using model::MutationBatch; +using model::ResourcePath; +using nanopb::ByteString; + +MemoryMutationQueue::MemoryMutationQueue(MemoryPersistence* persistence) + : persistence_(persistence) { +} + +bool MemoryMutationQueue::IsEmpty() { + // If the queue has any entries at all, the first entry must not be a + // tombstone (otherwise it would have been removed already). + return queue_.empty(); +} + +void MemoryMutationQueue::AcknowledgeBatch(const MutationBatch& batch, + const ByteString& stream_token) { + HARD_ASSERT(!queue_.empty(), "Cannot acknowledge batch on an empty queue"); + + // Guaranteed to exist, due to above assert + const MutationBatch& check = queue_.front(); + // Verify that the batch in the queue is the one to be acknowledged. + HARD_ASSERT(batch.batch_id() == check.batch_id(), + "Queue ordering failure: expected batch %s, got batch %s", + batch.batch_id(), check.batch_id()); + last_stream_token_ = stream_token; +} + +void MemoryMutationQueue::Start() { + // Note: The queue may be shutdown / started multiple times, since we maintain + // the queue for the duration of the app session in case a user logs out / + // back in. To behave like the LevelDB-backed MutationQueue (and accommodate + // tests that expect as much), we reset next_batch_id_ if the queue is empty. + if (IsEmpty()) { + next_batch_id_ = 1; + } +} + +MutationBatch MemoryMutationQueue::AddMutationBatch( + const Timestamp& local_write_time, + std::vector&& base_mutations, + std::vector&& mutations) { + HARD_ASSERT(!mutations.empty(), "Mutation batches should not be empty"); + + BatchId batch_id = next_batch_id_; + next_batch_id_++; + + if (!queue_.empty()) { + const MutationBatch& prior = queue_.back(); + HARD_ASSERT(prior.batch_id() < batch_id, + "Mutation batch_ids must be in monotonically increasing order"); + } + + MutationBatch batch(batch_id, local_write_time, std::move(base_mutations), + std::move(mutations)); + queue_.push_back(batch); + + // Track references by document key and index collection parents. + for (const Mutation& mutation : batch.mutations()) { + batches_by_document_key_ = batches_by_document_key_.insert( + DocumentKeyReference{mutation.key(), batch_id}); + + persistence_->index_manager()->AddToCollectionParentIndex( + mutation.key().path().PopLast()); + } + + return batch; +} + +void MemoryMutationQueue::RemoveMutationBatch(const MutationBatch& batch) { + // Can only remove the first batch + HARD_ASSERT(!queue_.empty(), "Trying to remove batch from empty queue"); + const MutationBatch& head = queue_.front(); + HARD_ASSERT(head.batch_id() == batch.batch_id(), + "Can only remove the first entry of the mutation queue"); + + queue_.erase(queue_.begin()); + + // Remove entries from the index too. + for (const Mutation& mutation : batch.mutations()) { + const DocumentKey& key = mutation.key(); + persistence_->reference_delegate()->RemoveMutationReference(key); + + DocumentKeyReference reference{key, batch.batch_id()}; + batches_by_document_key_ = batches_by_document_key_.erase(reference); + } +} + +std::vector +MemoryMutationQueue::AllMutationBatchesAffectingDocumentKeys( + const DocumentKeySet& document_keys) { + // First find the set of affected batch IDs. + std::set batch_ids; + for (const DocumentKey& key : document_keys) { + DocumentKeyReference start{key, 0}; + + for (const auto& reference : batches_by_document_key_.values_from(start)) { + if (key != reference.key()) break; + + batch_ids.insert(reference.ref_id()); + } + } + + return AllMutationBatchesWithIds(batch_ids); +} + +std::vector +MemoryMutationQueue::AllMutationBatchesAffectingDocumentKey( + const DocumentKey& key) { + std::vector result; + + DocumentKeyReference start{key, 0}; + for (const auto& reference : batches_by_document_key_.values_from(start)) { + if (key != reference.key()) break; + + auto batch = LookupMutationBatch(reference.ref_id()); + HARD_ASSERT(batch.has_value(), + "Batches in the index must exist in the main table"); + result.push_back(*batch); + } + return result; +} + +std::vector +MemoryMutationQueue::AllMutationBatchesAffectingQuery(const Query& query) { + HARD_ASSERT( + !query.IsCollectionGroupQuery(), + "CollectionGroup queries should be handled in LocalDocumentsView"); + + // Use the query path as a prefix for testing if a document matches the query. + const ResourcePath& prefix = query.path(); + size_t immediate_children_path_length = prefix.size() + 1; + + // Construct a document reference for actually scanning the index. Unlike the + // prefix, the document key in this reference must have an even number of + // segments. The empty segment can be used as a suffix of the query path + // because it precedes all other segments in an ordered traversal. + ResourcePath start_path = query.path(); + if (!DocumentKey::IsDocumentKey(start_path)) { + start_path = start_path.Append(""); + } + DocumentKeyReference start{DocumentKey{start_path}, 0}; + + // Find unique batch_ids referenced by all documents potentially matching the + // query. + std::set unique_batch_ids; + for (const auto& reference : batches_by_document_key_.values_from(start)) { + const ResourcePath& row_key_path = reference.key().path(); + if (!prefix.IsPrefixOf(row_key_path)) { + break; + } + + // Rows with document keys more than one segment longer than the query path + // can't be matches. For example, a query on 'rooms' can't match the + // document /rooms/abc/messages/xyx. + // TODO(mcg): we'll need a different scanner when we implement ancestor + // queries. + if (row_key_path.size() != immediate_children_path_length) { + continue; + } + + unique_batch_ids.insert(reference.ref_id()); + } + + return AllMutationBatchesWithIds(unique_batch_ids); +} + +absl::optional +MemoryMutationQueue::NextMutationBatchAfterBatchId(BatchId batch_id) { + BatchId next_batch_id = batch_id + 1; + + // The requested batch_id may still be out of range so normalize it to the + // start of the queue. + int raw_index = IndexOfBatchId(next_batch_id); + size_t index = raw_index < 0 ? 0 : static_cast(raw_index); + if (queue_.size() <= index) { + return absl::nullopt; + } + + return queue_[index]; +} + +BatchId MemoryMutationQueue::GetHighestUnacknowledgedBatchId() { + return IsEmpty() ? kBatchIdUnknown : next_batch_id_ - 1; +} + +absl::optional MemoryMutationQueue::LookupMutationBatch( + BatchId batch_id) { + if (queue_.empty()) { + return absl::nullopt; + } + + int index = IndexOfBatchId(batch_id); + if (index < 0 || static_cast(index) >= queue_.size()) { + return absl::nullopt; + } + + const MutationBatch& batch = queue_[index]; + HARD_ASSERT(batch.batch_id() == batch_id, "If found, batch must match"); + return batch; +} + +void MemoryMutationQueue::PerformConsistencyCheck() { + if (queue_.empty()) { + HARD_ASSERT(batches_by_document_key_.empty(), + "Document leak -- detected dangling mutation references when " + "queue is empty."); + } +} + +bool MemoryMutationQueue::ContainsKey(const model::DocumentKey& key) { + // Create a reference with a zero ID as the start position to find any + // document reference with this key. + DocumentKeyReference reference{key, 0}; + auto range = batches_by_document_key_.values_from(reference); + auto begin = range.begin(); + return begin != range.end() && begin->key() == key; +} + +int64_t MemoryMutationQueue::CalculateByteSize(const Sizer& sizer) { + int64_t count = 0; + for (const auto& batch : queue_) { + count += sizer.CalculateByteSize(batch); + } + return count; +} + +ByteString MemoryMutationQueue::GetLastStreamToken() { + return last_stream_token_; +} + +void MemoryMutationQueue::SetLastStreamToken(ByteString token) { + last_stream_token_ = std::move(token); +} + +std::vector MemoryMutationQueue::AllMutationBatchesWithIds( + const std::set& batch_ids) { + std::vector result; + for (BatchId batch_id : batch_ids) { + auto batch = LookupMutationBatch(batch_id); + if (batch.has_value()) { + result.push_back(*batch); + } + } + + return result; +} + +int MemoryMutationQueue::IndexOfBatchId(BatchId batch_id) { + if (queue_.empty()) { + // As an index this is past the end of the queue + return 0; + } + + // Examine the front of the queue to figure out the difference between the + // batch_id and indexes in the array. Note that since the queue is ordered by + // batch_id, if the first batch has a larger batch_id then the requested + // batch_id doesn't exist in the queue. + const MutationBatch& first_batch = queue_.front(); + return batch_id - first_batch.batch_id(); +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_mutation_queue.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_mutation_queue.h index 927317c..afc98de 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_mutation_queue.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_mutation_queue.h @@ -17,17 +17,10 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_MUTATION_QUEUE_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_MUTATION_QUEUE_H_ -#if !defined(__OBJC__) -#error "For now, this file must only be included by ObjC source files." -#endif // !defined(__OBJC__) - -#import - #include #include -#import "Firestore/Source/Public/FIRTimestamp.h" - +#include "Firestore/core/include/firebase/firestore/timestamp.h" #include "Firestore/core/src/firebase/firestore/immutable/sorted_set.h" #include "Firestore/core/src/firebase/firestore/local/document_key_reference.h" #include "Firestore/core/src/firebase/firestore/local/mutation_queue.h" @@ -35,73 +28,70 @@ #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/types.h" -@class FSTLocalSerializer; -@class FSTMemoryPersistence; -@class FSTMutation; -@class FSTMutationBatch; -@class FSTQuery; - -NS_ASSUME_NONNULL_BEGIN - namespace firebase { namespace firestore { namespace local { +class MemoryPersistence; +class Sizer; + class MemoryMutationQueue : public MutationQueue { public: - explicit MemoryMutationQueue(FSTMemoryPersistence* persistence); + explicit MemoryMutationQueue(MemoryPersistence* persistence); void Start() override; bool IsEmpty() override; - void AcknowledgeBatch(FSTMutationBatch* batch, - NSData* _Nullable stream_token) override; + void AcknowledgeBatch(const model::MutationBatch& batch, + const nanopb::ByteString& stream_token) override; - FSTMutationBatch* AddMutationBatch( - FIRTimestamp* local_write_time, - std::vector&& base_mutations, - std::vector&& mutations) override; + model::MutationBatch AddMutationBatch( + const Timestamp& local_write_time, + std::vector&& base_mutations, + std::vector&& mutations) override; - void RemoveMutationBatch(FSTMutationBatch* batch) override; + void RemoveMutationBatch(const model::MutationBatch& batch) override; - std::vector AllMutationBatches() override { + std::vector AllMutationBatches() override { return queue_; } - std::vector AllMutationBatchesAffectingDocumentKeys( + std::vector AllMutationBatchesAffectingDocumentKeys( const model::DocumentKeySet& document_keys) override; - std::vector AllMutationBatchesAffectingDocumentKey( + std::vector AllMutationBatchesAffectingDocumentKey( const model::DocumentKey& key) override; - std::vector AllMutationBatchesAffectingQuery( - FSTQuery* query) override; + std::vector AllMutationBatchesAffectingQuery( + const core::Query& query) override; - FSTMutationBatch* _Nullable LookupMutationBatch( + absl::optional LookupMutationBatch( model::BatchId batch_id) override; - FSTMutationBatch* _Nullable NextMutationBatchAfterBatchId( + absl::optional NextMutationBatchAfterBatchId( model::BatchId batch_id) override; + model::BatchId GetHighestUnacknowledgedBatchId() override; + void PerformConsistencyCheck() override; bool ContainsKey(const model::DocumentKey& key); - size_t CalculateByteSize(FSTLocalSerializer* serializer); + int64_t CalculateByteSize(const Sizer& sizer); - NSData* _Nullable GetLastStreamToken() override; - void SetLastStreamToken(NSData* _Nullable token) override; + nanopb::ByteString GetLastStreamToken() override; + void SetLastStreamToken(nanopb::ByteString token) override; private: using DocumentKeyReferenceSet = immutable::SortedSet; - std::vector AllMutationBatchesWithIds( + std::vector AllMutationBatchesWithIds( const std::set& batch_ids); /** - * Finds the index of the given batchID in the mutation queue. This operation + * Finds the index of the given batch_id in the mutation queue. This operation * is O(1). * * @return The computed index of the batch with the given BatchID, based on @@ -111,8 +101,9 @@ class MemoryMutationQueue : public MutationQueue { */ int IndexOfBatchId(model::BatchId batch_id); - // This instance is owned by FSTMemoryPersistence; avoid a retain cycle. - __weak FSTMemoryPersistence* persistence_; + // This instance is owned by MemoryPersistence. + MemoryPersistence* persistence_; + /** * A FIFO queue of all mutations to apply to the backend. Mutations are added * to the end of the queue as they're written, and removed from the front of @@ -131,7 +122,7 @@ class MemoryMutationQueue : public MutationQueue { * Once the held write acknowledgements become visible they are removed from * the head of the queue along with any tombstones that follow. */ - std::vector queue_; + std::vector queue_; /** * The next value to use when assigning sequential IDs to each mutation @@ -144,7 +135,7 @@ class MemoryMutationQueue : public MutationQueue { * responses the client has processed. Stream tokens are opaque checkpoint * markers whose only real value is their inclusion in the next request. */ - NSData* _Nullable last_stream_token_; + nanopb::ByteString last_stream_token_; /** An ordered mapping between documents and the mutation batch IDs. */ DocumentKeyReferenceSet batches_by_document_key_; @@ -154,6 +145,4 @@ class MemoryMutationQueue : public MutationQueue { } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_MUTATION_QUEUE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_mutation_queue.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_mutation_queue.mm deleted file mode 100644 index aace5e5..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_mutation_queue.mm +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/local/memory_mutation_queue.h" - -#include - -#import "Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Local/FSTLocalSerializer.h" -#import "Firestore/Source/Local/FSTMemoryPersistence.h" -#import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Model/FSTMutationBatch.h" - -#include "Firestore/core/src/firebase/firestore/local/document_key_reference.h" -#include "Firestore/core/src/firebase/firestore/model/resource_path.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace firebase { -namespace firestore { -namespace local { - -using model::BatchId; -using model::DocumentKey; -using model::DocumentKeySet; -using model::ResourcePath; - -MemoryMutationQueue::MemoryMutationQueue(FSTMemoryPersistence* persistence) - : persistence_(persistence) { -} - -bool MemoryMutationQueue::IsEmpty() { - // If the queue has any entries at all, the first entry must not be a - // tombstone (otherwise it would have been removed already). - return queue_.empty(); -} - -void MemoryMutationQueue::AcknowledgeBatch(FSTMutationBatch* batch, - NSData* _Nullable stream_token) { - HARD_ASSERT(!queue_.empty(), "Cannot acknowledge batch on an empty queue"); - - // Guaranteed to exist, due to above assert - FSTMutationBatch* check = queue_.front(); - // Verify that the batch in the queue is the one to be acknowledged. - HARD_ASSERT(batch.batchID == check.batchID, - "Queue ordering failure: expected batch %s, got batch %s", - batch.batchID, check.batchID); - last_stream_token_ = stream_token; -} - -void MemoryMutationQueue::Start() { - // Note: The queue may be shutdown / started multiple times, since we maintain - // the queue for the duration of the app session in case a user logs out / - // back in. To behave like the LevelDB-backed MutationQueue (and accommodate - // tests that expect as much), we reset nextBatchID if the queue is empty. - if (IsEmpty()) { - next_batch_id_ = 1; - } -} - -FSTMutationBatch* MemoryMutationQueue::AddMutationBatch( - FIRTimestamp* local_write_time, - std::vector&& base_mutations, - std::vector&& mutations) { - HARD_ASSERT(!mutations.empty(), "Mutation batches should not be empty"); - - BatchId batch_id = next_batch_id_; - next_batch_id_++; - - if (!queue_.empty()) { - FSTMutationBatch* prior = queue_.back(); - HARD_ASSERT(prior.batchID < batch_id, - "Mutation batchIDs must be in monotonically increasing order"); - } - - FSTMutationBatch* batch = - [[FSTMutationBatch alloc] initWithBatchID:batch_id - localWriteTime:local_write_time - baseMutations:std::move(base_mutations) - mutations:std::move(mutations)]; - queue_.push_back(batch); - - // Track references by document key and index collection parents. - for (FSTMutation* mutation : [batch mutations]) { - batches_by_document_key_ = batches_by_document_key_.insert( - DocumentKeyReference{mutation.key, batch_id}); - - persistence_.indexManager->AddToCollectionParentIndex( - mutation.key.path().PopLast()); - } - - return batch; -} - -void MemoryMutationQueue::RemoveMutationBatch(FSTMutationBatch* batch) { - // Can only remove the first batch - HARD_ASSERT(!queue_.empty(), "Trying to remove batch from empty queue"); - FSTMutationBatch* head = queue_.front(); - HARD_ASSERT(head.batchID == batch.batchID, - "Can only remove the first entry of the mutation queue"); - - queue_.erase(queue_.begin()); - - // Remove entries from the index too. - for (FSTMutation* mutation : [batch mutations]) { - const DocumentKey& key = mutation.key; - [persistence_.referenceDelegate removeMutationReference:key]; - - DocumentKeyReference reference{key, batch.batchID}; - batches_by_document_key_ = batches_by_document_key_.erase(reference); - } -} - -std::vector -MemoryMutationQueue::AllMutationBatchesAffectingDocumentKeys( - const DocumentKeySet& document_keys) { - // First find the set of affected batch IDs. - std::set batch_ids; - for (const DocumentKey& key : document_keys) { - DocumentKeyReference start{key, 0}; - - for (const auto& reference : batches_by_document_key_.values_from(start)) { - if (key != reference.key()) break; - - batch_ids.insert(reference.ref_id()); - } - } - - return AllMutationBatchesWithIds(batch_ids); -} - -std::vector -MemoryMutationQueue::AllMutationBatchesAffectingDocumentKey( - const DocumentKey& key) { - std::vector result; - - DocumentKeyReference start{key, 0}; - for (const auto& reference : batches_by_document_key_.values_from(start)) { - if (key != reference.key()) break; - - FSTMutationBatch* batch = LookupMutationBatch(reference.ref_id()); - HARD_ASSERT(batch, "Batches in the index must exist in the main table"); - result.push_back(batch); - } - return result; -} - -std::vector -MemoryMutationQueue::AllMutationBatchesAffectingQuery(FSTQuery* query) { - HARD_ASSERT( - ![query isCollectionGroupQuery], - "CollectionGroup queries should be handled in LocalDocumentsView"); - - // Use the query path as a prefix for testing if a document matches the query. - const ResourcePath& prefix = query.path; - size_t immediate_children_path_length = prefix.size() + 1; - - // Construct a document reference for actually scanning the index. Unlike the - // prefix, the document key in this reference must have an even number of - // segments. The empty segment can be used as a suffix of the query path - // because it precedes all other segments in an ordered traversal. - ResourcePath start_path = query.path; - if (!DocumentKey::IsDocumentKey(start_path)) { - start_path = start_path.Append(""); - } - DocumentKeyReference start{DocumentKey{start_path}, 0}; - - // Find unique batchIDs referenced by all documents potentially matching the - // query. - std::set unique_batch_ids; - for (const auto& reference : batches_by_document_key_.values_from(start)) { - const ResourcePath& row_key_path = reference.key().path(); - if (!prefix.IsPrefixOf(row_key_path)) { - break; - } - - // Rows with document keys more than one segment longer than the query path - // can't be matches. For example, a query on 'rooms' can't match the - // document /rooms/abc/messages/xyx. - // TODO(mcg): we'll need a different scanner when we implement ancestor - // queries. - if (row_key_path.size() != immediate_children_path_length) { - continue; - } - - unique_batch_ids.insert(reference.ref_id()); - }; - - return AllMutationBatchesWithIds(unique_batch_ids); -} - -FSTMutationBatch* _Nullable MemoryMutationQueue::NextMutationBatchAfterBatchId( - BatchId batch_id) { - BatchId next_batch_id = batch_id + 1; - - // The requested batchID may still be out of range so normalize it to the - // start of the queue. - int raw_index = IndexOfBatchId(next_batch_id); - int index = raw_index < 0 ? 0 : raw_index; - return queue_.size() > index ? queue_[index] : nil; -} - -FSTMutationBatch* _Nullable MemoryMutationQueue::LookupMutationBatch( - BatchId batch_id) { - if (queue_.empty()) { - return nil; - } - - int index = IndexOfBatchId(batch_id); - if (index < 0 || index >= queue_.size()) { - return nil; - } - - FSTMutationBatch* batch = queue_[index]; - HARD_ASSERT(batch.batchID == batch_id, "If found, batch must match"); - return batch; -} - -void MemoryMutationQueue::PerformConsistencyCheck() { - if (queue_.empty()) { - HARD_ASSERT(batches_by_document_key_.empty(), - "Document leak -- detected dangling mutation references when " - "queue is empty."); - } -} - -bool MemoryMutationQueue::ContainsKey(const model::DocumentKey& key) { - // Create a reference with a zero ID as the start position to find any - // document reference with this key. - DocumentKeyReference reference{key, 0}; - auto range = batches_by_document_key_.values_from(reference); - auto begin = range.begin(); - return begin != range.end() && begin->key() == key; -} - -size_t MemoryMutationQueue::CalculateByteSize(FSTLocalSerializer* serializer) { - size_t count = 0; - for (const auto& batch : queue_) { - count += [[serializer encodedMutationBatch:batch] serializedSize]; - }; - return count; -} - -NSData* _Nullable MemoryMutationQueue::GetLastStreamToken() { - return last_stream_token_; -} - -void MemoryMutationQueue::SetLastStreamToken(NSData* _Nullable token) { - last_stream_token_ = token; -} - -std::vector MemoryMutationQueue::AllMutationBatchesWithIds( - const std::set& batch_ids) { - std::vector result; - for (BatchId batch_id : batch_ids) { - FSTMutationBatch* batch = LookupMutationBatch(batch_id); - if (batch) { - result.push_back(batch); - } - } - - return result; -} - -int MemoryMutationQueue::IndexOfBatchId(BatchId batch_id) { - if (queue_.empty()) { - // As an index this is past the end of the queue - return 0; - } - - // Examine the front of the queue to figure out the difference between the - // batchID and indexes in the array. Note that since the queue is ordered by - // batchID, if the first batch has a larger batchID then the requested batchID - // doesn't exist in the queue. - FSTMutationBatch* first_batch = queue_.front(); - return batch_id - first_batch.batchID; -} - -} // namespace local -} // namespace firestore -} // namespace firebase - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_persistence.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_persistence.cc new file mode 100644 index 0000000..c890b0c --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_persistence.cc @@ -0,0 +1,117 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/memory_persistence.h" + +#include "Firestore/core/src/firebase/firestore/auth/user.h" +#include "Firestore/core/src/firebase/firestore/local/listen_sequence.h" +#include "Firestore/core/src/firebase/firestore/local/lru_garbage_collector.h" +#include "Firestore/core/src/firebase/firestore/local/memory_eager_reference_delegate.h" +#include "Firestore/core/src/firebase/firestore/local/memory_index_manager.h" +#include "Firestore/core/src/firebase/firestore/local/memory_lru_reference_delegate.h" +#include "Firestore/core/src/firebase/firestore/local/memory_mutation_queue.h" +#include "Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h" +#include "Firestore/core/src/firebase/firestore/local/memory_target_cache.h" +#include "Firestore/core/src/firebase/firestore/local/reference_delegate.h" +#include "Firestore/core/src/firebase/firestore/local/sizer.h" +#include "absl/memory/memory.h" + +namespace firebase { +namespace firestore { +namespace local { + +using auth::User; +using model::ListenSequenceNumber; + +std::unique_ptr +MemoryPersistence::WithEagerGarbageCollector() { + std::unique_ptr persistence(new MemoryPersistence()); + auto delegate = + absl::make_unique(persistence.get()); + persistence->set_reference_delegate(std::move(delegate)); + return persistence; +} + +std::unique_ptr MemoryPersistence::WithLruGarbageCollector( + LruParams lru_params, std::unique_ptr sizer) { + std::unique_ptr persistence(new MemoryPersistence()); + auto delegate = absl::make_unique( + persistence.get(), lru_params, std::move(sizer)); + persistence->set_reference_delegate(std::move(delegate)); + return persistence; +} + +MemoryPersistence::MemoryPersistence() + : target_cache_(this), remote_document_cache_(this), started_(true) { +} + +MemoryPersistence::~MemoryPersistence() = default; + +ListenSequenceNumber MemoryPersistence::current_sequence_number() const { + return reference_delegate_->current_sequence_number(); +} + +void MemoryPersistence::set_reference_delegate( + std::unique_ptr delegate) { + reference_delegate_ = std::move(delegate); +} + +void MemoryPersistence::Shutdown() { + // No durable state to ensure is closed on shutdown. + HARD_ASSERT(started_, "MemoryPersistence shutdown without start!"); + started_ = false; +} + +MemoryMutationQueue* MemoryPersistence::GetMutationQueueForUser( + const User& user) { + auto iter = mutation_queues_.find(user); + if (iter == mutation_queues_.end()) { + auto queue = absl::make_unique(this); + MemoryMutationQueue* result = queue.get(); + + mutation_queues_.emplace(user, std::move(queue)); + return result; + } else { + return iter->second.get(); + } +} + +MemoryTargetCache* MemoryPersistence::target_cache() { + return &target_cache_; +} + +MemoryRemoteDocumentCache* MemoryPersistence::remote_document_cache() { + return &remote_document_cache_; +} + +MemoryIndexManager* MemoryPersistence::index_manager() { + return &index_manager_; +} + +ReferenceDelegate* MemoryPersistence::reference_delegate() { + return reference_delegate_.get(); +} + +void MemoryPersistence::RunInternal(absl::string_view label, + std::function block) { + TransactionGuard guard(reference_delegate_.get(), label); + + block(); +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_persistence.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_persistence.h new file mode 100644 index 0000000..51b4d88 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_persistence.h @@ -0,0 +1,125 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_PERSISTENCE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_PERSISTENCE_H_ + +#include +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/auth/user.h" +#include "Firestore/core/src/firebase/firestore/local/memory_index_manager.h" +#include "Firestore/core/src/firebase/firestore/local/memory_mutation_queue.h" +#include "Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h" +#include "Firestore/core/src/firebase/firestore/local/memory_target_cache.h" +#include "Firestore/core/src/firebase/firestore/local/persistence.h" + +namespace firebase { +namespace firestore { +namespace local { + +struct LruParams; +class MemoryIndexManager; +class MemoryMutationQueue; +class MemoryRemoteDocumentCache; +class MemoryTargetCache; +class MutationQueue; +class TargetCache; +class ReferenceDelegate; +class RemoteDocumentCache; +class Sizer; + +/** + * An in-memory implementation of the Persistence interface. Values are stored + * only in RAM and are never persisted to any durable storage. + */ +class MemoryPersistence : public Persistence { + public: + using MutationQueues = + std::unordered_map, + auth::HashUser>; + + static std::unique_ptr WithEagerGarbageCollector(); + + static std::unique_ptr WithLruGarbageCollector( + LruParams params, std::unique_ptr sizer); + + ~MemoryPersistence() override; + + const MutationQueues& mutation_queues() const { + return mutation_queues_; + } + + // MARK: Persistence overrides + + model::ListenSequenceNumber current_sequence_number() const override; + + void Shutdown() override; + + MemoryMutationQueue* GetMutationQueueForUser(const auth::User& user) override; + + MemoryTargetCache* target_cache() override; + + MemoryRemoteDocumentCache* remote_document_cache() override; + + MemoryIndexManager* index_manager() override; + + ReferenceDelegate* reference_delegate() override; + + protected: + void RunInternal(absl::string_view label, + std::function block) override; + + private: + MemoryPersistence(); + + void set_reference_delegate(std::unique_ptr delegate); + + MutationQueues mutation_queues_; + + /** + * The TargetCache representing the persisted cache of queries. + * + * Note that this is retained here to make it easier to write tests affecting + * both the in-memory and LevelDB-backed persistence layers. Tests can create + * a new LocalStore wrapping this Persistence instance and this will make + * the in-memory persistence layer behave as if it were actually persisting + * values. + */ + MemoryTargetCache target_cache_; + + /** + * The RemoteDocumentCache representing the persisted cache of remote + * documents. + */ + MemoryRemoteDocumentCache remote_document_cache_; + + MemoryIndexManager index_manager_; + + std::unique_ptr reference_delegate_; + + bool started_ = false; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_PERSISTENCE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_query_cache.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_query_cache.h deleted file mode 100644 index 747756a..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_query_cache.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_QUERY_CACHE_H_ -#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_QUERY_CACHE_H_ - -#if !defined(__OBJC__) -#error "For now, this file must only be included by ObjC source files." -#endif // !defined(__OBJC__) - -#import - -#include -#include -#include - -#include "Firestore/core/src/firebase/firestore/local/query_cache.h" -#include "Firestore/core/src/firebase/firestore/local/reference_set.h" -#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" -#include "Firestore/core/src/firebase/firestore/util/objc_compatibility.h" - -@class FSTLocalSerializer; -@class FSTMemoryPersistence; -@class FSTQuery; -@class FSTQueryData; - -NS_ASSUME_NONNULL_BEGIN - -namespace firebase { -namespace firestore { -namespace local { - -class MemoryQueryCache : public QueryCache { - public: - explicit MemoryQueryCache(FSTMemoryPersistence* persistence); - - // Target-related methods - void AddTarget(FSTQueryData* query_data) override; - - void UpdateTarget(FSTQueryData* query_data) override; - - void RemoveTarget(FSTQueryData* query_data) override; - - FSTQueryData* _Nullable GetTarget(FSTQuery* query) override; - - void EnumerateTargets(const TargetCallback& callback) override; - - int RemoveTargets(model::ListenSequenceNumber upper_bound, - const std::unordered_map& - live_targets) override; - - // Key-related methods - void AddMatchingKeys(const model::DocumentKeySet& keys, - model::TargetId target_id) override; - - void RemoveMatchingKeys(const model::DocumentKeySet& keys, - model::TargetId target_id) override; - - model::DocumentKeySet GetMatchingKeys(model::TargetId target_id) override; - - bool Contains(const model::DocumentKey& key) override; - - // Other methods and accessors - size_t CalculateByteSize(FSTLocalSerializer* serializer); - - size_t size() const override { - return queries_.size(); - } - - model::ListenSequenceNumber highest_listen_sequence_number() const override { - return highest_listen_sequence_number_; - } - - model::TargetId highest_target_id() const override { - return highest_target_id_; - } - - const model::SnapshotVersion& GetLastRemoteSnapshotVersion() const override; - - void SetLastRemoteSnapshotVersion(model::SnapshotVersion version) override; - - private: - // This instance is owned by FSTMemoryPersistence; avoid a retain cycle. - __weak FSTMemoryPersistence* persistence_; - - /** The highest sequence number encountered */ - model::ListenSequenceNumber highest_listen_sequence_number_; - /** The highest numbered target ID encountered. */ - model::TargetId highest_target_id_; - /** The last received snapshot version. */ - model::SnapshotVersion last_remote_snapshot_version_; - - /** Maps a query to the data about that query. */ - util::objc::unordered_map queries_; - - /** - * A ordered bidirectional mapping between documents and the remote target - * IDs. - */ - ReferenceSet references_; -}; - -} // namespace local -} // namespace firestore -} // namespace firebase - -NS_ASSUME_NONNULL_END - -#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_QUERY_CACHE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_query_cache.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_query_cache.mm deleted file mode 100644 index 05a6985..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_query_cache.mm +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/local/memory_query_cache.h" - -#import - -#include - -#import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Local/FSTMemoryPersistence.h" -#import "Firestore/Source/Local/FSTQueryData.h" - -#include "Firestore/core/src/firebase/firestore/model/document_key.h" - -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::DocumentKeySet; -using firebase::firestore::model::ListenSequenceNumber; -using firebase::firestore::model::SnapshotVersion; -using firebase::firestore::model::TargetId; - -namespace firebase { -namespace firestore { -namespace local { - -NS_ASSUME_NONNULL_BEGIN - -MemoryQueryCache::MemoryQueryCache(FSTMemoryPersistence* persistence) - : persistence_(persistence), - highest_listen_sequence_number_(ListenSequenceNumber(0)), - highest_target_id_(TargetId(0)), - last_remote_snapshot_version_(SnapshotVersion::None()), - queries_() { -} - -void MemoryQueryCache::AddTarget(FSTQueryData* query_data) { - queries_[query_data.query] = query_data; - if (query_data.targetID > highest_target_id_) { - highest_target_id_ = query_data.targetID; - } - if (query_data.sequenceNumber > highest_listen_sequence_number_) { - highest_listen_sequence_number_ = query_data.sequenceNumber; - } -} - -void MemoryQueryCache::UpdateTarget(FSTQueryData* query_data) { - // For the memory query cache, adds and updates are treated the same. - AddTarget(query_data); -} - -void MemoryQueryCache::RemoveTarget(FSTQueryData* query_data) { - queries_.erase(query_data.query); - references_.RemoveReferences(query_data.targetID); -} - -FSTQueryData* _Nullable MemoryQueryCache::GetTarget(FSTQuery* query) { - auto iter = queries_.find(query); - return iter == queries_.end() ? nil : iter->second; -} - -void MemoryQueryCache::EnumerateTargets(const TargetCallback& callback) { - for (const auto& kv : queries_) { - callback(kv.second); - } -} - -int MemoryQueryCache::RemoveTargets( - model::ListenSequenceNumber upper_bound, - const std::unordered_map& live_targets) { - std::vector to_remove; - for (const auto& kv : queries_) { - FSTQuery* query = kv.first; - FSTQueryData* query_data = kv.second; - - if (query_data.sequenceNumber <= upper_bound) { - if (live_targets.find(query_data.targetID) == live_targets.end()) { - to_remove.push_back(query); - references_.RemoveReferences(query_data.targetID); - } - } - } - - for (FSTQuery* element : to_remove) { - queries_.erase(element); - } - return static_cast(to_remove.size()); -} - -void MemoryQueryCache::AddMatchingKeys(const DocumentKeySet& keys, - TargetId target_id) { - references_.AddReferences(keys, target_id); - for (const DocumentKey& key : keys) { - [persistence_.referenceDelegate addReference:key]; - } -} - -void MemoryQueryCache::RemoveMatchingKeys(const DocumentKeySet& keys, - TargetId target_id) { - references_.RemoveReferences(keys, target_id); - for (const DocumentKey& key : keys) { - [persistence_.referenceDelegate removeReference:key]; - } -} - -DocumentKeySet MemoryQueryCache::GetMatchingKeys(TargetId target_id) { - return references_.ReferencedKeys(target_id); -} - -bool MemoryQueryCache::Contains(const DocumentKey& key) { - return references_.ContainsKey(key); -} - -size_t MemoryQueryCache::CalculateByteSize(FSTLocalSerializer* serializer) { - size_t count = 0; - for (const auto& kv : queries_) { - FSTQueryData* query_data = kv.second; - count += [[serializer encodedQueryData:query_data] serializedSize]; - } - return count; -} - -const SnapshotVersion& MemoryQueryCache::GetLastRemoteSnapshotVersion() const { - return last_remote_snapshot_version_; -} - -void MemoryQueryCache::SetLastRemoteSnapshotVersion(SnapshotVersion version) { - last_remote_snapshot_version_ = std::move(version); -} - -NS_ASSUME_NONNULL_END - -} // namespace local -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.cc new file mode 100644 index 0000000..93d09df --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.cc @@ -0,0 +1,135 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h" + +#include "Firestore/core/src/firebase/firestore/local/memory_lru_reference_delegate.h" +#include "Firestore/core/src/firebase/firestore/local/memory_persistence.h" +#include "Firestore/core/src/firebase/firestore/local/sizer.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" + +namespace firebase { +namespace firestore { +namespace local { + +using core::Query; +using model::Document; +using model::DocumentKey; +using model::DocumentKeySet; +using model::DocumentMap; +using model::ListenSequenceNumber; +using model::MaybeDocument; +using model::MaybeDocumentMap; +using model::OptionalMaybeDocumentMap; +using model::SnapshotVersion; + +MemoryRemoteDocumentCache::MemoryRemoteDocumentCache( + MemoryPersistence* persistence) { + persistence_ = persistence; +} + +void MemoryRemoteDocumentCache::Add(const MaybeDocument& document, + const model::SnapshotVersion& read_time) { + docs_ = docs_.insert(document.key(), std::make_pair(document, read_time)); + + persistence_->index_manager()->AddToCollectionParentIndex( + document.key().path().PopLast()); +} + +void MemoryRemoteDocumentCache::Remove(const DocumentKey& key) { + docs_ = docs_.erase(key); +} + +absl::optional MemoryRemoteDocumentCache::Get( + const DocumentKey& key) { + const auto& entry = docs_.get(key); + return entry ? entry->first : absl::optional(); +} + +OptionalMaybeDocumentMap MemoryRemoteDocumentCache::GetAll( + const DocumentKeySet& keys) { + OptionalMaybeDocumentMap results; + for (const DocumentKey& key : keys) { + // Make sure each key has a corresponding entry, which is nullopt in case + // the document is not found. + // TODO(http://b/32275378): Don't conflate missing / deleted. + results = results.insert(key, Get(key)); + } + return results; +} + +DocumentMap MemoryRemoteDocumentCache::GetMatching( + const Query& query, const SnapshotVersion& since_read_time) { + HARD_ASSERT( + !query.IsCollectionGroupQuery(), + "CollectionGroup queries should be handled in LocalDocumentsView"); + + DocumentMap results; + + // Documents are ordered by key, so we can use a prefix scan to narrow down + // the documents we need to match the query against. + DocumentKey prefix{query.path().Append("")}; + for (auto it = docs_.lower_bound(prefix); it != docs_.end(); ++it) { + const DocumentKey& key = it->first; + if (!query.path().IsPrefixOf(key.path())) { + break; + } + const MaybeDocument& maybe_doc = it->second.first; + if (!maybe_doc.is_document()) { + continue; + } + + const SnapshotVersion& read_time = it->second.second; + if (read_time <= since_read_time) { + continue; + } + + Document doc(maybe_doc); + if (query.Matches(doc)) { + results = results.insert(key, std::move(doc)); + } + } + return results; +} + +std::vector MemoryRemoteDocumentCache::RemoveOrphanedDocuments( + MemoryLruReferenceDelegate* reference_delegate, + ListenSequenceNumber upper_bound) { + std::vector removed; + auto updated_docs = docs_; + for (const auto& kv : docs_) { + const DocumentKey& key = kv.first; + if (!reference_delegate->IsPinnedAtSequenceNumber(upper_bound, key)) { + updated_docs = updated_docs.erase(key); + removed.push_back(key); + } + } + docs_ = updated_docs; + return removed; +} + +int64_t MemoryRemoteDocumentCache::CalculateByteSize(const Sizer& sizer) { + int64_t count = 0; + for (const auto& kv : docs_) { + const MaybeDocument& maybe_doc = kv.second.first; + count += sizer.CalculateByteSize(maybe_doc); + } + return count; +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h index e0f3cda..3b6e18a 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h @@ -17,10 +17,7 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_ -#if !defined(__OBJC__) -#error "For now, this file must only be included by ObjC source files." -#endif // !defined(__OBJC__) - +#include #include #include "Firestore/core/src/firebase/firestore/local/remote_document_cache.h" @@ -29,47 +26,48 @@ #include "Firestore/core/src/firebase/firestore/model/document_map.h" #include "Firestore/core/src/firebase/firestore/model/types.h" -@class FSTLocalSerializer; -@class FSTMaybeDocument; -@class FSTMemoryLRUReferenceDelegate; -@class FSTMemoryPersistence; -@class FSTQuery; - -NS_ASSUME_NONNULL_BEGIN - namespace firebase { namespace firestore { namespace local { +class MemoryLruReferenceDelegate; +class MemoryPersistence; +class Sizer; + class MemoryRemoteDocumentCache : public RemoteDocumentCache { public: - explicit MemoryRemoteDocumentCache(FSTMemoryPersistence *persistence); + explicit MemoryRemoteDocumentCache(MemoryPersistence* persistence); - void Add(FSTMaybeDocument *document) override; - void Remove(const model::DocumentKey &key) override; + void Add(const model::MaybeDocument& document, + const model::SnapshotVersion& read_time) override; + void Remove(const model::DocumentKey& key) override; - FSTMaybeDocument *_Nullable Get(const model::DocumentKey &key) override; - model::MaybeDocumentMap GetAll(const model::DocumentKeySet &keys) override; - model::DocumentMap GetMatching(FSTQuery *query) override; + absl::optional Get( + const model::DocumentKey& key) override; + model::OptionalMaybeDocumentMap GetAll( + const model::DocumentKeySet& keys) override; + model::DocumentMap GetMatching( + const core::Query& query, + const model::SnapshotVersion& since_read_time) override; std::vector RemoveOrphanedDocuments( - FSTMemoryLRUReferenceDelegate *reference_delegate, + MemoryLruReferenceDelegate* reference_delegate, model::ListenSequenceNumber upper_bound); - size_t CalculateByteSize(FSTLocalSerializer *serializer); + int64_t CalculateByteSize(const Sizer& sizer); private: - /** Underlying cache of documents. */ - model::MaybeDocumentMap docs_; + /** Underlying cache of documents and their read times. */ + immutable::SortedMap> + docs_; - // This instance is owned by FSTMemoryPersistence; avoid a retain cycle. - __weak FSTMemoryPersistence *persistence_; + // This instance is owned by MemoryPersistence; avoid a retain cycle. + MemoryPersistence* persistence_; }; } // namespace local } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.mm deleted file mode 100644 index 82503a0..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.mm +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h" - -#import "Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h" -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Local/FSTMemoryPersistence.h" - -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" - -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::DocumentKeySet; -using firebase::firestore::model::DocumentMap; -using firebase::firestore::model::ListenSequenceNumber; -using firebase::firestore::model::MaybeDocumentMap; - -namespace firebase { -namespace firestore { -namespace local { - -namespace { -/** - * Returns an estimate of the number of bytes used to store the given - * document key in memory. This is only an estimate and includes the size - * of the segments of the path, but not any object overhead or path separators. - */ -size_t DocumentKeyByteSize(const DocumentKey& key) { - size_t count = 0; - for (const auto& segment : key.path()) { - count += segment.size(); - } - return count; -} -} // namespace - -MemoryRemoteDocumentCache::MemoryRemoteDocumentCache( - FSTMemoryPersistence* persistence) { - persistence_ = persistence; -} - -void MemoryRemoteDocumentCache::Add(FSTMaybeDocument* document) { - docs_ = docs_.insert(document.key, document); - - persistence_.indexManager->AddToCollectionParentIndex( - document.key.path().PopLast()); -} - -void MemoryRemoteDocumentCache::Remove(const DocumentKey& key) { - docs_ = docs_.erase(key); -} - -FSTMaybeDocument* _Nullable MemoryRemoteDocumentCache::Get( - const DocumentKey& key) { - auto found = docs_.find(key); - return found != docs_.end() ? found->second : nil; -} - -MaybeDocumentMap MemoryRemoteDocumentCache::GetAll(const DocumentKeySet& keys) { - MaybeDocumentMap results; - for (const DocumentKey& key : keys) { - // Make sure each key has a corresponding entry, which is null in case the - // document is not found. - // TODO(http://b/32275378): Don't conflate missing / deleted. - results = results.insert(key, Get(key)); - } - return results; -} - -DocumentMap MemoryRemoteDocumentCache::GetMatching(FSTQuery* query) { - HARD_ASSERT( - ![query isCollectionGroupQuery], - "CollectionGroup queries should be handled in LocalDocumentsView"); - - DocumentMap results; - - // Documents are ordered by key, so we can use a prefix scan to narrow down - // the documents we need to match the query against. - DocumentKey prefix{query.path.Append("")}; - for (auto it = docs_.lower_bound(prefix); it != docs_.end(); ++it) { - const DocumentKey& key = it->first; - if (!query.path.IsPrefixOf(key.path())) { - break; - } - FSTMaybeDocument* maybeDoc = it->second; - if (![maybeDoc isKindOfClass:[FSTDocument class]]) { - continue; - } - FSTDocument* doc = static_cast(maybeDoc); - if ([query matchesDocument:doc]) { - results = results.insert(key, doc); - } - } - return results; -} - -std::vector MemoryRemoteDocumentCache::RemoveOrphanedDocuments( - FSTMemoryLRUReferenceDelegate* reference_delegate, - ListenSequenceNumber upper_bound) { - std::vector removed; - MaybeDocumentMap updated_docs = docs_; - for (const auto& kv : docs_) { - const DocumentKey& key = kv.first; - if (![reference_delegate isPinnedAtSequenceNumber:upper_bound - document:key]) { - updated_docs = updated_docs.erase(key); - removed.push_back(key); - } - } - docs_ = updated_docs; - return removed; -} - -size_t MemoryRemoteDocumentCache::CalculateByteSize( - FSTLocalSerializer* serializer) { - size_t count = 0; - for (const auto& kv : docs_) { - count += DocumentKeyByteSize(kv.first); - count += [[serializer encodedMaybeDocument:kv.second] serializedSize]; - } - return count; -} - -} // namespace local -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_target_cache.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_target_cache.cc new file mode 100644 index 0000000..61284ad --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_target_cache.cc @@ -0,0 +1,141 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/memory_target_cache.h" + +#include + +#include "Firestore/core/src/firebase/firestore/local/memory_persistence.h" +#include "Firestore/core/src/firebase/firestore/local/reference_delegate.h" +#include "Firestore/core/src/firebase/firestore/local/sizer.h" +#include "Firestore/core/src/firebase/firestore/local/target_data.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" + +namespace firebase { +namespace firestore { +namespace local { + +using core::Target; +using model::DocumentKey; +using model::DocumentKeySet; +using model::ListenSequenceNumber; +using model::SnapshotVersion; +using model::TargetId; + +MemoryTargetCache::MemoryTargetCache(MemoryPersistence* persistence) + : persistence_(persistence), + highest_listen_sequence_number_(ListenSequenceNumber(0)), + highest_target_id_(TargetId(0)), + last_remote_snapshot_version_(SnapshotVersion::None()), + targets_() { +} + +void MemoryTargetCache::AddTarget(const TargetData& target_data) { + targets_[target_data.target()] = target_data; + if (target_data.target_id() > highest_target_id_) { + highest_target_id_ = target_data.target_id(); + } + if (target_data.sequence_number() > highest_listen_sequence_number_) { + highest_listen_sequence_number_ = target_data.sequence_number(); + } +} + +void MemoryTargetCache::UpdateTarget(const TargetData& target_data) { + // For the memory target cache, adds and updates are treated the same. + AddTarget(target_data); +} + +void MemoryTargetCache::RemoveTarget(const TargetData& target_data) { + targets_.erase(target_data.target()); + references_.RemoveReferences(target_data.target_id()); +} + +absl::optional MemoryTargetCache::GetTarget(const Target& target) { + auto iter = targets_.find(target); + return iter == targets_.end() ? absl::optional{} : iter->second; +} + +void MemoryTargetCache::EnumerateTargets(const TargetCallback& callback) { + for (const auto& kv : targets_) { + callback(kv.second); + } +} + +int MemoryTargetCache::RemoveTargets( + model::ListenSequenceNumber upper_bound, + const std::unordered_map& live_targets) { + std::vector to_remove; + for (const auto& kv : targets_) { + const Target& target = kv.first; + const TargetData& target_data = kv.second; + + if (target_data.sequence_number() <= upper_bound) { + if (live_targets.find(target_data.target_id()) == live_targets.end()) { + to_remove.push_back(&target); + references_.RemoveReferences(target_data.target_id()); + } + } + } + + for (const Target* element : to_remove) { + targets_.erase(*element); + } + return static_cast(to_remove.size()); +} + +void MemoryTargetCache::AddMatchingKeys(const DocumentKeySet& keys, + TargetId target_id) { + references_.AddReferences(keys, target_id); + for (const DocumentKey& key : keys) { + persistence_->reference_delegate()->AddReference(key); + } +} + +void MemoryTargetCache::RemoveMatchingKeys(const DocumentKeySet& keys, + TargetId target_id) { + references_.RemoveReferences(keys, target_id); + for (const DocumentKey& key : keys) { + persistence_->reference_delegate()->RemoveReference(key); + } +} + +DocumentKeySet MemoryTargetCache::GetMatchingKeys(TargetId target_id) { + return references_.ReferencedKeys(target_id); +} + +bool MemoryTargetCache::Contains(const DocumentKey& key) { + return references_.ContainsKey(key); +} + +int64_t MemoryTargetCache::CalculateByteSize(const Sizer& sizer) { + int64_t count = 0; + for (const auto& kv : targets_) { + count += sizer.CalculateByteSize(kv.second); + } + return count; +} + +const SnapshotVersion& MemoryTargetCache::GetLastRemoteSnapshotVersion() const { + return last_remote_snapshot_version_; +} + +void MemoryTargetCache::SetLastRemoteSnapshotVersion(SnapshotVersion version) { + last_remote_snapshot_version_ = std::move(version); +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_target_cache.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_target_cache.h new file mode 100644 index 0000000..8d7bd14 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/memory_target_cache.h @@ -0,0 +1,111 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_TARGET_CACHE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_TARGET_CACHE_H_ + +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/local/reference_set.h" +#include "Firestore/core/src/firebase/firestore/local/target_cache.h" +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" + +namespace firebase { +namespace firestore { +namespace local { + +class MemoryPersistence; +class Sizer; + +class MemoryTargetCache : public TargetCache { + public: + explicit MemoryTargetCache(MemoryPersistence* persistence); + + // Target-related methods + void AddTarget(const TargetData& target_data) override; + + void UpdateTarget(const TargetData& target_data) override; + + void RemoveTarget(const TargetData& target_data) override; + + absl::optional GetTarget(const core::Target& target) override; + + void EnumerateTargets(const TargetCallback& callback) override; + + int RemoveTargets(model::ListenSequenceNumber upper_bound, + const std::unordered_map& + live_targets) override; + + // Key-related methods + void AddMatchingKeys(const model::DocumentKeySet& keys, + model::TargetId target_id) override; + + void RemoveMatchingKeys(const model::DocumentKeySet& keys, + model::TargetId target_id) override; + + model::DocumentKeySet GetMatchingKeys(model::TargetId target_id) override; + + bool Contains(const model::DocumentKey& key) override; + + // Other methods and accessors + int64_t CalculateByteSize(const Sizer& sizer); + + size_t size() const override { + return targets_.size(); + } + + model::ListenSequenceNumber highest_listen_sequence_number() const override { + return highest_listen_sequence_number_; + } + + model::TargetId highest_target_id() const override { + return highest_target_id_; + } + + const model::SnapshotVersion& GetLastRemoteSnapshotVersion() const override; + + void SetLastRemoteSnapshotVersion(model::SnapshotVersion version) override; + + private: + // This instance is owned by MemoryPersistence. + MemoryPersistence* persistence_; + + /** The highest sequence number encountered */ + model::ListenSequenceNumber highest_listen_sequence_number_; + /** The highest numbered target ID encountered. */ + model::TargetId highest_target_id_; + /** The last received snapshot version. */ + model::SnapshotVersion last_remote_snapshot_version_; + + /** Maps a target to the data about that query. */ + std::unordered_map targets_; + + /** + * A ordered bidirectional mapping between documents and the remote target + * IDs. + */ + ReferenceSet references_; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_TARGET_CACHE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/mutation_queue.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/mutation_queue.h index 6977b73..f19b35c 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/mutation_queue.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/mutation_queue.h @@ -17,24 +17,16 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MUTATION_QUEUE_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MUTATION_QUEUE_H_ -#if !defined(__OBJC__) -#error "For now, this file must only be included by ObjC source files." -#endif // !defined(__OBJC__) - -#import - #include +#include "Firestore/core/include/firebase/firestore/timestamp.h" +#include "Firestore/core/src/firebase/firestore/core/query.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" #include "Firestore/core/src/firebase/firestore/model/types.h" - -@class FIRTimestamp; -@class FSTMutation; -@class FSTMutationBatch; -@class FSTQuery; - -NS_ASSUME_NONNULL_BEGIN +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" +#include "absl/types/optional.h" namespace firebase { namespace firestore { @@ -43,8 +35,7 @@ namespace local { /** A queue of mutations to apply to the remote store. */ class MutationQueue { public: - virtual ~MutationQueue() { - } + virtual ~MutationQueue() = default; /** * Starts the mutation queue, performing any initial reads that might be @@ -56,8 +47,8 @@ class MutationQueue { virtual bool IsEmpty() = 0; /** Acknowledges the given batch. */ - virtual void AcknowledgeBatch(FSTMutationBatch* batch, - NSData* _Nullable stream_token) = 0; + virtual void AcknowledgeBatch(const model::MutationBatch& batch, + const nanopb::ByteString& stream_token) = 0; /** * Creates a new mutation batch and adds it to this mutation queue. @@ -68,10 +59,10 @@ class MutationQueue { * overwrite values that are persisted in the remote document cache. * @param mutations The user-provided mutations in this mutation batch. */ - virtual FSTMutationBatch* AddMutationBatch( - FIRTimestamp* local_write_time, - std::vector&& base_mutations, - std::vector&& mutations) = 0; + virtual model::MutationBatch AddMutationBatch( + const Timestamp& local_write_time, + std::vector&& base_mutations, + std::vector&& mutations) = 0; /** * Removes the given mutation batch from the queue. This is useful in two @@ -80,12 +71,12 @@ class MutationQueue { * + Removing applied mutations from the head of the queue * + Removing rejected mutations from anywhere in the queue */ - virtual void RemoveMutationBatch(FSTMutationBatch* batch) = 0; + virtual void RemoveMutationBatch(const model::MutationBatch& batch) = 0; /** Gets all mutation batches in the mutation queue. */ // TODO(mikelehen): PERF: Current consumer only needs mutated keys; if we can // provide that cheaply, we should replace this. - virtual std::vector AllMutationBatches() = 0; + virtual std::vector AllMutationBatches() = 0; /** * Finds all mutation batches that could @em possibly affect the given @@ -98,7 +89,7 @@ class MutationQueue { * if it's convenient. */ // TODO(mcg): This should really return an iterator - virtual std::vector + virtual std::vector AllMutationBatchesAffectingDocumentKeys( const model::DocumentKeySet& document_keys) = 0; @@ -113,8 +104,8 @@ class MutationQueue { * convenient. */ // TODO(mcg): This should really return an iterator - virtual std::vector AllMutationBatchesAffectingDocumentKey( - const model::DocumentKey& key) = 0; + virtual std::vector + AllMutationBatchesAffectingDocumentKey(const model::DocumentKey& key) = 0; /** * Finds all mutation batches that could affect the results for the given @@ -125,31 +116,41 @@ class MutationQueue { * Note that because of this requirement implementations are free to return * mutation batches that don't match the query at all if it's convenient. * - * NOTE: A FSTPatchMutation does not need to include all fields in the query + * NOTE: A PatchMutation does not need to include all fields in the query * filter criteria in order to be a match (but any fields it does contain do * need to match). */ // TODO(mikelehen): This should perhaps return an iterator, though I'm not // sure we can avoid loading them all in memory. - virtual std::vector AllMutationBatchesAffectingQuery( - FSTQuery* query) = 0; + virtual std::vector AllMutationBatchesAffectingQuery( + const core::Query& query) = 0; /** Loads the mutation batch with the given batch_id. */ - virtual FSTMutationBatch* _Nullable LookupMutationBatch( + virtual absl::optional LookupMutationBatch( model::BatchId batch_id) = 0; /** - * Gets the first unacknowledged mutation batch after the passed in batchId in - * the mutation queue or nil if empty. + * Gets the first unacknowledged mutation batch after the passed in batch_id + * in the mutation queue or nil if empty. * * @param batch_id The batch to search after, or kBatchIdUnknown for the first * mutation in the queue. * * @return the next mutation or nil if there wasn't one. */ - virtual FSTMutationBatch* _Nullable NextMutationBatchAfterBatchId( + virtual absl::optional NextMutationBatchAfterBatchId( model::BatchId batch_id) = 0; + /** + * Gets the largest (latest) batch id in mutation queue for the current user + * that is pending server response, returns `kBatchIdUnknown` if the queue + * is empty. + * + * @return the largest batch id in the mutation queue that is not + * acknowledged. + */ + virtual model::BatchId GetHighestUnacknowledgedBatchId() = 0; + /** * Performs a consistency check, examining the mutation queue for any leaks, * if possible. @@ -157,16 +158,14 @@ class MutationQueue { virtual void PerformConsistencyCheck() = 0; /** Returns the current stream token for this mutation queue. */ - virtual NSData* _Nullable GetLastStreamToken() = 0; + virtual nanopb::ByteString GetLastStreamToken() = 0; /** Sets the stream token for this mutation queue. */ - virtual void SetLastStreamToken(NSData* _Nullable stream_token) = 0; + virtual void SetLastStreamToken(nanopb::ByteString stream_token) = 0; }; } // namespace local } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MUTATION_QUEUE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/persistence.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/persistence.h new file mode 100644 index 0000000..ad9af1c --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/persistence.h @@ -0,0 +1,162 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_PERSISTENCE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_PERSISTENCE_H_ + +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/types.h" +#include "absl/strings/string_view.h" + +namespace firebase { +namespace firestore { +namespace auth { + +class User; + +} // namespace auth + +namespace local { + +class IndexManager; +class MutationQueue; +class ReferenceDelegate; +class RemoteDocumentCache; +class TargetCache; + +/** + * Persistence is the lowest-level shared interface to data storage in + * Firestore. + * + * Persistence creates MutationQueue and RemoteDocumentCache instances backed + * by some underlying storage mechanism (which might be in-memory or LevelDB). + * + * Persistence also exposes an API to run transactions against the backing + * store. All read and write operations must be wrapped in a transaction. + * Implementations of Persistence only need to guarantee that writes made + * against the transaction are not made to durable storage until the transaction + * commits. Since memory-only storage components do not alter durable storage, + * they are free to ignore the transaction. + * + * This contract is enough to allow the LocalStore to be written independently + * of whether or not the stored state actually is durably persisted. If a user + * enables persistent storage, writes are grouped together to avoid inconsistent + * state that could cause crashes. + * + * Concretely, when persistent storage is enabled, the durable versions of + * MutationQueue, RemoteDocumentCache, and others (the mutators) will group + * their writes in a transaction. Once the local store has completed one logical + * operation, it commits the transaction. + * + * When persistent storage is disabled, the non-durable versions of the mutators + * ignore the transaction. This short-cut is allowed because memory-only storage + * leaves no state so it cannot be inconsistent. + * + * This simplifies the implementations of the mutators and allows memory-only + * implementations to supplement the durable ones without requiring any special + * dual-store implementation of Persistence. The cost is that LocalStore needs + * to be slightly careful about the order of its reads and writes in order to + * avoid relying on being able to read back uncommitted writes. + */ +class Persistence { + public: + virtual ~Persistence() = default; + + virtual model::ListenSequenceNumber current_sequence_number() const = 0; + + /** Releases any resources held during eager shutdown. */ + virtual void Shutdown() = 0; + + /** + * Returns a MutationQueue representing the persisted mutations for the given + * user. + * + * Note: The implementation is free to return the same instance every time + * this is called for a given user. In particular, the memory-backed + * implementation does this to emulate the persisted implementation to the + * extent possible (e.g. in the case of UID switching from sally=>jack=>sally, + * sally's mutation queue will be preserved). + */ + virtual MutationQueue* GetMutationQueueForUser(const auth::User& user) = 0; + + /** Returns a TargetCache representing the persisted cache of queries. */ + virtual TargetCache* target_cache() = 0; + + /** + * Returns a RemoteDocumentCache representing the persisted cache of remote + * documents. + */ + virtual RemoteDocumentCache* remote_document_cache() = 0; + + /** Returns an IndexManager that manages our persisted query indexes. */ + virtual IndexManager* index_manager() = 0; + + /** + * This property provides access to hooks around the document reference + * lifecycle. + */ + virtual ReferenceDelegate* reference_delegate() = 0; + + /** + * Accepts a function and runs it within a transaction. When called, a + * transaction will be started before a block is run, and committed after the + * block has executed. + * + * @param label A semi-unique name for the transaction, for logging. + * @param block A void-returning function to be executed within the + * transaction. + */ + template + auto Run(absl::string_view label, F block) -> + typename std::enable_if::value, + void>::type { + RunInternal(label, std::forward(block)); + } + + /** + * Accepts a function and runs it within a transaction. When called, a + * transaction will be started before a block is run, and committed after the + * block has executed. + * + * @param label A semi-unique name for the transaction, for logging. + * @param block A function to be executed within the transaction whose return + * value will be the result of the transaction. The type of the return + * value must be default constructible and copy- or move-assignable. + * @return The value returned from the invocation of `block`. + */ + template + auto Run(absl::string_view label, F block) -> + typename std::enable_if::value, + decltype(block())>::type { + decltype(block()) result; + + RunInternal(label, [&]() mutable { result = block(); }); + + return result; + } + + private: + virtual void RunInternal(absl::string_view label, + std::function block) = 0; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_PERSISTENCE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/proto_sizer.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/proto_sizer.cc new file mode 100644 index 0000000..357d64e --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/proto_sizer.cc @@ -0,0 +1,58 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/proto_sizer.h" + +#include + +#include "Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" +#include "Firestore/core/src/firebase/firestore/nanopb/message.h" + +namespace firebase { +namespace firestore { +namespace local { + +using model::DocumentKey; +using model::MaybeDocument; +using nanopb::ByteString; +using nanopb::Message; + +ProtoSizer::ProtoSizer(LocalSerializer serializer) + : serializer_(std::move(serializer)) { +} + +int64_t ProtoSizer::CalculateByteSize(const MaybeDocument& maybe_doc) const { + // TODO(varconst): implement a version of `nanopb::Writer` that only + // calculates sizes without actually doing the encoding (to the extent + // possible). This isn't high priority as long as `ProtoSizer` is only used in + // tests. + return MakeByteString(serializer_.EncodeMaybeDocument(maybe_doc)).size(); +} + +int64_t ProtoSizer::CalculateByteSize(const model::MutationBatch& batch) const { + return MakeByteString(serializer_.EncodeMutationBatch(batch)).size(); +} + +int64_t ProtoSizer::CalculateByteSize(const TargetData& target_data) const { + return MakeByteString(serializer_.EncodeTargetData(target_data)).size(); +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/proto_sizer.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/proto_sizer.h new file mode 100644 index 0000000..bcb42a4 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/proto_sizer.h @@ -0,0 +1,51 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_PROTO_SIZER_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_PROTO_SIZER_H_ + +#include "Firestore/core/src/firebase/firestore/local/local_serializer.h" +#include "Firestore/core/src/firebase/firestore/local/sizer.h" + +namespace firebase { +namespace firestore { +namespace local { + +/** + * Estimates the stored size of documents and queries by translating to protos + * and using the serialized sizes to estimate. + */ +class ProtoSizer : public Sizer { + public: + explicit ProtoSizer(LocalSerializer serializer); + + int64_t CalculateByteSize( + const model::MaybeDocument& maybe_doc) const override; + + int64_t CalculateByteSize( + const model::MutationBatch& mutation_batch) const override; + + int64_t CalculateByteSize(const TargetData& target_data) const override; + + private: + LocalSerializer serializer_; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_PROTO_SIZER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_cache.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_cache.h deleted file mode 100644 index 75240ce..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_cache.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_QUERY_CACHE_H_ -#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_QUERY_CACHE_H_ - -#if !defined(__OBJC__) -#error "For now, this file must only be included by ObjC source files." -#endif // !defined(__OBJC__) - -#import - -#include -#include - -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" - -@class FSTQuery; -@class FSTQueryData; - -NS_ASSUME_NONNULL_BEGIN - -namespace firebase { -namespace firestore { -namespace local { - -using OrphanedDocumentCallback = - std::function; - -using TargetCallback = std::function; - -/** - * Represents cached targets received from the remote backend. This contains - * both a mapping between targets and the documents that matched them according - * to the server, but also metadata about the targets. - * - * The cache is keyed by FSTQuery and entries in the cache are FSTQueryData - * instances. - */ -class QueryCache { - public: - virtual ~QueryCache() { - } - - // Target-related methods - - /** - * Adds an entry in the cache. - * - * The cache key is extracted from `queryData.query`. The key must not already - * exist in the cache. - * - * @param query_data A new FSTQueryData instance to put in the cache. - */ - virtual void AddTarget(FSTQueryData* query_data) = 0; - - /** - * Updates an entry in the cache. - * - * The cache key is extracted from `queryData.query`. The entry must already - * exist in the cache, and it will be replaced. - * @param query_data An FSTQueryData instance to replace an existing entry in - * the cache - */ - virtual void UpdateTarget(FSTQueryData* query_data) = 0; - - /** Removes the cached entry for the given query data. The entry must already - * exist in the cache. */ - virtual void RemoveTarget(FSTQueryData* query_data) = 0; - - /** - * Looks up an FSTQueryData entry in the cache. - * - * @param query The query corresponding to the entry to look up. - * @return The cached FSTQueryData entry, or nil if the cache has no entry for - * the query. - */ - virtual FSTQueryData* _Nullable GetTarget(FSTQuery* query) = 0; - - virtual void EnumerateTargets(const TargetCallback& callback) = 0; - - virtual int RemoveTargets( - model::ListenSequenceNumber upper_bound, - const std::unordered_map& - live_targets) = 0; - - // Key-related methods - virtual void AddMatchingKeys(const model::DocumentKeySet& keys, - model::TargetId target_id) = 0; - - virtual void RemoveMatchingKeys(const model::DocumentKeySet& keys, - model::TargetId target_id) = 0; - - virtual model::DocumentKeySet GetMatchingKeys(model::TargetId target_id) = 0; - - virtual bool Contains(const model::DocumentKey& key) = 0; - - // Accessors - - /** Returns the number of targets cached. */ - virtual size_t size() const = 0; - - /** - * Returns the highest listen sequence number of any query seen by the cache. - */ - virtual model::ListenSequenceNumber highest_listen_sequence_number() - const = 0; - - /** - * Returns the highest target ID of any query in the cache. Typically called - * during startup to seed a target ID generator and avoid collisions with - * existing queries. If there are no queries in the cache, returns zero. - */ - virtual model::TargetId highest_target_id() const = 0; - - /** - * A global snapshot version representing the last consistent snapshot we - * received from the backend. This is monotonically increasing and any - * snapshots received from the backend prior to this version (e.g. for targets - * resumed with a resume_token) should be suppressed (buffered) until the - * backend has caught up to this snapshot version again. This prevents our - * cache from ever going backwards in time. - * - * This is updated whenever our we get a TargetChange with a read_time and - * empty target_ids. - */ - virtual const model::SnapshotVersion& GetLastRemoteSnapshotVersion() - const = 0; - - /** - * Set the snapshot version representing the last consistent snapshot received - * from the backend. (see `GetLastRemoteSnapshotVersion()` for more details). - * - * @param version The new snapshot version. - */ - virtual void SetLastRemoteSnapshotVersion(model::SnapshotVersion version) = 0; -}; - -} // namespace local -} // namespace firestore -} // namespace firebase - -NS_ASSUME_NONNULL_END - -#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_QUERY_CACHE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_data.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_data.cc deleted file mode 100644 index 0dc6ac5..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_data.cc +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/local/query_data.h" - -#include - -namespace firebase { -namespace firestore { -namespace local { - -using core::Query; -using model::SnapshotVersion; - -QueryData::QueryData(Query&& query, - model::TargetId target_id, - model::ListenSequenceNumber sequence_number, - QueryPurpose purpose, - SnapshotVersion&& snapshot_version, - std::vector&& resume_token) - : query_(std::move(query)), - target_id_(target_id), - sequence_number_(sequence_number), - purpose_(purpose), - snapshot_version_(std::move(snapshot_version)), - resume_token_(std::move(resume_token)) { -} - -// TODO(rsgowman): Implement once WatchStream::EmptyResumeToken exists. -/* -QueryData::QueryData(const Query& query, int target_id, QueryPurpose purpose) - : QueryData(query, - target_id, - purpose, - model::SnapshotVersion::None(), - WatchStream::EmptyResumeToken()) { -} -*/ - -QueryData QueryData::Invalid() { - return QueryData(Query::Invalid(), /*target_id=*/-1, /*sequence_number=*/-1, - QueryPurpose::kListen, - SnapshotVersion(SnapshotVersion::None()), {}); -} - -QueryData QueryData::Copy(SnapshotVersion&& snapshot_version, - std::vector&& resume_token) const { - return QueryData(Query(query_), target_id_, sequence_number_, purpose_, - std::move(snapshot_version), std::move(resume_token)); -} - -} // namespace local -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_data.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_data.h deleted file mode 100644 index 0ec0883..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_data.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_QUERY_DATA_H_ -#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_QUERY_DATA_H_ - -#include -#include - -#include "Firestore/core/src/firebase/firestore/core/query.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" - -namespace firebase { -namespace firestore { -namespace local { - -/** An enumeration for the different purposes we have for queries. */ -enum class QueryPurpose { - /** A regular, normal query. */ - kListen, - - /** - * The query was used to refill a query after an existence filter mismatch. - */ - kExistenceFilterMismatch, - - /** The query was used to resolve a limbo document. */ - kLimboResolution, -}; - -/** - * An immutable set of metadata that the store will need to keep track of for - * each query. - */ -class QueryData { - public: - /** - * Creates a new QueryData with the given values. - * - * @param query The query being listened to. - * @param target_id The target to which the query corresponds, assigned by the - * LocalStore for user queries or the SyncEngine for limbo queries. - * @param purpose The purpose of the query. - * @param snapshot_version The latest snapshot version seen for this target. - * @param resume_token An opaque, server-assigned token that allows watching a - * query to be resumed after disconnecting without retransmitting all the - * data that matches the query. The resume token essentially identifies a - * point in time from which the server should resume sending results. - */ - QueryData(core::Query&& query, - model::TargetId target_id, - model::ListenSequenceNumber sequence_number, - QueryPurpose purpose, - model::SnapshotVersion&& snapshot_version, - std::vector&& resume_token); - - /** - * Convenience constructor for use when creating a QueryData for the first - * time. - */ - // TODO(rsgowman): Define once WatchStream::EmptyResumeToken exists. - // QueryData(const core::Query& query, int target_id, QueryPurpose purpose); - - /** - * Constructs an invalid QueryData. Reading any properties of the returned - * value is undefined. - */ - static QueryData Invalid(); - - const core::Query& query() const { - return query_; - } - - model::TargetId target_id() const { - return target_id_; - } - - model::ListenSequenceNumber sequence_number() const { - return sequence_number_; - } - - QueryPurpose purpose() const { - return purpose_; - } - - const model::SnapshotVersion& snapshot_version() const { - return snapshot_version_; - } - - const std::vector& resume_token() const { - return resume_token_; - } - - QueryData Copy(model::SnapshotVersion&& snapshot_version, - std::vector&& resume_token) const; - - private: - const core::Query query_; - model::TargetId target_id_; - model::ListenSequenceNumber sequence_number_; - QueryPurpose purpose_; - const model::SnapshotVersion snapshot_version_; - const std::vector resume_token_; -}; - -inline bool operator==(const QueryData& lhs, const QueryData& rhs) { - return lhs.query() == rhs.query() && lhs.target_id() == rhs.target_id() && - lhs.sequence_number() == rhs.sequence_number() && - lhs.purpose() == rhs.purpose() && - lhs.snapshot_version() == rhs.snapshot_version() && - lhs.resume_token() == rhs.resume_token(); -} - -inline bool operator!=(const QueryData& lhs, const QueryData& rhs) { - return !(lhs == rhs); -} - -} // namespace local -} // namespace firestore -} // namespace firebase - -#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_QUERY_DATA_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_engine.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_engine.h new file mode 100644 index 0000000..54a5376 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_engine.h @@ -0,0 +1,74 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_QUERY_ENGINE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_QUERY_ENGINE_H_ + +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" + +namespace firebase { +namespace firestore { + +namespace model { + +class DocumentMap; +class SnapshotVersion; + +} // namespace model + +namespace core { + +class Query; + +} // namespace core + +namespace local { + +class LocalDocumentsView; + +/** + * Represents a query engine capable of performing queries over the local + * document cache. You must call `SetLocalDocumentsView()` before using. + */ +class QueryEngine { + public: + enum Type { Simple, IndexFree }; + + virtual ~QueryEngine() = default; + + /** + * Sets the document view to query against. + * + * The caller owns the LocalDocumentView and must ensure that it outlives the + * QueryEngine. + */ + virtual void SetLocalDocumentsView(LocalDocumentsView* local_documents) = 0; + + /** Returns all local documents matching the specified query. */ + virtual model::DocumentMap GetDocumentsMatchingQuery( + const core::Query& query, + const model::SnapshotVersion& last_limbo_free_snapshot_version, + const model::DocumentKeySet& remote_keys) = 0; + + /** Returns the underlying algorithm used by the query engine. */ + virtual Type type() const = 0; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_QUERY_ENGINE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_result.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_result.h new file mode 100644 index 0000000..abb41fc --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/query_result.h @@ -0,0 +1,57 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_QUERY_RESULT_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_QUERY_RESULT_H_ + +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/document_map.h" + +namespace firebase { +namespace firestore { +namespace local { + +/** The result of executing a query against the local store. */ +class QueryResult { + public: + QueryResult() = default; + + /** Creates a new QueryResult with the given values. */ + QueryResult(model::DocumentMap documents, model::DocumentKeySet remote_keys) + : documents_{std::move(documents)}, remote_keys_{std::move(remote_keys)} { + } + + const model::DocumentMap& documents() const { + return documents_; + } + + const model::DocumentKeySet& remote_keys() const { + return remote_keys_; + } + + private: + model::DocumentMap documents_; + model::DocumentKeySet remote_keys_; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_QUERY_RESULT_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/reference_delegate.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/reference_delegate.h new file mode 100644 index 0000000..0f10f3c --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/reference_delegate.h @@ -0,0 +1,124 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_REFERENCE_DELEGATE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_REFERENCE_DELEGATE_H_ + +#include "Firestore/core/src/firebase/firestore/model/types.h" +#include "absl/strings/string_view.h" + +namespace firebase { +namespace firestore { +namespace model { + +class DocumentKey; + +} // namespace model + +namespace local { + +class ReferenceSet; +class TargetData; + +/** + * A ReferenceDelegate instance handles all of the hooks into the + * document-reference lifecycle. This includes being added to a target, being + * removed from a target, being subject to mutation, and being mutated by the + * user. + * + * Different implementations may do different things with each of these events. + * Not every implementation needs to do something with every lifecycle hook. + * + * Implementations that care about sequence numbers are responsible for + * generating them and making them available. + */ +class ReferenceDelegate { + public: + virtual ~ReferenceDelegate() = default; + + virtual model::ListenSequenceNumber current_sequence_number() const = 0; + + /** + * Registers a ReferenceSet of documents that should be considered + * 'referenced' and not eligible for removal during garbage collection. + */ + virtual void AddInMemoryPins(ReferenceSet* set) = 0; + + /** + * Notifies the delegate that the given document was added to a target. + */ + virtual void AddReference(const model::DocumentKey& key) = 0; + + /** + * Notifies the delegate that the given document was removed from a target. + */ + virtual void RemoveReference(const model::DocumentKey& key) = 0; + + /** + * Notifies the delegate that a document is no longer being mutated by the + * user. + */ + virtual void RemoveMutationReference(const model::DocumentKey& key) = 0; + + /** + * Notifies the delegate that a target was removed. + */ + virtual void RemoveTarget(const local::TargetData& target_data) = 0; + + /** + * Notifies the delegate that a limbo document was updated. + */ + virtual void UpdateLimboDocument(const model::DocumentKey& key) = 0; + + /** + * Lifecycle hook that notifies the delegate that a transaction has started. + */ + virtual void OnTransactionStarted(absl::string_view label) = 0; + + /** + * Lifecycle hook that notifies the delegate that a transaction has committed. + */ + virtual void OnTransactionCommitted() = 0; +}; + +/** + * Calls `OnTransactionStarted` in its constructor and then ensures that + * `OnTransactionCommitted` is called at the close of any block in which it is + * declared. + */ +struct TransactionGuard { + TransactionGuard(ReferenceDelegate* reference_delegate, + absl::string_view label) + : reference_delegate_(reference_delegate) { + reference_delegate_->OnTransactionStarted(label); + } + + ~TransactionGuard() { + reference_delegate_->OnTransactionCommitted(); + } + + TransactionGuard(const TransactionGuard&) = delete; + TransactionGuard& operator=(const TransactionGuard&) = delete; + + private: + ReferenceDelegate* reference_delegate_; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_REFERENCE_DELEGATE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/remote_document_cache.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/remote_document_cache.h index f1ff54c..5415ef5 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/remote_document_cache.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/remote_document_cache.h @@ -17,22 +17,12 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_REMOTE_DOCUMENT_CACHE_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_REMOTE_DOCUMENT_CACHE_H_ -#if !defined(__OBJC__) -#error "For now, this file must only be included by ObjC source files." -#endif // !defined(__OBJC__) - -#import - +#include "Firestore/core/src/firebase/firestore/core/query.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/document_map.h" #include "Firestore/core/src/firebase/firestore/model/types.h" -@class FSTMaybeDocument; -@class FSTQuery; - -NS_ASSUME_NONNULL_BEGIN - namespace firebase { namespace firestore { namespace local { @@ -40,10 +30,10 @@ namespace local { /** * Represents cached documents received from the remote backend. * - * The cache is keyed by DocumentKey and entries in the cache are - * FSTMaybeDocument instances, meaning we can cache both FSTDocument instances - * (an actual document with data) as well as FSTDeletedDocument instances - * (indicating that the document is known to not exist). + * The cache is keyed by DocumentKey and entries in the cache are MaybeDocument + * instances, meaning we can cache both Document instances (an actual document + * with data) as well as DeletedDocument instances (indicating that the document + * is known to not exist). */ class RemoteDocumentCache { public: @@ -56,9 +46,11 @@ class RemoteDocumentCache { * The cache key is extracted from `document.key`. If there is already a cache * entry for the key, it will be replaced. * - * @param document A FSTDocument or FSTDeletedDocument to put in the cache. + * @param document A Document or DeletedDocument to put in the cache. + * @param read_time The time at which the document was read or committed. */ - virtual void Add(FSTMaybeDocument* document) = 0; + virtual void Add(const model::MaybeDocument& document, + const model::SnapshotVersion& read_time) = 0; /** Removes the cached entry for the given key (no-op if no entry exists). */ virtual void Remove(const model::DocumentKey& key) = 0; @@ -67,10 +59,11 @@ class RemoteDocumentCache { * Looks up an entry in the cache. * * @param key The key of the entry to look up. - * @return The cached FSTDocument or FSTDeletedDocument entry, or nil if we + * @return The cached Document or DeletedDocument entry, or nullopt if we * have nothing cached. */ - virtual FSTMaybeDocument* _Nullable Get(const model::DocumentKey& key) = 0; + virtual absl::optional Get( + const model::DocumentKey& key) = 0; /** * Looks up a set of entries in the cache. @@ -79,26 +72,29 @@ class RemoteDocumentCache { * @return The cached Document or NoDocument entries indexed by key. If an * entry is not cached, the corresponding key will be mapped to a null value. */ - virtual model::MaybeDocumentMap GetAll(const model::DocumentKeySet& keys) = 0; + virtual model::OptionalMaybeDocumentMap GetAll( + const model::DocumentKeySet& keys) = 0; /** - * Executes a query against the cached FSTDocument entries + * Executes a query against the cached Document entries * * Implementations may return extra documents if convenient. The results * should be re-filtered by the consumer before presenting them to the user. * - * Cached FSTDeletedDocument entries have no bearing on query results. + * Cached DeletedDocument entries have no bearing on query results. * * @param query The query to match documents against. + * @param since_read_time If not set to SnapshotVersion::None(), return only + * documents that have been read since this snapshot version (exclusive). * @return The set of matching documents. */ - virtual model::DocumentMap GetMatching(FSTQuery* query) = 0; + virtual model::DocumentMap GetMatching( + const core::Query& query, + const model::SnapshotVersion& since_read_time) = 0; }; } // namespace local } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_REMOTE_DOCUMENT_CACHE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/simple_query_engine.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/simple_query_engine.cc new file mode 100644 index 0000000..b263fba --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/simple_query_engine.cc @@ -0,0 +1,42 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/simple_query_engine.h" + +#include "Firestore/core/src/firebase/firestore/core/query.h" +#include "Firestore/core/src/firebase/firestore/local/local_documents_view.h" +#include "Firestore/core/src/firebase/firestore/model/document_map.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" + +namespace firebase { +namespace firestore { +namespace local { + +using model::SnapshotVersion; + +model::DocumentMap SimpleQueryEngine::GetDocumentsMatchingQuery( + const core::Query& query, + const SnapshotVersion& last_limbo_free_snapshot_version, + const model::DocumentKeySet& remote_keys) { + HARD_ASSERT(local_documents_view_, "SetLocalDocumentsView() not called"); + + return local_documents_view_->GetDocumentsMatchingQuery( + query, SnapshotVersion::None()); +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/simple_query_engine.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/simple_query_engine.h new file mode 100644 index 0000000..ea741d0 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/simple_query_engine.h @@ -0,0 +1,49 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_SIMPLE_QUERY_ENGINE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_SIMPLE_QUERY_ENGINE_H_ + +#include "Firestore/core/src/firebase/firestore/local/query_engine.h" + +namespace firebase { +namespace firestore { +namespace local { + +class SimpleQueryEngine : public QueryEngine { + public: + void SetLocalDocumentsView(LocalDocumentsView* local_documents) override { + local_documents_view_ = local_documents; + } + + model::DocumentMap GetDocumentsMatchingQuery( + const core::Query& query, + const model::SnapshotVersion& last_limbo_free_snapshot_version, + const model::DocumentKeySet& remote_keys) override; + + Type type() const override { + return Type::Simple; + } + + private: + LocalDocumentsView* local_documents_view_; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_SIMPLE_QUERY_ENGINE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/sizer.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/sizer.h new file mode 100644 index 0000000..127d833 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/sizer.h @@ -0,0 +1,65 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_SIZER_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_SIZER_H_ + +#include + +namespace firebase { +namespace firestore { +namespace model { + +class MaybeDocument; +class MutationBatch; + +} // namespace model + +namespace local { + +class TargetData; + +/** + * Estimates the stored size of documents and queries. + */ +class Sizer { + public: + virtual ~Sizer() = default; + + /** + * Calculates the size of the given maybe_doc in bytes. Note that even + * NoDocuments have an associated size. + */ + virtual int64_t CalculateByteSize( + const model::MaybeDocument& maybe_doc) const = 0; + + /** + * Calculates the size of the given mutation_batch in bytes. + */ + virtual int64_t CalculateByteSize( + const model::MutationBatch& batch) const = 0; + + /** + * Calculates the size of the given target_data in bytes. + */ + virtual int64_t CalculateByteSize(const TargetData& target_data) const = 0; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_SIZER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/target_cache.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/target_cache.h new file mode 100644 index 0000000..daa0d7b --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/target_cache.h @@ -0,0 +1,150 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_TARGET_CACHE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_TARGET_CACHE_H_ + +#include +#include + +#include "Firestore/core/src/firebase/firestore/core/query.h" +#include "Firestore/core/src/firebase/firestore/local/target_data.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" + +namespace firebase { +namespace firestore { +namespace local { + +using OrphanedDocumentCallback = + std::function; + +using TargetCallback = std::function; + +/** + * Represents cached targets received from the remote backend. This contains + * both a mapping between targets and the documents that matched them according + * to the server, but also metadata about the targets. + * + * The cache is keyed by Target and entries in the cache are TargetData + * instances. + */ +class TargetCache { + public: + virtual ~TargetCache() { + } + + // Target-related methods + + /** + * Adds an entry in the cache. + * + * The cache key is extracted from `TargetData.target()`. The key must not + * already exist in the cache. + * + * @param target_data A new TargetData instance to put in the cache. + */ + virtual void AddTarget(const TargetData& target_data) = 0; + + /** + * Updates an entry in the cache. + * + * The cache key is extracted from `TargetData.target()`. The entry must + * already exist in the cache, and it will be replaced. + * + * @param target_data A TargetData instance to replace an existing entry in + * the cache + */ + virtual void UpdateTarget(const TargetData& target_data) = 0; + + /** Removes the cached entry for the given target data. The entry must already + * exist in the cache. */ + virtual void RemoveTarget(const TargetData& target_data) = 0; + + /** + * Looks up a TargetData entry in the cache. + * + * @param target The target corresponding to the entry to look up. + * @return The cached TargetData entry, or nullopt if the cache has no entry + * for the target. + */ + virtual absl::optional GetTarget(const core::Target& target) = 0; + + virtual void EnumerateTargets(const TargetCallback& callback) = 0; + + virtual int RemoveTargets( + model::ListenSequenceNumber upper_bound, + const std::unordered_map& live_targets) = 0; + + // Key-related methods + virtual void AddMatchingKeys(const model::DocumentKeySet& keys, + model::TargetId target_id) = 0; + + virtual void RemoveMatchingKeys(const model::DocumentKeySet& keys, + model::TargetId target_id) = 0; + + virtual model::DocumentKeySet GetMatchingKeys(model::TargetId target_id) = 0; + + virtual bool Contains(const model::DocumentKey& key) = 0; + + // Accessors + + /** Returns the number of targets cached. */ + virtual size_t size() const = 0; + + /** + * Returns the highest listen sequence number of any target seen by the cache. + */ + virtual model::ListenSequenceNumber highest_listen_sequence_number() + const = 0; + + /** + * Returns the highest target ID of any target in the cache. Typically called + * during startup to seed a target ID generator and avoid collisions with + * existing queries. If there are no targets in the cache, returns zero. + */ + virtual model::TargetId highest_target_id() const = 0; + + /** + * A global snapshot version representing the last consistent snapshot we + * received from the backend. This is monotonically increasing and any + * snapshots received from the backend prior to this version (e.g. for targets + * resumed with a resume_token) should be suppressed (buffered) until the + * backend has caught up to this snapshot version again. This prevents our + * cache from ever going backwards in time. + * + * This is updated whenever our we get a TargetChange with a read_time and + * empty target_ids. + */ + virtual const model::SnapshotVersion& GetLastRemoteSnapshotVersion() + const = 0; + + /** + * Set the snapshot version representing the last consistent snapshot received + * from the backend. (see `GetLastRemoteSnapshotVersion()` for more details). + * + * @param version The new snapshot version. + */ + virtual void SetLastRemoteSnapshotVersion(model::SnapshotVersion version) = 0; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_TARGET_CACHE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/target_data.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/target_data.cc new file mode 100644 index 0000000..3481f1b --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/target_data.cc @@ -0,0 +1,147 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/target_data.h" + +#include +#include +#include + +namespace firebase { +namespace firestore { +namespace local { + +using core::Target; +using model::ListenSequenceNumber; +using model::SnapshotVersion; +using model::TargetId; +using nanopb::ByteString; + +// MARK: - QueryPurpose + +namespace { + +const char* ToString(QueryPurpose purpose) { + switch (purpose) { + case QueryPurpose::Listen: + return "Listen"; + case QueryPurpose::ExistenceFilterMismatch: + return "ExistenceFilterMismatch"; + case QueryPurpose::LimboResolution: + return "LimboResolution"; + } + + UNREACHABLE(); +} + +} // namespace + +std::ostream& operator<<(std::ostream& os, QueryPurpose purpose) { + return os << ToString(purpose); +} + +// MARK: - TargetData + +TargetData::TargetData(Target target, + TargetId target_id, + ListenSequenceNumber sequence_number, + QueryPurpose purpose, + SnapshotVersion snapshot_version, + SnapshotVersion last_limbo_free_snapshot_version, + ByteString resume_token) + : target_(std::move(target)), + target_id_(target_id), + sequence_number_(sequence_number), + purpose_(purpose), + snapshot_version_(std::move(snapshot_version)), + last_limbo_free_snapshot_version_( + std::move(last_limbo_free_snapshot_version)), + resume_token_(std::move(resume_token)) { +} + +TargetData::TargetData(Target target, + int target_id, + ListenSequenceNumber sequence_number, + QueryPurpose purpose) + : TargetData(std::move(target), + target_id, + sequence_number, + purpose, + SnapshotVersion::None(), + SnapshotVersion::None(), + ByteString()) { +} + +TargetData TargetData::Invalid() { + return TargetData({}, /*target_id=*/-1, /*sequence_number=*/-1, + QueryPurpose::Listen, + SnapshotVersion(SnapshotVersion::None()), + SnapshotVersion(SnapshotVersion::None()), {}); +} + +TargetData TargetData::WithSequenceNumber( + ListenSequenceNumber sequence_number) const { + return TargetData(target_, target_id_, sequence_number, purpose_, + snapshot_version_, last_limbo_free_snapshot_version_, + resume_token_); +} + +TargetData TargetData::WithResumeToken(ByteString resume_token, + SnapshotVersion snapshot_version) const { + return TargetData(target_, target_id_, sequence_number_, purpose_, + std::move(snapshot_version), + last_limbo_free_snapshot_version_, std::move(resume_token)); +} + +TargetData TargetData::WithLastLimboFreeSnapshotVersion( + SnapshotVersion last_limbo_free_snapshot_version) const { + return TargetData(target_, target_id_, sequence_number_, purpose_, + snapshot_version_, + std::move(last_limbo_free_snapshot_version), resume_token_); +} + +bool operator==(const TargetData& lhs, const TargetData& rhs) { + return lhs.target() == rhs.target() && lhs.target_id() == rhs.target_id() && + lhs.sequence_number() == rhs.sequence_number() && + lhs.purpose() == rhs.purpose() && + lhs.snapshot_version() == rhs.snapshot_version() && + lhs.resume_token() == rhs.resume_token(); +} + +size_t TargetData::Hash() const { + return util::Hash(target_, target_id_, sequence_number_, purpose_, + snapshot_version_, resume_token_); +} + +std::string TargetData::ToString() const { + std::ostringstream ss; + ss << *this; + return ss.str(); +} + +std::ostream& operator<<(std::ostream& os, const TargetData& value) { + return os << "TargetData(target=" << value.target_ + << ", target_id=" << value.target_id_ + << ", purpose=" << value.purpose_ + << ", version=" << value.snapshot_version_ + << ", last_limbo_free_snapshot_version=" + << value.last_limbo_free_snapshot_version_ + << ", resume_token=" << value.resume_token_ << ")"; +} + +} // namespace local +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/target_data.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/target_data.h new file mode 100644 index 0000000..e3447f7 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/local/target_data.h @@ -0,0 +1,189 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_TARGET_DATA_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_TARGET_DATA_H_ + +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/core/target.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" + +namespace firebase { +namespace firestore { +namespace local { + +/** An enumeration for the different purposes we have for queries. */ +enum class QueryPurpose { + /** A regular, normal query. */ + Listen, + + /** + * The query was used to refill a query after an existence filter mismatch. + */ + ExistenceFilterMismatch, + + /** The query was used to resolve a limbo document. */ + LimboResolution, +}; + +std::ostream& operator<<(std::ostream& os, QueryPurpose purpose); + +/** + * An immutable set of metadata that the store will need to keep track of for + * each target. + */ +class TargetData { + public: + /** + * Creates a new TargetData with the given values. + * + * @param target The target being listened to. + * @param target_id The target to which the query corresponds, assigned by the + * LocalStore for user queries or the SyncEngine for limbo queries. + * @param purpose The purpose of the query. + * @param snapshot_version The latest snapshot version seen for this target. + * @param last_limbo_free_snapshot_version The maximum snapshot version at + * which the associated target view contained no limbo documents. + * @param resume_token An opaque, server-assigned token that allows watching a + * target to be resumed after disconnecting without retransmitting all the + * data that matches the query. The resume token essentially identifies a + * point in time from which the server should resume sending results. + */ + TargetData(core::Target target, + model::TargetId target_id, + model::ListenSequenceNumber sequence_number, + QueryPurpose purpose, + model::SnapshotVersion snapshot_version, + model::SnapshotVersion last_limbo_free_snapshot_version, + nanopb::ByteString resume_token); + + /** + * Convenience constructor for use when creating a TargetData for the first + * time. + */ + TargetData(const core::Target target, + int target_id, + model::ListenSequenceNumber sequence_number, + QueryPurpose purpose); + + /** + * Creates an invalid TargetData. Prefer TargetData::Invalid() for + * readability. + */ + TargetData() = default; + + /** + * Constructs an invalid TargetData. Reading any properties of the returned + * value is undefined. + */ + static TargetData Invalid(); + + /** The target being listened to. */ + const core::Target& target() const { + return target_; + } + + /** + * The TargetId to which the target corresponds, assigned by the LocalStore + * for user queries or the SyncEngine for limbo queries. + */ + model::TargetId target_id() const { + return target_id_; + } + + model::ListenSequenceNumber sequence_number() const { + return sequence_number_; + } + + /** The purpose of the target. */ + QueryPurpose purpose() const { + return purpose_; + } + + /** The latest snapshot version seen for this target. */ + const model::SnapshotVersion& snapshot_version() const { + return snapshot_version_; + } + + /** + * Returns the last snapshot version for which the associated view contained + * no limbo documents. + */ + const model::SnapshotVersion& last_limbo_free_snapshot_version() const { + return last_limbo_free_snapshot_version_; + } + + /** + * An opaque, server-assigned token that allows watching a query to be resumed + * after disconnecting without retransmitting all the data that matches the + * query. The resume token essentially identifies a point in time from which + * the server should resume sending results. + */ + const nanopb::ByteString& resume_token() const { + return resume_token_; + } + + /** Creates a new target data instance with an updated sequence number. */ + TargetData WithSequenceNumber( + model::ListenSequenceNumber sequence_number) const; + + /** + * Creates a new target data instance with an updated resume token and + * snapshot version. + */ + TargetData WithResumeToken(nanopb::ByteString resume_token, + model::SnapshotVersion snapshot_version) const; + + /** + * Creates a new target data instance with an updated last limbo free snapshot + * version. + */ + TargetData WithLastLimboFreeSnapshotVersion( + model::SnapshotVersion last_limbo_free_snapshot_version) const; + + friend bool operator==(const TargetData& lhs, const TargetData& rhs); + + size_t Hash() const; + + std::string ToString() const; + + friend std::ostream& operator<<(std::ostream& os, const TargetData& value); + + private: + core::Target target_; + model::TargetId target_id_ = 0; + model::ListenSequenceNumber sequence_number_ = 0; + QueryPurpose purpose_ = QueryPurpose::Listen; + model::SnapshotVersion snapshot_version_; + model::SnapshotVersion last_limbo_free_snapshot_version_; + nanopb::ByteString resume_token_; +}; + +inline bool operator!=(const TargetData& lhs, const TargetData& rhs) { + return !(lhs == rhs); +} + +} // namespace local +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_TARGET_DATA_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/base_path.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/base_path.h index 31aaebb..9a7e83f 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/base_path.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/base_path.h @@ -24,6 +24,7 @@ #include #include +#include "Firestore/core/src/firebase/firestore/util/comparison.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/hashing.h" @@ -149,23 +150,16 @@ class BasePath { std::equal(begin(), end(), potential_child.begin()); } - bool operator==(const BasePath& rhs) const { - return segments_ == rhs.segments_; + util::ComparisonResult CompareTo(const T& rhs) const { + return util::CompareContainer(segments_, rhs.segments_); } - bool operator!=(const BasePath& rhs) const { - return segments_ != rhs.segments_; - } - bool operator<(const BasePath& rhs) const { - return segments_ < rhs.segments_; - } - bool operator>(const BasePath& rhs) const { - return segments_ > rhs.segments_; - } - bool operator<=(const BasePath& rhs) const { - return segments_ <= rhs.segments_; + + friend bool operator==(const BasePath& lhs, const BasePath& rhs) { + return lhs.segments_ == rhs.segments_; } - bool operator>=(const BasePath& rhs) const { - return segments_ >= rhs.segments_; + + size_t Hash() const { + return util::Hash(segments_); } protected: diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/database_id.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/database_id.cc index 9fe7bb3..efec02e 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/database_id.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/database_id.cc @@ -16,9 +16,10 @@ #include "Firestore/core/src/firebase/firestore/model/database_id.h" -#include +#include #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/hashing.h" namespace firebase { namespace firestore { @@ -26,10 +27,31 @@ namespace model { constexpr const char* DatabaseId::kDefault; -DatabaseId::DatabaseId(std::string project_id, std::string database_id) - : project_id_{std::move(project_id)}, database_id_{std::move(database_id)} { - HARD_ASSERT(!project_id_.empty()); - HARD_ASSERT(!database_id_.empty()); +DatabaseId::DatabaseId(std::string project_id, std::string database_id) { + HARD_ASSERT(!project_id.empty()); + HARD_ASSERT(!database_id.empty()); + + rep_ = std::make_shared(std::move(project_id), std::move(database_id)); +} + +util::ComparisonResult DatabaseId::CompareTo( + const firebase::firestore::model::DatabaseId& rhs) const { + util::ComparisonResult cmp = util::Compare(project_id(), rhs.project_id()); + if (!util::Same(cmp)) return cmp; + + return util::Compare(database_id(), rhs.database_id()); +} + +std::string DatabaseId::ToString() const { + return absl::StrCat("DatabaseId(", project_id(), ":", database_id(), ")"); +} + +std::ostream& operator<<(std::ostream& out, const DatabaseId& database_id) { + return out << database_id.ToString(); +} + +size_t DatabaseId::Hash() const { + return util::Hash(project_id(), database_id()); } } // namespace model diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/database_id.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/database_id.h index c7f66d1..6787f91 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/database_id.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/database_id.h @@ -17,27 +17,25 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DATABASE_ID_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DATABASE_ID_H_ -#include +#include +#include #include +#include -#include "Firestore/core/src/firebase/firestore/util/hashing.h" -#include "absl/strings/string_view.h" +#include "Firestore/core/src/firebase/firestore/util/comparison.h" namespace firebase { namespace firestore { namespace model { /** A DatabaseId represents a particular database in the Firestore. */ -class DatabaseId { +class DatabaseId : public util::Comparable { public: /** The default name for "unset" database ID in resource names. */ static constexpr const char* kDefault = "(default)"; -#if defined(__OBJC__) - // For objective-c++ initialization; to be removed after migration. - // Do NOT use in C++ code. + // TODO(wilhuff): Remove this after FieldValue rewrite. DatabaseId() = default; -#endif // defined(__OBJC__) /** * Creates and returns a new DatabaseId. @@ -45,63 +43,45 @@ class DatabaseId { * @param project_id The project for the database. * @param database_id The database in the project to use. */ - DatabaseId(std::string project_id, std::string database_id); + explicit DatabaseId(std::string project_id, + std::string database_id = kDefault); const std::string& project_id() const { - return project_id_; + return rep_->project_id; } const std::string& database_id() const { - return database_id_; + return rep_->database_id; } /** Whether this is the default database of the project. */ bool IsDefaultDatabase() const { - return database_id_ == kDefault; + return rep_->database_id == kDefault; } -#if defined(__OBJC__) - // For objective-c++ hash; to be removed after migration. - // Do NOT use in C++ code. - size_t Hash() const { - return util::Hash(project_id_, database_id_); - } -#endif // defined(__OBJC__) + util::ComparisonResult CompareTo(const DatabaseId& rhs) const; + + std::string ToString() const; + friend std::ostream& operator<<(std::ostream& out, + const DatabaseId& database_id); - friend bool operator<(const DatabaseId& lhs, const DatabaseId& rhs); + size_t Hash() const; private: - std::string project_id_; - std::string database_id_; + // DocumentIds are copied into every ReferenceValue we create so hide the + // actual values behind a shared_ptr to make copying cheaper. + struct Rep { + Rep(std::string&& project_id, std::string&& database_id) + : project_id{std::move(project_id)}, + database_id{std::move(database_id)} { + } + std::string project_id; + std::string database_id; + }; + + std::shared_ptr rep_; }; -/** Compares against another DatabaseId. */ -inline bool operator<(const DatabaseId& lhs, const DatabaseId& rhs) { - return lhs.project_id_ < rhs.project_id_ || - (lhs.project_id_ == rhs.project_id_ && - lhs.database_id_ < rhs.database_id_); -} - -inline bool operator>(const DatabaseId& lhs, const DatabaseId& rhs) { - return rhs < lhs; -} - -inline bool operator>=(const DatabaseId& lhs, const DatabaseId& rhs) { - return !(lhs < rhs); -} - -inline bool operator<=(const DatabaseId& lhs, const DatabaseId& rhs) { - return !(lhs > rhs); -} - -inline bool operator!=(const DatabaseId& lhs, const DatabaseId& rhs) { - return lhs < rhs || lhs > rhs; -} - -inline bool operator==(const DatabaseId& lhs, const DatabaseId& rhs) { - return !(lhs != rhs); -} - } // namespace model } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/delete_mutation.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/delete_mutation.cc new file mode 100644 index 0000000..2a167bb --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/delete_mutation.cc @@ -0,0 +1,83 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/model/delete_mutation.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/document.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/model/no_document.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" + +namespace firebase { +namespace firestore { +namespace model { + +static_assert( + sizeof(Mutation) == sizeof(DeleteMutation), + "DeleteMutation may not have additional members (everything goes in Rep)"); + +DeleteMutation::DeleteMutation(DocumentKey key, Precondition precondition) + : Mutation(std::make_shared(std::move(key), std::move(precondition))) { +} + +DeleteMutation::DeleteMutation(const Mutation& mutation) : Mutation(mutation) { + HARD_ASSERT(type() == Type::Delete); +} + +MaybeDocument DeleteMutation::Rep::ApplyToRemoteDocument( + const absl::optional& maybe_doc, + const MutationResult& mutation_result) const { + VerifyKeyMatches(maybe_doc); + + HARD_ASSERT(mutation_result.transform_results() == absl::nullopt, + "Transform results received by DeleteMutation."); + + // Unlike ApplyToLocalView, if we're applying a mutation to a remote document + // the server has accepted the mutation so the precondition must have held. + + // We store the deleted document at the commit version of the delete. Any + // document version that the server sends us before the delete was applied is + // discarded. + return NoDocument(key(), mutation_result.version(), + /* has_committed_mutations= */ true); +} + +absl::optional DeleteMutation::Rep::ApplyToLocalView( + const absl::optional& maybe_doc, + const absl::optional&, + const Timestamp&) const { + VerifyKeyMatches(maybe_doc); + + if (!precondition().IsValidFor(maybe_doc)) { + return maybe_doc; + } + + return NoDocument(key(), SnapshotVersion::None(), + /* has_committed_mutations= */ false); +} + +std::string DeleteMutation::Rep::ToString() const { + return absl::StrCat("DeleteMutation(key=", key().ToString(), + ", precondition=", precondition().ToString(), ")"); +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/delete_mutation.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/delete_mutation.h new file mode 100644 index 0000000..a3b5c8e --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/delete_mutation.h @@ -0,0 +1,79 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DELETE_MUTATION_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DELETE_MUTATION_H_ + +#include +#include +#include +#include + +#include "Firestore/core/include/firebase/firestore/timestamp.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" +#include "Firestore/core/src/firebase/firestore/model/mutation.h" +#include "Firestore/core/src/firebase/firestore/model/precondition.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace model { + +/** Represents a Delete operation. */ +class DeleteMutation : public Mutation { + public: + DeleteMutation(DocumentKey key, Precondition precondition); + + /** + * Casts a Mutation to a DeleteMutation. This is a checked operation that will + * assert if the type of the Mutation isn't actually Type::Delete. + */ + explicit DeleteMutation(const Mutation& mutation); + + /** Creates an invalid DeleteMutation instance. */ + DeleteMutation() = default; + + private: + class Rep : public Mutation::Rep { + public: + using Mutation::Rep::Rep; + + Type type() const override { + return Type::Delete; + } + + MaybeDocument ApplyToRemoteDocument( + const absl::optional& maybe_doc, + const MutationResult& mutation_result) const override; + + absl::optional ApplyToLocalView( + const absl::optional& maybe_doc, + const absl::optional&, + const Timestamp&) const override; + + // Does not override Equals or Hash; Mutation's versions are sufficient. + + std::string ToString() const override; + }; +}; + +} // namespace model +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DELETE_MUTATION_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document.cc index da540c8..cafc4f0 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document.cc @@ -16,6 +16,8 @@ #include "Firestore/core/src/firebase/firestore/model/document.h" +#include +#include #include #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" @@ -24,24 +26,148 @@ namespace firebase { namespace firestore { namespace model { -Document::Document(ObjectValue&& data, +static_assert( + sizeof(MaybeDocument) == sizeof(Document), + "Document may not have additional members (everything goes in Rep)"); + +class Document::Rep : public MaybeDocument::Rep { + public: + Rep(ObjectValue&& data, + DocumentKey&& key, + SnapshotVersion version, + DocumentState document_state) + : MaybeDocument::Rep(Type::Document, std::move(key), version), + data_(std::move(data)), + document_state_(document_state) { + } + + Rep(ObjectValue&& data, + DocumentKey&& key, + SnapshotVersion version, + DocumentState document_state, + absl::any proto) + : Rep(std::move(data), std::move(key), version, document_state) { + proto_ = std::move(proto); + } + + const ObjectValue& data() const { + return data_; + } + + DocumentState document_state() const { + return document_state_; + } + + bool has_local_mutations() const { + return document_state_ == DocumentState::kLocalMutations; + } + + bool has_committed_mutations() const { + return document_state_ == DocumentState::kCommittedMutations; + } + + bool has_pending_writes() const override { + return has_local_mutations() || has_committed_mutations(); + } + + bool Equals(const MaybeDocument::Rep& other) const override { + if (!MaybeDocument::Rep::Equals(other)) return false; + + const auto& other_rep = static_cast(other); + return document_state_ == other_rep.document_state_ && + data_ == other_rep.data_; + } + + size_t Hash() const override { + return util::Hash(MaybeDocument::Rep::Hash(), data_, document_state_); + } + + std::string ToString() const override { + return absl::StrCat( + "Document(key=", key().ToString(), ", version=", version().ToString(), + ", document_state=", document_state_, ", data=", data_.ToString(), ")"); + } + + private: + friend class Document; + + ObjectValue data_; + DocumentState document_state_; + absl::any proto_; +}; + +Document::Document(ObjectValue data, DocumentKey key, SnapshotVersion version, DocumentState document_state) - : MaybeDocument(std::move(key), std::move(version)), - data_(std::move(data)), - document_state_(document_state) { - set_type(Type::Document); + : MaybeDocument(std::make_shared( + std::move(data), std::move(key), version, document_state)) { } -bool Document::Equals(const MaybeDocument& other) const { - if (other.type() != Type::Document) { - return false; +Document::Document(ObjectValue data, + DocumentKey key, + SnapshotVersion version, + DocumentState document_state, + absl::any proto) + : MaybeDocument(std::make_shared(std::move(data), + std::move(key), + version, + document_state, + std::move(proto))) { +} + +Document::Document(const MaybeDocument& document) : MaybeDocument(document) { + HARD_ASSERT(type() == Type::Document); +} + +const ObjectValue& Document::data() const { + return doc_rep().data(); +} + +absl::optional Document::field(const FieldPath& path) const { + return data().Get(path); +} + +DocumentState Document::document_state() const { + return doc_rep().document_state_; +} + +bool Document::has_local_mutations() const { + return doc_rep().has_local_mutations(); +} + +bool Document::has_committed_mutations() const { + return doc_rep().has_committed_mutations(); +} + +const absl::any& Document::proto() const { + return doc_rep().proto_; +} + +const Document::Rep& Document::doc_rep() const { + return static_cast(MaybeDocument::rep()); +} + +std::ostream& operator<<(std::ostream& os, DocumentState state) { + switch (state) { + case DocumentState::kCommittedMutations: + return os << "kCommittedMutations"; + case DocumentState::kLocalMutations: + return os << "kLocalMutations"; + case DocumentState::kSynced: + return os << "kLocalSynced"; } - auto& other_doc = static_cast(other); - return MaybeDocument::Equals(other) && - document_state_ == other_doc.document_state_ && - data_ == other_doc.data_; + + UNREACHABLE(); +} + +std::ostream& operator<<(std::ostream& os, const Document& doc) { + return os << doc.doc_rep().ToString(); +} + +/** Compares against another Document. */ +bool operator==(const Document& lhs, const Document& rhs) { + return lhs.doc_rep().Equals(rhs.doc_rep()); } } // namespace model diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document.h index acd0421..6f62812 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document.h @@ -17,15 +17,25 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DOCUMENT_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DOCUMENT_H_ +#include +#include +#include + #include "Firestore/core/src/firebase/firestore/model/field_path.h" #include "Firestore/core/src/firebase/firestore/model/field_value.h" #include "Firestore/core/src/firebase/firestore/model/maybe_document.h" +#include "absl/types/any.h" #include "absl/types/optional.h" namespace firebase { namespace firestore { +namespace remote { +class Serializer; +} // namespace remote + namespace model { +/** Describes the `has_pending_writes` state of a document. */ enum class DocumentState { /** * Local mutations applied via the mutation queue. Document is potentially @@ -43,54 +53,62 @@ enum class DocumentState { kSynced, }; +std::ostream& operator<<(std::ostream& os, DocumentState state); + /** * Represents a document in Firestore with a key, version, data and whether the * data has local mutations applied to it. */ class Document : public MaybeDocument { public: - /** - * Construct a document. ObjectValue must be passed by rvalue. - */ - Document(ObjectValue&& data, + Document(ObjectValue data, DocumentKey key, SnapshotVersion version, DocumentState document_state); - const ObjectValue& data() const { - return data_; - } + private: + // TODO(b/146372592): Make this public once we can use Abseil across + // iOS/public C++ library boundaries. + friend class remote::Serializer; + + Document(ObjectValue data, + DocumentKey key, + SnapshotVersion version, + DocumentState document_state, + absl::any proto); + + public: + /** + * Casts a MaybeDocument to a Document. This is a checked operation that will + * assert if the type of the MaybeDocument isn't actually Type::Document. + */ + explicit Document(const MaybeDocument& document); + + /** Creates an invalid Document instance. */ + Document() = default; + + const ObjectValue& data() const; - absl::optional field(const FieldPath& path) const { - return data_.Get(path); - } + absl::optional field(const FieldPath& path) const; - bool HasLocalMutations() const { - return document_state_ == DocumentState::kLocalMutations; - } + DocumentState document_state() const; - bool HasCommittedMutations() const { - return document_state_ == DocumentState::kCommittedMutations; - } + bool has_local_mutations() const; - bool HasPendingWrites() const override { - return HasLocalMutations() || HasCommittedMutations(); - } + bool has_committed_mutations() const; - protected: - bool Equals(const MaybeDocument& other) const override; + const absl::any& proto() const; + + /** Compares against another Document. */ + friend bool operator==(const Document& lhs, const Document& rhs); + + friend std::ostream& operator<<(std::ostream& os, const Document& doc); private: - ObjectValue data_; - DocumentState document_state_; -}; + class Rep; -/** Compares against another Document. */ -inline bool operator==(const Document& lhs, const Document& rhs) { - return lhs.version() == rhs.version() && lhs.key() == rhs.key() && - lhs.HasLocalMutations() == rhs.HasLocalMutations() && - lhs.data() == rhs.data(); -} + const Rep& doc_rep() const; +}; inline bool operator!=(const Document& lhs, const Document& rhs) { return !(lhs == rhs); diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_key.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_key.cc index 7dae412..a400502 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_key.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_key.cc @@ -16,6 +16,7 @@ #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include #include #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" @@ -48,6 +49,18 @@ const DocumentKey& DocumentKey::Empty() { return empty; } +util::ComparisonResult DocumentKey::CompareTo(const DocumentKey& other) const { + return path().CompareTo(other.path()); +} + +std::string DocumentKey::ToString() const { + return path().CanonicalString(); +} + +std::ostream& operator<<(std::ostream& os, const DocumentKey& key) { + return os << key.ToString(); +} + } // namespace model } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_key.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_key.h index 2443e26..a139a21 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_key.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_key.h @@ -19,13 +19,10 @@ #include #include +#include #include #include -#if defined(__OBJC__) -#import "Firestore/Source/Model/FSTDocumentKey.h" -#endif // defined(__OBJC__) - #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/util/comparison.h" #include "Firestore/core/src/firebase/firestore/util/hashing.h" @@ -38,7 +35,7 @@ namespace model { /** * DocumentKey represents the location of a document in the Firestore database. */ -class DocumentKey { +class DocumentKey : public util::InequalityComparable { public: /** Creates a "blank" document key not associated with any document. */ DocumentKey() : path_{std::make_shared()} { @@ -50,22 +47,12 @@ class DocumentKey { /** Creates a new document key, taking ownership of the given path. */ explicit DocumentKey(ResourcePath&& path); -#if defined(__OBJC__) - NSUInteger Hash() const { - return util::Hash(ToString()); - } -#endif // defined(__OBJC__) - - std::string ToString() const { - return path().CanonicalString(); - } - /** * Creates and returns a new document key using '/' to split the string into * segments. */ - static DocumentKey FromPathString(absl::string_view path) { - return DocumentKey{ResourcePath::FromString(path)}; + static DocumentKey FromPathString(const std::string& path) { + return DocumentKey{ResourcePath::FromStringView(path)}; } /** Creates and returns a new document key with the given segments. */ @@ -81,13 +68,27 @@ class DocumentKey { return path.size() % 2 == 0; } + util::ComparisonResult CompareTo(const DocumentKey& other) const; + + friend bool operator==(const DocumentKey& lhs, const DocumentKey& rhs) { + return lhs.path() == rhs.path(); + } + + size_t Hash() const { + return util::Hash(ToString()); + } + + std::string ToString() const; + + friend std::ostream& operator<<(std::ostream& os, const DocumentKey& key); + /** The path to the document. */ const ResourcePath& path() const { return path_ ? *path_ : Empty().path(); } - /** Returns true if the document is in the specified collectionId. */ - bool HasCollectionId(absl::string_view collection_id) const { + /** Returns true if the document is in the specified collection_id. */ + bool HasCollectionId(const std::string& collection_id) const { size_t size = path().size(); return size >= 2 && path()[size - 2] == collection_id; } @@ -98,53 +99,13 @@ class DocumentKey { std::shared_ptr path_; }; -inline bool operator==(const DocumentKey& lhs, const DocumentKey& rhs) { - return lhs.path() == rhs.path(); -} -inline bool operator!=(const DocumentKey& lhs, const DocumentKey& rhs) { - return lhs.path() != rhs.path(); -} -inline bool operator<(const DocumentKey& lhs, const DocumentKey& rhs) { - return lhs.path() < rhs.path(); -} -inline bool operator<=(const DocumentKey& lhs, const DocumentKey& rhs) { - return lhs.path() <= rhs.path(); -} -inline bool operator>(const DocumentKey& lhs, const DocumentKey& rhs) { - return lhs.path() > rhs.path(); -} -inline bool operator>=(const DocumentKey& lhs, const DocumentKey& rhs) { - return lhs.path() >= rhs.path(); -} - struct DocumentKeyHash { size_t operator()(const DocumentKey& key) const { return util::Hash(key.path()); } }; -#if defined(__OBJC__) -inline NSComparisonResult CompareKeys(const DocumentKey& lhs, - const DocumentKey& rhs) { - if (lhs < rhs) { - return NSOrderedAscending; - } - if (lhs > rhs) { - return NSOrderedDescending; - } - return NSOrderedSame; -} - -#endif // defined(__OBJC__) - } // namespace model - -namespace util { - -template <> -struct Comparator : public std::less {}; - -} // namespace util } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_map.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_map.cc new file mode 100644 index 0000000..0cc2334 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_map.cc @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/model/document_map.h" + +namespace firebase { +namespace firestore { +namespace model { + +ABSL_MUST_USE_RESULT DocumentMap +DocumentMap::insert(const DocumentKey& key, const Document& value) const { + return DocumentMap{map_.insert(key, value)}; +} + +ABSL_MUST_USE_RESULT DocumentMap +DocumentMap::erase(const DocumentKey& key) const { + return DocumentMap{map_.erase(key)}; +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_map.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_map.h index 59ae69f..3c4edfd 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_map.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_map.h @@ -19,12 +19,12 @@ #include -#import "Firestore/Source/Model/FSTDocument.h" - #include "Firestore/core/src/firebase/firestore/immutable/sorted_map.h" +#include "Firestore/core/src/firebase/firestore/model/document.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" - +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" #include "absl/base/attributes.h" +#include "absl/types/optional.h" namespace firebase { namespace firestore { @@ -34,7 +34,10 @@ namespace model { * Convenience type for a map of keys to MaybeDocuments, since they are so * common. */ -using MaybeDocumentMap = immutable::SortedMap; +using MaybeDocumentMap = immutable::SortedMap; + +using OptionalMaybeDocumentMap = + immutable::SortedMap>; /** * Convenience type for a map of keys to Documents, since they are so common. @@ -44,27 +47,22 @@ using MaybeDocumentMap = immutable::SortedMap; * alias similar to `MaybeDocumentMap`, it couldn't be passed to functions * expecting `MaybeDocumentMap`. * - * To work around this, in C++ `DocumentMap` is a simple wrapper over - * a `MaybeDocumentMap` that forwards all functions to the underlying map but - * with added type safety (it only accepts `FSTDocument`s, not - * `FSTMaybeDocument`s). Use `DocumentMap` in functions creating and/or - * returning maps that only contain `FSTDocument`s; when the `DocumentMap` needs - * to be passed to a function accepting a `MaybeDocumentMap`, use - * `underlying_map` function to get (read-only) access to the representation. - * Also use `underlying_map` for iterating and searching. + * To work around this, in C++ `DocumentMap` is a simple wrapper over a + * `MaybeDocumentMap` that forwards all functions to the underlying map but with + * added type safety (it only accepts `Document`, not `MaybeDocument`). Use + * `DocumentMap` in functions creating and/or returning maps that only contain + * `Document`; when the `DocumentMap` needs to be passed to a function accepting + * a `MaybeDocumentMap`, use `underlying_map` function to get (read-only) access + * to the representation. Also use `underlying_map` for iterating and searching. */ class DocumentMap { public: DocumentMap() = default; ABSL_MUST_USE_RESULT DocumentMap insert(const DocumentKey& key, - FSTDocument* value) const { - return DocumentMap{map_.insert(key, value)}; - } + const Document& value) const; - ABSL_MUST_USE_RESULT DocumentMap erase(const DocumentKey& key) const { - return DocumentMap{map_.erase(key)}; - } + ABSL_MUST_USE_RESULT DocumentMap erase(const DocumentKey& key) const; bool empty() const { return map_.empty(); @@ -85,17 +83,6 @@ class DocumentMap { MaybeDocumentMap map_; }; -inline FSTDocument* GetFSTDocumentOrNil(FSTMaybeDocument* maybeDoc) { - if ([maybeDoc isKindOfClass:[FSTDocument class]]) { - return static_cast(maybeDoc); - } - return nil; -} - -inline FSTDocument* GetFSTDocumentOrNil(FSTDocument* doc) { - return doc; -} - } // namespace model } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_set.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_set.cc new file mode 100644 index 0000000..ebe734e --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_set.cc @@ -0,0 +1,123 @@ +/* + * Copyright 2017 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/model/document_set.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/immutable/sorted_set.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "Firestore/core/src/firebase/firestore/util/to_string.h" +#include "absl/algorithm/container.h" + +namespace firebase { +namespace firestore { +namespace model { +namespace { + +using immutable::SortedSet; + +inline absl::optional none() { + return absl::optional{}; +} + +} // namespace + +DocumentComparator DocumentComparator::ByKey() { + return DocumentComparator([](const Document& lhs, const Document& rhs) { + return util::Compare(lhs.key(), rhs.key()); + }); +} + +DocumentSet::DocumentSet(DocumentComparator&& comparator) + : index_{}, sorted_set_{std::move(comparator)} { +} + +bool operator==(const DocumentSet& lhs, const DocumentSet& rhs) { + return absl::c_equal(lhs.sorted_set_, rhs.sorted_set_); +} + +std::string DocumentSet::ToString() const { + return util::ToString(sorted_set_); +} + +std::ostream& operator<<(std::ostream& os, const DocumentSet& set) { + return os << set.ToString(); +} + +size_t DocumentSet::Hash() const { + return util::Hash(sorted_set_); +} + +bool DocumentSet::ContainsKey(const DocumentKey& key) const { + return index_.underlying_map().find(key) != index_.underlying_map().end(); +} + +absl::optional DocumentSet::GetDocument( + const DocumentKey& key) const { + auto found = index_.underlying_map().find(key); + return found != index_.underlying_map().end() ? Document(found->second) + : none(); +} + +absl::optional DocumentSet::GetFirstDocument() const { + auto result = sorted_set_.min(); + return result != sorted_set_.end() ? *result : none(); +} + +absl::optional DocumentSet::GetLastDocument() const { + auto result = sorted_set_.max(); + return result != sorted_set_.end() ? *result : none(); +} + +size_t DocumentSet::IndexOf(const DocumentKey& key) const { + absl::optional doc = GetDocument(key); + return doc ? sorted_set_.find_index(*doc) : npos; +} + +DocumentSet DocumentSet::insert( + const absl::optional& document) const { + // TODO(mcg): look into making document non-optional. + if (!document) { + return *this; + } + + // Remove any prior mapping of the document's key before adding, preventing + // the sorted_set_ from accumulating values that aren't in the index. + const DocumentKey& key = document->key(); + DocumentSet removed = erase(key); + + DocumentMap index = removed.index_.insert(key, *document); + SetType set = removed.sorted_set_.insert(*document); + return {std::move(index), std::move(set)}; +} + +DocumentSet DocumentSet::erase(const DocumentKey& key) const { + absl::optional doc = GetDocument(key); + if (!doc) { + return *this; + } + + DocumentMap index = index_.erase(key); + SetType set = sorted_set_.erase(*doc); + return {std::move(index), std::move(set)}; +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_set.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_set.h index 003f105..fd9b224 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_set.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_set.h @@ -17,12 +17,6 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DOCUMENT_SET_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DOCUMENT_SET_H_ -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import - #include #include #include @@ -30,34 +24,25 @@ #include "Firestore/core/src/firebase/firestore/immutable/sorted_container.h" #include "Firestore/core/src/firebase/firestore/immutable/sorted_set.h" +#include "Firestore/core/src/firebase/firestore/model/document.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_map.h" #include "Firestore/core/src/firebase/firestore/util/comparison.h" -@class FSTDocument; - -NS_ASSUME_NONNULL_BEGIN - namespace firebase { namespace firestore { namespace model { -/** - * A C++ comparator that returns less-than, implemented by delegating to - * an NSComparator. - */ -class DocumentSetComparator { +class DocumentComparator : public util::FunctionComparator { public: - explicit DocumentSetComparator(NSComparator delegate = nil) - : delegate_(delegate) { - } + using FunctionComparator::FunctionComparator; - bool operator()(FSTDocument* lhs, FSTDocument* rhs) const { - return delegate_(lhs, rhs) == NSOrderedAscending; - } + static DocumentComparator ByKey(); - private: - NSComparator delegate_; + // TODO(wilhuff): Remove this using statement + // This exists to put these two overloads on equal footing. Once the overload + // below is gone, this using statement can be removed as well. + using FunctionComparator::Compare; }; /** @@ -66,24 +51,23 @@ class DocumentSetComparator { * comparator on top of what is provided to guarantee document equality based on * the key. */ -class DocumentSet : public immutable::SortedContainer, - public util::Equatable { +class DocumentSet : public immutable::SortedContainer { public: /** * The type of the main collection of documents in an DocumentSet. * @see sorted_set_. */ - using SetType = immutable::SortedSet; + using SetType = immutable::SortedSet; // STL container types - using value_type = FSTDocument*; + using value_type = Document; using const_iterator = SetType::const_iterator; /** * Creates a new, empty DocumentSet sorted by the given comparator, then by * keys. */ - explicit DocumentSet(NSComparator comparator); + explicit DocumentSet(DocumentComparator&& comparator); size_t size() const { return index_.size(); @@ -97,6 +81,10 @@ class DocumentSet : public immutable::SortedContainer, /** Returns true if this set contains a document with the given key. */ bool ContainsKey(const DocumentKey& key) const; + const DocumentComparator& comparator() const { + return sorted_set_.comparator(); + } + SetType::const_iterator begin() const { return sorted_set_.begin(); } @@ -108,19 +96,19 @@ class DocumentSet : public immutable::SortedContainer, * Returns the document from this set with the given key if it exists or nil * if it doesn't. */ - FSTDocument* _Nullable GetDocument(const DocumentKey& key) const; + absl::optional GetDocument(const DocumentKey& key) const; /** * Returns the first document in the set according to its built in ordering, * or nil if the set is empty. */ - FSTDocument* _Nullable GetFirstDocument() const; + absl::optional GetFirstDocument() const; /** * Returns the last document in the set according to its built in ordering, or * nil if the set is empty. */ - FSTDocument* _Nullable GetLastDocument() const; + absl::optional GetLastDocument() const; /** * Returns the index of the document with the provided key in the document @@ -129,7 +117,7 @@ class DocumentSet : public immutable::SortedContainer, size_t IndexOf(const DocumentKey& key) const; /** Returns a new DocumentSet that contains the given document. */ - DocumentSet insert(FSTDocument* _Nullable document) const; + DocumentSet insert(const absl::optional& document) const; /** * Returns a new DocumentSet that excludes any document associated with @@ -165,10 +153,12 @@ class DocumentSet : public immutable::SortedContainer, SetType sorted_set_; }; +inline bool operator!=(const DocumentSet& lhs, const DocumentSet& rhs) { + return !(lhs == rhs); +} + } // namespace model } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_DOCUMENT_SET_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_set.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_set.mm deleted file mode 100644 index 47cb3d2..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/document_set.mm +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2017 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/model/document_set.h" - -#include -#include - -#import "Firestore/Source/Model/FSTDocument.h" - -#include "Firestore/core/src/firebase/firestore/immutable/sorted_set.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/util/objc_compatibility.h" -#include "absl/algorithm/container.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace firebase { -namespace firestore { -namespace model { - -namespace objc = util::objc; -using immutable::SortedSet; - -DocumentSet::DocumentSet(NSComparator comparator) - : index_{}, sorted_set_{DocumentSetComparator{comparator}} { -} - -bool operator==(const DocumentSet& lhs, const DocumentSet& rhs) { - return absl::c_equal(lhs.sorted_set_, rhs.sorted_set_, - [](FSTDocument* left_doc, FSTDocument* right_doc) { - return [left_doc isEqual:right_doc]; - }); -} - -std::string DocumentSet::ToString() const { - return util::ToString(sorted_set_); -} - -std::ostream& operator<<(std::ostream& os, const DocumentSet& set) { - return os << set.ToString(); -} - -size_t DocumentSet::Hash() const { - size_t hash = 0; - for (FSTDocument* doc : sorted_set_) { - hash = 31 * hash + [doc hash]; - } - return hash; -} - -bool DocumentSet::ContainsKey(const DocumentKey& key) const { - return index_.underlying_map().find(key) != index_.underlying_map().end(); -} - -FSTDocument* _Nullable DocumentSet::GetDocument(const DocumentKey& key) const { - auto found = index_.underlying_map().find(key); - return found != index_.underlying_map().end() - ? static_cast(found->second) - : nil; -} - -FSTDocument* _Nullable DocumentSet::GetFirstDocument() const { - auto result = sorted_set_.min(); - return result != sorted_set_.end() ? *result : nil; -} - -FSTDocument* _Nullable DocumentSet::GetLastDocument() const { - auto result = sorted_set_.max(); - return result != sorted_set_.end() ? *result : nil; -} - -size_t DocumentSet::IndexOf(const DocumentKey& key) const { - FSTDocument* doc = GetDocument(key); - return doc ? sorted_set_.find_index(doc) : npos; -} - -DocumentSet DocumentSet::insert(FSTDocument* _Nullable document) const { - // TODO(mcg): look into making document nonnull. - if (!document) { - return *this; - } - - // Remove any prior mapping of the document's key before adding, preventing - // sortedSet from accumulating values that aren't in the index. - DocumentSet removed = erase(document.key); - - DocumentMap index = removed.index_.insert(document.key, document); - SetType set = removed.sorted_set_.insert(document); - return {std::move(index), std::move(set)}; -} - -DocumentSet DocumentSet::erase(const DocumentKey& key) const { - FSTDocument* doc = GetDocument(key); - if (!doc) { - return *this; - } - - DocumentMap index = index_.erase(key); - SetType set = sorted_set_.erase(doc); - return {std::move(index), std::move(set)}; -} - -} // namespace model -} // namespace firestore -} // namespace firebase - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_mask.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_mask.cc new file mode 100644 index 0000000..2c8c2ca --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_mask.cc @@ -0,0 +1,52 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/model/field_mask.h" + +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/util/hashing.h" + +namespace firebase { +namespace firestore { +namespace model { + +bool FieldMask::covers(const FieldPath& field_path) const { + for (const FieldPath& field_mask_path : fields_) { + if (field_mask_path.IsPrefixOf(field_path)) { + return true; + } + } + + return false; +} + +std::string FieldMask::ToString() const { + // Ideally, one should use a string builder. Since this is only non-critical + // code for logging and debugging, the logic is kept simple here. + std::string result("{ "); + for (const FieldPath& field : fields_) { + result += field.CanonicalString() + " "; + } + return result + "}"; +} + +size_t FieldMask::Hash() const { + return util::Hash(fields_); +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_mask.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_mask.h index d8cdfba..4d31cf0 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_mask.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_mask.h @@ -23,12 +23,13 @@ #include #include "Firestore/core/src/firebase/firestore/model/field_path.h" -#include "Firestore/core/src/firebase/firestore/util/hashing.h" namespace firebase { namespace firestore { namespace model { +class ObjectValue; + /** * Provides a set of fields that can be used to partially patch a document. * FieldMask is used in conjunction with FieldValue of Object type. @@ -43,6 +44,8 @@ class FieldMask { public: using const_iterator = std::set::const_iterator; + FieldMask() = default; + FieldMask(std::initializer_list list) : fields_{list} { } template @@ -66,39 +69,16 @@ class FieldMask { } /** - * Verifies that `fieldPath` is included by at least one field in this field + * Verifies that `field_path` is included by at least one field in this field * mask. * * This is an O(n) operation, where `n` is the size of the field mask. */ - bool covers(const FieldPath& fieldPath) const { - for (const FieldPath& fieldMaskPath : fields_) { - if (fieldMaskPath.IsPrefixOf(fieldPath)) { - return true; - } - } - - return false; - } + bool covers(const FieldPath& field_path) const; - std::string ToString() const { - // Ideally, one should use a string builder. Since this is only non-critical - // code for logging and debugging, the logic is kept simple here. - std::string result("{ "); - for (const FieldPath& field : fields_) { - result += field.CanonicalString() + " "; - } - return result + "}"; - } + std::string ToString() const; -#if defined(__OBJC__) - FieldMask() { - } - - NSUInteger Hash() const { - return util::Hash(fields_); - } -#endif + size_t Hash() const; friend bool operator==(const FieldMask& lhs, const FieldMask& rhs); diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_path.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_path.cc index b1dcad7..e00ae76 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_path.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_path.cc @@ -19,6 +19,7 @@ #include #include +#include "Firestore/core/src/firebase/firestore/util/exception.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "absl/strings/str_join.h" #include "absl/strings/str_replace.h" @@ -28,6 +29,8 @@ namespace firebase { namespace firestore { namespace model { +using util::ThrowInvalidArgument; + namespace { /** @@ -78,7 +81,39 @@ struct JoinEscaped { }; } // namespace -FieldPath FieldPath::FromServerFormat(const absl::string_view path) { +constexpr const char* FieldPath::kDocumentKeyPath; + +FieldPath FieldPath::FromDotSeparatedString(const std::string& path) { + return FromDotSeparatedStringView(path); +} + +FieldPath FieldPath::FromDotSeparatedStringView(absl::string_view path) { + if (path.find_first_of("~*/[]") != absl::string_view::npos) { + ThrowInvalidArgument( + "Invalid field path (%s). Paths must not contain '~', '*', '/', '[', " + "or ']'", + path); + } + + SegmentsT segments = + absl::StrSplit(path, '.', [path](absl::string_view segment) { + if (segment.empty()) { + ThrowInvalidArgument( + "Invalid field path (%s). Paths must not be empty, begin with " + "'.', end with '.', or contain '..'", + path); + } + return true; + }); + + return FieldPath(std::move(segments)); +} + +FieldPath FieldPath::FromServerFormat(const std::string& path) { + return FromServerFormatView(path); +} + +FieldPath FieldPath::FromServerFormatView(absl::string_view path) { SegmentsT segments; std::string segment; segment.reserve(path.size()); @@ -156,6 +191,20 @@ std::string FieldPath::CanonicalString() const { return absl::StrJoin(begin(), end(), ".", JoinEscaped()); } +void FieldPath::ValidateSegments(const SegmentsT& segments) { + if (segments.empty()) { + ThrowInvalidArgument( + "Invalid field path. Provided names must not be empty."); + } + + for (size_t i = 0; i < segments.size(); i++) { + if (segments[i].empty()) { + ThrowInvalidArgument( + "Invalid field name at index %s. Field names must not be empty.", i); + } + } +} + } // namespace model } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_path.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_path.h index ce3527d..4c2c606 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_path.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_path.h @@ -26,6 +26,10 @@ namespace firebase { namespace firestore { +namespace remote { +class Serializer; +} + namespace model { /** @@ -33,7 +37,8 @@ namespace model { * * Immutable; all instances are fully independent. */ -class FieldPath : public impl::BasePath { +class FieldPath : public impl::BasePath, + public util::Comparable { public: /** The field path string that represents the document's key. */ static constexpr const char* kDocumentKeyPath = "__name__"; @@ -51,40 +56,59 @@ class FieldPath : public impl::BasePath { explicit FieldPath(SegmentsT&& segments) : BasePath{std::move(segments)} { } + /** + * Creates and returns a new path from a dot-separated field-path string, + * where path segments are separated by a dot ".". + * + * PORTING NOTE: We define this on the model class to avoid having a tiny + * api::FieldPath wrapper class. + */ + static FieldPath FromDotSeparatedString(const std::string& path); + + private: + // TODO(b/146372592): Make this public once we can use Abseil across + // iOS/public C++ library boundaries. + friend class remote::Serializer; + + static FieldPath FromDotSeparatedStringView(absl::string_view path); + + public: + /** + * Creates and returns a new path from a set of segments received from the + * public API. + */ + static FieldPath FromSegments(SegmentsT&& segments) { + ValidateSegments(segments); + FieldPath path(std::move(segments)); + return path; + } + /** * Creates and returns a new path from the server formatted field-path string, * where path segments are separated by a dot "." and optionally encoded using * backticks. */ - static FieldPath FromServerFormat(absl::string_view path); + static FieldPath FromServerFormat(const std::string& path); + + private: + // TODO(b/146372592): Make this public once we can use Abseil across + // iOS/public C++ library boundaries. + static FieldPath FromServerFormatView(absl::string_view path); + + public: /** Returns a field path that represents an empty path. */ static const FieldPath& EmptyPath(); /** Returns a field path that represents a document key. */ static const FieldPath& KeyFieldPath(); - /** Returns a standardized string representation of this path. */ - std::string CanonicalString() const; /** True if this FieldPath represents a document key. */ bool IsKeyFieldPath() const; - bool operator==(const FieldPath& rhs) const { - return BasePath::operator==(rhs); - } - bool operator!=(const FieldPath& rhs) const { - return BasePath::operator!=(rhs); - } - bool operator<(const FieldPath& rhs) const { - return BasePath::operator<(rhs); - } - bool operator>(const FieldPath& rhs) const { - return BasePath::operator>(rhs); - } - bool operator<=(const FieldPath& rhs) const { - return BasePath::operator<=(rhs); - } - bool operator>=(const FieldPath& rhs) const { - return BasePath::operator>=(rhs); - } + /** Returns a standardized string representation of this path. */ + std::string CanonicalString() const; + + private: + static void ValidateSegments(const SegmentsT& segments); }; } // namespace model diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_transform.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_transform.cc new file mode 100644 index 0000000..b05566b --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_transform.cc @@ -0,0 +1,50 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/model/field_transform.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/transform_operation.h" +#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "absl/strings/str_cat.h" + +namespace firebase { +namespace firestore { +namespace model { + +FieldTransform::FieldTransform(FieldPath path, + TransformOperation transformation) noexcept + : path_{std::move(path)}, transformation_{std::move(transformation)} { +} + +bool FieldTransform::operator==(const FieldTransform& other) const { + return path_ == other.path_ && transformation_ == other.transformation_; +} + +size_t FieldTransform::Hash() const { + return util::Hash(path_, transformation_); +} + +std::string FieldTransform::ToString() const { + return absl::StrCat("FieldTransform(path=", path_.CanonicalString(), + "transformation=", transformation_.ToString(), ")"); +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_transform.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_transform.h index 4591802..8f19e11 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_transform.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_transform.h @@ -17,12 +17,10 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_TRANSFORM_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_TRANSFORM_H_ -#include -#include +#include #include "Firestore/core/src/firebase/firestore/model/field_path.h" -#include "Firestore/core/src/firebase/firestore/model/transform_operations.h" -#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "Firestore/core/src/firebase/firestore/model/transform_operation.h" namespace firebase { namespace firestore { @@ -31,39 +29,25 @@ namespace model { /** A field path and the TransformOperation to perform upon it. */ class FieldTransform { public: - FieldTransform(FieldPath path, - std::unique_ptr transformation) noexcept - : path_{std::move(path)}, transformation_{std::move(transformation)} { - } + FieldTransform(FieldPath path, TransformOperation transformation) noexcept; const FieldPath& path() const { return path_; } const TransformOperation& transformation() const { - return *transformation_.get(); + return transformation_; } - bool idempotent() const { - return transformation_->idempotent(); - } + bool operator==(const FieldTransform& other) const; - bool operator==(const FieldTransform& other) const { - return path_ == other.path_ && *transformation_ == *other.transformation_; - } + size_t Hash() const; -#if defined(__OBJC__) - // For Objective-C++ hash; to be removed after migration. - // Do NOT use in C++ code. - NSUInteger Hash() const { - return util::Hash(path_, transformation_->Hash()); - } -#endif // defined(__OBJC__) + std::string ToString() const; private: FieldPath path_; - // Shared by copies of the same FieldTransform. - std::shared_ptr transformation_; + TransformOperation transformation_; }; } // namespace model diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_value.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_value.cc index fee1045..8ecc82b 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_value.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_value.cc @@ -18,117 +18,500 @@ #include #include +#include #include #include +#include #include #include #include "Firestore/core/src/firebase/firestore/immutable/sorted_map.h" +#include "Firestore/core/src/firebase/firestore/model/field_mask.h" +#include "Firestore/core/src/firebase/firestore/timestamp_internal.h" #include "Firestore/core/src/firebase/firestore/util/comparison.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "Firestore/core/src/firebase/firestore/util/to_string.h" +#include "absl/algorithm/container.h" +#include "absl/base/casts.h" #include "absl/memory/memory.h" - -using firebase::firestore::util::Comparator; +#include "absl/strings/escaping.h" namespace firebase { namespace firestore { namespace model { +namespace { + +using BaseValue = FieldValue::BaseValue; +using Reference = FieldValue::Reference; +using ServerTimestamp = FieldValue::ServerTimestamp; using Type = FieldValue::Type; -using firebase::firestore::util::ComparisonResult; -FieldValue::FieldValue(const FieldValue& value) { - *this = value; +using nanopb::ByteString; +using util::Compare; +using util::CompareContainer; +using util::ComparisonResult; + +template +const T& Cast(const BaseValue& rep) { + return static_cast(rep); } -FieldValue::FieldValue(FieldValue&& value) { - *this = std::move(value); +class NullValue : public FieldValue::BaseValue { + public: + Type type() const override { + return Type::Null; + } + + std::string ToString() const override { + return util::ToString(nullptr); + } + + bool Equals(const BaseValue& other) const override { + if (type() != other.type()) return false; + + // NullValue is the only instance of itself + return true; + } + + ComparisonResult CompareTo(const BaseValue& other) const override { + ComparisonResult cmp = CompareTypes(other); + if (!util::Same(cmp)) return cmp; + + // Null is only comparable with itself and is defined to be the same. + return ComparisonResult::Same; + } + + size_t Hash() const override { + // std::hash is not defined for nullptr_t. + return util::Hash(static_cast(nullptr)); + } +}; + +/** + * A base class for implementing a "simple" field value type. Simple field + * values: + * + * * Are only comparable with values of their own type + * * Can be implemented by delegating to standard utilities, e.g. ToString() + * by calling util::ToString. + */ +template +class SimpleFieldValue : public FieldValue::BaseValue { + public: + explicit SimpleFieldValue(ValueType value) : value_(std::move(value)) { + } + + Type type() const override { + return type_enum; + } + + std::string ToString() const override { + return util::ToString(value_); + } + + bool Equals(const BaseValue& other) const override { + if (type() != other.type()) return false; + + auto& other_value = Cast(other); + return value_ == other_value.value(); + } + + ComparisonResult CompareTo(const BaseValue& other) const override { + ComparisonResult cmp = CompareTypes(other); + if (!util::Same(cmp)) return cmp; + + auto& other_value = Cast(other); + return Compare(value_, other_value.value()); + } + + size_t Hash() const override { + return util::Hash(value_); + } + + const ValueType& value() const { + return value_; + } + + private: + ValueType value_; +}; + +class BooleanValue : public SimpleFieldValue { + public: + using SimpleFieldValue::SimpleFieldValue; +}; + +template +class NumberValue : public SimpleFieldValue { + public: + using SimpleFieldValue::SimpleFieldValue; + + ComparisonResult CompareTo(const BaseValue& other) const override; +}; + +class IntegerValue : public NumberValue { + public: + using NumberValue::NumberValue; +}; + +int64_t Integer(const BaseValue& rep) { + return Cast(rep).value(); } -FieldValue::~FieldValue() { - SwitchTo(Type::Null); +class DoubleValue : public NumberValue { + public: + using NumberValue::NumberValue; + + bool Equals(const BaseValue& other) const override { + if (type() != other.type()) return false; + + auto& other_value = Cast(other); + return util::DoubleBitwiseEquals(value(), other_value.value()); + } + + size_t Hash() const override { + return util::DoubleBitwiseHash(value()); + } +}; + +double Double(const BaseValue& rep) { + return Cast(rep).value(); } -FieldValue& FieldValue::operator=(const FieldValue& value) { - SwitchTo(value.tag_); - switch (tag_) { - case Type::Null: - break; - case Type::Boolean: - boolean_value_ = value.boolean_value_; - break; - case Type::Integer: - integer_value_ = value.integer_value_; - break; - case Type::Double: - double_value_ = value.double_value_; - break; - case Type::Timestamp: - *timestamp_value_ = *value.timestamp_value_; - break; - case Type::ServerTimestamp: - *server_timestamp_value_ = *value.server_timestamp_value_; - break; - case Type::String: - *string_value_ = *value.string_value_; - break; - case Type::Blob: { - // copy-and-swap - std::vector tmp = *value.blob_value_; - std::swap(*blob_value_, tmp); - break; - } - case Type::Reference: - *reference_value_ = *value.reference_value_; - break; - case Type::GeoPoint: - *geo_point_value_ = *value.geo_point_value_; - break; - case Type::Array: { - // copy-and-swap - std::vector tmp = *value.array_value_; - std::swap(*array_value_, tmp); - break; +template +ComparisonResult NumberValue::CompareTo( + const BaseValue& other) const { + ComparisonResult cmp = this->CompareTypes(other); + if (!util::Same(cmp)) return cmp; + + Type this_type = this->type(); + Type other_type = other.type(); + + if (this_type == other_type) { + if (this_type == Type::Integer) { + return Compare(Integer(*this), Integer(other)); + } else { + return Compare(Double(*this), Double(other)); } - case Type::Object: { - // copy-and-swap - Map tmp = *value.object_value_; - std::swap(*object_value_, tmp); - break; + + } else { + if (this_type == Type::Integer) { + // CompareMixedNumber only takes (double, int64_t) so reverse the argument + // order and then reverse the result. + return util::ReverseOrder( + util::CompareMixedNumber(Double(other), Integer(*this))); + } else { + return util::CompareMixedNumber(Double(*this), Integer(other)); } - default: - HARD_FAIL("Unsupported type %s", value.type()); } - return *this; } -FieldValue& FieldValue::operator=(FieldValue&& value) { - switch (value.tag_) { - case Type::String: - SwitchTo(Type::String); - string_value_->swap(*value.string_value_); - return *this; - case Type::Blob: - SwitchTo(Type::Blob); - std::swap(blob_value_, value.blob_value_); - return *this; - case Type::Reference: - SwitchTo(Type::Reference); - std::swap(reference_value_, value.reference_value_); - return *this; - case Type::Array: - SwitchTo(Type::Array); - std::swap(array_value_, value.array_value_); - return *this; - case Type::Object: - SwitchTo(Type::Object); - std::swap(object_value_, value.object_value_); - return *this; - default: - // We just copy over POD union types. - *this = value; - return *this; +// TODO(wilhuff): Use SimpleFieldValue as a base once we migrate to absl::Hash. +// +// This can't extend SimpleFieldValue because `util::Hash` is undefined for +// Timestamp (and you can't override a compile-time error in a base class out +// of existence). absl::Hash allows us to implement hashing in a way that +// requires no public declaration of conformance. +class TimestampValue : public BaseValue { + public: + explicit TimestampValue(Timestamp value) : value_(value) { } + + Type type() const override { + return Type::Timestamp; + } + + std::string ToString() const override { + return util::ToString(value_); + } + + bool Equals(const BaseValue& other) const override { + if (type() != other.type()) return false; + + auto& other_value = Cast(other); + return value_ == other_value.value_; + } + + ComparisonResult CompareTo(const BaseValue& other) const override { + ComparisonResult cmp = CompareTypes(other); + if (!util::Same(cmp)) return cmp; + + if (other.type() == Type::Timestamp) { + return Compare(value_, Cast(other).value_); + } else { + return ComparisonResult::Ascending; + } + } + + size_t Hash() const override { + return TimestampInternal::Hash(value()); + } + + const Timestamp& value() const { + return value_; + } + + private: + Timestamp value_; +}; + +/** + * Represents a locally-applied Server Timestamp. + * + * Notes: + * - ServerTimestampValue instances are created as the result of applying an + * TransformMutation. They can only exist in the local view of a document. + * Therefore they do not need to be parsed or serialized. + * - When evaluated locally (e.g. via DocumentSnapshot data), they by default + * evaluate to null. + * - This behavior can be configured by passing custom FieldValueOptions to + * `valueWithOptions:`. + * - They sort after all Timestamp values. With respect to other + * ServerTimestampValues, they sort by their local_write_time. + */ +class ServerTimestampValue : public FieldValue::BaseValue { + public: + explicit ServerTimestampValue(ServerTimestamp server_timestamp) + : server_timestamp_(std::move(server_timestamp)) { + } + + Type type() const override { + return Type::ServerTimestamp; + } + + std::string ToString() const override { + std::string time = value().local_write_time().ToString(); + return absl::StrCat("ServerTimestamp(local_write_time=", time, ")"); + } + + bool Equals(const BaseValue& other) const override { + if (type() != other.type()) return false; + + auto& other_value = Cast(other); + return value().local_write_time() == other_value.value().local_write_time(); + } + + ComparisonResult CompareTo(const BaseValue& other) const override { + ComparisonResult cmp = CompareTypes(other); + if (!util::Same(cmp)) return cmp; + + if (other.type() == Type::ServerTimestamp) { + return Compare( + value().local_write_time(), + Cast(other).value().local_write_time()); + } else { + return ComparisonResult::Descending; + } + } + + size_t Hash() const override { + size_t result = TimestampInternal::Hash(value().local_write_time()); + if (value().previous_value()) { + result = util::Hash(result, *value().previous_value()); + } + return result; + } + + const ServerTimestamp& value() const { + return server_timestamp_; + } + + private: + ServerTimestamp server_timestamp_; +}; + +class StringValue : public SimpleFieldValue { + public: + using SimpleFieldValue::SimpleFieldValue; +}; + +class BlobValue : public SimpleFieldValue { + public: + using SimpleFieldValue::SimpleFieldValue; +}; + +class ReferenceValue : public FieldValue::BaseValue { + public: + explicit ReferenceValue(Reference reference) + : reference_(std::move(reference)) { + } + + Type type() const override { + return Type::Reference; + } + + bool Equals(const BaseValue& other) const override { + if (type() != other.type()) return false; + + auto& other_value = Cast(other); + return database_id() == other_value.database_id() && + key() == other_value.key(); + } + + ComparisonResult CompareTo(const BaseValue& other) const override { + ComparisonResult cmp = CompareTypes(other); + if (!util::Same(cmp)) return cmp; + + auto& other_value = Cast(other); + cmp = Compare(database_id(), other_value.database_id()); + if (!util::Same(cmp)) return cmp; + + return Compare(key(), other_value.key()); + } + + std::string ToString() const override { + return absl::StrCat("Reference(key=", key().ToString(), ")"); + } + + size_t Hash() const override { + return util::Hash(database_id(), key()); + } + + const Reference& value() const { + return reference_; + } + + const DatabaseId& database_id() const { + return reference_.database_id(); + } + + const DocumentKey& key() const { + return reference_.key(); + } + + private: + Reference reference_; +}; + +class GeoPointValue : public BaseValue { + public: + explicit GeoPointValue(GeoPoint value) : value_(value) { + } + + Type type() const override { + return Type::GeoPoint; + } + + std::string ToString() const override { + return util::ToString(value_); + } + + bool Equals(const BaseValue& other) const override { + if (type() != other.type()) return false; + + auto& other_value = Cast(other); + return value_ == other_value.value_; + } + + ComparisonResult CompareTo(const BaseValue& other) const override { + ComparisonResult cmp = CompareTypes(other); + if (!util::Same(cmp)) return cmp; + + auto& other_value = Cast(other); + return Compare(value_, other_value.value_); + } + + size_t Hash() const override { + return util::Hash(value_.latitude(), value_.longitude()); + } + + const GeoPoint& value() const { + return value_; + } + + private: + GeoPoint value_; +}; + +class ArrayContents : public FieldValue::BaseValue { + public: + explicit ArrayContents(FieldValue::Array value) : value_(std::move(value)) { + } + + Type type() const override { + return Type::Array; + } + + bool Equals(const BaseValue& other) const override { + if (type() != other.type()) return false; + + auto& other_value = Cast(other); + return absl::c_equal(value_, other_value.value_); + } + + ComparisonResult CompareTo(const BaseValue& other) const override { + ComparisonResult cmp = CompareTypes(other); + if (!util::Same(cmp)) return cmp; + + auto& other_value = Cast(other); + return util::CompareContainer(value_, other_value.value_); + } + + std::string ToString() const override { + return util::ToString(value_); + } + + size_t Hash() const override { + return util::Hash(value_); + } + + const FieldValue::Array& value() const { + return value_; + } + + private: + FieldValue::Array value_; +}; + +class MapContents : public FieldValue::BaseValue { + public: + explicit MapContents(FieldValue::Map value) : value_(std::move(value)) { + } + + Type type() const override { + return Type::Object; + } + + bool Equals(const BaseValue& other) const override { + if (type() != other.type()) return false; + + auto& other_value = Cast(other); + return absl::c_equal(value_, other_value.value_); + } + + ComparisonResult CompareTo(const BaseValue& other) const override { + ComparisonResult cmp = CompareTypes(other); + if (!util::Same(cmp)) return cmp; + + auto& other_value = Cast(other); + return util::CompareContainer(value_, other_value.value_); + } + + std::string ToString() const override { + return util::ToString(value_); + } + + size_t Hash() const override { + size_t result = 0; + for (auto&& entry : value_) { + result = util::Hash(result, entry.first, entry.second); + } + return result; + } + + const FieldValue::Map& value() const { + return value_; + } + + private: + FieldValue::Map value_; +}; + +} // namespace + +FieldValue::FieldValue() : FieldValue(std::make_shared()) { } bool FieldValue::Comparable(Type lhs, Type rhs) { @@ -144,20 +527,79 @@ bool FieldValue::Comparable(Type lhs, Type rhs) { } } +bool FieldValue::boolean_value() const { + HARD_ASSERT(type() == Type::Boolean); + return Cast(*rep_).value(); +} + +int64_t FieldValue::integer_value() const { + HARD_ASSERT(type() == Type::Integer); + return Cast(*rep_).value(); +} + +double FieldValue::double_value() const { + HARD_ASSERT(type() == Type::Double); + return Cast(*rep_).value(); +} + +Timestamp FieldValue::timestamp_value() const { + HARD_ASSERT(type() == Type::Timestamp); + return Cast(*rep_).value(); +} + +const ServerTimestamp& FieldValue::server_timestamp_value() const { + HARD_ASSERT(type() == Type::ServerTimestamp); + return Cast(*rep_).value(); +} + +const std::string& FieldValue::string_value() const { + HARD_ASSERT(type() == Type::String); + return Cast(*rep_).value(); +} + +const ByteString& FieldValue::blob_value() const { + HARD_ASSERT(type() == Type::Blob); + return Cast(*rep_).value(); +} + +const Reference& FieldValue::reference_value() const { + HARD_ASSERT(type() == Type::Reference); + return Cast(*rep_).value(); +} + +const GeoPoint& FieldValue::geo_point_value() const { + HARD_ASSERT(type() == Type::GeoPoint); + return Cast(*rep_).value(); +} + +const FieldValue::Array& FieldValue::array_value() const { + HARD_ASSERT(type() == Type::Array); + return Cast(*rep_).value(); +} + +const FieldValue::Map& FieldValue::object_value() const { + HARD_ASSERT(type() == Type::Object); + return Cast(*rep_).value(); +} + // TODO(rsgowman): Reorder this file to match its header. ObjectValue ObjectValue::Set(const FieldPath& field_path, const FieldValue& value) const { HARD_ASSERT(!field_path.empty(), "Cannot set field for empty path on FieldValue"); + // Set the value by recursively calling on child object. const std::string& child_name = field_path.first_segment(); if (field_path.size() == 1) { + // Recursive base case: return SetChild(child_name, value); } else { + // Nested path. Recursively generate a new sub-object and then wrap a new + // ObjectValue around the result. ObjectValue child = ObjectValue::Empty(); - const auto iter = fv_.object_value_->find(child_name); - if (iter != fv_.object_value_->end() && - iter->second.type() == Type::Object) { + const FieldValue::Map& entries = fv_.object_value(); + const auto iter = entries.find(child_name); + if (iter != entries.end() && iter->second.type() == Type::Object) { child = ObjectValue(iter->second); } ObjectValue new_child = child.Set(field_path.PopFirst(), value); @@ -171,11 +613,11 @@ ObjectValue ObjectValue::Delete(const FieldPath& field_path) const { // Delete the value by recursively calling on child object. const std::string& child_name = field_path.first_segment(); if (field_path.size() == 1) { - return ObjectValue::FromMap(fv_.object_value_->erase(child_name)); + return ObjectValue::FromMap(fv_.object_value().erase(child_name)); } else { - const auto iter = fv_.object_value_->find(child_name); - if (iter != fv_.object_value_->end() && - iter->second.type() == Type::Object) { + const FieldValue::Map& entries = fv_.object_value(); + const auto iter = entries.find(child_name); + if (iter != entries.end() && iter->second.type() == Type::Object) { ObjectValue new_child = ObjectValue(iter->second).Delete(field_path.PopFirst()); return SetChild(child_name, new_child.fv_); @@ -194,8 +636,10 @@ absl::optional ObjectValue::Get(const FieldPath& field_path) const { if (current->type() != Type::Object) { return absl::nullopt; } - const auto iter = current->object_value_->find(path); - if (iter == current->object_value_->end()) { + + const FieldValue::Map& entries = current->object_value(); + const auto iter = entries.find(path); + if (iter == entries.end()) { return absl::nullopt; } else { current = &iter->second; @@ -204,9 +648,37 @@ absl::optional ObjectValue::Get(const FieldPath& field_path) const { return *current; } +FieldMask ObjectValue::ToFieldMask() const { + std::set fields; + + for (FieldValue::Map::const_iterator iter = fv_.object_value().begin(); + iter != fv_.object_value().end(); ++iter) { + FieldPath current_path{iter->first}; + FieldValue value = iter->second; + + if (value.type() == Type::Object) { + ObjectValue nested_map{value}; + FieldMask nested_mask = nested_map.ToFieldMask(); + if (nested_mask.size() == 0) { + // Preserve the empty map by adding it to the FieldMask. + fields.insert(current_path); + } else { + // For nested and non-empty ObjectValues, add the FieldPath of the leaf + // nodes. + for (const FieldPath& nested_path : nested_mask) { + fields.insert(current_path.Append(nested_path)); + } + } + } else { + fields.insert(current_path); + } + } + return FieldMask(fields); +} + ObjectValue ObjectValue::SetChild(const std::string& child_name, const FieldValue& value) const { - return ObjectValue::FromMap(fv_.object_value_->insert(child_name, value)); + return ObjectValue::FromMap(fv_.object_value().insert(child_name, value)); } FieldValue FieldValue::Null() { @@ -214,11 +686,11 @@ FieldValue FieldValue::Null() { } FieldValue FieldValue::True() { - return FieldValue(true); + return FieldValue(std::make_shared(true)); } FieldValue FieldValue::False() { - return FieldValue(false); + return FieldValue(std::make_shared(false)); } FieldValue FieldValue::FromBoolean(bool value) { @@ -234,258 +706,114 @@ FieldValue FieldValue::EmptyObject() { } FieldValue FieldValue::FromInteger(int64_t value) { - FieldValue result; - result.SwitchTo(Type::Integer); - result.integer_value_ = value; - return result; -} + return FieldValue(std::make_shared(value)); +} + +// We use a canonical NaN bit pattern that's common for both Objective-C and +// Java. Specifically: +// +// - sign: 0 +// - exponent: 11 bits, all 1 +// - significand: 52 bits, MSB=1, rest=0 +// +// This matches the Firestore backend which uses Double.doubleToLongBits from +// the JDK (which is defined to normalize all NaNs to this value). This also +// happens to be a common value for NAN in C++, but C++ does not require this +// specific NaN value to be used, so we normalize. +const uint64_t kCanonicalNanBits = 0x7ff8000000000000ULL; FieldValue FieldValue::FromDouble(double value) { - FieldValue result; - result.SwitchTo(Type::Double); - result.double_value_ = value; - return result; + static double canonical_nan = absl::bit_cast(kCanonicalNanBits); + if (std::isnan(value)) { + value = canonical_nan; + } + + return FieldValue(std::make_shared(value)); } FieldValue FieldValue::FromTimestamp(const Timestamp& value) { - FieldValue result; - result.SwitchTo(Type::Timestamp); - *result.timestamp_value_ = value; - return result; + return FieldValue(std::make_shared(value)); } -FieldValue FieldValue::FromServerTimestamp(const Timestamp& local_write_time, - const Timestamp& previous_value) { - FieldValue result; - result.SwitchTo(Type::ServerTimestamp); - result.server_timestamp_value_->local_write_time = local_write_time; - result.server_timestamp_value_->previous_value = previous_value; - return result; +FieldValue FieldValue::FromServerTimestamp(const Timestamp& local_write_time) { + return FromServerTimestamp(local_write_time, absl::nullopt); } -FieldValue FieldValue::FromServerTimestamp(const Timestamp& local_write_time) { - FieldValue result; - result.SwitchTo(Type::ServerTimestamp); - result.server_timestamp_value_->local_write_time = local_write_time; - result.server_timestamp_value_->previous_value = absl::nullopt; - return result; +FieldValue FieldValue::FromServerTimestamp( + const Timestamp& local_write_time, + absl::optional previous_value) { + return FieldValue(std::make_shared( + ServerTimestamp(local_write_time, std::move(previous_value)))); } FieldValue FieldValue::FromString(const char* value) { - std::string copy(value); - return FromString(std::move(copy)); + return FieldValue(std::make_shared(value)); } FieldValue FieldValue::FromString(const std::string& value) { - std::string copy(value); - return FromString(std::move(copy)); + return FieldValue(std::make_shared(value)); } FieldValue FieldValue::FromString(std::string&& value) { - FieldValue result; - result.SwitchTo(Type::String); - result.string_value_->swap(value); - return result; + return FieldValue(std::make_shared(std::move(value))); } -FieldValue FieldValue::FromBlob(const uint8_t* source, size_t size) { - FieldValue result; - result.SwitchTo(Type::Blob); - std::vector copy(source, source + size); - std::swap(*result.blob_value_, copy); - return result; +FieldValue FieldValue::FromBlob(ByteString blob) { + return FieldValue(std::make_shared(std::move(blob))); } -// Does NOT pass ownership of database_id. -FieldValue FieldValue::FromReference(const DocumentKey& value, - const DatabaseId* database_id) { - FieldValue result; - result.SwitchTo(Type::Reference); - result.reference_value_->reference = value; - result.reference_value_->database_id = database_id; - return result; -} - -// Does NOT pass ownership of database_id. -FieldValue FieldValue::FromReference(DocumentKey&& value, - const DatabaseId* database_id) { - FieldValue result; - result.SwitchTo(Type::Reference); - std::swap(result.reference_value_->reference, value); - result.reference_value_->database_id = database_id; - return result; +FieldValue FieldValue::FromReference(DatabaseId database_id, DocumentKey key) { + return FieldValue(std::make_shared( + Reference(std::move(database_id), std::move(key)))); } FieldValue FieldValue::FromGeoPoint(const GeoPoint& value) { - FieldValue result; - result.SwitchTo(Type::GeoPoint); - *result.geo_point_value_ = value; - return result; + return FieldValue(std::make_shared(value)); } -FieldValue FieldValue::FromArray(const std::vector& value) { - std::vector copy(value); - return FromArray(std::move(copy)); +FieldValue FieldValue::FromArray(const Array& value) { + return FieldValue(std::make_shared(value)); } -FieldValue FieldValue::FromArray(std::vector&& value) { - FieldValue result; - result.SwitchTo(Type::Array); - std::swap(*result.array_value_, value); - return result; +FieldValue FieldValue::FromArray(Array&& value) { + return FieldValue(std::make_shared(std::move(value))); } -FieldValue FieldValue::FromMap(const FieldValue::Map& value) { - FieldValue::Map copy(value); - return FromMap(std::move(copy)); +FieldValue FieldValue::FromMap(const Map& value) { + return FieldValue(std::make_shared(value)); } FieldValue FieldValue::FromMap(FieldValue::Map&& value) { - FieldValue result; - result.SwitchTo(Type::Object); - std::swap(*result.object_value_, value); - return result; + return FieldValue(std::make_shared(std::move(value))); } -bool operator<(const FieldValue::Map& lhs, const FieldValue::Map& rhs) { - return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), - rhs.end()); +bool operator==(const FieldValue& lhs, const FieldValue& rhs) { + return lhs.rep_->Equals(*rhs.rep_); } -bool operator<(const FieldValue& lhs, const FieldValue& rhs) { - if (!FieldValue::Comparable(lhs.type(), rhs.type())) { - return lhs.type() < rhs.type(); - } +std::ostream& operator<<(std::ostream& os, const FieldValue& value) { + return os << value.ToString(); +} - switch (lhs.type()) { - case Type::Null: - return false; - case Type::Boolean: - return Comparator()(lhs.boolean_value_, rhs.boolean_value_); - case Type::Integer: - if (rhs.type() == Type::Integer) { - return Comparator()(lhs.integer_value_, rhs.integer_value_); - } else { - return util::CompareMixedNumber(rhs.double_value_, - lhs.integer_value_) == - ComparisonResult::Descending; - } - case Type::Double: - if (rhs.type() == Type::Double) { - return Comparator()(lhs.double_value_, rhs.double_value_); - } else { - return util::CompareMixedNumber(lhs.double_value_, - rhs.integer_value_) == - ComparisonResult::Ascending; - } - case Type::Timestamp: - if (rhs.type() == Type::Timestamp) { - return *lhs.timestamp_value_ < *rhs.timestamp_value_; - } else { - return true; - } - case Type::ServerTimestamp: - if (rhs.type() == Type::ServerTimestamp) { - return lhs.server_timestamp_value_->local_write_time < - rhs.server_timestamp_value_->local_write_time; - } else { - return false; - } - case Type::String: - return lhs.string_value_->compare(*rhs.string_value_) < 0; - case Type::Blob: - return *lhs.blob_value_ < *rhs.blob_value_; - case Type::Reference: - return *lhs.reference_value_->database_id < - *rhs.reference_value_->database_id || - (*lhs.reference_value_->database_id == - *rhs.reference_value_->database_id && - lhs.reference_value_->reference < - rhs.reference_value_->reference); - case Type::GeoPoint: - return *lhs.geo_point_value_ < *rhs.geo_point_value_; - case Type::Array: - return *lhs.array_value_ < *rhs.array_value_; - case Type::Object: - return *lhs.object_value_ < *rhs.object_value_; - default: - HARD_FAIL("Unsupported type %s", lhs.type()); - // return false if assertion does not abort the program. We will say - // each unsupported type takes only one value thus everything is equal. - return false; +ComparisonResult FieldValue::BaseValue::CompareTypes( + const BaseValue& other) const { + Type this_type = type(); + Type other_type = other.type(); + + // This does not necessarily mean the types are actually the same. For those + // types that allow mixed types they'll need to handle this further. + if (FieldValue::Comparable(this_type, other_type)) { + return ComparisonResult::Same; } + + // Otherwise, the types themselves are defined in order. + return Compare(this_type, other_type); } -void FieldValue::SwitchTo(const Type type) { - if (tag_ == type) { - return; - } - // Not same type. Destruct old type first and then initialize new type. - // Must call destructor explicitly for any non-POD type. - switch (tag_) { - case Type::Timestamp: - timestamp_value_.~unique_ptr(); - break; - case Type::ServerTimestamp: - server_timestamp_value_.~unique_ptr(); - break; - case Type::String: - string_value_.~unique_ptr(); - break; - case Type::Blob: - blob_value_.~unique_ptr>(); - break; - case Type::Reference: - reference_value_.~unique_ptr(); - break; - case Type::GeoPoint: - geo_point_value_.~unique_ptr(); - break; - case Type::Array: - array_value_.~unique_ptr>(); - break; - case Type::Object: - object_value_.~unique_ptr(); - break; - default: {} // The other types where there is nothing to worry about. - } - tag_ = type; - // Must call constructor explicitly for any non-POD type to initialize. - switch (tag_) { - case Type::Timestamp: - new (×tamp_value_) - std::unique_ptr(absl::make_unique(0, 0)); - break; - case Type::ServerTimestamp: - new (&server_timestamp_value_) std::unique_ptr( - absl::make_unique()); - break; - case Type::String: - new (&string_value_) - std::unique_ptr(absl::make_unique()); - break; - case Type::Blob: - // Do not even bother to allocate a new array of size 0. - new (&blob_value_) std::unique_ptr>( - absl::make_unique>()); - break; - case Type::Reference: - new (&reference_value_) - std::unique_ptr(absl::make_unique()); - break; - case Type::GeoPoint: - new (&geo_point_value_) - std::unique_ptr(absl::make_unique()); - break; - case Type::Array: - new (&array_value_) std::unique_ptr>( - absl::make_unique>()); - break; - case Type::Object: - new (&object_value_) std::unique_ptr(absl::make_unique()); - break; - default: {} // The other types where there is nothing to worry about. - } +// Default construction is insufficient because FieldValue's default constructor +// would make this have Type::Null, which then blows up when you try to Set +// on it. +ObjectValue::ObjectValue() : fv_(FieldValue::EmptyObject()) { } ObjectValue ObjectValue::FromMap(const FieldValue::Map& value) { @@ -496,6 +824,26 @@ ObjectValue ObjectValue::FromMap(FieldValue::Map&& value) { return ObjectValue(FieldValue::FromMap(std::move(value))); } +ComparisonResult ObjectValue::CompareTo(const ObjectValue& rhs) const { + return fv_.CompareTo(rhs.fv_); +} + +const FieldValue::Map& ObjectValue::GetInternalValue() const { + return fv_.object_value(); +} + +std::string ObjectValue::ToString() const { + return fv_.ToString(); +} + +std::ostream& operator<<(std::ostream& os, const ObjectValue& value) { + return os << value.ToString(); +} + +size_t ObjectValue::Hash() const { + return fv_.Hash(); +} + } // namespace model } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_value.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_value.h index c7137c1..904af54 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_value.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_value.h @@ -17,7 +17,9 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_H_ +#include #include +#include #include #include #include @@ -28,24 +30,19 @@ #include "Firestore/core/src/firebase/firestore/immutable/sorted_map.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/field_mask.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "absl/base/attributes.h" #include "absl/types/optional.h" namespace firebase { namespace firestore { namespace model { -struct ServerTimestamp { - Timestamp local_write_time; - absl::optional previous_value; -}; - -struct ReferenceValue { - DocumentKey reference; - // Does not own the DatabaseId instance. - const DatabaseId* database_id; -}; +class ObjectValue; /** * tagged-union class representing an immutable data value as stored in @@ -54,6 +51,9 @@ struct ReferenceValue { */ class FieldValue { public: + class Reference; + class ServerTimestamp; + using Array = std::vector; using Map = immutable::SortedMap; /** @@ -80,22 +80,66 @@ class FieldValue { // position instead, see the doc comment above. }; - FieldValue() { + FieldValue(); + + FieldValue(ObjectValue object); // NOLINT(runtime/explicit) + + /** Returns the true type for this value. */ + Type type() const { + return rep_->type(); } - // Do not inline these ctor/dtor below, which contain call to non-trivial - // operator=. - FieldValue(const FieldValue& value); - FieldValue(FieldValue&& value); + bool is_boolean() const { + return type() == Type::Boolean; + } - ~FieldValue(); + bool is_integer() const { + return type() == Type::Integer; + } - FieldValue& operator=(const FieldValue& value); - FieldValue& operator=(FieldValue&& value); + bool is_double() const { + return type() == Type::Double; + } - /** Returns the true type for this value. */ - Type type() const { - return tag_; + bool is_timestamp() const { + return type() == Type::Timestamp; + } + + bool is_server_timestamp() const { + return type() == Type::ServerTimestamp; + } + + bool is_string() const { + return type() == Type::String; + } + + bool is_blob() const { + return type() == Type::Blob; + } + + bool is_reference() const { + return type() == Type::Reference; + } + + bool is_geo_point() const { + return type() == Type::GeoPoint; + } + + bool is_array() const { + return type() == Type::Array; + } + + bool is_object() const { + return type() == Type::Object; + } + + /** + * Checks if the given type is a numeric, such as Type::Integer or + * Type::Double. + */ + bool is_number() const { + Type t = type(); + return t == Type::Integer || t == Type::Double; } /** @@ -107,44 +151,35 @@ class FieldValue { */ static bool Comparable(Type lhs, Type rhs); - bool boolean_value() const { - HARD_ASSERT(tag_ == Type::Boolean); - return boolean_value_; - } + bool boolean_value() const; - int64_t integer_value() const { - HARD_ASSERT(tag_ == Type::Integer); - return integer_value_; - } + int64_t integer_value() const; - double double_value() const { - HARD_ASSERT(tag_ == Type::Double); - return double_value_; - } + double double_value() const; - Timestamp timestamp_value() const { - HARD_ASSERT(tag_ == Type::Timestamp); - return *timestamp_value_; - } + Timestamp timestamp_value() const; - const std::string& string_value() const { - HARD_ASSERT(tag_ == Type::String); - return *string_value_; - } + const ServerTimestamp& server_timestamp_value() const; - const std::vector& blob_value() const { - HARD_ASSERT(tag_ == Type::Blob); - return *blob_value_; - } + const std::string& string_value() const; + + const nanopb::ByteString& blob_value() const; - const GeoPoint& geo_point_value() const { - HARD_ASSERT(tag_ == Type::GeoPoint); - return *geo_point_value_; + const Reference& reference_value() const; + + const GeoPoint& geo_point_value() const; + + const Array& array_value() const; + + const Map& object_value() const; + + bool is_null() const { + return type() == Type::Null; } - const std::vector& array_value() const { - HARD_ASSERT(tag_ == Type::Array); - return *array_value_; + bool is_nan() const { + if (type() != Type::Double) return false; + return std::isnan(double_value()); } /** factory methods. */ @@ -157,57 +192,99 @@ class FieldValue { static FieldValue FromInteger(int64_t value); static FieldValue FromDouble(double value); static FieldValue FromTimestamp(const Timestamp& value); - static FieldValue FromServerTimestamp(const Timestamp& local_write_time, - const Timestamp& previous_value); + static FieldValue FromServerTimestamp(const Timestamp& local_write_time); + + private: + // TODO(b/146372592): Make this public once we can use Abseil across + // iOS/public C++ library boundaries. + friend class FieldValueTest; + friend class ServerTimestampTransform; + + static FieldValue FromServerTimestamp( + const Timestamp& local_write_time, + absl::optional previous_value); + + public: static FieldValue FromString(const char* value); static FieldValue FromString(const std::string& value); static FieldValue FromString(std::string&& value); - static FieldValue FromBlob(const uint8_t* source, size_t size); - static FieldValue FromReference(const DocumentKey& value, - const DatabaseId* database_id); - static FieldValue FromReference(DocumentKey&& value, - const DatabaseId* database_id); + static FieldValue FromBlob(nanopb::ByteString blob); + static FieldValue FromReference(DatabaseId database_id, DocumentKey value); static FieldValue FromGeoPoint(const GeoPoint& value); - static FieldValue FromArray(const std::vector& value); - static FieldValue FromArray(std::vector&& value); + static FieldValue FromArray(const Array& value); + static FieldValue FromArray(Array&& value); static FieldValue FromMap(const Map& value); static FieldValue FromMap(Map&& value); - friend bool operator<(const FieldValue& lhs, const FieldValue& rhs); - - private: - friend class ObjectValue; + size_t Hash() const { + return rep_->Hash(); + } - explicit FieldValue(bool value) : tag_(Type::Boolean), boolean_value_(value) { + util::ComparisonResult CompareTo(const FieldValue& rhs) const { + return rep_->CompareTo(*rhs.rep_); } /** - * Switch to the specified type, if different from the current type. + * Checks if the two values are equal, returning false if the value is + * perceptibly different in any regard. + * + * Comparison for FieldValues is defined by whether or not values should + * match for the purposes of querying. Comparison therefore makes the broadest + * possible allowance, looking only for logical equality. This means that e.g. + * -0.0, +0.0 and 0 (floating point and integer zeros) are all considered the + * same value for comparison purposes. + * + * Equality for FieldValues is defined by whether or not a user could + * perceive a change to the value. That is, a change from integer zero to + * a double zero can be perceived and so these values are unequal despite + * comparing same. + * + * This makes FieldValue one of the special cases where equality is + * inconsistent with comparison. There are cases where CompareTo will return + * Same but operator== will return false. */ - void SwitchTo(Type type); - - Type tag_ = Type::Null; - union { - // There is no null type as tag_ alone is enough for Null FieldValue. - bool boolean_value_; - int64_t integer_value_; - double double_value_; - std::unique_ptr timestamp_value_; - std::unique_ptr server_timestamp_value_; - // TODO(rsgowman): Change unique_ptr to nanopb::String? - std::unique_ptr string_value_; - std::unique_ptr> blob_value_; - std::unique_ptr reference_value_; - std::unique_ptr geo_point_value_; - std::unique_ptr> array_value_; - std::unique_ptr object_value_; + friend bool operator==(const FieldValue& lhs, const FieldValue& rhs); + + std::string ToString() const { + return rep_->ToString(); + } + + friend std::ostream& operator<<(std::ostream& os, const FieldValue& value); + + friend class ObjectValue; + class BaseValue { + public: + virtual ~BaseValue() = default; + + virtual Type type() const = 0; + + virtual std::string ToString() const = 0; + + virtual bool Equals(const BaseValue& other) const = 0; + + virtual util::ComparisonResult CompareTo(const BaseValue& other) const = 0; + + virtual size_t Hash() const = 0; + + protected: + util::ComparisonResult CompareTypes(const BaseValue& other) const; }; + + private: + explicit FieldValue(std::shared_ptr rep) : rep_(std::move(rep)) { + } + + std::shared_ptr rep_; }; /** A structured object value stored in Firestore. */ -class ObjectValue { +class ObjectValue : public util::Comparable { public: + // Default constructible to make using this easy, though prefer + // ObjectValue::Empty() to make intentions clear to readers. + ObjectValue(); + explicit ObjectValue(FieldValue fv) : fv_(std::move(fv)) { HARD_ASSERT(fv_.type() == FieldValue::Type::Object); } @@ -237,6 +314,9 @@ class ObjectValue { * @return A new FieldValue with the field set. */ ObjectValue Set(const FieldPath& field_path, const FieldValue& value) const; + ObjectValue Set(const FieldPath& field_path, const ObjectValue& value) const { + return Set(field_path, value.fv_); + } /** * Returns a FieldValue with the field path deleted. If there is no field at @@ -247,74 +327,112 @@ class ObjectValue { */ ObjectValue Delete(const FieldPath& field_path) const; + /** + * Returns a FieldMask built from all FieldPaths starting from this + * ObjectValue, including paths from nested objects. + */ + FieldMask ToFieldMask() const; + // TODO(rsgowman): Add Value() method? // // Java has a value() method which returns a (non-immutable) java.util.Map, // which is a copy of the immutable map, but with some fields (such as server // timestamps) optionally resolved. Do we need the same here? - const FieldValue::Map& GetInternalValue() const { - return *fv_.object_value_; + const FieldValue::Map& GetInternalValue() const; + + const FieldValue& AsFieldValue() const { + return fv_; } - private: - friend bool operator<(const ObjectValue& lhs, const ObjectValue& rhs); + util::ComparisonResult CompareTo(const ObjectValue& rhs) const; + + std::string ToString() const; + friend std::ostream& operator<<(std::ostream& os, const ObjectValue& value); + + size_t Hash() const; + + size_t size() const { + return fv_.object_value().size(); + } + private: ObjectValue SetChild(const std::string& child_name, const FieldValue& value) const; FieldValue fv_; }; -bool operator<(const FieldValue::Map& lhs, const FieldValue::Map& rhs); +class FieldValue::Reference { + public: + Reference(DatabaseId database_id, DocumentKey key) + : database_id_(std::move(database_id)), key_(std::move(key)) { + } -/** Compares against another FieldValue. */ -bool operator<(const FieldValue& lhs, const FieldValue& rhs); + const DatabaseId& database_id() const { + return database_id_; + } -inline bool operator>(const FieldValue& lhs, const FieldValue& rhs) { - return rhs < lhs; -} + const DocumentKey& key() const { + return key_; + } -inline bool operator>=(const FieldValue& lhs, const FieldValue& rhs) { - return !(lhs < rhs); -} + private: + DatabaseId database_id_; + DocumentKey key_; +}; -inline bool operator<=(const FieldValue& lhs, const FieldValue& rhs) { - return !(lhs > rhs); -} +class FieldValue::ServerTimestamp { + private: + // TODO(b/146372592): Make this public once we can use Abseil across + // iOS/public C++ library boundaries. + friend class FieldValue; + + ServerTimestamp(Timestamp local_write_time, + absl::optional previous_value) + : local_write_time_(local_write_time), + previous_value_(std::move(previous_value)) { + } -inline bool operator!=(const FieldValue& lhs, const FieldValue& rhs) { - return lhs < rhs || lhs > rhs; -} + public: + const Timestamp& local_write_time() const { + return local_write_time_; + } -inline bool operator==(const FieldValue& lhs, const FieldValue& rhs) { - return !(lhs != rhs); -} + const absl::optional& previous_value() const { + return previous_value_; + } -/** Compares against another ObjectValue. */ -inline bool operator<(const ObjectValue& lhs, const ObjectValue& rhs) { - return lhs.fv_ < rhs.fv_; -} + private: + Timestamp local_write_time_; + absl::optional previous_value_; +}; -inline bool operator>(const ObjectValue& lhs, const ObjectValue& rhs) { - return rhs < lhs; +// Pretend you can automatically upcast from ObjectValue to FieldValue. +inline FieldValue::FieldValue(ObjectValue object) + : FieldValue(object.AsFieldValue()) { } -inline bool operator>=(const ObjectValue& lhs, const ObjectValue& rhs) { - return !(lhs < rhs); +inline bool operator!=(const FieldValue& lhs, const FieldValue& rhs) { + // See operator== for why this isn't using util::Same(). + return !(lhs == rhs); } -inline bool operator<=(const ObjectValue& lhs, const ObjectValue& rhs) { - return !(lhs > rhs); +inline bool operator<(const FieldValue& lhs, const FieldValue& rhs) { + return util::Ascending(lhs.CompareTo(rhs)); } - -inline bool operator!=(const ObjectValue& lhs, const ObjectValue& rhs) { - return lhs < rhs || lhs > rhs; +inline bool operator>(const FieldValue& lhs, const FieldValue& rhs) { + return util::Descending(lhs.CompareTo(rhs)); } - -inline bool operator==(const ObjectValue& lhs, const ObjectValue& rhs) { - return !(lhs != rhs); +inline bool operator<=(const FieldValue& lhs, const FieldValue& rhs) { + return !(rhs < lhs); } +inline bool operator>=(const FieldValue& lhs, const FieldValue& rhs) { + return !(lhs < rhs); +} + +// A bit pattern for our canonical NaN value. Exposed here for testing. +ABSL_CONST_INIT extern const uint64_t kCanonicalNanBits; } // namespace model } // namespace firestore diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_value_options.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_value_options.h new file mode 100644 index 0000000..b3cd57c --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/field_value_options.h @@ -0,0 +1,57 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_OPTIONS_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_OPTIONS_H_ + +namespace firebase { +namespace firestore { +namespace model { + +/** Defines the return value for pending server timestamps. */ +enum class ServerTimestampBehavior { kNone, kEstimate, kPrevious }; + +/** Holds properties that define field value deserialization options. */ +class FieldValueOptions { + public: + /** + * Creates an FieldValueOptions instance that specifies deserialization + * behavior for pending server timestamps. + */ + FieldValueOptions(ServerTimestampBehavior server_timestamp_behavior, + bool timestamps_in_snapshots_enabled) + : server_timestamp_behavior_(server_timestamp_behavior), + timestamps_in_snapshots_enabled_(timestamps_in_snapshots_enabled) { + } + + ServerTimestampBehavior server_timestamp_behavior() const { + return server_timestamp_behavior_; + } + + bool timestamps_in_snapshots_enabled() const { + return timestamps_in_snapshots_enabled_; + } + + private: + ServerTimestampBehavior server_timestamp_behavior_; + bool timestamps_in_snapshots_enabled_; +}; + +} // namespace model +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_OPTIONS_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/maybe_document.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/maybe_document.cc index aa5e15a..c5cd3b1 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/maybe_document.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/maybe_document.cc @@ -16,19 +16,30 @@ #include "Firestore/core/src/firebase/firestore/model/maybe_document.h" +#include #include namespace firebase { namespace firestore { namespace model { -MaybeDocument::MaybeDocument(DocumentKey key, SnapshotVersion version) - : key_(std::move(key)), version_(std::move(version)) { +bool MaybeDocument::Rep::Equals(const MaybeDocument::Rep& other) const { + return type() == other.type() && version() == other.version() && + key() == other.key(); } -bool MaybeDocument::Equals(const MaybeDocument& other) const { - return type_ == other.type_ && version_ == other.version_ && - key_ == other.key_; +size_t MaybeDocument::Rep::Hash() const { + return util::Hash(type_, key_, version_); +} + +std::ostream& operator<<(std::ostream& os, const MaybeDocument& doc) { + return os << doc.rep_->ToString(); +} + +bool operator==(const MaybeDocument& lhs, const MaybeDocument& rhs) { + return lhs.rep_ == nullptr + ? rhs.rep_ == nullptr + : (rhs.rep_ != nullptr && lhs.rep_->Equals(*rhs.rep_)); } } // namespace model diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/maybe_document.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/maybe_document.h index 1039de1..0fd3c99 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/maybe_document.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/maybe_document.h @@ -18,7 +18,10 @@ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_MAYBE_DOCUMENT_H_ #include +#include #include +#include +#include #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" @@ -30,6 +33,19 @@ namespace model { /** * The result of a lookup for a given path may be an existing document or a * tombstone that marks the path deleted. + * + * Note: MaybeDocument and its subclasses are specially designed to avoid + * slicing. You can assign a subclass of MaybeDocument to an instance of + * MaybeDocument and the full value is preserved, unsliced. Each subclass + * declares an explicit constructor that can recover the derived type. This + * means that code like this will work: + * + * Document doc(...); + * MaybeDocument maybe_doc = doc; + * Document recovered(maybe_doc); + * + * The final line results in an explicit check that will fail if the type of + * the underlying data is not actually Type::Document. */ class MaybeDocument { public: @@ -44,26 +60,39 @@ class MaybeDocument { // TODO(rsgowman): Since it's no longer possible to directly create // MaybeDocument's, we can likely remove this value entirely. But // investigate impact on the serializers first. - Unknown, + Invalid, Document, NoDocument, UnknownDocument, }; - MaybeDocument(DocumentKey key, SnapshotVersion version); + MaybeDocument() = default; - virtual ~MaybeDocument() { + bool is_valid() const { + return rep_ != nullptr; } /** The runtime type of this document. */ Type type() const { - return type_; + return rep_ ? rep_->type() : Type::Invalid; + } + + bool is_document() const { + return type() == Type::Document; + } + + bool is_no_document() const { + return type() == Type::NoDocument; + } + + bool is_unknown_document() const { + return type() == Type::UnknownDocument; } /** The key for this document. */ const DocumentKey& key() const { - return key_; + return rep_->key(); } /** @@ -71,41 +100,81 @@ class MaybeDocument { * this document was guaranteed to not exist. */ const SnapshotVersion& version() const { - return version_; + return rep_->version(); } /** * Whether this document has a local mutation applied that has not yet been * acknowledged by Watch. */ - virtual bool HasPendingWrites() const = 0; + bool has_pending_writes() const { + return rep_->has_pending_writes(); + } + + size_t Hash() const { + return rep_->Hash(); + } + + std::string ToString() const { + return rep_->ToString(); + } + + friend std::ostream& operator<<(std::ostream& os, const MaybeDocument& doc); protected: - // Only allow subclass to set their types. - void set_type(Type type) { - type_ = type; + class Rep { + public: + Rep(Type type, DocumentKey&& key, SnapshotVersion version) + : type_(type), key_(std::move(key)), version_(version) { + } + + virtual ~Rep() = default; + + Type type() const { + return type_; + } + + const DocumentKey& key() const { + return key_; + } + + const SnapshotVersion& version() const { + return version_; + } + + virtual bool has_pending_writes() const = 0; + + virtual bool Equals(const Rep& other) const; + + virtual size_t Hash() const; + + virtual std::string ToString() const = 0; + + private: + Type type_ = Type::Invalid; + DocumentKey key_; + SnapshotVersion version_; + }; + + explicit MaybeDocument(std::shared_ptr rep) : rep_(std::move(rep)) { } - virtual bool Equals(const MaybeDocument& other) const; + const Rep& rep() const { + return *rep_; + } friend bool operator==(const MaybeDocument& lhs, const MaybeDocument& rhs); private: - Type type_ = Type::Unknown; - DocumentKey key_; - SnapshotVersion version_; + std::shared_ptr rep_; }; -inline bool operator==(const MaybeDocument& lhs, const MaybeDocument& rhs) { - return lhs.Equals(rhs); -} - inline bool operator!=(const MaybeDocument& lhs, const MaybeDocument& rhs) { return !(lhs == rhs); } /** Compares against another MaybeDocument by keys only. */ -struct DocumentKeyComparator : public std::less { +struct DocumentKeyComparator { bool operator()(const MaybeDocument& lhs, const MaybeDocument& rhs) const { return lhs.key() < rhs.key(); } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation.cc index e863b34..526caa5 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation.cc @@ -17,6 +17,8 @@ #include "Firestore/core/src/firebase/firestore/model/mutation.h" #include +#include +#include #include #include "Firestore/core/src/firebase/firestore/model/document.h" @@ -24,182 +26,66 @@ #include "Firestore/core/src/firebase/firestore/model/field_value.h" #include "Firestore/core/src/firebase/firestore/model/no_document.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/to_string.h" +#include "absl/strings/str_cat.h" namespace firebase { namespace firestore { namespace model { -Mutation::Mutation(DocumentKey&& key, Precondition&& precondition) - : key_(std::move(key)), precondition_(std::move(precondition)) { -} - -void Mutation::VerifyKeyMatches(const MaybeDocument* maybe_doc) const { - if (maybe_doc) { - HARD_ASSERT(maybe_doc->key() == key(), - "Can only apply a mutation to a document with the same key"); - } -} - -SnapshotVersion Mutation::GetPostMutationVersion( - const MaybeDocument* maybe_doc) { - if (maybe_doc && maybe_doc->type() == MaybeDocument::Type::Document) { - return maybe_doc->version(); - } else { - return SnapshotVersion::None(); - } -} - -bool Mutation::equal_to(const Mutation& other) const { - return key_ == other.key_ && precondition_ == other.precondition_ && - type() == other.type(); -} - -SetMutation::SetMutation(DocumentKey&& key, - ObjectValue&& value, - Precondition&& precondition) - : Mutation(std::move(key), std::move(precondition)), - value_(std::move(value)) { +std::string MutationResult::ToString() const { + return absl::StrCat( + "MutationResult(version=", version_.ToString(), + ", transform_results=", util::ToString(transform_results_), ")"); } -MaybeDocumentPtr SetMutation::ApplyToRemoteDocument( - const MaybeDocumentPtr& maybe_doc, - const MutationResult& mutation_result) const { - VerifyKeyMatches(maybe_doc.get()); - - HARD_ASSERT(mutation_result.transform_results() == nullptr, - "Transform results received by SetMutation."); - - // Unlike applyToLocalView, if we're applying a mutation to a remote document - // the server has accepted the mutation so the precondition must have held. - - const SnapshotVersion& version = mutation_result.version(); - return absl::make_unique(ObjectValue(value_), key(), version, - DocumentState::kCommittedMutations); +std::ostream& operator<<(std::ostream& os, const MutationResult& result) { + return os << result.ToString(); } -MaybeDocumentPtr SetMutation::ApplyToLocalView( - const MaybeDocumentPtr& maybe_doc, - const MaybeDocument*, - const Timestamp&) const { - VerifyKeyMatches(maybe_doc.get()); - - if (!precondition().IsValidFor(maybe_doc.get())) { - return maybe_doc; - } - - SnapshotVersion version = GetPostMutationVersion(maybe_doc.get()); - return absl::make_unique(ObjectValue(value_), key(), version, - DocumentState::kLocalMutations); +bool operator==(const MutationResult& lhs, const MutationResult& rhs) { + return lhs.version() == rhs.version() && + lhs.transform_results() == rhs.transform_results(); } -bool SetMutation::equal_to(const Mutation& other) const { - if (!Mutation::equal_to(other)) return false; - return value_ == static_cast(other).value_; +Mutation::Rep::Rep(DocumentKey&& key, Precondition&& precondition) + : key_(std::move(key)), precondition_(std::move(precondition)) { } -PatchMutation::PatchMutation(DocumentKey&& key, - ObjectValue&& value, - FieldMask&& mask, - Precondition&& precondition) - : Mutation(std::move(key), std::move(precondition)), - value_(std::move(value)), - mask_(std::move(mask)) { +bool Mutation::Rep::Equals(const Mutation::Rep& other) const { + return type() == other.type() && key_ == other.key_ && + precondition_ == other.precondition_; } -MaybeDocumentPtr PatchMutation::ApplyToRemoteDocument( - const MaybeDocumentPtr& maybe_doc, - const MutationResult& mutation_result) const { - VerifyKeyMatches(maybe_doc.get()); - HARD_ASSERT(mutation_result.transform_results() == nullptr, - "Transform results received by PatchMutation."); - - if (!precondition().IsValidFor(maybe_doc.get())) { - // Since the mutation was not rejected, we know that the precondition - // matched on the backend. We therefore must not have the expected version - // of the document in our cache and return an UnknownDocument with the known - // updateTime. - - // TODO(rsgowman): heldwriteacks: Implement. Like this (once UnknownDocument - // is ported): - // return absl::make_unique(key(), - // mutation_result.version()); - - abort(); +void Mutation::Rep::VerifyKeyMatches( + const absl::optional& maybe_doc) const { + if (maybe_doc) { + HARD_ASSERT(maybe_doc->key() == key(), + "Can only apply a mutation to a document with the same key"); } - - const SnapshotVersion& version = mutation_result.version(); - ObjectValue new_data = PatchDocument(maybe_doc.get()); - return absl::make_unique(std::move(new_data), key(), version, - DocumentState::kCommittedMutations); } -MaybeDocumentPtr PatchMutation::ApplyToLocalView( - const MaybeDocumentPtr& maybe_doc, - const MaybeDocument*, - const Timestamp&) const { - VerifyKeyMatches(maybe_doc.get()); - - if (!precondition().IsValidFor(maybe_doc.get())) { - return maybe_doc; - } - - SnapshotVersion version = GetPostMutationVersion(maybe_doc.get()); - ObjectValue new_data = PatchDocument(maybe_doc.get()); - return absl::make_unique(std::move(new_data), key(), version, - DocumentState::kLocalMutations); -} - -ObjectValue PatchMutation::PatchDocument(const MaybeDocument* maybe_doc) const { +SnapshotVersion Mutation::Rep::GetPostMutationVersion( + const absl::optional& maybe_doc) { if (maybe_doc && maybe_doc->type() == MaybeDocument::Type::Document) { - return PatchObject(static_cast(maybe_doc)->data()); + return maybe_doc->version(); } else { - return PatchObject(ObjectValue::Empty()); - } -} - -ObjectValue PatchMutation::PatchObject(ObjectValue obj) const { - for (const FieldPath& path : mask_) { - if (!path.empty()) { - absl::optional new_value = value_.Get(path); - if (!new_value) { - obj = obj.Delete(path); - } else { - obj = obj.Set(path, *new_value); - } - } + return SnapshotVersion::None(); } - return obj; } -bool PatchMutation::equal_to(const Mutation& other) const { - if (!Mutation::equal_to(other)) return false; - const PatchMutation& patch_other = static_cast(other); - return value_ == patch_other.value_ && mask_ == patch_other.mask_; +bool operator==(const Mutation& lhs, const Mutation& rhs) { + return lhs.rep_ == nullptr + ? rhs.rep_ == nullptr + : (rhs.rep_ != nullptr && lhs.rep_->Equals(*rhs.rep_)); } -DeleteMutation::DeleteMutation(DocumentKey&& key, Precondition&& precondition) - : Mutation(std::move(key), std::move(precondition)) { +size_t Mutation::Rep::Hash() const { + return util::Hash(type(), key(), precondition()); } -MaybeDocumentPtr DeleteMutation::ApplyToRemoteDocument( - const MaybeDocumentPtr& /*maybe_doc*/, - const MutationResult& /*mutation_result*/) const { - // TODO(rsgowman): Implement. - abort(); -} - -MaybeDocumentPtr DeleteMutation::ApplyToLocalView( - const MaybeDocumentPtr& maybe_doc, - const MaybeDocument*, - const Timestamp&) const { - VerifyKeyMatches(maybe_doc.get()); - - if (!precondition().IsValidFor(maybe_doc.get())) { - return maybe_doc; - } - - return absl::make_unique(key(), SnapshotVersion::None(), - /*hasCommittedMutations=*/false); +std::ostream& operator<<(std::ostream& os, const Mutation& mutation) { + return os << mutation.ToString(); } } // namespace model diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation.h index 8e4ad56..82f59e1 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation.h @@ -17,7 +17,9 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_MUTATION_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_MUTATION_H_ +#include #include +#include #include #include @@ -27,13 +29,13 @@ #include "Firestore/core/src/firebase/firestore/model/maybe_document.h" #include "Firestore/core/src/firebase/firestore/model/precondition.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "absl/types/optional.h" namespace firebase { namespace firestore { namespace model { -using MaybeDocumentPtr = std::shared_ptr; - /** * The result of applying a mutation to the server. This is a model of the * WriteResult proto message. @@ -45,10 +47,9 @@ using MaybeDocumentPtr = std::shared_ptr; class MutationResult { public: MutationResult( - SnapshotVersion&& version, - const std::shared_ptr>& transform_results) - : version_(std::move(version)), - transform_results_(std::move(transform_results)) { + SnapshotVersion version, + absl::optional> transform_results) + : version_(version), transform_results_(std::move(transform_results)) { } /** @@ -67,19 +68,26 @@ class MutationResult { /** * The resulting fields returned from the backend after a TransformMutation - * has been committed. Contains one ObjectValue for each FieldTransform - * that was in the mutation. + * has been committed. Contains one FieldValue for each FieldTransform that + * was in the mutation. * - * Will be null if the mutation was not a TransformMutation. + * Will be nullopt if the mutation was not a TransformMutation. */ - const std::shared_ptr>& transform_results() + const absl::optional>& transform_results() const { return transform_results_; } + std::string ToString() const; + + friend std::ostream& operator<<(std::ostream& os, + const MutationResult& result); + + friend bool operator==(const MutationResult& lhs, const MutationResult& rhs); + private: - const SnapshotVersion version_; - const std::shared_ptr> transform_results_; + SnapshotVersion version_; + absl::optional> transform_results_; }; /** @@ -109,14 +117,14 @@ class MutationResult { * DeleteMutation NoDocument(v3) NoDocument(v0) * DeleteMutation null NoDocument(v0) * - * For acknowledged mutations, we use the updateTime of the WriteResponse as the - * resulting version for Set, Patch, and Transform mutations. As deletes have no - * explicit update time, we use the commitTime of the WriteResponse for - * acknowledged deletes. + * For acknowledged mutations, we use the update_time of the WriteResponse as + * the resulting version for Set, Patch, and Transform mutations. As deletes + * have no explicit update time, we use the commit_time of the WriteResponse + * for acknowledged deletes. * - * If a mutation is acknowledged by the backend but fails the precondition check - * locally, we return an `UnknownDocument` and rely on Watch to send us the - * updated version. + * If a mutation is acknowledged by the backend but fails the precondition + * check locally, we return an `UnknownDocument` and rely on Watch to send us + * the updated version. * * Note that TransformMutations don't create Documents (in the case of being * applied to a NoDocument), even though they would on the backend. This is @@ -124,204 +132,211 @@ class MutationResult { * or PatchMutation and we only want to apply the transform if the prior * mutation resulted in a Document (always true for a SetMutation, but not * necessarily for an PatchMutation). + * + * Note: Mutation and its subclasses are specially designed to avoid slicing. + * You can assign a subclass of Mutation to an instance of Mutation and the + * full value is preserved, unsliced. Each subclass declares an explicit + * constructor that can recover the derived type. This means that code like + * this will work: + * + * SetMutation set(...); + * Mutation mutation = set; + * SetMutation recovered(mutation); + * + * The final line results in an explicit check that will fail if the type of + * the underlying data is not actually Type::Set. */ class Mutation { public: /** * Represents the mutation type. This is used in place of dynamic_cast. */ - enum class Type { kSet, kPatch, kDelete }; + enum class Type { Set, Patch, Transform, Delete, Verify }; + + /** Creates an invalid mutation. */ + Mutation() = default; + + /** + * Returns true if the given mutation is a valid instance. Default constructed + * and moved-from Mutations are not valid. + */ + bool is_valid() const { + return rep_ != nullptr; + } - virtual ~Mutation() { + /** The runtime type of this mutation. */ + Type type() const { + return rep().type(); } const DocumentKey& key() const { - return key_; + return rep().key(); } const Precondition& precondition() const { - return precondition_; + return rep().precondition(); } - /** The runtime type of this mutation. */ - virtual Type type() const = 0; - /** * Applies this mutation to the given MaybeDocument for the purposes of - * computing a new remote document. If the input document doesn't match the - * expected state (e.g. it is null or outdated), an `UnknownDocument` can be - * returned. + * computing the committed state of the document after the server has + * acknowledged that this mutation has been successfully committed. This + * means that if the input document doesn't match the expected state (e.g. it + * is `nullopt` or outdated), the local cache must have been incorrect so an + * `UnknownDocument` is returned. * - * @param maybe_doc The document to mutate. The input document can be nullptr - * if the client has no knowledge of the pre-mutation state of the - * document. - * @param mutation_result The result of applying the mutation from the - * backend. - * @return The mutated document. The returned document may be an - * UnknownDocument if the mutation could not be applied to the locally - * cached base document. + * @param maybe_doc The document to mutate. The input document can be + * `nullopt` if the client has no knowledge of the pre-mutation state of + * the document. + * @param mutation_result The backend's response of successfully applying the + * mutation. + * @return The mutated document. The returned document is not optional + * because the server successfully committed this mutation. If the local + * cache might have caused a `nullopt` result, this method will return an + * `UnknownDocument` instead. */ - virtual MaybeDocumentPtr ApplyToRemoteDocument( - const MaybeDocumentPtr& maybe_doc, - const MutationResult& mutation_result) const = 0; + MaybeDocument ApplyToRemoteDocument( + const absl::optional& maybe_doc, + const MutationResult& mutation_result) const { + return rep().ApplyToRemoteDocument(maybe_doc, mutation_result); + } /** - * Applies this mutation to the given MaybeDocument for the purposes of - * computing the new local view of a document. Both the input and returned - * documents can be nullptr. + * Estimates the latency compensated view of this mutation applied to the + * given MaybeDocument. * - * @param maybe_doc The document to mutate. The input document can be nullptr - * if the client has no knowledge of the pre-mutation state of the - * document. + * Unlike ApplyToRemoteDocument, this method is used before the mutation has + * been committed and so it's possible that the mutation is operating on a + * locally non-existent document and may produce a non-existent document. + * + * Note: `maybe_doc` and `base_doc` are similar but not the same: + * + * - `base_doc` is the pristine version of the document as it was _before_ + * applying any of the mutations in the batch. This means that for each + * mutation in the batch, `base_doc` stays unchanged; + * - `maybe_doc` is the state of the document _after_ applying all the + * preceding mutations from the batch. In other words, `maybe_doc` is + * passed on from one mutation in the batch to the next, accumulating + * changes. + * + * The only time `maybe_doc` and `base_doc` are guaranteed to be the same is + * for the very first mutation in the batch. The distinction between + * `maybe_doc` and `base_doc` helps ServerTimestampTransform determine the + * "previous" value in a way that makes sense to users. + * + * @param maybe_doc The document to mutate. The input document can be + * `nullopt` if the client has no knowledge of the pre-mutation state of + * the document. * @param base_doc The state of the document prior to this mutation batch. The - * input document can be nullptr if the client has no knowledge of the + * input document can be nullopt if the client has no knowledge of the * pre-mutation state of the document. * @param local_write_time A timestamp indicating the local write time of the * batch this mutation is a part of. - * @return The mutated document. The returned document may be nullptr, but - * only if maybe_doc was nullptr and the mutation would not create a new + * @return The mutated document. The returned document may be nullopt, but + * only if maybe_doc was nullopt and the mutation would not create a new * document. */ - virtual MaybeDocumentPtr ApplyToLocalView( - const MaybeDocumentPtr& maybe_doc, - const MaybeDocument* base_doc, - const Timestamp& local_write_time) const = 0; + absl::optional ApplyToLocalView( + const absl::optional& maybe_doc, + const absl::optional& base_doc, + const Timestamp& local_write_time) const { + return rep().ApplyToLocalView(maybe_doc, base_doc, local_write_time); + } - friend bool operator==(const Mutation& lhs, const Mutation& rhs); + /** + * If this mutation is not idempotent, returns the base value to persist with + * this mutation. If a base value is returned, the mutation is always + * applied to this base value, even if document has already been updated. + * + * The base value is a sparse object that consists of only the document + * fields for which this mutation contains a non-idempotent transformation + * (e.g. a numeric increment). The provided value guarantees consistent + * behavior for non-idempotent transforms and allow us to return the same + * latency-compensated value even if the backend has already applied the + * mutation. The base value is empty for idempotent mutations, as they can be + * re-played even if the backend has already applied them. + * + * @return a base value to store along with the mutation, or empty for + * idempotent mutations. + */ + absl::optional ExtractBaseValue( + const absl::optional& maybe_doc) const { + return rep_->ExtractBaseValue(maybe_doc); + } - protected: - Mutation(DocumentKey&& key, Precondition&& precondition); + friend bool operator==(const Mutation& lhs, const Mutation& rhs); - void VerifyKeyMatches(const MaybeDocument* maybe_doc) const; + size_t Hash() const { + return rep().Hash(); + } - static SnapshotVersion GetPostMutationVersion(const MaybeDocument* maybe_doc); + std::string ToString() const { + return rep_ ? rep().ToString() : "(invalid)"; + } - virtual bool equal_to(const Mutation& other) const; + friend std::ostream& operator<<(std::ostream& os, const Mutation& mutation); - private: - const DocumentKey key_; - const Precondition precondition_; -}; + protected: + class Rep { + public: + Rep(DocumentKey&& key, Precondition&& precondition); -inline bool operator==(const Mutation& lhs, const Mutation& rhs) { - return lhs.equal_to(rhs); -} + virtual ~Rep() = default; -inline bool operator!=(const Mutation& lhs, const Mutation& rhs) { - return !(lhs == rhs); -} + virtual Type type() const = 0; -/** - * A mutation that creates or replaces the document at the given key with the - * object value contents. - */ -class SetMutation : public Mutation { - public: - SetMutation(DocumentKey&& key, - ObjectValue&& value, - Precondition&& precondition); + const DocumentKey& key() const { + return key_; + } - Type type() const override { - return Mutation::Type::kSet; - } + const Precondition& precondition() const { + return precondition_; + } - MaybeDocumentPtr ApplyToRemoteDocument( - const MaybeDocumentPtr& maybe_doc, - const MutationResult& mutation_result) const override; + virtual MaybeDocument ApplyToRemoteDocument( + const absl::optional& maybe_doc, + const MutationResult& mutation_result) const = 0; - MaybeDocumentPtr ApplyToLocalView( - const MaybeDocumentPtr& maybe_doc, - const MaybeDocument* base_doc, - const Timestamp& local_write_time) const override; + virtual absl::optional ApplyToLocalView( + const absl::optional& maybe_doc, + const absl::optional& base_doc, + const Timestamp& local_write_time) const = 0; - /** Returns the object value to use when setting the document. */ - const ObjectValue& value() const { - return value_; - } + virtual absl::optional ExtractBaseValue( + const absl::optional&) const { + return absl::nullopt; + } - protected: - bool equal_to(const Mutation& other) const override; + virtual bool Equals(const Rep& other) const; - private: - const ObjectValue value_; -}; + virtual size_t Hash() const; -/** - * A mutation that modifies fields of the document at the given key with the - * given values. The values are applied through a field mask: - * - * - When a field is in both the mask and the values, the corresponding field is - * updated. - * - When a field is in neither the mask nor the values, the corresponding field - * is unmodified. - * - When a field is in the mask but not in the values, the corresponding field - * is deleted. - * - When a field is not in the mask but is in the values, the values map is - * ignored. - */ -class PatchMutation : public Mutation { - public: - PatchMutation(DocumentKey&& key, - ObjectValue&& value, - FieldMask&& mask, - Precondition&& precondition); + virtual std::string ToString() const = 0; - Type type() const override { - return Mutation::Type::kPatch; - } + protected: + void VerifyKeyMatches(const absl::optional& maybe_doc) const; - MaybeDocumentPtr ApplyToRemoteDocument( - const MaybeDocumentPtr& maybe_doc, - const MutationResult& mutation_result) const override; + static SnapshotVersion GetPostMutationVersion( + const absl::optional& maybe_doc); - MaybeDocumentPtr ApplyToLocalView( - const MaybeDocumentPtr& maybe_doc, - const MaybeDocument* base_doc, - const Timestamp& local_write_time) const override; + private: + DocumentKey key_; + Precondition precondition_; + }; - /** - * Returns the fields and associated values to use when patching the document. - */ - const ObjectValue& value() const { - return value_; + explicit Mutation(std::shared_ptr&& rep) : rep_(std::move(rep)) { } - /** - * Returns the mask to apply to value(), where only fields that are in both - * the field_mask and the value will be updated. - */ - const FieldMask& mask() const { - return mask_; + const Rep& rep() const { + return *NOT_NULL(rep_); } - protected: - bool equal_to(const Mutation& other) const override; - private: - ObjectValue PatchDocument(const MaybeDocument* maybe_doc) const; - ObjectValue PatchObject(ObjectValue obj) const; - - const ObjectValue value_; - const FieldMask mask_; + std::shared_ptr rep_; }; -/** Represents a Delete operation. */ -class DeleteMutation : public Mutation { - public: - DeleteMutation(DocumentKey&& key, Precondition&& precondition); - - Type type() const override { - return Mutation::Type::kDelete; - } - - MaybeDocumentPtr ApplyToRemoteDocument( - const MaybeDocumentPtr& maybe_doc, - const MutationResult& mutation_result) const override; - - MaybeDocumentPtr ApplyToLocalView( - const MaybeDocumentPtr& maybe_doc, - const MaybeDocument* base_doc, - const Timestamp& local_write_time) const override; -}; +inline bool operator!=(const Mutation& lhs, const Mutation& rhs) { + return !(lhs == rhs); +} } // namespace model } // namespace firestore diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation_batch.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation_batch.cc index 8c339bd..1ceede2 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation_batch.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation_batch.cc @@ -16,51 +16,123 @@ #include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" +#include #include +#include "Firestore/core/src/firebase/firestore/model/mutation_batch_result.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/to_string.h" namespace firebase { namespace firestore { namespace model { -namespace { - -/** - * Compares two vectors of unique pointers, and ensures the Mutation contents of - * the pointer (not just the memory address itself) is equal. - */ -bool deep_equals(const std::vector>& lhs, - const std::vector>& rhs) { - if (lhs.size() != rhs.size()) return false; - - for (size_t i = 0; i < lhs.size(); i++) { - if (!lhs[i] && !rhs[i]) - continue; - else if (!lhs[i] || !rhs[i]) - return false; - else if (*lhs[i] != *rhs[i]) - return false; - } - - return true; -} - -} // namespace - MutationBatch::MutationBatch(int batch_id, Timestamp local_write_time, - std::vector>&& mutations) + std::vector base_mutations, + std::vector mutations) : batch_id_(batch_id), local_write_time_(std::move(local_write_time)), + base_mutations_(std::move(base_mutations)), mutations_(std::move(mutations)) { HARD_ASSERT(!mutations_.empty(), "Cannot create an empty mutation batch"); } +absl::optional MutationBatch::ApplyToRemoteDocument( + absl::optional maybe_doc, + const DocumentKey& document_key, + const MutationBatchResult& mutation_batch_result) const { + HARD_ASSERT(!maybe_doc || maybe_doc->key() == document_key, + "ApplyTo: key %s doesn't match maybe_doc key %s", + document_key.ToString(), maybe_doc->key().ToString()); + + const auto& mutation_results = mutation_batch_result.mutation_results(); + HARD_ASSERT(mutation_results.size() == mutations_.size(), + "Mismatch between mutations length (%s) and results length (%s)", + mutations_.size(), mutation_results.size()); + + for (size_t i = 0; i < mutations_.size(); i++) { + const Mutation& mutation = mutations_[i]; + const MutationResult& mutation_result = mutation_results[i]; + if (mutation.key() == document_key) { + maybe_doc = mutation.ApplyToRemoteDocument(maybe_doc, mutation_result); + } + } + return maybe_doc; +} + +absl::optional MutationBatch::ApplyToLocalDocument( + absl::optional maybe_doc, + const DocumentKey& document_key) const { + HARD_ASSERT(!maybe_doc || maybe_doc->key() == document_key, + "key %s doesn't match maybe_doc key %s", document_key.ToString(), + maybe_doc->key().ToString()); + + // First, apply the base state. This allows us to apply non-idempotent + // transform against a consistent set of values. + for (const Mutation& mutation : base_mutations_) { + if (mutation.key() == document_key) { + maybe_doc = + mutation.ApplyToLocalView(maybe_doc, maybe_doc, local_write_time_); + } + } + + absl::optional base_doc = maybe_doc; + + // Second, apply all user-provided mutations. + for (const Mutation& mutation : mutations_) { + if (mutation.key() == document_key) { + maybe_doc = + mutation.ApplyToLocalView(maybe_doc, base_doc, local_write_time_); + } + } + return maybe_doc; +} + +MaybeDocumentMap MutationBatch::ApplyToLocalDocumentSet( + const MaybeDocumentMap& document_set) const { + // TODO(mrschmidt): This implementation is O(n^2). If we iterate through the + // mutations first (as done in `applyToLocalDocument:documentKey:`), we can + // reduce the complexity to O(n). + + MaybeDocumentMap mutated_documents = document_set; + for (const Mutation& mutation : mutations_) { + const DocumentKey& key = mutation.key(); + + absl::optional previous_document = + mutated_documents.get(key); + absl::optional mutated_document = + ApplyToLocalDocument(std::move(previous_document), key); + if (mutated_document) { + mutated_documents = mutated_documents.insert(key, *mutated_document); + } + } + return mutated_documents; +} + +DocumentKeySet MutationBatch::keys() const { + DocumentKeySet set; + for (const Mutation& mutation : mutations_) { + set = set.insert(mutation.key()); + } + return set; +} + bool operator==(const MutationBatch& lhs, const MutationBatch& rhs) { return lhs.batch_id() == rhs.batch_id() && lhs.local_write_time() == rhs.local_write_time() && - deep_equals(lhs.mutations(), rhs.mutations()); + lhs.base_mutations() == rhs.base_mutations() && + lhs.mutations() == rhs.mutations(); +} + +std::string MutationBatch::ToString() const { + return absl::StrCat("MutationBatch(id=", batch_id_, + ", local_write_time=", local_write_time_.ToString(), + ", mutations=", util::ToString(mutations_), ")"); +} + +std::ostream& operator<<(std::ostream& os, const MutationBatch& batch) { + return os << batch.ToString(); } } // namespace model diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation_batch.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation_batch.h index 6c498d5..3d3d851 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation_batch.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation_batch.h @@ -17,10 +17,14 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_MUTATION_BATCH_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_MUTATION_BATCH_H_ +#include #include +#include #include #include "Firestore/core/include/firebase/firestore/timestamp.h" +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/document_map.h" #include "Firestore/core/src/firebase/firestore/model/mutation.h" #include "Firestore/core/src/firebase/firestore/model/types.h" @@ -28,9 +32,11 @@ namespace firebase { namespace firestore { namespace model { +class MutationBatchResult; + /** - * A BatchID that was searched for and not found or a batch ID value known to be - * before all known batches. + * A BatchID that was searched for and not found or a batch ID value known to + * be before all known batches. * * BatchId values from the local store are non-negative so this value is before * all batches. @@ -47,8 +53,8 @@ constexpr BatchId kBatchIdUnknown = -1; class MutationBatch { public: /** - * A batch ID that was searched for and not found or a batch ID value known to - * be before all known batches. + * A batch ID that was searched for and not found or a batch ID value known + * to be before all known batches. * * Batch ID values from the local store are non-negative so this value is * before all batches. @@ -57,12 +63,10 @@ class MutationBatch { MutationBatch(int batch_id, Timestamp local_write_time, - std::vector>&& mutations); - - // TODO(rsgowman): Port ApplyToRemoteDocument() - // TODO(rsgowman): Port ApplyToLocalView() - // TODO(rsgowman): Port GetKeys() + std::vector base_mutations, + std::vector mutations); + /** The unique ID of this mutation batch. */ int batch_id() const { return batch_id_; } @@ -75,18 +79,80 @@ class MutationBatch { return local_write_time_; } - const std::vector>& mutations() const { + /** + * Mutations that are used to populate the base values when this mutation is + * applied locally. This can be used to locally overwrite values that are + * persisted in the remote document cache. Base mutations are never sent to + * the backend. + */ + const std::vector& base_mutations() const { + return base_mutations_; + } + + /** + * The user-provided mutations in this mutation batch. User-provided + * mutations are applied both locally and remotely on the backend. + */ + const std::vector& mutations() const { return mutations_; } + /** + * Applies all the mutations in this MutationBatch to the specified document + * to create a new remote document. + * + * @param maybe_doc The document to which to apply mutations or nullopt if + * there's no existing document. + * @param document_key The key of the document to apply mutations to. + * @param mutation_batch_result The result of applying the MutationBatch to + * the backend. + */ + absl::optional ApplyToRemoteDocument( + absl::optional maybe_doc, + const DocumentKey& document_key, + const MutationBatchResult& mutation_batch_result) const; + + /** + * Estimates the latency compensated view of all the mutations in this batch + * applied to the given MaybeDocument. + * + * Unlike ApplyToRemoteDocument, this method is used before the mutation has + * been committed and so it's possible that the mutation is operating on a + * locally non-existent document and may produce a non-existent document. + * + * @param maybe_doc The document to which to apply mutations or nullopt if + * there's no existing document. + * @param document_key The key of the document to apply mutations to. + */ + absl::optional ApplyToLocalDocument( + absl::optional maybe_doc, + const DocumentKey& document_key) const; + + /** + * Computes the local view for all provided documents given the mutations in + * this batch. + */ + MaybeDocumentMap ApplyToLocalDocumentSet( + const MaybeDocumentMap& document_set) const; + + /** + * Returns the set of unique keys referenced by all mutations in the batch. + */ + DocumentKeySet keys() const; + + friend bool operator==(const MutationBatch& lhs, const MutationBatch& rhs); + + std::string ToString() const; + + friend std::ostream& operator<<(std::ostream& os, const MutationBatch& batch); + private: int batch_id_; - const Timestamp local_write_time_; - std::vector> mutations_; + Timestamp local_write_time_; + std::vector base_mutations_; + std::vector mutations_; }; -bool operator==(const MutationBatch& lhs, const MutationBatch& rhs); - inline bool operator!=(const MutationBatch& lhs, const MutationBatch& rhs) { return !(lhs == rhs); } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation_batch_result.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation_batch_result.cc new file mode 100644 index 0000000..d79b041 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation_batch_result.cc @@ -0,0 +1,72 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/model/mutation_batch_result.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/mutation.h" +#include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/to_string.h" +#include "absl/strings/str_cat.h" + +namespace firebase { +namespace firestore { +namespace model { + +MutationBatchResult::MutationBatchResult( + MutationBatch batch, + model::SnapshotVersion commit_version, + std::vector mutation_results, + nanopb::ByteString stream_token) + : batch_(std::move(batch)), + commit_version_(commit_version), + mutation_results_(std::move(mutation_results)), + stream_token_(std::move(stream_token)) { + HARD_ASSERT(batch_.mutations().size() == mutation_results_.size(), + "Number of mutations sent %s must equal results received %s", + batch_.mutations().size(), mutation_results_.size()); + + const auto& mutations = batch_.mutations(); + for (size_t i = 0; i < mutations.size(); i++) { + absl::optional version = mutation_results_[i].version(); + if (!version) { + // Deletes don't have a version, so we substitute the commit_version + // of the entire batch. + version = commit_version_; + } + + const DocumentKey& key = mutations[i].key(); + doc_versions_[key] = *version; + } +} + +std::string MutationBatchResult::ToString() const { + return absl::StrCat("MutationBatchResult(batch=", batch_.ToString(), + ", commit_version=", commit_version_.ToString(), + ", mutation_results=", util::ToString(mutation_results_), + ", stream_token=", util::ToString(stream_token_), ")"); +} + +std::ostream& operator<<(std::ostream& os, const MutationBatchResult& result) { + return os << result.ToString(); +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation_batch_result.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation_batch_result.h new file mode 100644 index 0000000..447dfab --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/mutation_batch_result.h @@ -0,0 +1,96 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_MUTATION_BATCH_RESULT_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_MUTATION_BATCH_RESULT_H_ + +#include +#include +#include +#include +#include + +#include "Firestore/core/include/firebase/firestore/timestamp.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/document_map.h" +#include "Firestore/core/src/firebase/firestore/model/mutation.h" +#include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" + +namespace firebase { +namespace firestore { +namespace model { + +using DocumentVersionMap = + std::unordered_map; + +/** + * The result of applying a mutation batch to the backend. + * + * Note that unlike most classes in firebase::firestore::model, this class is + * just a grouping of result values and is not optimized for copying. + */ +class MutationBatchResult { + public: + /** + * Creates a new MutationBatchResult for the given batch and results. There + * must be one result for each mutation in the batch. This constructor caches + * a document=>version mapping (as doc_versions()). + */ + MutationBatchResult(MutationBatch batch, + SnapshotVersion commit_version, + std::vector mutation_results, + nanopb::ByteString stream_token); + + const MutationBatch& batch() const { + return batch_; + } + + const SnapshotVersion& commit_version() const { + return commit_version_; + } + + const std::vector& mutation_results() const { + return mutation_results_; + } + + const nanopb::ByteString& stream_token() const { + return stream_token_; + } + + const DocumentVersionMap& doc_versions() const { + return doc_versions_; + } + + std::string ToString() const; + + friend std::ostream& operator<<(std::ostream& os, + const MutationBatchResult& result); + + private: + MutationBatch batch_; + SnapshotVersion commit_version_; + std::vector mutation_results_; + nanopb::ByteString stream_token_; + DocumentVersionMap doc_versions_; +}; + +} // namespace model +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_MUTATION_BATCH_RESULT_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/no_document.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/no_document.cc index 5f348af..3974774 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/no_document.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/no_document.cc @@ -16,18 +16,72 @@ #include "Firestore/core/src/firebase/firestore/model/no_document.h" +#include #include +#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "absl/strings/str_cat.h" + namespace firebase { namespace firestore { namespace model { +static_assert( + sizeof(MaybeDocument) == sizeof(NoDocument), + "NoDocument may not have additional members (everything goes in Rep)"); + +class NoDocument::Rep : public MaybeDocument::Rep { + public: + Rep(DocumentKey key, SnapshotVersion version, bool has_committed_mutations) + : MaybeDocument::Rep(Type::NoDocument, std::move(key), version), + has_committed_mutations_(has_committed_mutations) { + } + + bool has_pending_writes() const override { + return has_committed_mutations_; + } + + bool Equals(const MaybeDocument::Rep& other) const override { + if (!MaybeDocument::Rep::Equals(other)) return false; + + const auto& other_rep = static_cast(other); + return has_committed_mutations_ == other_rep.has_committed_mutations_; + } + + size_t Hash() const override { + return util::Hash(MaybeDocument::Rep::Hash(), has_committed_mutations_); + } + + std::string ToString() const override { + return absl::StrCat( + "NoDocument(key=", key().ToString(), ", version=", version().ToString(), + ", has_committed_mutations=", has_committed_mutations_, ")"); + } + + private: + friend class NoDocument; + + bool has_committed_mutations_ = false; +}; + NoDocument::NoDocument(DocumentKey key, SnapshotVersion version, bool has_committed_mutations) - : MaybeDocument(std::move(key), std::move(version)), - has_committed_mutations_(has_committed_mutations) { - set_type(Type::NoDocument); + : MaybeDocument(std::make_shared( + std::move(key), version, has_committed_mutations)) { +} + +NoDocument::NoDocument(const MaybeDocument& document) + : MaybeDocument(document) { + HARD_ASSERT(type() == Type::NoDocument); +} + +bool NoDocument::has_committed_mutations() const { + return doc_rep().has_committed_mutations_; +} + +const NoDocument::Rep& NoDocument::doc_rep() const { + return static_cast(MaybeDocument::rep()); } } // namespace model diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/no_document.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/no_document.h index da2cac0..15b4319 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/no_document.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/no_document.h @@ -17,6 +17,8 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_NO_DOCUMENT_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_NO_DOCUMENT_H_ +#include + #include "Firestore/core/src/firebase/firestore/model/maybe_document.h" namespace firebase { @@ -30,12 +32,22 @@ class NoDocument : public MaybeDocument { SnapshotVersion version, bool has_committed_mutations); - bool HasPendingWrites() const override { - return has_committed_mutations_; - } + /** + * Casts a MaybeDocument to a NoDocument. This is a checked operation that + * will assert if the type of the MaybeDocument isn't actually + * Type::NoDocument. + */ + explicit NoDocument(const MaybeDocument& document); + + /** Creates an invalid NoDocument instance. */ + NoDocument() = default; + + bool has_committed_mutations() const; private: - bool has_committed_mutations_; + class Rep; + + const Rep& doc_rep() const; }; } // namespace model diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/patch_mutation.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/patch_mutation.cc new file mode 100644 index 0000000..1b758e8 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/patch_mutation.cc @@ -0,0 +1,140 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/model/patch_mutation.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/document.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/model/no_document.h" +#include "Firestore/core/src/firebase/firestore/model/unknown_document.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" + +namespace firebase { +namespace firestore { +namespace model { + +static_assert( + sizeof(Mutation) == sizeof(PatchMutation), + "PatchMutation may not have additional members (everything goes in Rep)"); + +PatchMutation::PatchMutation(DocumentKey key, + ObjectValue value, + FieldMask mask, + Precondition precondition) + : Mutation(std::make_shared(std::move(key), + std::move(value), + std::move(mask), + std::move(precondition))) { +} + +PatchMutation::PatchMutation(const Mutation& mutation) : Mutation(mutation) { + HARD_ASSERT(type() == Type::Patch); +} + +PatchMutation::Rep::Rep(DocumentKey&& key, + ObjectValue&& value, + FieldMask&& mask, + Precondition&& precondition) + : Mutation::Rep(std::move(key), std::move(precondition)), + value_(std::move(value)), + mask_(std::move(mask)) { +} + +MaybeDocument PatchMutation::Rep::ApplyToRemoteDocument( + const absl::optional& maybe_doc, + const MutationResult& mutation_result) const { + VerifyKeyMatches(maybe_doc); + HARD_ASSERT(mutation_result.transform_results() == absl::nullopt, + "Transform results received by PatchMutation."); + + if (!precondition().IsValidFor(maybe_doc)) { + // Since the mutation was not rejected, we know that the precondition + // matched on the backend. We therefore must not have the expected version + // of the document in our cache and return an UnknownDocument with the known + // update_time. + return UnknownDocument(key(), mutation_result.version()); + } + + ObjectValue new_data = PatchDocument(maybe_doc); + const SnapshotVersion& version = mutation_result.version(); + return Document(std::move(new_data), key(), version, + DocumentState::kCommittedMutations); +} + +absl::optional PatchMutation::Rep::ApplyToLocalView( + const absl::optional& maybe_doc, + const absl::optional&, + const Timestamp&) const { + VerifyKeyMatches(maybe_doc); + + if (!precondition().IsValidFor(maybe_doc)) { + return maybe_doc; + } + + ObjectValue new_data = PatchDocument(maybe_doc); + SnapshotVersion version = GetPostMutationVersion(maybe_doc); + return Document(std::move(new_data), key(), version, + DocumentState::kLocalMutations); +} + +ObjectValue PatchMutation::Rep::PatchDocument( + const absl::optional& maybe_doc) const { + if (maybe_doc && maybe_doc->type() == MaybeDocument::Type::Document) { + return PatchObject(Document(*maybe_doc).data()); + } else { + return PatchObject(ObjectValue::Empty()); + } +} + +ObjectValue PatchMutation::Rep::PatchObject(ObjectValue obj) const { + for (const FieldPath& path : mask_) { + if (!path.empty()) { + absl::optional new_value = value_.Get(path); + if (!new_value) { + obj = obj.Delete(path); + } else { + obj = obj.Set(path, *new_value); + } + } + } + return obj; +} + +bool PatchMutation::Rep::Equals(const Mutation::Rep& other) const { + if (!Mutation::Rep::Equals(other)) return false; + + const auto& other_rep = static_cast(other); + return value_ == other_rep.value_ && mask_ == other_rep.mask_; +} + +size_t PatchMutation::Rep::Hash() const { + return util::Hash(Mutation::Rep::Hash(), mask_, value_); +} + +std::string PatchMutation::Rep::ToString() const { + return absl::StrCat("PatchMutation(key=", key().ToString(), + ", precondition=", precondition().ToString(), + ", value=", value().ToString(), + ", mask=", mask().ToString(), ")"); +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/patch_mutation.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/patch_mutation.h new file mode 100644 index 0000000..64101fc --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/patch_mutation.h @@ -0,0 +1,136 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_PATCH_MUTATION_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_PATCH_MUTATION_H_ + +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/field_mask.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" +#include "Firestore/core/src/firebase/firestore/model/mutation.h" +#include "Firestore/core/src/firebase/firestore/model/precondition.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace model { + +/** + * A mutation that modifies fields of the document at the given key with the + * given values. The values are applied through a field mask: + * + * - When a field is in both the mask and the values, the corresponding field is + * updated. + * - When a field is in neither the mask nor the values, the corresponding field + * is unmodified. + * - When a field is in the mask but not in the values, the corresponding field + * is deleted. + * - When a field is not in the mask but is in the values, the values map is + * ignored. + */ +class PatchMutation : public Mutation { + public: + PatchMutation(DocumentKey key, + ObjectValue value, + FieldMask mask, + Precondition precondition); + + /** + * Casts a Mutation to a PatchMutation. This is a checked operation that will + * assert if the type of the Mutation isn't actually Type::Patch. + */ + explicit PatchMutation(const Mutation& mutation); + + /** Creates an invalid PatchMutation instance. */ + PatchMutation() = default; + + /** + * Returns the fields and associated values to use when patching the document. + */ + const ObjectValue& value() const { + return patch_rep().value(); + } + + /** + * Returns the mask to apply to value(), where only fields that are in both + * the field_mask and the value will be updated. + */ + const FieldMask& mask() const { + return patch_rep().mask(); + } + + private: + class Rep : public Mutation::Rep { + public: + Rep(DocumentKey&& key, + ObjectValue&& value, + FieldMask&& mask, + Precondition&& precondition); + + Type type() const override { + return Type::Patch; + } + + const ObjectValue& value() const { + return value_; + } + + const FieldMask& mask() const { + return mask_; + } + + MaybeDocument ApplyToRemoteDocument( + const absl::optional& maybe_doc, + const MutationResult& mutation_result) const override; + + absl::optional ApplyToLocalView( + const absl::optional& maybe_doc, + const absl::optional&, + const Timestamp&) const override; + + bool Equals(const Mutation::Rep& other) const override; + + size_t Hash() const override; + + std::string ToString() const override; + + private: + ObjectValue PatchDocument( + const absl::optional& maybe_doc) const; + + ObjectValue PatchObject(ObjectValue obj) const; + + ObjectValue value_; + FieldMask mask_; + }; + + const Rep& patch_rep() const { + return static_cast(rep()); + } +}; + +} // namespace model +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_PATCH_MUTATION_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/precondition.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/precondition.cc index 4d22eaa..ab5b1a6 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/precondition.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/precondition.cc @@ -19,6 +19,7 @@ #include "Firestore/core/src/firebase/firestore/model/maybe_document.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "absl/strings/str_cat.h" namespace firebase { namespace firestore { @@ -45,14 +46,14 @@ Precondition Precondition::None() { return Precondition{Type::None, SnapshotVersion::None(), false}; } -bool Precondition::IsValidFor(const MaybeDocument* maybe_doc) const { +bool Precondition::IsValidFor( + const absl::optional& maybe_doc) const { switch (type_) { case Type::UpdateTime: - return maybe_doc != nullptr && - maybe_doc->type() == MaybeDocument::Type::Document && + return maybe_doc && maybe_doc->type() == MaybeDocument::Type::Document && maybe_doc->version() == update_time_; case Type::Exists: - return (exists_ == (maybe_doc != nullptr && + return (exists_ == (maybe_doc && maybe_doc->type() == MaybeDocument::Type::Document)); case Type::None: return true; @@ -60,6 +61,23 @@ bool Precondition::IsValidFor(const MaybeDocument* maybe_doc) const { UNREACHABLE(); } +size_t Precondition::Hash() const { + return util::Hash(update_time_, exists_, type_); +} + +std::string Precondition::ToString() const { + switch (type_) { + case Type::None: + return "Precondition()"; + case Type::Exists: + return absl::StrCat("Precondition(exists=", exists_, ")"); + case Type::UpdateTime: + return absl::StrCat("Precondition(update_time=", update_time_.ToString(), + ")"); + } + UNREACHABLE(); +} + } // namespace model } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/precondition.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/precondition.h index 6f9bb43..bda237f 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/precondition.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/precondition.h @@ -17,16 +17,13 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_PRECONDITION_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_PRECONDITION_H_ +#include #include -#if defined(__OBJC__) -#import "Firestore/Source/Model/FSTDocument.h" -#include "Firestore/core/include/firebase/firestore/timestamp.h" -#endif // defined(__OBJC__) - #include "Firestore/core/src/firebase/firestore/model/maybe_document.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "absl/types/optional.h" namespace firebase { namespace firestore { @@ -54,21 +51,27 @@ class Precondition { /** Returns a precondition representing no precondition. */ static Precondition None(); + /** + * Default constructor which is equivalent to Precondition::None(). Prefer + * calling Precondition::None for readability. + */ + Precondition() = default; + /** * Returns true if the precondition is valid for the given document (and the * document is available). */ - bool IsValidFor(const MaybeDocument* maybe_doc) const; - - /** Returns whether this Precondition represents no precondition. */ - bool IsNone() const { - return type_ == Type::None; - } + bool IsValidFor(const absl::optional& maybe_doc) const; Type type() const { return type_; } + /** Returns whether this Precondition represents no precondition. */ + bool is_none() const { + return type_ == Type::None; + } + const SnapshotVersion& update_time() const { return update_time_; } @@ -82,61 +85,9 @@ class Precondition { exists_ == other.exists_; } -#if defined(__OBJC__) - // Objective-C requires a default constructor. - Precondition() - : type_(Type::None), - update_time_(SnapshotVersion::None()), - exists_(false) { - } + size_t Hash() const; - // MaybeDocument is not fully ported yet. So we suppose this addition helper. - bool IsValidFor(FSTMaybeDocument* maybe_doc) const { - switch (type_) { - case Type::UpdateTime: - return [maybe_doc isKindOfClass:[FSTDocument class]] && - firebase::firestore::model::SnapshotVersion(maybe_doc.version) == - update_time_; - case Type::Exists: - if (exists_) { - return [maybe_doc isKindOfClass:[FSTDocument class]]; - } else { - return maybe_doc == nil || - [maybe_doc isKindOfClass:[FSTDeletedDocument class]]; - } - case Type::None: - return true; - } - UNREACHABLE(); - } - - // For Objective-C++ hash; to be removed after migration. - // Do NOT use in C++ code. - NSUInteger Hash() const { - NSUInteger hash = std::hash()(update_time_.timestamp()); - hash = hash * 31 + exists_; - hash = hash * 31 + static_cast(type_); - return hash; - } - - NSString* description() const { - switch (type_) { - case Type::None: - return @">"; - case Type::Exists: - if (exists_) { - return @""; - } else { - return @""; - } - case Type::UpdateTime: - return [NSString - stringWithFormat:@"", - update_time_.timestamp().ToString().c_str()]; - } - UNREACHABLE(); - } -#endif // defined(__OBJC__) + std::string ToString() const; private: Precondition(Type type, SnapshotVersion update_time, bool exists); @@ -144,12 +95,13 @@ class Precondition { // The actual time of this precondition. Type type_ = Type::None; - // For UpdateTime type, preconditions a mutation based on the last updateTime. + // For UpdateTime type, preconditions a mutation based on the last + // update_time_. SnapshotVersion update_time_; // For Exists type, preconditions a mutation based on whether the document // exists. - bool exists_; + bool exists_ = false; }; } // namespace model diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/resource_path.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/resource_path.cc index cdd795f..b0ca7d5 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/resource_path.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/resource_path.cc @@ -28,7 +28,11 @@ namespace firebase { namespace firestore { namespace model { -ResourcePath ResourcePath::FromString(const absl::string_view path) { +ResourcePath ResourcePath::FromString(const std::string& path) { + return FromStringView(path); +} + +ResourcePath ResourcePath::FromStringView(absl::string_view path) { // NOTE: The client is ignorant of any path segments containing escape // sequences (e.g. __id123__) and just passes them through raw (they exist // for legacy reasons and should not be used frequently). diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/resource_path.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/resource_path.h index a149dc8..0198375 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/resource_path.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/resource_path.h @@ -22,17 +22,23 @@ #include #include "Firestore/core/src/firebase/firestore/model/base_path.h" +#include "Firestore/core/src/firebase/firestore/util/comparison.h" #include "absl/strings/string_view.h" namespace firebase { namespace firestore { +namespace remote { +class Serializer; +} // namespace remote + namespace model { /** * A slash-separated path for navigating resources (documents and collections) * within Firestore. Immutable; all instances are fully independent. */ -class ResourcePath : public impl::BasePath { +class ResourcePath : public impl::BasePath, + public util::InequalityComparable { public: ResourcePath() = default; /** Constructs the path from segments. */ @@ -47,33 +53,23 @@ class ResourcePath : public impl::BasePath { * Creates and returns a new path from the given resource-path string, where * the path segments are separated by a slash "/". */ - static ResourcePath FromString(absl::string_view path); + static ResourcePath FromString(const std::string& path); + + private: + // TODO(b/146372592): Make this public once we can use Abseil across + // iOS/public C++ library boundaries. + friend class DocumentKey; + friend class remote::Serializer; + + static ResourcePath FromStringView(absl::string_view path); + public: static ResourcePath Empty() { return ResourcePath{}; } /** Returns a standardized string representation of this path. */ std::string CanonicalString() const; - - bool operator==(const ResourcePath& rhs) const { - return BasePath::operator==(rhs); - } - bool operator!=(const ResourcePath& rhs) const { - return BasePath::operator!=(rhs); - } - bool operator<(const ResourcePath& rhs) const { - return BasePath::operator<(rhs); - } - bool operator>(const ResourcePath& rhs) const { - return BasePath::operator>(rhs); - } - bool operator<=(const ResourcePath& rhs) const { - return BasePath::operator<=(rhs); - } - bool operator>=(const ResourcePath& rhs) const { - return BasePath::operator>=(rhs); - } }; } // namespace model diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/set_mutation.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/set_mutation.cc new file mode 100644 index 0000000..72824e2 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/set_mutation.cc @@ -0,0 +1,104 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/model/set_mutation.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/document.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/model/no_document.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "absl/strings/str_cat.h" + +namespace firebase { +namespace firestore { +namespace model { + +static_assert( + sizeof(Mutation) == sizeof(SetMutation), + "SetMutation may not have additional members (everything goes in Rep)"); + +SetMutation::SetMutation(DocumentKey key, + ObjectValue value, + Precondition precondition) + : Mutation(std::make_shared( + std::move(key), std::move(value), std::move(precondition))) { +} + +SetMutation::SetMutation(const Mutation& mutation) : Mutation(mutation) { + HARD_ASSERT(type() == Type::Set); +} + +SetMutation::Rep::Rep(DocumentKey&& key, + ObjectValue&& value, + Precondition&& precondition) + : Mutation::Rep(std::move(key), std::move(precondition)), + value_(std::move(value)) { +} + +MaybeDocument SetMutation::Rep::ApplyToRemoteDocument( + const absl::optional& maybe_doc, + const MutationResult& mutation_result) const { + VerifyKeyMatches(maybe_doc); + + HARD_ASSERT(mutation_result.transform_results() == absl::nullopt, + "Transform results received by SetMutation."); + + // Unlike ApplyToLocalView, if we're applying a mutation to a remote document + // the server has accepted the mutation so the precondition must have held. + + const SnapshotVersion& version = mutation_result.version(); + return Document(value_, key(), version, DocumentState::kCommittedMutations); +} + +absl::optional SetMutation::Rep::ApplyToLocalView( + const absl::optional& maybe_doc, + const absl::optional&, + const Timestamp&) const { + VerifyKeyMatches(maybe_doc); + + if (!precondition().IsValidFor(maybe_doc)) { + return maybe_doc; + } + + SnapshotVersion version = GetPostMutationVersion(maybe_doc); + return Document(value_, key(), version, DocumentState::kLocalMutations); +} + +bool SetMutation::Rep::Equals(const Mutation::Rep& other) const { + if (!Mutation::Rep::Equals(other)) return false; + + const auto& other_rep = static_cast(other); + return value_ == other_rep.value_; +} + +size_t SetMutation::Rep::Hash() const { + return util::Hash(Mutation::Rep::Hash(), value_); +} + +std::string SetMutation::Rep::ToString() const { + return absl::StrCat("SetMutation(key=", key().ToString(), + ", precondition=", precondition().ToString(), + ", value=", value().ToString(), ")"); +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/set_mutation.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/set_mutation.h new file mode 100644 index 0000000..6d7c9f2 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/set_mutation.h @@ -0,0 +1,101 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_SET_MUTATION_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_SET_MUTATION_H_ + +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/field_mask.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" +#include "Firestore/core/src/firebase/firestore/model/mutation.h" +#include "Firestore/core/src/firebase/firestore/model/precondition.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace model { + +/** + * A mutation that creates or replaces the document at the given key with the + * object value contents. + */ +class SetMutation : public Mutation { + public: + SetMutation(DocumentKey key, ObjectValue value, Precondition precondition); + + /** + * Casts a Mutation to a SetMutation. This is a checked operation that will + * assert if the type of the Mutation isn't actually Type::Set. + */ + explicit SetMutation(const Mutation& mutation); + + /** Creates an invalid SetMutation instance. */ + SetMutation() = default; + + /** Returns the object value to use when setting the document. */ + const ObjectValue& value() const { + return set_rep().value(); + } + + private: + class Rep : public Mutation::Rep { + public: + Rep(DocumentKey&& key, ObjectValue&& value, Precondition&& precondition); + + Type type() const override { + return Type::Set; + } + + const ObjectValue& value() const { + return value_; + } + + MaybeDocument ApplyToRemoteDocument( + const absl::optional& maybe_doc, + const MutationResult& mutation_result) const override; + + absl::optional ApplyToLocalView( + const absl::optional& maybe_doc, + const absl::optional&, + const Timestamp&) const override; + + bool Equals(const Mutation::Rep& other) const override; + + size_t Hash() const override; + + std::string ToString() const override; + + private: + ObjectValue value_; + }; + + const Rep& set_rep() const { + return static_cast(rep()); + } +}; + +} // namespace model +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_SET_MUTATION_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/snapshot_version.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/snapshot_version.cc index 114e313..eed605f 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/snapshot_version.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/snapshot_version.cc @@ -16,6 +16,10 @@ #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include + +#include "Firestore/core/src/firebase/firestore/util/hashing.h" + namespace firebase { namespace firestore { namespace model { @@ -29,6 +33,23 @@ const SnapshotVersion& SnapshotVersion::None() { return kNone; } +util::ComparisonResult SnapshotVersion::CompareTo( + const SnapshotVersion& rhs) const { + return util::Compare(timestamp(), rhs.timestamp()); +} + +size_t SnapshotVersion::Hash() const { + return util::Hash(timestamp_.seconds(), timestamp_.nanoseconds()); +} + +std::string SnapshotVersion::ToString() const { + return timestamp_.ToString(); +} + +std::ostream& operator<<(std::ostream& os, const SnapshotVersion& version) { + return os << version.timestamp_; +} + } // namespace model } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/snapshot_version.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/snapshot_version.h index dbecea1..f1ae0ce 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/snapshot_version.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/snapshot_version.h @@ -17,7 +17,11 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_SNAPSHOT_VERSION_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_SNAPSHOT_VERSION_H_ +#include +#include + #include "Firestore/core/include/firebase/firestore/timestamp.h" +#include "Firestore/core/src/firebase/firestore/util/comparison.h" namespace firebase { namespace firestore { @@ -27,12 +31,13 @@ namespace model { * A version of a document in Firestore. This corresponds to the version * timestamp, such as update_time or read_time. */ -class SnapshotVersion { +class SnapshotVersion : public util::Comparable { public: -#if __OBJC__ - SnapshotVersion() { - } -#endif // __OBJC__ + /** + * Creates a default SnapshotVersion equivalent to SnapshotVersion::None(). + * Prefer SnapshotVersion::None() for readability. + */ + SnapshotVersion() = default; explicit SnapshotVersion(const Timestamp& timestamp); @@ -43,40 +48,18 @@ class SnapshotVersion { /** Creates a new version that is smaller than all other versions. */ static const SnapshotVersion& None(); -#if __OBJC__ - size_t Hash() const { - return std::hash{}(timestamp_); - } -#endif // __OBJC__ - - private: - Timestamp timestamp_; -}; - -/** Compares against another SnapshotVersion. */ -inline bool operator<(const SnapshotVersion& lhs, const SnapshotVersion& rhs) { - return lhs.timestamp() < rhs.timestamp(); -} - -inline bool operator>(const SnapshotVersion& lhs, const SnapshotVersion& rhs) { - return lhs.timestamp() > rhs.timestamp(); -} + util::ComparisonResult CompareTo(const SnapshotVersion& rhs) const; -inline bool operator>=(const SnapshotVersion& lhs, const SnapshotVersion& rhs) { - return lhs.timestamp() >= rhs.timestamp(); -} + size_t Hash() const; -inline bool operator<=(const SnapshotVersion& lhs, const SnapshotVersion& rhs) { - return lhs.timestamp() <= rhs.timestamp(); -} + std::string ToString() const; -inline bool operator!=(const SnapshotVersion& lhs, const SnapshotVersion& rhs) { - return lhs.timestamp() != rhs.timestamp(); -} + friend std::ostream& operator<<(std::ostream& os, + const SnapshotVersion& version); -inline bool operator==(const SnapshotVersion& lhs, const SnapshotVersion& rhs) { - return lhs.timestamp() == rhs.timestamp(); -} + private: + Timestamp timestamp_; +}; } // namespace model } // namespace firestore diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_mutation.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_mutation.cc new file mode 100644 index 0000000..796bb01 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_mutation.cc @@ -0,0 +1,222 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/model/transform_mutation.h" + +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/document.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/model/no_document.h" +#include "Firestore/core/src/firebase/firestore/model/transform_operation.h" +#include "Firestore/core/src/firebase/firestore/model/unknown_document.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/to_string.h" +#include "absl/strings/str_cat.h" + +namespace firebase { +namespace firestore { +namespace model { + +static_assert(sizeof(Mutation) == sizeof(TransformMutation), + "TransformMutation may not have additional members (everything " + "goes in Rep)"); + +TransformMutation::TransformMutation( + DocumentKey key, std::vector field_transforms) + : Mutation( + std::make_shared(std::move(key), std::move(field_transforms))) { +} + +TransformMutation::TransformMutation(const Mutation& mutation) + : Mutation(mutation) { + HARD_ASSERT(type() == Type::Transform); +} + +TransformMutation::Rep::Rep(DocumentKey&& key, + std::vector&& field_transforms) + : Mutation::Rep(std::move(key), Precondition::Exists(true)), + field_transforms_(std::move(field_transforms)) { + std::set fields; + for (const auto& transform : field_transforms_) { + fields.insert(transform.path()); + } + + field_mask_ = FieldMask(std::move(fields)); +} + +MaybeDocument TransformMutation::Rep::ApplyToRemoteDocument( + const absl::optional& maybe_doc, + const MutationResult& mutation_result) const { + VerifyKeyMatches(maybe_doc); + + HARD_ASSERT(mutation_result.transform_results() != absl::nullopt, + "Transform results missing from TransformMutation."); + + if (!precondition().IsValidFor(maybe_doc)) { + // Since the mutation was not rejected, we know that the precondition + // matched on the backend. We therefore must not have the expected version + // of the document in our cache and return an UnknownDocument with the + // known update_time. + return UnknownDocument(key(), mutation_result.version()); + } + + // We only support transforms with precondition exists, so we can only apply + // it to an existing document + HARD_ASSERT(maybe_doc && maybe_doc->is_document(), + "Unknown MaybeDocument type %s", maybe_doc->type()); + Document doc(*maybe_doc); + + HARD_ASSERT(mutation_result.transform_results() != absl::nullopt); + + std::vector transform_results = + ServerTransformResults(maybe_doc, *mutation_result.transform_results()); + + ObjectValue new_data = TransformObject(doc.data(), transform_results); + + return Document(std::move(new_data), key(), mutation_result.version(), + DocumentState::kCommittedMutations); +} + +absl::optional TransformMutation::Rep::ApplyToLocalView( + const absl::optional& maybe_doc, + const absl::optional& base_doc, + const Timestamp& local_write_time) const { + VerifyKeyMatches(maybe_doc); + + if (!precondition().IsValidFor(maybe_doc)) { + return maybe_doc; + } + + // We only support transforms with precondition exists, so we can only apply + // it to an existing document + HARD_ASSERT(maybe_doc && maybe_doc->is_document(), + "Unknown MaybeDocument type %s", maybe_doc->type()); + Document doc(*maybe_doc); + + std::vector transform_results = + LocalTransformResults(maybe_doc, base_doc, local_write_time); + ObjectValue new_data = TransformObject(doc.data(), transform_results); + + return Document(std::move(new_data), doc.key(), doc.version(), + DocumentState::kLocalMutations); +} + +absl::optional TransformMutation::Rep::ExtractBaseValue( + const absl::optional& maybe_doc) const { + absl::optional base_object; + + for (const FieldTransform& transform : field_transforms_) { + absl::optional existing_value; + if (maybe_doc && maybe_doc->is_document()) { + existing_value = Document(*maybe_doc).field(transform.path()); + } + + absl::optional coerced_value = + transform.transformation().ComputeBaseValue(existing_value); + if (coerced_value) { + if (!base_object) { + base_object = ObjectValue::Empty(); + } + base_object = base_object->Set(transform.path(), *coerced_value); + } + } + + return base_object; +} + +bool TransformMutation::Rep::Equals(const Mutation::Rep& other) const { + if (!Mutation::Rep::Equals(other)) return false; + + const auto& other_rep = static_cast(other); + return field_transforms_ == other_rep.field_transforms_; +} + +std::string TransformMutation::Rep::ToString() const { + return absl::StrCat("TransformMutation(key=", key().ToString(), + ", transforms=", util::ToString(field_transforms()), ")"); +} + +std::vector TransformMutation::Rep::ServerTransformResults( + const absl::optional& base_doc, + const std::vector& server_transform_results) const { + HARD_ASSERT(field_transforms_.size() == server_transform_results.size(), + "server transform result size (%s) should match field transforms " + "size (%s)", + server_transform_results.size(), field_transforms_.size()); + + std::vector transform_results; + for (size_t i = 0; i < server_transform_results.size(); i++) { + const FieldTransform& field_transform = field_transforms_[i]; + const TransformOperation& transform = field_transform.transformation(); + + absl::optional previous_value; + if (base_doc && base_doc->is_document()) { + previous_value = Document(*base_doc).field(field_transform.path()); + } + + transform_results.push_back(transform.ApplyToRemoteDocument( + previous_value, server_transform_results[i])); + } + return transform_results; +} + +std::vector TransformMutation::Rep::LocalTransformResults( + const absl::optional& maybe_doc, + const absl::optional& base_doc, + const Timestamp& local_write_time) const { + std::vector transform_results; + for (const FieldTransform& field_transform : field_transforms_) { + const TransformOperation& transform = field_transform.transformation(); + + absl::optional previous_value; + if (maybe_doc && maybe_doc->is_document()) { + previous_value = Document(*maybe_doc).field(field_transform.path()); + } + + if (!previous_value && base_doc && base_doc->is_document()) { + // If the current document does not contain a value for the mutated field, + // use the value that existed before applying this mutation batch. This + // solves an edge case where a PatchMutation clears the values in a nested + // map before the TransformMutation is applied. + previous_value = Document(*base_doc).field(field_transform.path()); + } + transform_results.push_back( + transform.ApplyToLocalView(previous_value, local_write_time)); + } + return transform_results; +} + +ObjectValue TransformMutation::Rep::TransformObject( + ObjectValue object_value, + const std::vector& transform_results) const { + HARD_ASSERT(transform_results.size() == field_transforms_.size(), + "Transform results size mismatch."); + + for (size_t i = 0; i < field_transforms_.size(); i++) { + const FieldTransform& field_transform = field_transforms_[i]; + const FieldPath& field_path = field_transform.path(); + object_value = object_value.Set(field_path, transform_results[i]); + } + return object_value; +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_mutation.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_mutation.h new file mode 100644 index 0000000..955a032 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_mutation.h @@ -0,0 +1,138 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TRANSFORM_MUTATION_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TRANSFORM_MUTATION_H_ + +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/field_mask.h" +#include "Firestore/core/src/firebase/firestore/model/field_transform.h" +#include "Firestore/core/src/firebase/firestore/model/mutation.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace model { + +/** + * A mutation that modifies specific fields of the document with transform + * operations. Tranforms include operation like increment and server + * timestamps. See tranform_operations.h for all supported operations. + * + * It is somewhat similar to a PatchMutation in that it patches specific fields + * and has no effect when applied to nullopt or a DeletedDocument (see comments + * on PatchMutation for more details). + */ +class TransformMutation : public Mutation { + public: + TransformMutation(DocumentKey key, + std::vector field_transforms); + + /** + * Casts a Mutation to a TransformMutation. This is a checked operation that + * will assert if the type of the Mutation isn't actually Type::Transform. + */ + explicit TransformMutation(const Mutation& mutation); + + /** Creates an invalid TransformMutation instance. */ + TransformMutation() = default; + + /** Returns the field transforms to use when transforming the document. */ + const std::vector& field_transforms() const { + return set_rep().field_transforms(); + } + + private: + class Rep : public Mutation::Rep { + public: + Rep(DocumentKey&& key, std::vector&& field_transforms); + + Type type() const override { + return Type::Transform; + } + + const std::vector& field_transforms() const { + return field_transforms_; + } + + MaybeDocument ApplyToRemoteDocument( + const absl::optional& maybe_doc, + const MutationResult& mutation_result) const override; + + absl::optional ApplyToLocalView( + const absl::optional& maybe_doc, + const absl::optional&, + const Timestamp&) const override; + + absl::optional ExtractBaseValue( + const absl::optional& maybe_doc) const override; + + bool Equals(const Mutation::Rep& other) const override; + + std::string ToString() const override; + + private: + /** + * Creates an array of "transform results" (a transform result is a field + * value representing the result of applying a transform) for use after a + * TransformMutation has been acknowledged by the server. + * + * @param base_doc The document prior to applying this mutation batch. + * @param server_transform_results The transform results received by the + * server. + * @return The transform results array. + */ + std::vector ServerTransformResults( + const absl::optional& base_doc, + const std::vector& server_transform_results) const; + + /** + * Creates an array of "transform results" (a transform result is a field + * value representing the result of applying a transform) for use when + * applying an TransformMutation locally. + * + * @param maybe_doc The current state of the document after applying all + * previous mutations. + * @param base_doc The document prior to applying this mutation batch. + * @param local_write_time The local time of the transform mutation (used to + * generate ServerTimestampValues). + * @return The transform results array. + */ + std::vector LocalTransformResults( + const absl::optional& maybe_doc, + const absl::optional& base_doc, + const Timestamp& local_write_time) const; + + ObjectValue TransformObject( + ObjectValue object_value, + const std::vector& transform_results) const; + + std::vector field_transforms_; + FieldMask field_mask_; + }; + + const Rep& set_rep() const { + return static_cast(rep()); + } +}; + +} // namespace model +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TRANSFORM_MUTATION_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_operation.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_operation.cc new file mode 100644 index 0000000..877564f --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_operation.cc @@ -0,0 +1,395 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/model/transform_operation.h" + +#include +#include +#include +#include + +#include "Firestore/core/include/firebase/firestore/timestamp.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/to_string.h" +#include "absl/algorithm/container.h" +#include "absl/strings/str_cat.h" + +namespace firebase { +namespace firestore { +namespace model { + +using Type = TransformOperation::Type; + +// MARK: - TransformOperation + +TransformOperation::TransformOperation(std::shared_ptr rep) + : rep_(std::move(rep)) { +} + +/** Returns whether the two are equal. */ +bool operator==(const TransformOperation& lhs, const TransformOperation& rhs) { + return lhs.rep_ == nullptr + ? rhs.rep_ == nullptr + : (rhs.rep_ != nullptr && lhs.rep_->Equals(*rhs.rep_)); +} + +std::ostream& operator<<(std::ostream& os, const TransformOperation& op) { + return os << op.ToString(); +} + +// MARK: - ServerTimestampTransform + +static_assert(sizeof(TransformOperation) == sizeof(ServerTimestampTransform), + "No additional members allowed (everything must go in Rep)"); + +class ServerTimestampTransform::Rep : public TransformOperation::Rep { + public: + Type type() const override { + return Type::ServerTimestamp; + } + + model::FieldValue ApplyToLocalView( + const absl::optional& previous_value, + const Timestamp& local_write_time) const override { + return FieldValue::FromServerTimestamp(local_write_time, previous_value); + } + + model::FieldValue ApplyToRemoteDocument( + const absl::optional&, + const model::FieldValue& transform_result) const override { + return transform_result; + } + + absl::optional ComputeBaseValue( + const absl::optional&) const override { + // Server timestamps are idempotent and don't require a base value. + return absl::nullopt; + } + + bool Equals(const TransformOperation::Rep& other) const override { + // All ServerTimestampTransform objects are equal. + return other.type() == Type::ServerTimestamp; + } + + size_t Hash() const override { + // An arbitrary number, since all instances are equal. + return 37; + } + + std::string ToString() const override { + return "ServerTimestamp"; + } +}; + +ServerTimestampTransform::ServerTimestampTransform() + : TransformOperation(std::make_shared()) { +} + +// MARK: - ArrayTransform + +static_assert(sizeof(TransformOperation) == sizeof(ArrayTransform), + "No additional members allowed (everything must go in Rep)"); + +/** + * Transforms an array via a union or remove operation (for convenience, we use + * this class for both Type::ArrayUnion and Type::ArrayRemove). + */ +class ArrayTransform::Rep : public TransformOperation::Rep { + public: + Rep(Type type, std::vector elements) + : type_(type), elements_(std::move(elements)) { + } + + Type type() const override { + return type_; + } + + model::FieldValue ApplyToLocalView( + const absl::optional& previous_value, + const Timestamp&) const override { + return Apply(previous_value); + } + + model::FieldValue ApplyToRemoteDocument( + const absl::optional& previous_value, + const model::FieldValue&) const override { + // The server just sends null as the transform result for array operations, + // so we have to calculate a result the same as we do for local + // applications. + return Apply(previous_value); + } + + absl::optional ComputeBaseValue( + const absl::optional&) const override { + // Array transforms are idempotent and don't require a base value. + return absl::nullopt; + } + + const std::vector& elements() const { + return elements_; + } + + bool Equals(const TransformOperation::Rep& other) const override; + + size_t Hash() const override; + + std::string ToString() const override; + + static const std::vector& Elements( + const TransformOperation& op); + + private: + friend class ArrayTransform; + + /** + * Inspects the provided value, returning a mutable copy of the internal array + * if it's of type Array and an empty mutable array if it's nil or any other + * type of FieldValue. + */ + static std::vector CoercedFieldValuesArray( + const absl::optional& value); + + model::FieldValue Apply( + const absl::optional& previous_value) const; + + Type type_; + std::vector elements_; +}; + +namespace { + +constexpr bool IsArrayTransform(Type type) { + return type == Type::ArrayUnion || type == Type::ArrayRemove; +} + +} // namespace + +ArrayTransform::ArrayTransform(Type type, + std::vector elements) + : TransformOperation( + std::make_shared(type, std::move(elements))) { + HARD_ASSERT(IsArrayTransform(type), "Expected array transform type; got %s", + type); +} + +ArrayTransform::ArrayTransform(const TransformOperation& op) + : TransformOperation(op) { + HARD_ASSERT(IsArrayTransform(op.type()), + "Expected array transform type; got %s", op.type()); +} + +const std::vector& ArrayTransform::elements() const { + return array_rep().elements_; +} + +const ArrayTransform::Rep& ArrayTransform::array_rep() const { + return static_cast(rep()); +} + +bool ArrayTransform::Rep::Equals(const TransformOperation::Rep& other) const { + if (other.type() != type()) { + return false; + } + auto other_rep = static_cast(other); + if (other_rep.elements_.size() != elements_.size()) { + return false; + } + for (size_t i = 0; i < elements_.size(); i++) { + if (other_rep.elements_[i] != elements_[i]) { + return false; + } + } + return true; +} + +size_t ArrayTransform::Rep::Hash() const { + size_t result = 37; + result = 31 * result + (type() == Type::ArrayUnion ? 1231 : 1237); + for (const FieldValue& element : elements_) { + result = 31 * result + element.Hash(); + } + return result; +} + +std::string ArrayTransform::Rep::ToString() const { + const char* name = type_ == Type::ArrayUnion ? "ArrayUnion" : "ArrayRemove"; + return absl::StrCat(name, "(", util::ToString(elements_), ")"); +} + +FieldValue::Array ArrayTransform::Rep::CoercedFieldValuesArray( + const absl::optional& value) { + if (value && value->type() == FieldValue::Type::Array) { + return value->array_value(); + } else { + // coerce to empty array. + return {}; + } +} + +FieldValue ArrayTransform::Rep::Apply( + const absl::optional& previous_value) const { + FieldValue::Array result = CoercedFieldValuesArray(previous_value); + for (const FieldValue& element : elements_) { + auto pos = absl::c_find(result, element); + if (type_ == Type::ArrayUnion) { + if (pos == result.end()) { + result.push_back(element); + } + } else { + HARD_ASSERT(type_ == Type::ArrayRemove); + if (pos != result.end()) { + result.erase(pos); + } + } + } + return FieldValue::FromArray(std::move(result)); +} + +// MARK: - NumericIncrementTransform + +static_assert(sizeof(TransformOperation) == sizeof(NumericIncrementTransform), + "No additional members allowed (everything must go in Rep)"); + +class NumericIncrementTransform::Rep : public TransformOperation::Rep { + public: + explicit Rep(model::FieldValue operand) : operand_(std::move(operand)) { + } + + Type type() const override { + return Type::Increment; + } + + model::FieldValue ApplyToLocalView( + const absl::optional& previous_value, + const Timestamp& local_write_time) const override; + + model::FieldValue ApplyToRemoteDocument( + const absl::optional&, + const model::FieldValue& transform_result) const override { + return transform_result; + } + + absl::optional ComputeBaseValue( + const absl::optional& previous_value) const override; + + model::FieldValue operand() const { + return operand_; + } + + bool Equals(const TransformOperation::Rep& other) const override; + + size_t Hash() const override { + return operand_.Hash(); + } + + std::string ToString() const override { + return absl::StrCat("NumericIncrement(", operand_.ToString(), ")"); + } + + private: + friend class NumericIncrementTransform; + + model::FieldValue operand_; +}; + +NumericIncrementTransform::NumericIncrementTransform(FieldValue operand) + : TransformOperation(std::make_shared(operand)) { + HARD_ASSERT(operand.is_number()); +} + +NumericIncrementTransform::NumericIncrementTransform( + const TransformOperation& op) + : TransformOperation(op) { + HARD_ASSERT(op.type() == Type::Increment, "Expected increment type; got %s", + op.type()); +} + +const FieldValue& NumericIncrementTransform::operand() const { + return static_cast(rep()).operand_; +} + +namespace { + +/** + * Implements saturating integer addition. Overflows are resolved to + * LONG_MAX/LONG_MIN. + */ +int64_t SafeIncrement(int64_t x, int64_t y) { + if (x > 0 && y > LONG_MAX - x) { + return LONG_MAX; + } + + if (x < 0 && y < LONG_MIN - x) { + return LONG_MIN; + } + + return x + y; +} + +double AsDouble(const FieldValue& value) { + if (value.type() == FieldValue::Type::Double) { + return value.double_value(); + } else if (value.type() == FieldValue::Type::Integer) { + return static_cast(value.integer_value()); + } else { + HARD_FAIL("Expected 'operand' to be of numeric type, but was %s (type %s)", + value.ToString(), value.type()); + } +} + +} // namespace + +FieldValue NumericIncrementTransform::Rep::ApplyToLocalView( + const absl::optional& previous_value, + const Timestamp& /* local_write_time */) const { + absl::optional base_value = ComputeBaseValue(previous_value); + + // Return an integer value only if the previous value and the operand is an + // integer. + if (base_value && base_value->type() == FieldValue::Type::Integer && + operand_.type() == FieldValue::Type::Integer) { + int64_t sum = + SafeIncrement(base_value->integer_value(), operand_.integer_value()); + return FieldValue::FromInteger(sum); + } else { + HARD_ASSERT(base_value && base_value->is_number(), + "'base_value' is not of numeric type"); + double sum = AsDouble(*base_value) + AsDouble(operand_); + return FieldValue::FromDouble(sum); + } +} + +absl::optional NumericIncrementTransform::Rep::ComputeBaseValue( + const absl::optional& previous_value) const { + return previous_value && previous_value->is_number() + ? previous_value + : absl::optional{FieldValue::FromInteger(0)}; +} + +bool NumericIncrementTransform::Rep::Equals( + const TransformOperation::Rep& other) const { + if (other.type() != type()) { + return false; + } + + auto other_rep = static_cast(other); + return operand_ == other_rep.operand_; +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_operation.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_operation.h new file mode 100644 index 0000000..72ccea9 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_operation.h @@ -0,0 +1,231 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TRANSFORM_OPERATION_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TRANSFORM_OPERATION_H_ + +#include +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "absl/types/optional.h" + +namespace firebase { + +class Timestamp; + +namespace firestore { +namespace model { + +/** + * Represents a transform within a TransformMutation. + * + * Note: TransformOperation and its subclasses are specially designed to avoid + * slicing. You can assign a subclass of TransformOperation to an instance of + * TransformOperation and the full value is preserved, unsliced. Each subclass + * declares an explicit constructor that can recover the derived type. This + * means that code like this will work: + * + * ArrayTransform array_transform(...); + * TransformOperation transform = array_transform; + * ArrayTransform recovered(transform); + * + * The final line results in an explicit check that will fail if the type of + * the underlying data is not actually an ArrayTransform. + */ +class TransformOperation { + public: + /** All the different kinds to TransformOperation. */ + enum class Type { + ServerTimestamp, + ArrayUnion, + ArrayRemove, + Increment, + }; + + TransformOperation() = default; + + /** Returns the actual type. */ + Type type() const { + return rep().type(); + } + + private: + // TODO(b/146372592): Make this public once we can use Abseil across + // iOS/public C++ library boundaries. + friend class TransformMutation; + + /** + * Computes the local transform result against the provided `previous_value`, + * optionally using the provided local_write_time. + */ + FieldValue ApplyToLocalView(const absl::optional& previous_value, + const Timestamp& local_write_time) const { + return rep().ApplyToLocalView(previous_value, local_write_time); + } + + /** + * Computes a final transform result after the transform has been acknowledged + * by the server, potentially using the server-provided transform_result. + */ + FieldValue ApplyToRemoteDocument( + const absl::optional& previous_value, + const FieldValue& transform_result) const { + return rep().ApplyToRemoteDocument(previous_value, transform_result); + } + + /** + * If this transform operation is not idempotent, returns the base value to + * persist for this transform operation. If a base value is returned, the + * transform operation is always applied to this base value, even if document + * has already been updated. + * + * Base values provide consistent behavior for non-idempotent transforms and + * allow us to return the same latency-compensated value even if the backend + * has already applied the transform operation. The base value is empty for + * idempotent transforms, as they can be re-played even if the backend has + * already applied them. + * + * @return a base value to store along with the mutation, or empty for + * idempotent transforms. + */ + absl::optional ComputeBaseValue( + const absl::optional& previous_value) const { + return rep().ComputeBaseValue(previous_value); + } + + public: + /** Returns whether the two are equal. */ + friend bool operator==(const TransformOperation& lhs, + const TransformOperation& rhs); + + size_t Hash() const { + return rep().Hash(); + } + + std::string ToString() const { + return rep_ ? rep().ToString() : "(invalid)"; + } + + friend std::ostream& operator<<(std::ostream& os, + const TransformOperation& op); + + protected: + class Rep { + public: + virtual ~Rep() = default; + + virtual Type type() const = 0; + + virtual FieldValue ApplyToLocalView( + const absl::optional& previous_value, + const Timestamp& local_write_time) const = 0; + + virtual FieldValue ApplyToRemoteDocument( + const absl::optional& previous_value, + const FieldValue& transform_result) const = 0; + + virtual absl::optional ComputeBaseValue( + const absl::optional& previous_value) const = 0; + + virtual bool Equals(const TransformOperation::Rep& other) const = 0; + + virtual size_t Hash() const = 0; + + virtual std::string ToString() const = 0; + }; + + explicit TransformOperation(std::shared_ptr rep); + + const Rep& rep() const { + return *NOT_NULL(rep_); + } + + private: + std::shared_ptr rep_; +}; + +/** Transforms a value into a server-generated timestamp. */ +class ServerTimestampTransform : public TransformOperation { + public: + ServerTimestampTransform(); + + private: + class Rep; +}; + +/** + * Transforms an array via a union or remove operation (for convenience, we use + * this class for both `Type::ArrayUnion` and `Type::ArrayRemove`). + */ +class ArrayTransform : public TransformOperation { + public: + ArrayTransform(Type type, std::vector elements); + + /** + * Casts a TransformOperation to an ArrayTransform. This is a checked + * operation that will assert if the type of the TransformOperation isn't + * actually `Type::ArrayUnion` or `Type::ArrayRemove`. + */ + explicit ArrayTransform(const TransformOperation& op); + + ArrayTransform() = default; + + const std::vector& elements() const; + + private: + class Rep; + + const Rep& array_rep() const; +}; + +/** + * Implements the backend semantics for locally computed NUMERIC_ADD (increment) + * transforms. Converts all field values to longs or doubles and resolves + * overflows to LONG_MAX/LONG_MIN. + */ +class NumericIncrementTransform : public TransformOperation { + public: + explicit NumericIncrementTransform(FieldValue operand); + + /** + * Casts a TransformOperation to a NumericIncrementTransform. This is a + * checked operation that will assert if the type of the TransformOperation + * isn't actually Type::Increment. + */ + explicit NumericIncrementTransform(const TransformOperation& op); + + const FieldValue& operand() const; + + private: + class Rep; +}; + +/** Returns whether the two are not equal. */ +inline bool operator!=(const TransformOperation& lhs, + const TransformOperation& rhs) { + return !(lhs == rhs); +} + +} // namespace model +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TRANSFORM_OPERATION_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_operations.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_operations.h deleted file mode 100644 index 8002907..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/transform_operations.h +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TRANSFORM_OPERATIONS_H_ -#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TRANSFORM_OPERATIONS_H_ - -#if !defined(__OBJC__) -#error "This header only supports Objective-C++." -#endif // !defined(__OBJC__) - -#include -#include - -#import "Firestore/Source/Model/FSTFieldValue.h" - -#include "Firestore/core/include/firebase/firestore/timestamp.h" - -namespace firebase { -namespace firestore { -namespace model { - -// TODO(zxu123): We might want to refactor transform_operations.h into several -// files when the number of different types of operations grows gigantically. -// For now, put the interface and the only operation here. - -/** Represents a transform within a TransformMutation. */ -class TransformOperation { - public: - /** All the different kinds to TransformOperation. */ - enum class Type { - ServerTimestamp, - ArrayUnion, - ArrayRemove, - Increment, - Test, // Purely for test purpose. - }; - - virtual ~TransformOperation() { - } - - /** Returns the actual type. */ - virtual Type type() const = 0; - - /** - * Computes the local transform result against the provided `previousValue`, - * optionally using the provided localWriteTime. - */ - virtual FSTFieldValue* ApplyToLocalView( - FSTFieldValue* previousValue, FIRTimestamp* localWriteTime) const = 0; - - /** - * Computes a final transform result after the transform has been acknowledged - * by the server, potentially using the server-provided transformResult. - */ - virtual FSTFieldValue* ApplyToRemoteDocument( - FSTFieldValue* previousValue, FSTFieldValue* transformResult) const = 0; - - /** Returns whether this field transform is idempotent. */ - virtual bool idempotent() const = 0; - - /** Returns whether the two are equal. */ - virtual bool operator==(const TransformOperation& other) const = 0; - - /** Returns whether the two are not equal. */ - bool operator!=(const TransformOperation& other) const { - return !operator==(other); - } - - // For Objective-C++ hash; to be removed after migration. - // Do NOT use in C++ code. - virtual NSUInteger Hash() const = 0; -}; - -/** Transforms a value into a server-generated timestamp. */ -class ServerTimestampTransform : public TransformOperation { - public: - Type type() const override { - return Type::ServerTimestamp; - } - - FSTFieldValue* ApplyToLocalView(FSTFieldValue* previousValue, - FIRTimestamp* localWriteTime) const override { - return [FSTServerTimestampValue - serverTimestampValueWithLocalWriteTime:localWriteTime - previousValue:previousValue]; - } - - FSTFieldValue* ApplyToRemoteDocument( - FSTFieldValue* /* previousValue */, - FSTFieldValue* transformResult) const override { - return transformResult; - } - - bool idempotent() const override { - return true; - } - - bool operator==(const TransformOperation& other) const override { - // All ServerTimestampTransform objects are equal. - return other.type() == Type::ServerTimestamp; - } - - static const ServerTimestampTransform& Get() { - static ServerTimestampTransform shared_instance; - return shared_instance; - } - - // For Objective-C++ hash; to be removed after migration. - // Do NOT use in C++ code. - NSUInteger Hash() const override { - // arbitrary number, the same as used in ObjC implementation, since all - // instances are equal. - return 37; - } - - private: - ServerTimestampTransform() { - } -}; - -/** - * Transforms an array via a union or remove operation (for convenience, we use - * this class for both Type::ArrayUnion and Type::ArrayRemove). - */ -class ArrayTransform : public TransformOperation { - public: - ArrayTransform(Type type, std::vector elements) - : type_(type), elements_(std::move(elements)) { - } - - Type type() const override { - return type_; - } - - FSTFieldValue* ApplyToLocalView( - FSTFieldValue* previousValue, - FIRTimestamp* /* localWriteTime */) const override { - return Apply(previousValue); - } - - FSTFieldValue* ApplyToRemoteDocument( - FSTFieldValue* previousValue, - FSTFieldValue* /* transformResult */) const override { - // The server just sends null as the transform result for array operations, - // so we have to calculate a result the same as we do for local - // applications. - return Apply(previousValue); - } - - const std::vector& elements() const { - return elements_; - } - - bool idempotent() const override { - return true; - } - - bool operator==(const TransformOperation& other) const override { - if (other.type() != type()) { - return false; - } - auto array_transform = static_cast(other); - if (array_transform.elements_.size() != elements_.size()) { - return false; - } - for (size_t i = 0; i < elements_.size(); i++) { - if (![array_transform.elements_[i] isEqual:elements_[i]]) { - return false; - } - } - return true; - } - - // For Objective-C++ hash; to be removed after migration. - // Do NOT use in C++ code. - NSUInteger Hash() const override { - NSUInteger result = 37; - result = 31 * result + (type() == Type::ArrayUnion ? 1231 : 1237); - for (FSTFieldValue* element : elements_) { - result = 31 * result + [element hash]; - } - return result; - } - - static const std::vector& Elements( - const TransformOperation& op) { - HARD_ASSERT(op.type() == Type::ArrayUnion || - op.type() == Type::ArrayRemove); - return static_cast(op).elements(); - } - - private: - Type type_; - std::vector elements_; - - /** - * Inspects the provided value, returning a mutable copy of the internal array - * if it's an FSTArrayValue and an empty mutable array if it's nil or any - * other type of FSTFieldValue. - */ - static NSMutableArray* CoercedFieldValuesArray( - FSTFieldValue* value) { - if ([value isMemberOfClass:[FSTArrayValue class]]) { - return [NSMutableArray - arrayWithArray:reinterpret_cast(value).internalValue]; - } else { - // coerce to empty array. - return [NSMutableArray array]; - } - } - - FSTFieldValue* Apply(FSTFieldValue* previousValue) const { - NSMutableArray* result = - ArrayTransform::CoercedFieldValuesArray(previousValue); - for (FSTFieldValue* element : elements_) { - if (type_ == Type::ArrayUnion) { - if (![result containsObject:element]) { - [result addObject:element]; - } - } else { - HARD_ASSERT(type_ == Type::ArrayRemove); - [result removeObject:element]; - } - } - return [[FSTArrayValue alloc] initWithValueNoCopy:result]; - } -}; - -/** - * Implements the backend semantics for locally computed NUMERIC_ADD (increment) - * transforms. Converts all field values to longs or doubles and resolves - * overflows to LONG_MAX/LONG_MIN. - */ -class NumericIncrementTransform : public TransformOperation { - public: - explicit NumericIncrementTransform(FSTNumberValue* operand) - : operand_(operand) { - } - - Type type() const override { - return Type::Increment; - } - - FSTFieldValue* ApplyToLocalView( - FSTFieldValue* previousValue, - FIRTimestamp* /* localWriteTime */) const override { - // Return an integer value only if the previous value and the operand is an - // integer. - if ([previousValue isKindOfClass:[FSTIntegerValue class]] && - [operand_ isKindOfClass:[FSTIntegerValue class]]) { - int64_t sum = SafeIncrement( - (static_cast(previousValue)).internalValue, - (static_cast(operand_)).internalValue); - return [FSTIntegerValue integerValue:sum]; - } else if ([previousValue isKindOfClass:[FSTIntegerValue class]]) { - double sum = - (static_cast(previousValue)).internalValue + - OperandAsDouble(); - return [FSTDoubleValue doubleValue:sum]; - } else if ([previousValue isKindOfClass:[FSTDoubleValue class]]) { - double sum = (static_cast(previousValue)).internalValue + - OperandAsDouble(); - return [FSTDoubleValue doubleValue:sum]; - } else { - // If the existing value is not a number, use the value of the transform - // as the new base value. - return operand_; - } - } - - FSTFieldValue* ApplyToRemoteDocument( - FSTFieldValue*, FSTFieldValue* transformResult) const override { - return transformResult; - } - - FSTNumberValue* operand() const { - return operand_; - } - - bool idempotent() const override { - return false; - } - - bool operator==(const TransformOperation& other) const override { - if (other.type() != type()) { - return false; - } - auto numeric_add = static_cast(other); - return [operand_ isEqual:numeric_add.operand_]; - } - - // For Objective-C++ hash; to be removed after migration. - // Do NOT use in C++ code. - NSUInteger Hash() const override { - NSUInteger result = 37; - result = 31 * result + [operand_ hash]; - return result; - } - - private: - FSTNumberValue* operand_; - - /** - * Implements integer addition. Overflows are resolved to LONG_MAX/LONG_MIN. - */ - int64_t SafeIncrement(int64_t x, int64_t y) const { - if (x > 0 && y > LONG_MAX - x) { - return LONG_MAX; - } - - if (x < 0 && y < LONG_MIN - x) { - return LONG_MIN; - } - - return x + y; - } - - double OperandAsDouble() const { - if ([operand_ isKindOfClass:[FSTDoubleValue class]]) { - return (static_cast(operand_)).internalValue; - } else if ([operand_ isKindOfClass:[FSTIntegerValue class]]) { - return (static_cast(operand_)).internalValue; - } else { - HARD_FAIL("Expected 'operand' to be of FSTNumerValue type, but was %s", - NSStringFromClass([operand_ class])); - } - } -}; - -} // namespace model -} // namespace firestore -} // namespace firebase - -#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TRANSFORM_OPERATIONS_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/types.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/types.h index 39eb96a..d7b4cd3 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/types.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/types.h @@ -19,10 +19,6 @@ #include -#if defined(__OBJC__) -#import -#endif - namespace firebase { namespace firestore { namespace model { @@ -51,7 +47,7 @@ using TargetId = int32_t; * indicate whether or not the remote store is trying to connect or not. This is * primarily used by the View / EventManager code to change their behavior while * offline (e.g. get() calls shouldn't wait for data from the server and - * snapshot events should set metadata.isFromCache=true). + * snapshot events should set metadata.from_cache() to true). */ enum class OnlineState { /** @@ -71,7 +67,7 @@ enum class OnlineState { /** * The client is either trying to establish a connection but failing, or it - * has been explicitly marked offline via a call to `disableNetwork`. + * has been explicitly marked offline via a call to `DisableNetwork`. * Higher-level components should operate in offline mode. */ Offline diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/unknown_document.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/unknown_document.cc index ea42c57..6124098 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/unknown_document.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/unknown_document.cc @@ -16,15 +16,46 @@ #include "Firestore/core/src/firebase/firestore/model/unknown_document.h" +#include #include namespace firebase { namespace firestore { namespace model { +static_assert( + sizeof(MaybeDocument) == sizeof(UnknownDocument), + "UnknownDocument may not have additional members (everything goes in Rep)"); + +class UnknownDocument::Rep : public MaybeDocument::Rep { + public: + Rep(DocumentKey key, SnapshotVersion version) + : MaybeDocument::Rep(Type::UnknownDocument, std::move(key), version) { + } + + bool has_pending_writes() const override { + // Unknown documents can only exist because of a logical inconsistency + // between the server successfully committing a mutation and our local + // cache believing it should not apply. We record UnknownDocuments to + // prevent flicker after the committed mutation is removed from the queue. + // If we ever read an UnknownDocument back, this means the cache entry for + // that document must be dirty. + return true; + } + + std::string ToString() const override { + return absl::StrCat("UnknownDocument(key=", key().ToString(), + ", version=", version().ToString(), ")"); + } +}; + UnknownDocument::UnknownDocument(DocumentKey key, SnapshotVersion version) - : MaybeDocument(std::move(key), std::move(version)) { - set_type(Type::UnknownDocument); + : MaybeDocument(std::make_shared(std::move(key), version)) { +} + +UnknownDocument::UnknownDocument(const MaybeDocument& document) + : MaybeDocument(document) { + HARD_ASSERT(type() == Type::UnknownDocument); } } // namespace model diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/unknown_document.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/unknown_document.h index fb031c7..8f7c8b0 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/unknown_document.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/unknown_document.h @@ -17,6 +17,8 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_UNKNOWN_DOCUMENT_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_UNKNOWN_DOCUMENT_H_ +#include + #include "Firestore/core/src/firebase/firestore/model/maybe_document.h" namespace firebase { @@ -31,9 +33,18 @@ class UnknownDocument : public MaybeDocument { public: UnknownDocument(DocumentKey key, SnapshotVersion version); - bool HasPendingWrites() const override { - return true; - } + /** + * Casts a MaybeDocument to a UnknownDocument. This is a checked operation + * that will assert if the type of the MaybeDocument isn't actually + * Type::UnknownDocument. + */ + explicit UnknownDocument(const MaybeDocument& document); + + /** Creates an invalid UnknownDocument. */ + UnknownDocument() = default; + + private: + class Rep; }; } // namespace model diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/verify_mutation.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/verify_mutation.cc new file mode 100644 index 0000000..76d6a21 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/verify_mutation.cc @@ -0,0 +1,61 @@ +/* + * Copyright 2020 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/model/verify_mutation.h" + +#include + +#include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/model/no_document.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" + +namespace firebase { +namespace firestore { +namespace model { + +static_assert( + sizeof(Mutation) == sizeof(VerifyMutation), + "VerifyMutation may not have additional members (everything goes in Rep)"); + +VerifyMutation::VerifyMutation(DocumentKey key, Precondition precondition) + : Mutation(std::make_shared(std::move(key), std::move(precondition))) { +} + +VerifyMutation::VerifyMutation(const Mutation& mutation) : Mutation(mutation) { + HARD_ASSERT(type() == Type::Verify); +} + +MaybeDocument VerifyMutation::Rep::ApplyToRemoteDocument( + const absl::optional& maybe_doc, + const MutationResult& mutation_result) const { + HARD_FAIL("VerifyMutation should only be used in Transactions."); +} + +absl::optional VerifyMutation::Rep::ApplyToLocalView( + const absl::optional& maybe_doc, + const absl::optional&, + const Timestamp&) const { + HARD_FAIL("VerifyMutation should only be used in Transactions."); +} + +std::string VerifyMutation::Rep::ToString() const { + return absl::StrCat("VerifyMutation(key=", key().ToString(), + ", precondition=", precondition().ToString(), ")"); +} + +} // namespace model +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/verify_mutation.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/verify_mutation.h new file mode 100644 index 0000000..fc3958b --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/model/verify_mutation.h @@ -0,0 +1,85 @@ +/* + * Copyright 2020 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_VERIFY_MUTATION_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_VERIFY_MUTATION_H_ + +#include +#include +#include +#include + +#include "Firestore/core/include/firebase/firestore/timestamp.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" +#include "Firestore/core/src/firebase/firestore/model/mutation.h" +#include "Firestore/core/src/firebase/firestore/model/precondition.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace model { + +/** + * A mutation that verifies the existence of the document at the given key + * with the provided precondition. + * + * The `verify` operation is only used in Transactions, and this class serves + * primarily to facilitate serialization into protos. + */ +class VerifyMutation : public Mutation { + public: + VerifyMutation(DocumentKey key, Precondition precondition); + + /** + * Casts a Mutation to a VerifyMutation. This is a checked operation that will + * assert if the type of the Mutation isn't actually Type::Verify. + */ + explicit VerifyMutation(const Mutation& mutation); + + /** Creates an invalid VerifyMutation instance. */ + VerifyMutation() = default; + + private: + class Rep : public Mutation::Rep { + public: + using Mutation::Rep::Rep; + + Type type() const override { + return Type::Verify; + } + + MaybeDocument ApplyToRemoteDocument( + const absl::optional& maybe_doc, + const MutationResult& mutation_result) const override; + + absl::optional ApplyToLocalView( + const absl::optional& maybe_doc, + const absl::optional&, + const Timestamp&) const override; + + // Does not override Equals or Hash; Mutation's versions are sufficient. + + std::string ToString() const override; + }; +}; + +} // namespace model +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_VERIFY_MUTATION_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/byte_string.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/byte_string.cc new file mode 100644 index 0000000..b53ca84 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/byte_string.cc @@ -0,0 +1,125 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" + +#include +#include +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h" +#include "Firestore/core/src/firebase/firestore/util/hashing.h" +#include "Firestore/core/src/firebase/firestore/util/range.h" +#include "absl/strings/escaping.h" + +namespace firebase { +namespace firestore { +namespace nanopb { + +ByteString::ByteString(const pb_bytes_array_t* bytes) { + if (bytes != nullptr) { + bytes_ = MakeBytesArray(bytes->bytes, bytes->size); + } +} + +ByteString::ByteString(const void* value, size_t size) + : bytes_(MakeBytesArray(value, size)) { +} + +ByteString::ByteString(absl::string_view value) + : ByteString(value.data(), value.size()) { +} + +ByteString::ByteString(std::initializer_list value) + : ByteString(value.begin(), value.size()) { +} + +ByteString::ByteString(const ByteString& other) + : ByteString(other.data(), other.size()) { +} + +ByteString::ByteString(ByteString&& other) noexcept { + bytes_ = other.bytes_; + other.bytes_ = nullptr; +} + +ByteString::~ByteString() { + std::free(bytes_); +} + +ByteString& ByteString::operator=(const ByteString& other) { + if (bytes_ != other.bytes_) { + std::free(bytes_); + bytes_ = MakeBytesArray(other.data(), other.size()); + } + return *this; +} + +ByteString& ByteString::operator=(ByteString&& other) noexcept { + if (bytes_ != other.bytes_) { + std::free(bytes_); + bytes_ = other.bytes_; + other.bytes_ = nullptr; + } + return *this; +} + +/* static */ ByteString ByteString::Take(pb_bytes_array_t* bytes) { + return ByteString{bytes, 0}; +} + +const uint8_t* ByteString::data() const { + static const uint8_t kEmpty[] = ""; + return bytes_ ? bytes_->bytes : kEmpty; +} + +pb_bytes_array_t* ByteString::release() { + pb_bytes_array_t* result = bytes_; + bytes_ = nullptr; + return result; +} + +void swap(ByteString& lhs, ByteString& rhs) noexcept { + std::swap(lhs.bytes_, rhs.bytes_); +} + +util::ComparisonResult ByteString::CompareTo(const ByteString& rhs) const { + return util::Compare(MakeStringView(*this), MakeStringView(rhs)); +} + +size_t ByteString::Hash() const { + return util::Hash(util::make_range(begin(), end())); +} + +std::string ByteString::ToString() const { + return absl::CEscape(MakeStringView(*this)); +} + +std::ostream& operator<<(std::ostream& out, const ByteString& str) { + return out << str.ToString(); +} + +std::string ByteString::ToHexString() const { + std::string hex = absl::BytesToHexString(MakeStringView(*this)); + return absl::StrCat("<", hex, ">"); +} + +} // namespace nanopb +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/byte_string.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/byte_string.h new file mode 100644 index 0000000..480aa01 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/byte_string.h @@ -0,0 +1,168 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_BYTE_STRING_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_BYTE_STRING_H_ + +#include + +#include +#include +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/util/comparison.h" +#include "absl/strings/string_view.h" + +namespace firebase { +namespace firestore { +namespace nanopb { + +/** + * An immutable string-like object backed by a nanopb byte array. `ByteString` + * owns its memory, has deep copy semantics, and creates a copy of any input + * given to its constructors. + * + * `ByteString` is similar in spirit to `com.google.protobuf.ByteString`. It + * serves mostly the same purpose: it's a holder of a byte array that's + * compatible with the proto marshaling layer. + * + * Unlike protobuf's `ByteString`, nanopb doesn't supply this class so this + * class additionally makes it possible to cheaply translate to and from raw + * `pb_bytes_array_t*` values. `ByteString` allows taking values directly from + * nanopb messages and avoids copying while doing so. + */ +class ByteString : public util::Comparable { + public: + ByteString() = default; + + /** + * Creates a new `ByteString` that copies the given bytes. + */ + explicit ByteString(const pb_bytes_array_t* bytes); + + /** + * Creates a new `ByteString` whose backing byte array is a copy of the given + * bytes. + */ + ByteString(const void* value, size_t size); + + /** + * Creates a new `ByteString` whose backing byte array is a copy of the given + * string_view. + */ + explicit ByteString(absl::string_view value); + + ByteString(std::initializer_list value); + + ByteString(const ByteString& other); + + ByteString(ByteString&& other) noexcept; + + ~ByteString(); + + ByteString& operator=(const ByteString& other); + ByteString& operator=(ByteString&& other) noexcept; + + friend void swap(ByteString& lhs, ByteString& rhs) noexcept; + + /** + * Creates a new `ByteString` that takes ownership of the given byte array. If + * taking from a nanopb-created message struct, the caller should null out + * the pointer there so that pb_release won't free the buffer that the + * returned `ByteString` now owns. + */ + static ByteString Take(pb_bytes_array_t* bytes); + + /** + * Returns a pointer to the character data backing this `ByteString`. The + * returned buffer is always non-null, even if the nanopb byte array is null. + */ + const uint8_t* data() const; + + size_t size() const { + return bytes_ ? bytes_->size : 0; + } + + bool empty() const { + return bytes_ == nullptr || bytes_->size == 0; + } + + const uint8_t* begin() const { + return data(); + } + + const uint8_t* end() const { + return data() + size(); + } + + /** + * Returns a const view of the raw underlying byte array pointer. + * + * This value may be null because nanopb (and protobuf generally) treat null + * and empty byte arrays as equivalent. + * + * For actually reading the data in the buffer, prefer `data()` and `size()` + * or `begin()` and `end()`, which handle this nullability for you. + */ + const pb_bytes_array_t* get() const { + return bytes_; + } + + /** + * Releases ownership of the backing byte array, and returns it to the caller. + * The backing byte array is set to null. + * + * This value may be null because nanopb (and protobuf generally) treat null + * and empty byte arrays as equivalent. Assigning a null value to a nanopb + * message field will be treated as empty. + */ + pb_bytes_array_t* release(); + + /** + * Performs a lexicographical comparison between this and the other bytes. + */ + util::ComparisonResult CompareTo(const ByteString& rhs) const; + + size_t Hash() const; + + // Interprets the value as an ASCII string; the way control characters are + // represented is implementation-defined. + std::string ToString() const; + friend std::ostream& operator<<(std::ostream& out, const ByteString& str); + + // Represents the value as hexadecimal values. + std::string ToHexString() const; + + private: + /** + * Private constructor directly assigns to bytes_. The extra integer tag + * helps disambiguate this constructor from the public constructor that takes + * `const pb_bytes_array_t*`. + */ + explicit ByteString(pb_bytes_array_t* bytes, int) : bytes_{bytes} { + } + + pb_bytes_array_t* bytes_ = nullptr; +}; + +} // namespace nanopb +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_BYTE_STRING_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/fields_array.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/fields_array.h new file mode 100644 index 0000000..b74317e --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/fields_array.h @@ -0,0 +1,164 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_FIELDS_ARRAY_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_FIELDS_ARRAY_H_ + +#include "Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.h" +#include "Firestore/Protos/nanopb/firestore/local/mutation.nanopb.h" +#include "Firestore/Protos/nanopb/firestore/local/target.nanopb.h" +#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" +#include "Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.h" +#include "Firestore/Protos/nanopb/google/type/latlng.nanopb.h" + +namespace firebase { +namespace firestore { +namespace nanopb { + +/** + * Returns a pointer to the Nanopb-generated array that describes the fields + * of the Nanopb proto; the array is required to call most Nanopb functions. + * + * There is always a one-to-one correspondence between a Nanopb-generated + * message type and its fields descriptor; essentially, the fields descriptor is + * a property of the type. + */ +// The non-specialized version of this function is deleted to make sure that +// forgetting to specialize it results in a compile-time-, not link-time error. +// If you run into an error where compiler complains about the deleted function, +// simply add the missing specialization. +template +const pb_field_t* FieldsArray() = delete; + +template <> +inline const pb_field_t* FieldsArray() { + return firestore_client_MaybeDocument_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return firestore_client_MutationQueue_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return firestore_client_Target_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return firestore_client_TargetGlobal_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return firestore_client_WriteBatch_fields; +} + +template <> +inline const pb_field_t* +FieldsArray() { + return google_firestore_v1_BatchGetDocumentsRequest_fields; +} + +template <> +inline const pb_field_t* +FieldsArray() { + return google_firestore_v1_BatchGetDocumentsResponse_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return google_firestore_v1_CommitRequest_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return google_firestore_v1_CommitResponse_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return google_firestore_v1_ListenRequest_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return google_firestore_v1_ListenResponse_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return google_firestore_v1_RunQueryRequest_fields; +} + +template <> +inline const pb_field_t* +FieldsArray() { + return google_firestore_v1_StructuredQuery_Filter_fields; +} + +template <> +inline const pb_field_t* +FieldsArray() { + return google_firestore_v1_Target_DocumentsTarget_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return google_firestore_v1_TargetChange_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return google_firestore_v1_Target_QueryTarget_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return google_firestore_v1_Value_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return google_firestore_v1_Write_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return google_firestore_v1_WriteRequest_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return google_firestore_v1_WriteResponse_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return google_firestore_v1_WriteResult_fields; +} + +template <> +inline const pb_field_t* FieldsArray() { + return google_protobuf_Empty_fields; +} + +} // namespace nanopb +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_FIELDS_ARRAY_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/message.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/message.cc new file mode 100644 index 0000000..9624b59 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/message.cc @@ -0,0 +1,29 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/nanopb/message.h" + +namespace firebase { +namespace firestore { +namespace nanopb { + +void FreeNanopbMessage(const pb_field_t* fields, void* dest_struct) { + pb_release(fields, dest_struct); +} + +} // namespace nanopb +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/message.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/message.h new file mode 100644 index 0000000..c0ecb7f --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/message.h @@ -0,0 +1,229 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_MESSAGE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_MESSAGE_H_ + +#include +#include + +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" +#include "Firestore/core/src/firebase/firestore/nanopb/fields_array.h" +#include "Firestore/core/src/firebase/firestore/nanopb/reader.h" +#include "Firestore/core/src/firebase/firestore/nanopb/writer.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "grpcpp/support/byte_buffer.h" + +namespace firebase { +namespace firestore { +namespace nanopb { + +/** + * Free the dynamically-allocated memory within a Nanopb-generated message. + * + * This essentially wraps calls to Nanopb's `pb_release()` function. + */ +void FreeNanopbMessage(const pb_field_t* fields, void* dest_struct); + +template +class Message; + +/** + * A unique-ownership RAII wrapper for Nanopb-generated message types. + * + * Nanopb-generated message types (from now on, "Nanopb protos") are plain + * C structs that contain some dynamically-allocated memory and should be + * deallocated by calling `pb_release`; `Message` implements a simple RAII + * wrapper that does just that. For simplicity, `Message` implements unique + * ownership model. It provides a pointer-like access to the underlying Nanopb + * proto. + * + * Note that moving *isn't* a particularly cheap operation in the general case. + * Even without doing deep copies, Nanopb protos contain *a lot* of member + * variables (at the time of writing, the largest `sizeof` of a Nanopb proto was + * 248). + */ +template +class Message { + public: + /** + * Creates a valid `Message` that wraps a value-constructed ("zeroed out") + * Nanopb proto. The created object can then be filled by using the + * pointer-like access. + */ + Message() = default; + + /** + * Attempts to parse a Nanopb message from the given `reader`. If the reader + * contains ill-formed bytes, returns a default-constructed `Message`; check + * the status on `reader` to see whether parsing was successful. + */ + static Message TryParse(Reader* reader); + + ~Message() { + Free(); + } + + /** `Message` models unique ownership. */ + Message(const Message&) = delete; + Message& operator=(const Message&) = delete; + + /** + * A moved-from `Message` is in an invalid state that is *not* equivalent to + * its default-constructed state. Calling `get()` on a moved-from `Message` + * returns a null pointer; attempting to "dereference" a moved-from `Message` + * results in undefined behavior. + */ + Message(Message&& other) noexcept + : owns_proto_{other.owns_proto_}, proto_{other.proto_} { + other.owns_proto_ = false; + } + + Message& operator=(Message&& other) noexcept { + Free(); + + owns_proto_ = other.owns_proto_; + proto_ = other.proto_; + other.owns_proto_ = false; + + return *this; + } + + T* release() { + auto result = get(); + owns_proto_ = false; + return result; + } + + /** + * Returns a pointer to the underlying Nanopb proto or null if the `Message` + * is moved-from. + */ + T* get() { + return owns_proto_ ? &proto_ : nullptr; + } + + /** + * Returns a pointer to the underlying Nanopb proto or null if the `Message` + * is moved-from. + */ + const T* get() const { + return owns_proto_ ? &proto_ : nullptr; + } + + /** + * Returns a reference to the underlying Nanopb proto; if the `Message` is + * moved-from, the behavior is undefined. + * + * For performance reasons, prefer assigning to individual fields to + * reassigning the whole Nanopb proto. + */ + T& operator*() { + return *get(); + } + + /** + * Returns a reference to the underlying Nanopb proto; if the `Message` is + * moved-from, the behavior is undefined. + */ + const T& operator*() const { + return *get(); + } + + T* operator->() { + return get(); + } + + const T* operator->() const { + return get(); + } + + /** + * Returns a pointer to the Nanopb-generated array that describes the fields + * of the Nanopb proto; the array is required to call most Nanopb functions. + * + * Note that this is essentially a property of the type, but cannot be made + * a template parameter for various technical reasons. + */ + static const pb_field_t* fields() { + return FieldsArray(); + } + + /** Creates a pretty-printed description of the proto for debugging. */ + std::string ToString() const { + return proto_.ToString(); + } + + private: + // Important: this function does *not* modify `owns_proto_`. + void Free() { + if (owns_proto_) { + FreeNanopbMessage(fields(), &proto_); + } + } + + bool owns_proto_ = true; + // The Nanopb-proto is value-initialized (zeroed out) to make sure that any + // member variables that aren't written to are in a valid state. + T proto_{}; +}; + +template +Message Message::TryParse(Reader* reader) { + Message result; + reader->Read(result.fields(), result.get()); + + if (!reader->ok()) { + // In the event reading a Nanopb proto fails, Nanopb calls `pb_release` on + // the partially-filled message; let go of ownership to make sure double + // deletion doesn't occur. + result.release(); + // Guarantee that a partially-filled message is never returned. + return Message{}; + } + + return result; +} + +/** + * Serializes the given `message` into a `ByteString`. + * + * The lifetime of the return value is entirely independent of the `message`. + */ +template +ByteString MakeByteString(const Message& message) { + ByteStringWriter writer; + writer.Write(message.fields(), message.get()); + return writer.Release(); +} + +/** + * Serializes the given `message` into a `std::string`. + * + * The lifetime of the return value is entirely independent of the `message`. + */ +template +std::string MakeStdString(const Message& message) { + StringWriter writer; + writer.Write(message.fields(), message.get()); + return writer.Release(); +} + +} // namespace nanopb +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_MESSAGE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/nanopb_string.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/nanopb_string.cc deleted file mode 100644 index 9085002..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/nanopb_string.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/nanopb/nanopb_string.h" - -#include -#include - -#include "Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h" - -namespace firebase { -namespace firestore { -namespace nanopb { - -String::~String() { - std::free(bytes_); -} - -/* static */ pb_bytes_array_t* String::MakeBytesArray(absl::string_view value) { - pb_size_t size = CheckedSize(value.size()); - - // Allocate one extra byte for the null terminator that's not necessarily - // there in a string_view. As long as we're making a copy, might as well - // make a copy that won't overrun when used as a regular C string. This is - // essentially just to make debugging easier--actual user data can have - // embedded nulls so we shouldn't be using this as a C string under normal - // circumstances. - auto result = static_cast( - malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size) + 1)); - result->size = size; - memcpy(result->bytes, value.data(), size); - result->bytes[size] = '\0'; - - return result; -} - -pb_bytes_array_t* String::release() { - pb_bytes_array_t* result = bytes_; - bytes_ = nullptr; - return result; -} - -void swap(String& lhs, String& rhs) noexcept { - using std::swap; - swap(lhs.bytes_, rhs.bytes_); -} - -/* static */ String String::Wrap(pb_bytes_array_t* bytes) { - return String{bytes}; -} - -/* static */ absl::string_view String::ToStringView(pb_bytes_array_t* bytes) { - const char* str = reinterpret_cast(bytes->bytes); - return absl::string_view{str, bytes->size}; -} - -} // namespace nanopb -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/nanopb_string.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/nanopb_string.h deleted file mode 100644 index 53a9668..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/nanopb_string.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_NANOPB_STRING_H_ -#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_NANOPB_STRING_H_ - -#include - -#include -#include - -#include "Firestore/core/src/firebase/firestore/util/comparison.h" -#include "absl/strings/string_view.h" - -namespace firebase { -namespace firestore { -namespace nanopb { - -/** - * A string-like object backed by a nanopb byte array. - */ -class String : public util::Comparable { - public: - /** - * Creates a new, null-terminated byte array that's a copy of the given string - * value. - */ - static pb_bytes_array_t* MakeBytesArray(absl::string_view value); - - String() { - } - - /** - * Creates a new String whose backing byte array is a copy of the of the - * given C string. - */ - explicit String(const char* value) : bytes_{MakeBytesArray(value)} { - } - - /** - * Creates a new String whose backing byte array is a copy of the of the - * given string. - */ - explicit String(const std::string& value) : bytes_{MakeBytesArray(value)} { - } - - /** - * Creates a new String whose backing byte array is a copy of the of the - * given string_view. - */ - explicit String(absl::string_view value) : bytes_{MakeBytesArray(value)} { - } - - String(const String& other) - : bytes_{MakeBytesArray(absl::string_view{other})} { - } - - String(String&& other) noexcept : String{} { - swap(*this, other); - } - - ~String(); - - String& operator=(String other) { - swap(*this, other); - return *this; - } - - /** - * Creates a new String that takes ownership of the given byte array. - */ - static String Wrap(pb_bytes_array_t* bytes); - - bool empty() const { - return !bytes_ || bytes_->size == 0; - } - - /** - * Returns a pointer to the character data backing this String. The return - * value is `nullptr` if the backing bytes are themselves null. - */ - const char* data() const { - return bytes_ ? reinterpret_cast(bytes_->bytes) : nullptr; - } - - /** Returns a const view of the underlying byte array. */ - const pb_bytes_array_t* get() const { - return bytes_; - } - - /** - * Returns the current byte array and assigns the backing byte array to - * nullptr, releasing the ownership of the array contents to the caller. - */ - pb_bytes_array_t* release(); - - /** - * Converts this String to an absl::string_view (without changing ownership). - */ - explicit operator absl::string_view() const { - return ToStringView(bytes_); - } - - /** - * Swaps the contents of the given Strings. - */ - friend void swap(String& lhs, String& rhs) noexcept; - - friend bool operator==(const String& lhs, const String& rhs) { - return absl::string_view{lhs} == absl::string_view{rhs}; - } - friend bool operator<(const String& lhs, const String& rhs) { - return absl::string_view{lhs} < absl::string_view{rhs}; - } - - friend bool operator==(const String& lhs, absl::string_view rhs) { - absl::string_view lhs_view{lhs}; - return lhs_view == rhs; - } - - friend bool operator!=(const String& lhs, absl::string_view rhs) { - return !(lhs == rhs); - } - - private: - explicit String(pb_bytes_array_t* bytes) : bytes_{bytes} { - } - - static absl::string_view ToStringView(pb_bytes_array_t* bytes); - - pb_bytes_array_t* bytes_ = nullptr; -}; - -} // namespace nanopb -} // namespace firestore -} // namespace firebase - -#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_NANOPB_STRING_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/nanopb_util.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/nanopb_util.cc new file mode 100644 index 0000000..f23b100 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/nanopb_util.cc @@ -0,0 +1,75 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h" + +#include + +namespace firebase { +namespace firestore { +namespace nanopb { + +pb_bytes_array_t* _Nullable CopyBytesArray( + const pb_bytes_array_t* _Nullable buffer) { + if (buffer == nullptr) return nullptr; + return MakeBytesArray(buffer->bytes, buffer->size); +} + +pb_bytes_array_t* _Nullable MakeBytesArray(const void* _Nullable data, + size_t size) { + if (size == 0) return nullptr; + + pb_size_t pb_size = CheckedSize(size); + + // Allocate one extra byte for the null terminator that's not necessarily + // there in a string_view. As long as we're making a copy, might as well + // make a copy that won't overrun when used as a regular C string. This is + // essentially just to make debugging easier--actual user data can have + // embedded nulls so we shouldn't be using this as a C string under normal + // circumstances. + auto result = static_cast( + std::malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(pb_size + 1))); + result->size = pb_size; + std::memcpy(result->bytes, data, pb_size); + result->bytes[pb_size] = '\0'; + + return result; +} + +std::string MakeString(const pb_bytes_array_t* _Nullable str) { + if (str == nullptr) return ""; + + auto bytes = reinterpret_cast(str->bytes); + auto size = static_cast(str->size); + return std::string{bytes, size}; +} + +absl::string_view MakeStringView(const pb_bytes_array_t* _Nullable str) { + if (str == nullptr) return absl::string_view(nullptr, 0); + + auto bytes = reinterpret_cast(str->bytes); + auto size = static_cast(str->size); + return absl::string_view{bytes, size}; +} + +absl::string_view MakeStringView(const ByteString& bytes) { + const char* str = reinterpret_cast(bytes.data()); + return absl::string_view{str, bytes.size()}; +} + +} // namespace nanopb +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h index 667c28a..07dfb74 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h @@ -19,7 +19,16 @@ #include +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/nullability.h" +#include "absl/base/casts.h" +#include "absl/memory/memory.h" namespace firebase { namespace firestore { @@ -35,6 +44,89 @@ inline pb_size_t CheckedSize(size_t size) { return static_cast(size); } +/** + * Creates a new, null-terminated byte array that's a copy of the bytes in the + * given buffer. Returns a null instance if the given buffer is null or empty. + */ +pb_bytes_array_t* _Nullable CopyBytesArray( + const pb_bytes_array_t* _Nullable buffer); + +/** + * Creates a new, null-terminated byte array that's a copy of the given bytes. + * Returns a null instance if the given size is zero. + */ +pb_bytes_array_t* _Nullable MakeBytesArray(const void* _Nullable data, + size_t size); + +/** + * Creates a new, null-terminated byte array that's a copy of the given bytes. + * Returns a null instance if the size of the given vector is zero. + */ +inline pb_bytes_array_t* _Nullable MakeBytesArray( + const std::vector& bytes) { + return MakeBytesArray(bytes.data(), bytes.size()); +} + +/** + * Creates a string_view of the given nanopb bytes. + */ +absl::string_view MakeStringView(const pb_bytes_array_t* _Nullable str); + +/** + * Creates a string_view of the given nanopb bytes. + */ +absl::string_view MakeStringView(const ByteString& bytes); + +inline pb_bytes_array_t* _Nullable MakeBytesArray(const std::string& str) { + return MakeBytesArray(str.data(), str.size()); +} + +std::string MakeString(const pb_bytes_array_t* _Nullable str); + +/** + * Copies the backing byte array into a new vector of bytes. + */ +inline std::vector MakeVector(const ByteString& str) { + return {str.begin(), str.end()}; +} + +/** + * Due to the nanopb implementation, nanopb_boolean could be an integer + * other than 0 or 1, (such as 2). This leads to undefined behaviour when + * it's read as a boolean. eg. on at least gcc, the value is treated as + * both true *and* false. So we'll instead memcpy to an integer (via + * absl::bit_cast) and compare with 0. + * + * Note that it is necessary to pass-by-reference here to get the original + * value of `nanopb_boolean`. + */ +inline bool SafeReadBoolean(const bool& nanopb_boolean) { + return absl::bit_cast(nanopb_boolean) != 0; +} + +template +T* _Nonnull MakeArray(pb_size_t count) { + return static_cast(calloc(count, sizeof(T))); +} + +#if __OBJC__ +inline ByteString MakeByteString(NSData* _Nullable value) { + if (value == nil) return ByteString(); + + auto size = static_cast(value.length); + return ByteString::Take(MakeBytesArray(value.bytes, size)); +} + +inline NSData* _Nonnull MakeNSData(const ByteString& str) { + return [[NSData alloc] initWithBytes:str.data() length:str.size()]; +} + +inline NSData* _Nullable MakeNullableNSData(const ByteString& str) { + if (str.empty()) return nil; + return MakeNSData(str); +} +#endif + } // namespace nanopb } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/pretty_printing.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/pretty_printing.cc new file mode 100644 index 0000000..d2bcd5d --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/pretty_printing.cc @@ -0,0 +1,82 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h" + +#include + +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" + +namespace firebase { +namespace firestore { +namespace nanopb { + +namespace internal { + +std::string Indent(int level, int indent_width) { + return std::string(level * indent_width, ' '); +} + +std::string ToString(pb_bytes_array_t* value) { + return absl::StrCat("\"", nanopb::ByteString(value).ToString(), "\""); +} + +std::string ToString(bool value) { + return value ? std::string{"true"} : std::string{"false"}; +} + +// Overloads for float and double exist to minimize the use of `stringstream`, +// which isn't necessary for other scalars. +std::string ToString(float value) { + // `std::to_string` doesn't allow changing width and precision for floating + // point values, leading to output inconsistent with "official" proto + // libraries. + // TODO(varconst): raise the precision. + // The Objective-C protobuf library would use higher precision. E.g., it would + // output 1.79769313486232e+308 in case where this implementation would only + // output 1.79769e+308 (tested in XCode 11, iOS simulator). + std::ostringstream stream; + stream << value; + return stream.str(); +} + +std::string ToString(double value) { + // See comment on the `float` overload. + std::ostringstream stream; + stream << value; + return stream.str(); +} + +} // namespace internal + +std::string PrintHeader(int indent_level, + absl::string_view message_name, + const void* message_ptr) { + if (indent_level == 0) { + auto p = absl::Hex{reinterpret_cast(message_ptr)}; + return absl::StrCat("<", message_name, " 0x", p, ">: {\n"); + } else { + return "{\n"; + } +} + +std::string PrintTail(int indent_level) { + return internal::Indent(indent_level) + '}'; +} + +} // namespace nanopb +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h new file mode 100644 index 0000000..215050f --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/pretty_printing.h @@ -0,0 +1,127 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_PRETTY_PRINTING_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_PRETTY_PRINTING_H_ + +#include + +#include + +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" + +namespace firebase { +namespace firestore { +namespace nanopb { + +namespace internal { + +// Creates a string of spaces corresponding to the given indentation level. +std::string Indent(int level, int indent_width = 2); + +std::string ToString(pb_bytes_array_t* value); +std::string ToString(bool value); +std::string ToString(float value); +std::string ToString(double value); + +template +std::string ToString(const T& value) { + return std::to_string(value); +} + +} // namespace internal + +// Prints a nested message by delegating to its `ToString` member function. +// +// If the nested message is empty, then: +// - if `always_print` is false, an empty string is returned. +// - if `always_print` is true, a string containing field name and empty braces +// is returned. +template +std::string PrintMessageField(absl::string_view name, + const T& value, + int indent_level, + bool always_print) { + auto contents = value.ToString(indent_level); + if (contents.empty()) { + if (!always_print) { + return ""; + } else { + return absl::StrCat(internal::Indent(indent_level), name, "{\n", + internal::Indent(indent_level), "}\n"); + } + } + + return absl::StrCat(internal::Indent(indent_level), name, contents, "\n"); +} + +// Prints a primitive type field. +// +// If the field has its default value (e.g., zero), then: +// - if `always_print` is false, an empty string is returned. +// - if `always_print` is true, a string representing the default value is +// returned. +template +std::string PrintPrimitiveField(absl::string_view name, + T value, + int indent_level, + bool always_print) { + if (value == T{} && !always_print) { + return ""; + } + return absl::StrCat(internal::Indent(indent_level), name, + internal::ToString(value), "\n"); +} + +// Prints an enum type field by delegating to a `EnumToString` free function. +// +// If the enum has its default value, zero), then: +// - if `always_print` is false, an empty string is returned. +// - if `always_print` is true, a string representing the default value is +// returned. +template +std::string PrintEnumField(absl::string_view name, + T value, + int indent_level, + bool always_print) { + if (value == T{} && !always_print) { + return ""; + } + + return absl::StrCat(internal::Indent(indent_level), name, EnumToString(value), + "\n"); +} + +// Begins output for a message. +// +// For a non-root message (determined by `indent_level`), this is just an +// opening brace. For the root message, `message_name` and the address of the +// object are additionally printed (e.g., ": {"). +std::string PrintHeader(int indent_level, + absl::string_view message_name, + const void* message_ptr); + +// Ends output for a message. +// +// This just outputs a closing brace. +std::string PrintTail(int indent_level); + +} // namespace nanopb +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_NANOPB_PRETTY_PRINTING_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/reader.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/reader.cc index d182102..2ea5612 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/reader.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/reader.cc @@ -20,30 +20,32 @@ namespace firebase { namespace firestore { namespace nanopb { -using firebase::firestore::util::Status; +using util::Status; -Reader Reader::Wrap(const uint8_t* bytes, size_t length) { - return Reader{pb_istream_from_buffer(bytes, length)}; +StringReader::StringReader(const ByteString& bytes) + : StringReader(bytes.data(), bytes.size()) { } -Reader Reader::Wrap(absl::string_view string_view) { - return Reader{pb_istream_from_buffer( - reinterpret_cast(string_view.data()), - string_view.size())}; +StringReader::StringReader(const std::vector& bytes) + : StringReader(bytes.data(), bytes.size()) { } -void Reader::ReadNanopbMessage(const pb_field_t fields[], void* dest_struct) { - if (!status_.ok()) return; +StringReader::StringReader(const uint8_t* bytes, size_t size) + : stream_(pb_istream_from_buffer(bytes, size)) { +} + +StringReader::StringReader(absl::string_view str) + : StringReader(reinterpret_cast(str.data()), str.size()) { +} + +void StringReader::Read(const pb_field_t fields[], void* dest_struct) { + if (!ok()) return; if (!pb_decode(&stream_, fields, dest_struct)) { Fail(PB_GET_ERROR(&stream_)); } } -void Reader::FreeNanopbMessage(const pb_field_t fields[], void* dest_struct) { - pb_release(fields, dest_struct); -} - } // namespace nanopb } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/reader.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/reader.h index eb95901..2c15768 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/reader.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/reader.h @@ -20,7 +20,12 @@ #include #include +#include +#include +#include + #include "Firestore/core/include/firebase/firestore/firestore_errors.h" +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" #include "Firestore/core/src/firebase/firestore/util/status.h" #include "absl/strings/string_view.h" @@ -29,91 +34,147 @@ namespace firestore { namespace nanopb { /** - * Docs TODO(rsgowman). But currently, this just wraps the underlying nanopb - * pb_istream_t. - * - * All 'ReadX' methods verify the wiretype (by examining the last_tag_ field, as - * set by ReadTag()) to ensure the correct type. If that fails, the status of - * the Reader instance is set to non-ok. + * Maintains whether any errors occurred between single reads within a larger + * read chain. The pattern is to pass the `ReadContext` as the first argument to + * any `Read` function that might fail, and for the function to exit early if + * the given context is failed already. */ -class Reader { +class ReadContext { public: - /** - * Creates an input stream that reads from the specified bytes. Note that - * this reference must remain valid for the lifetime of this Reader. - * - * (This is roughly equivalent to the nanopb function - * pb_istream_from_buffer()) - * - * @param bytes where the input should be deserialized from. - */ - static Reader Wrap(const uint8_t* bytes, size_t length); + bool ok() const { + return status_.ok(); + } + + const util::Status& status() const { + return status_; + } + + void set_status(util::Status status) { + status_ = std::move(status); + } /** - * Creates an input stream from bytes backing the string_view. Note that - * the backing buffer must remain valid for the lifetime of this Reader. + * Ensures this `ReadContext`'s status is `!ok()`. * - * (This is roughly equivalent to the nanopb function - * pb_istream_from_buffer()) + * If this `ReadContext`'s status is already `!ok()`, then this may augment + * the description, but will otherwise leave it alone. Otherwise, this + * `ReadContext`'s status will be set to `Error::DataLoss` with the specified + * description. */ - static Reader Wrap(absl::string_view); + void Fail(std::string description) { + status_.Update(util::Status(Error::DataLoss, std::move(description))); + } + + private: + util::Status status_ = util::Status::OK(); +}; + +/** + * An interface that: + * - maintains a `ReadContext` across the reads; + * - can read byte representations from the associated stream into a given + * Nanopb proto. + * + * Derived classes define what kinds of streams can be associated with the + * `Reader`. + */ +class Reader { + public: + virtual ~Reader() = default; /** - * Reads a nanopb message from the input stream. + * Reads a Nanopb proto from the stream associated with this `Reader`. * - * This essentially wraps calls to nanopb's pb_decode() method. This is the + * This essentially wraps calls to Nanopb's `pb_decode()` method. This is the * primary way of decoding messages. * - * Note that this allocates memory. You must call FreeNanopbMessage() (which - * essentially wraps pb_release()) on the dest_struct in order to avoid memory - * leaks. (This also implies code that uses this is not exception safe.) + * Note that this allocates memory. You must call + * `nanopb::FreeNanopbMessage()` (which essentially wraps `pb_release()`) on + * the `dest_struct` in order to avoid memory leaks. (This also implies code + * that uses this is not exception safe.) */ // TODO(rsgowman): At the moment we rely on the caller to manually free - // dest_struct via FreeNanopbMessage(). We might instead see if we can + // dest_struct via nanopb::FreeNanopbMessage(). We might instead see if we can // register allocated messages, track them, and free them ourselves. This may // be especially relevant if we start to use nanopb messages as the underlying // data within the model objects. - void ReadNanopbMessage(const pb_field_t fields[], void* dest_struct); + virtual void Read(const pb_field_t fields[], void* dest_struct) = 0; - /** - * Release memory allocated by ReadNanopbMessage(). - * - * This essentially wraps calls to nanopb's pb_release() method. - */ - void FreeNanopbMessage(const pb_field_t fields[], void* dest_struct); + bool ok() const { + return context_.ok(); + } - util::Status status() const { - return status_; + const util::Status& status() const { + return context_.status(); } void set_status(util::Status status) { - status_ = status; + context_.set_status(std::move(status)); + } + + ReadContext* context() { + return &context_; + } + + const ReadContext* context() const { + return &context_; + } + + void Fail(std::string description) { + context_.Fail(std::move(description)); } + private: + ReadContext context_; +}; + +/** + * Docs TODO(rsgowman). But currently, this just wraps the underlying nanopb + * pb_istream_t. + */ +class StringReader : public Reader { + public: /** - * Ensures this Reader's status is `!ok(). + * Creates an instance that isn't associated with any bytes. It can be used + * for error propagation. + * TODO(varconst): only use `ReadContext` for error propagation. + */ + StringReader() = default; + + /** + * Creates an input stream that reads from the specified bytes. Note that + * this reference must remain valid for the lifetime of this `StringReader`. * - * If this Reader's status is already !ok(), then this may augment the - * description, but will otherwise leave it alone. Otherwise, this Reader's - * status will be set to FirestoreErrorCode::DataLoss with the specified - * description. + * (This is roughly equivalent to the Nanopb function + * `pb_istream_from_buffer()`) + * + * @param bytes where the input should be deserialized from. */ - void Fail(const absl::string_view description) { - status_.Update(util::Status(FirestoreErrorCode::DataLoss, description)); - } + explicit StringReader(const nanopb::ByteString& bytes); + explicit StringReader(const std::vector& bytes); + StringReader(const uint8_t* bytes, size_t length); + + /** + * Creates an input stream from bytes backing the string_view. Note that + * the backing buffer must remain valid for the lifetime of this + * `StringReader`. + * + * (This is roughly equivalent to the Nanopb function + * `pb_istream_from_buffer()`) + */ + explicit StringReader(absl::string_view); + + void Read(const pb_field_t fields[], void* dest_struct) override; private: /** - * Creates a new Reader, based on the given nanopb pb_istream_t. Note that - * a shallow copy will be taken. (Non-null pointers within this struct must - * remain valid for the lifetime of this Reader.) + * Takes that a shallow copy of the given `stream`. (Non-null pointers within + * this struct must remain valid for the lifetime of this `StringReader`.) */ - explicit Reader(pb_istream_t stream) : stream_(stream) { + explicit StringReader(pb_istream_t stream) : stream_(stream) { } - util::Status status_ = util::Status::OK(); - - pb_istream_t stream_; + pb_istream_t stream_{}; }; } // namespace nanopb diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/writer.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/writer.cc index 0a28add..1c44a3b 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/writer.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/writer.cc @@ -16,64 +16,112 @@ #include "Firestore/core/src/firebase/firestore/nanopb/writer.h" +#include +#include + +#include "Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" namespace firebase { namespace firestore { namespace nanopb { +void Writer::Write(const pb_field_t fields[], const void* src_struct) { + if (!pb_encode(&stream_, fields, src_struct)) { + HARD_FAIL(PB_GET_ERROR(&stream_)); + } +} + namespace { -// TODO(rsgowman): find a better home for this constant. -// A document is defined to have a max size of 1MiB - 4 bytes. -const size_t kMaxDocumentSize = 1 * 1024 * 1024 - 4; +constexpr size_t kMinBufferSize = 4; -/** - * Creates a pb_ostream_t to the specified STL container. Note that this pointer - * must remain valid for the lifetime of the stream. - * - * (This is roughly equivalent to the nanopb function pb_ostream_from_buffer().) - * - * @tparm Container an STL container whose value_type is a char type. - * @param out_container where the output should be serialized to. - */ -template -pb_ostream_t WrapContainer(Container* out_container) { - // Construct a nanopb output stream. - // - // Set the max_size to be the max document size (as an upper bound; one would - // expect individual FieldValue's to be smaller than this). - // - // bytes_written is (always) initialized to 0. (NB: nanopb does not know or - // care about the underlying output vector, so where we are in the vector - // itself is irrelevant. i.e. don't use out_bytes->size()) - return {/*callback=*/[](pb_ostream_t* stream, const pb_byte_t* buf, - size_t count) -> bool { - auto* output = static_cast(stream->state); - output->insert(output->end(), buf, buf + count); - return true; - }, - /*state=*/out_container, - /*max_size=*/kMaxDocumentSize, - /*bytes_written=*/0, - /*errmsg=*/nullptr}; +bool AppendToBytesArray(pb_ostream_t* stream, + const pb_byte_t* buf, + size_t count) { + auto writer = static_cast(stream->state); + writer->Append(buf, count); + return true; } } // namespace -Writer Writer::Wrap(std::vector* out_bytes) { - return Writer{WrapContainer(out_bytes)}; +ByteStringWriter::ByteStringWriter() { + stream_.callback = AppendToBytesArray; + stream_.state = this; + stream_.max_size = SIZE_MAX; } -Writer Writer::Wrap(std::string* out_string) { - return Writer{WrapContainer(out_string)}; +ByteStringWriter::~ByteStringWriter() { + std::free(buffer_); } -void Writer::WriteNanopbMessage(const pb_field_t fields[], - const void* src_struct) { - if (!pb_encode(&stream_, fields, src_struct)) { - HARD_FAIL(PB_GET_ERROR(&stream_)); +void ByteStringWriter::Append(const void* data, size_t size) { + if (size == 0) return; + + pb_size_t pb_size = CheckedSize(size); + size_t current_size = this->size(); + size_t min_capacity = current_size + pb_size; + HARD_ASSERT(min_capacity >= current_size); // Avoid overflow + + Reserve(min_capacity); + uint8_t* pos = this->pos(); + std::memcpy(pos, data, size); + buffer_->size += pb_size; +} + +void ByteStringWriter::Reserve(size_t min_capacity) { + // Bump the min_capacity up so that an explicit Reserve will trigger an + // allocation, making pos() guaranteed to be valid. + min_capacity = std::max(min_capacity, kMinBufferSize); + if (min_capacity <= capacity_) return; + + // If capacity * 2 overflows, min_capacity will be larger. + size_t desired = std::max(capacity_ * 2, min_capacity); + + if (buffer_) { + buffer_ = static_cast( + std::realloc(buffer_, PB_BYTES_ARRAY_T_ALLOCSIZE(desired))); + } else { + // initialize on the first allocation. + buffer_ = static_cast( + std::calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(desired))); } + + capacity_ = desired; +} + +void ByteStringWriter::SetSize(size_t size) { + HARD_ASSERT(buffer_ != nullptr && + size <= capacity_); // Should have reserved. + buffer_->size = CheckedSize(size); +} + +ByteString ByteStringWriter::Release() { + pb_bytes_array_t* pending = buffer_; + buffer_ = nullptr; + capacity_ = 0; + return ByteString::Take(pending); +} + +namespace { + +bool AppendToString(pb_ostream_t* stream, const pb_byte_t* buf, size_t count) { + auto str = static_cast(stream->state); + str->insert(str->end(), buf, buf + count); + return true; +} + +} // namespace + +StringWriter::StringWriter() { + stream_.callback = AppendToString; + stream_.state = &buffer_; + stream_.max_size = SIZE_MAX; +} + +std::string StringWriter::Release() { + return std::move(buffer_); } } // namespace nanopb diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/writer.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/writer.h index b910930..641e6d4 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/writer.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/nanopb/writer.h @@ -24,57 +24,120 @@ #include #include +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" +#include "grpcpp/support/byte_buffer.h" + namespace firebase { namespace firestore { namespace nanopb { /** - * Docs TODO(rsgowman). But currently, this just wraps the underlying nanopb - * pb_ostream_t. All errors are considered fatal. + * Docs TODO(rsgowman). But currently, this just wraps the underlying Nanopb + * `pb_ostream_t`. All errors are considered fatal. */ class Writer { public: /** - * Creates an output stream that writes to the specified vector. Note that - * this vector pointer must remain valid for the lifetime of this Writer. - * - * (This is roughly equivalent to the nanopb function - * pb_ostream_from_buffer()) + * Writes a Nanopb proto to the output stream. * - * @param out_bytes where the output should be serialized to. + * This essentially wraps calls to Nanopb's `pb_encode()` method. */ - static Writer Wrap(std::vector* out_bytes); + void Write(const pb_field_t* fields, const void* src_struct); + protected: /** - * Creates an output stream that writes to the specified string. Note that - * this string pointer must remain valid for the lifetime of this Writer. - * - * (This is roughly equivalent to the nanopb function - * pb_ostream_from_buffer()) - * - * @param out_string where the output should be serialized to. + * Creates a `Writer` with a value-initialized `pb_ostream_t`. + */ + Writer() = default; + + pb_ostream_t stream_{}; +}; + +/** + * A `Writer` that writes into a vector of bytes. + * + * This is roughly equivalent to the Nanopb function `pb_ostream_from_buffer()`, + * except that `ByteStringWriter` manages the buffer. + */ +class ByteStringWriter : public Writer { + public: + ByteStringWriter(); + ~ByteStringWriter(); + + ByteStringWriter(const ByteStringWriter&) = delete; + ByteStringWriter& operator=(const ByteStringWriter&) = delete; + + /** + * Appends the given data to the internal buffer, growing the capacity of the + * buffer to fit. */ - static Writer Wrap(std::string* out_string); + void Append(const void* data, size_t size); /** - * Writes a nanopb message to the output stream. - * - * This essentially wraps calls to nanopb's `pb_encode()` method. If we didn't - * use `oneof`s in our protos, this would be the primary way of encoding - * messages. + * Reserves the given number of bytes of total capacity. To reserve `n` more + * bytes in a writer `w`, call `w.Reserve(w.size() + n)`. */ - void WriteNanopbMessage(const pb_field_t fields[], const void* src_struct); + void Reserve(size_t capacity); - private: /** - * Creates a new Writer, based on the given nanopb pb_ostream_t. Note that - * a shallow copy will be taken. (Non-null pointers within this struct must - * remain valid for the lifetime of this Writer.) + * Sets the size of the buffer to some value less than the current capacity, + * presumably after writing into the buffer with `pos()`. */ - explicit Writer(const pb_ostream_t& stream) : stream_(stream) { + void SetSize(size_t size); + + /** + * Returns a `ByteString` that takes ownership of the bytes backing this + * writer. + */ + ByteString Release(); + + size_t size() const { + return buffer_ ? buffer_->size : 0; } - pb_ostream_t stream_; + size_t capacity() const { + return capacity_; + } + + /** + * Returns the number of remaining bytes: the difference between capacity and + * size. + */ + size_t remaining() const { + return capacity_ - size(); + } + + /** + * Returns the current writing position within this writer's internal buffer. + * This can only be used after calling `Reserve()`. + */ + uint8_t* pos() { + return buffer_->bytes + buffer_->size; + } + + private: + pb_bytes_array_t* buffer_ = nullptr; + size_t capacity_ = 0; +}; + +/** + * A `Writer` that writes into a `std::string`. + * + * This is roughly equivalent to the Nanopb function `pb_ostream_from_buffer()`, + * except that `StringWriter` manages the string. + */ +class StringWriter : public Writer { + public: + StringWriter(); + + /** + * Returns the string backing this `StringWriter`, taking ownership of its + * contents. + */ + std::string Release(); + + private: + std::string buffer_; }; } // namespace nanopb diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/objc/objc_type_traits.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/objc/objc_type_traits.h new file mode 100644 index 0000000..0a8acad --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/objc/objc_type_traits.h @@ -0,0 +1,54 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_OBJC_OBJC_TYPE_TRAITS_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_OBJC_OBJC_TYPE_TRAITS_H_ + +#if __OBJC__ + +#include // for id + +#include + +namespace firebase { +namespace firestore { +namespace objc { + +/** + * A type trait that identifies whether or not the given pointer points to an + * Objective-C object. + * + * is_objc_pointer::value == true + * is_objc_pointer*>::value == true + * + * // id is a dynamically typed pointer to an Objective-C object. + * is_objc_pointer::value == true + * + * // pointers to C++ classes are not Objective-C pointers. + * is_objc_pointer::value == false + * is_objc_pointer::value == false + * is_objc_pointer>::value == false + */ +template +using is_objc_pointer = std::is_convertible; + +} // namespace objc +} // namespace firestore +} // namespace firebase + +#endif // __OBJC__ + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_OBJC_OBJC_TYPE_TRAITS_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/connectivity_monitor.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/connectivity_monitor.h index 6f7529c..86de93e 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/connectivity_monitor.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/connectivity_monitor.h @@ -50,9 +50,10 @@ class ConnectivityMonitor { /** Creates a platform-specific connectivity monitor. */ static std::unique_ptr Create( - util::AsyncQueue* worker_queue); + const std::shared_ptr& worker_queue); - explicit ConnectivityMonitor(util::AsyncQueue* worker_queue) + explicit ConnectivityMonitor( + const std::shared_ptr& worker_queue) : worker_queue_{worker_queue} { } @@ -71,12 +72,12 @@ class ConnectivityMonitor { // Invokes callbacks only if the status changed. void MaybeInvokeCallbacks(NetworkStatus new_status); - util::AsyncQueue* queue() { + const std::shared_ptr& queue() { return worker_queue_; } private: - util::AsyncQueue* worker_queue_ = nullptr; + std::shared_ptr worker_queue_; std::vector callbacks_; absl::optional status_; }; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/connectivity_monitor_apple.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/connectivity_monitor_apple.mm index f77a331..3f6c0df 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/connectivity_monitor_apple.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/connectivity_monitor_apple.mm @@ -24,7 +24,6 @@ #include -#include "Firestore/core/src/firebase/firestore/util/executor_libdispatch.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/log.h" #include "absl/memory/memory.h" @@ -37,7 +36,6 @@ using NetworkStatus = ConnectivityMonitor::NetworkStatus; using util::AsyncQueue; -using util::ExecutorLibdispatch; NetworkStatus ToNetworkStatus(SCNetworkReachabilityFlags flags) { if (!(flags & kSCNetworkReachabilityFlagsReachable)) { @@ -76,7 +74,8 @@ void OnReachabilityChangedCallback(SCNetworkReachabilityRef /*unused*/, */ class ConnectivityMonitorApple : public ConnectivityMonitor { public: - explicit ConnectivityMonitorApple(AsyncQueue* worker_queue) + explicit ConnectivityMonitorApple( + const std::shared_ptr& worker_queue) : ConnectivityMonitor{worker_queue} { reachability_ = CreateReachability(); if (!reachability_) { @@ -98,15 +97,12 @@ explicit ConnectivityMonitorApple(AsyncQueue* worker_queue) return; } - // TODO(varconst): 1. Make this at least more robust by adding an enum to - // `Executor` that allows asserting on the actual type before casting. - // 2. This is an unfortunate, brittle mechanism, see if better alternatives - // come up. - // On Apple platforms, the executor implementation must be the - // libdispatch-based one. - auto executor = static_cast(queue()->executor()); + // It's okay to use the main queue for reachability events because they are + // fairly infrequent, and there's no good way to get the underlying dispatch + // queue out of the worker queue. The callback itself is still executed on + // the worker queue. success = SCNetworkReachabilitySetDispatchQueue(reachability_, - executor->dispatch_queue()); + dispatch_get_main_queue()); if (!success) { LOG_DEBUG("Couldn't set reachability queue"); return; @@ -126,7 +122,7 @@ explicit ConnectivityMonitorApple(AsyncQueue* worker_queue) } void OnReachabilityChanged(SCNetworkReachabilityFlags flags) { - queue()->ExecuteBlocking( + queue()->Enqueue( [this, flags] { MaybeInvokeCallbacks(ToNetworkStatus(flags)); }); } @@ -147,7 +143,7 @@ void OnReachabilityChangedCallback(SCNetworkReachabilityRef /*unused*/, } // namespace std::unique_ptr ConnectivityMonitor::Create( - AsyncQueue* worker_queue) { + const std::shared_ptr& worker_queue) { return absl::make_unique(worker_queue); } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/datastore.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/datastore.cc new file mode 100644 index 0000000..9bf35ef --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/datastore.cc @@ -0,0 +1,357 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/remote/datastore.h" + +#include +#include + +#include "Firestore/core/include/firebase/firestore/firestore_errors.h" +#include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" +#include "Firestore/core/src/firebase/firestore/auth/token.h" +#include "Firestore/core/src/firebase/firestore/core/database_info.h" +#include "Firestore/core/src/firebase/firestore/model/database_id.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/remote/connectivity_monitor.h" +#include "Firestore/core/src/firebase/firestore/remote/grpc_completion.h" +#include "Firestore/core/src/firebase/firestore/remote/grpc_connection.h" +#include "Firestore/core/src/firebase/firestore/remote/grpc_nanopb.h" +#include "Firestore/core/src/firebase/firestore/remote/grpc_stream.h" +#include "Firestore/core/src/firebase/firestore/remote/grpc_streaming_reader.h" +#include "Firestore/core/src/firebase/firestore/remote/grpc_unary_call.h" +#include "Firestore/core/src/firebase/firestore/util/async_queue.h" +#include "Firestore/core/src/firebase/firestore/util/error_apple.h" +#include "Firestore/core/src/firebase/firestore/util/executor.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/statusor.h" +#include "absl/memory/memory.h" +#include "absl/strings/str_cat.h" + +namespace firebase { +namespace firestore { +namespace remote { +namespace { + +using auth::CredentialsProvider; +using auth::Token; +using core::DatabaseInfo; +using model::DocumentKey; +using model::MaybeDocument; +using model::Mutation; +using util::AsyncQueue; +using util::Executor; +using util::LogIsDebugEnabled; +using util::Status; +using util::StatusOr; + +const auto kRpcNameCommit = "/google.firestore.v1.Firestore/Commit"; +const auto kRpcNameLookup = "/google.firestore.v1.Firestore/BatchGetDocuments"; + +std::unique_ptr CreateExecutor() { + return Executor::CreateSerial("com.google.firebase.firestore.rpc"); +} + +std::string MakeString(grpc::string_ref grpc_str) { + return {grpc_str.begin(), grpc_str.size()}; +} + +absl::string_view MakeStringView(grpc::string_ref grpc_str) { + return {grpc_str.begin(), grpc_str.size()}; +} + +void LogGrpcCallFinished(absl::string_view rpc_name, + GrpcCall* call, + const Status& status) { + LOG_DEBUG("RPC %s completed. Error: %s: %s", rpc_name, status.code(), + status.error_message()); + if (LogIsDebugEnabled()) { + auto headers = + Datastore::GetWhitelistedHeadersAsString(call->GetResponseHeaders()); + LOG_DEBUG("RPC %s returned headers (whitelisted): %s", rpc_name, headers); + } +} + +} // namespace + +Datastore::Datastore(const DatabaseInfo& database_info, + const std::shared_ptr& worker_queue, + std::shared_ptr credentials) + : Datastore{database_info, worker_queue, credentials, + ConnectivityMonitor::Create(worker_queue)} { +} + +Datastore::Datastore(const DatabaseInfo& database_info, + const std::shared_ptr& worker_queue, + std::shared_ptr credentials, + std::unique_ptr connectivity_monitor) + : worker_queue_{NOT_NULL(worker_queue)}, + credentials_{std::move(credentials)}, + rpc_executor_{CreateExecutor()}, + connectivity_monitor_{std::move(connectivity_monitor)}, + grpc_connection_{database_info, worker_queue, &grpc_queue_, + connectivity_monitor_.get()}, + datastore_serializer_{database_info} { + if (!database_info.ssl_enabled()) { + GrpcConnection::UseInsecureChannel(database_info.host()); + } +} + +void Datastore::Start() { + rpc_executor_->Execute([this] { PollGrpcQueue(); }); +} + +void Datastore::Shutdown() { + is_shut_down_ = true; + + // Order matters here: shutting down `grpc_connection_`, which will quickly + // finish any pending gRPC calls, must happen before shutting down the gRPC + // queue. + grpc_connection_.Shutdown(); + + // `grpc::CompletionQueue::Next` will only return `false` once `Shutdown` has + // been called and all submitted tags have been extracted. Without this call, + // `rpc_executor_` will never finish. + grpc_queue_.Shutdown(); + // Drain the executor to make sure it extracted all the operations from gRPC + // completion queue. + rpc_executor_->ExecuteBlocking([] {}); +} + +void Datastore::PollGrpcQueue() { + HARD_ASSERT(rpc_executor_->IsCurrentExecutor(), + "PollGrpcQueue should only be called on the " + "dedicated Datastore executor"); + + void* tag = nullptr; + bool ok = false; + while (grpc_queue_.Next(&tag, &ok)) { + auto completion = static_cast(tag); + // While it's valid in principle, we never deliberately pass a null pointer + // to gRPC completion queue and expect it back. This assertion might be + // relaxed if necessary. + HARD_ASSERT(tag, "gRPC queue returned a null tag"); + completion->Complete(ok); + } +} + +std::shared_ptr Datastore::CreateWatchStream( + WatchStreamCallback* callback) { + return std::make_shared(worker_queue_, credentials_, + datastore_serializer_.serializer(), + &grpc_connection_, callback); +} + +std::shared_ptr Datastore::CreateWriteStream( + WriteStreamCallback* callback) { + return std::make_shared(worker_queue_, credentials_, + datastore_serializer_.serializer(), + &grpc_connection_, callback); +} + +void Datastore::CommitMutations(const std::vector& mutations, + CommitCallback&& callback) { + ResumeRpcWithCredentials( + // TODO(c++14): move into lambda. + [this, mutations, + callback](const StatusOr& maybe_credentials) mutable { + if (!maybe_credentials.ok()) { + callback(maybe_credentials.status()); + return; + } + CommitMutationsWithCredentials(maybe_credentials.ValueOrDie(), + mutations, std::move(callback)); + }); +} + +void Datastore::CommitMutationsWithCredentials( + const Token& token, + const std::vector& mutations, + CommitCallback&& callback) { + grpc::ByteBuffer message = + MakeByteBuffer(datastore_serializer_.EncodeCommitRequest(mutations)); + + std::unique_ptr call_owning = grpc_connection_.CreateUnaryCall( + kRpcNameCommit, token, std::move(message)); + GrpcUnaryCall* call = call_owning.get(); + active_calls_.push_back(std::move(call_owning)); + + call->Start( + // TODO(c++14): move into lambda. + [this, call, callback](const StatusOr& result) { + LogGrpcCallFinished("CommitRequest", call, result.status()); + HandleCallStatus(result.status()); + + // Response is deliberately ignored + callback(result.status()); + + RemoveGrpcCall(call); + }); +} + +void Datastore::LookupDocuments(const std::vector& keys, + LookupCallback&& callback) { + ResumeRpcWithCredentials( + // TODO(c++14): move into lambda. + [this, keys, callback](const StatusOr& maybe_credentials) mutable { + if (!maybe_credentials.ok()) { + callback(maybe_credentials.status()); + return; + } + LookupDocumentsWithCredentials(maybe_credentials.ValueOrDie(), keys, + std::move(callback)); + }); +} + +void Datastore::LookupDocumentsWithCredentials( + const Token& token, + const std::vector& keys, + LookupCallback&& callback) { + grpc::ByteBuffer message = + MakeByteBuffer(datastore_serializer_.EncodeLookupRequest(keys)); + + std::unique_ptr call_owning = + grpc_connection_.CreateStreamingReader(kRpcNameLookup, token, + std::move(message)); + GrpcStreamingReader* call = call_owning.get(); + active_calls_.push_back(std::move(call_owning)); + + // TODO(c++14): move into lambda. + call->Start([this, call, callback]( + const StatusOr>& result) { + LogGrpcCallFinished("BatchGetDocuments", call, result.status()); + HandleCallStatus(result.status()); + + OnLookupDocumentsResponse(result, callback); + + RemoveGrpcCall(call); + }); +} + +void Datastore::OnLookupDocumentsResponse( + const StatusOr>& result, + const LookupCallback& callback) { + if (!result.ok()) { + callback(result.status()); + return; + } + + std::vector responses = std::move(result).ValueOrDie(); + callback(datastore_serializer_.MergeLookupResponses(responses)); +} + +void Datastore::ResumeRpcWithCredentials(const OnCredentials& on_credentials) { + // Auth may outlive Firestore + std::weak_ptr weak_this{shared_from_this()}; + + credentials_->GetToken( + [weak_this, on_credentials](const StatusOr& result) { + auto strong_this = weak_this.lock(); + if (!strong_this) { + return; + } + + strong_this->worker_queue_->EnqueueRelaxed( + [weak_this, result, on_credentials] { + auto strong_this = weak_this.lock(); + if (!strong_this) { + return; + } + // In case Auth callback is invoked after Datastore has been shut + // down. + if (strong_this->is_shut_down_) { + return; + } + + on_credentials(result); + }); + }); +} + +void Datastore::HandleCallStatus(const Status& status) { + if (status.code() == Error::Unauthenticated) { + credentials_->InvalidateToken(); + } +} + +void Datastore::RemoveGrpcCall(GrpcCall* to_remove) { + auto found = std::find_if(active_calls_.begin(), active_calls_.end(), + [to_remove](const std::unique_ptr& call) { + return call.get() == to_remove; + }); + HARD_ASSERT(found != active_calls_.end(), "Missing gRPC call"); + active_calls_.erase(found); +} + +bool Datastore::IsAbortedError(const Status& error) { + return error.code() == Error::Aborted; +} + +bool Datastore::IsPermanentError(const Status& error) { + switch (error.code()) { + case Error::Ok: + HARD_FAIL("Treated status OK as error"); + case Error::Cancelled: + case Error::Unknown: + case Error::DeadlineExceeded: + case Error::ResourceExhausted: + case Error::Internal: + case Error::Unavailable: + // Unauthenticated means something went wrong with our token and we need + // to retry with new credentials which will happen automatically. + case Error::Unauthenticated: + return false; + case Error::InvalidArgument: + case Error::NotFound: + case Error::AlreadyExists: + case Error::PermissionDenied: + case Error::FailedPrecondition: + case Error::Aborted: + // Aborted might be retried in some scenarios, but that is dependant on + // the context and should handled individually by the calling code. + // See https://cloud.google.com/apis/design/errors + case Error::OutOfRange: + case Error::Unimplemented: + case Error::DataLoss: + return true; + } + + HARD_FAIL("Unknown status code: %s", error.code()); +} + +bool Datastore::IsPermanentWriteError(const Status& error) { + return IsPermanentError(error) && !IsAbortedError(error); +} + +std::string Datastore::GetWhitelistedHeadersAsString( + const GrpcCall::Metadata& headers) { + static std::unordered_set whitelist = { + "date", "x-google-backends", "x-google-netmon-label", "x-google-service", + "x-google-gfe-request-trace"}; + + std::string result; + for (const auto& kv : headers) { + if (whitelist.find(MakeString(kv.first)) != whitelist.end()) { + absl::StrAppend(&result, MakeStringView(kv.first), ": ", + MakeStringView(kv.second), "\n"); + } + } + return result; +} + +} // namespace remote +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/datastore.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/datastore.h index 30ab827..c992c49 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/datastore.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/datastore.h @@ -17,12 +17,6 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_DATASTORE_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_DATASTORE_H_ -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import - #include #include #include @@ -39,14 +33,11 @@ #include "Firestore/core/src/firebase/firestore/remote/write_stream.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" #include "Firestore/core/src/firebase/firestore/util/executor.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" -#include "Firestore/core/src/firebase/firestore/util/statusor.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "absl/strings/string_view.h" #include "grpcpp/completion_queue.h" #include "grpcpp/support/status.h" -#import "Firestore/Source/Core/FSTTypes.h" - namespace firebase { namespace firestore { namespace remote { @@ -68,15 +59,13 @@ namespace remote { */ class Datastore : public std::enable_shared_from_this { public: - // TODO(varconst): once `FSTMaybeDocument` is replaced with a C++ equivalent, - // this function could take a single `StatusOr` parameter. using LookupCallback = std::function&, const util::Status&)>; + const util::StatusOr>&)>; using CommitCallback = std::function; Datastore(const core::DatabaseInfo& database_info, - util::AsyncQueue* worker_queue, - auth::CredentialsProvider* credentials); + const std::shared_ptr& worker_queue, + std::shared_ptr credentials); virtual ~Datastore() { } @@ -99,7 +88,7 @@ class Datastore : public std::enable_shared_from_this { virtual std::shared_ptr CreateWriteStream( WriteStreamCallback* callback); - void CommitMutations(const std::vector& mutations, + void CommitMutations(const std::vector& mutations, CommitCallback&& callback); void LookupDocuments(const std::vector& keys, LookupCallback&& callback); @@ -141,8 +130,8 @@ class Datastore : public std::enable_shared_from_this { protected: /** Test-only constructor */ Datastore(const core::DatabaseInfo& database_info, - util::AsyncQueue* worker_queue, - auth::CredentialsProvider* credentials, + const std::shared_ptr& worker_queue, + std::shared_ptr credentials, std::unique_ptr connectivity_monitor); /** Test-only method */ @@ -164,7 +153,7 @@ class Datastore : public std::enable_shared_from_this { void CommitMutationsWithCredentials( const auth::Token& token, - const std::vector& mutations, + const std::vector& mutations, CommitCallback&& callback); void LookupDocumentsWithCredentials( @@ -189,19 +178,19 @@ class Datastore : public std::enable_shared_from_this { // down. bool is_shut_down_ = false; - util::AsyncQueue* worker_queue_ = nullptr; - auth::CredentialsProvider* credentials_ = nullptr; + std::shared_ptr worker_queue_; + std::shared_ptr credentials_; // A separate executor dedicated to polling gRPC completion queue (which is // shared for all spawned gRPC streams and calls). std::unique_ptr rpc_executor_; grpc::CompletionQueue grpc_queue_; - // TODO(varconst): move `ConnectivityMonitor` to `FSTFirestoreClient`. + // TODO(varconst): move `ConnectivityMonitor` to `FirestoreClient`. std::unique_ptr connectivity_monitor_; GrpcConnection grpc_connection_; std::vector> active_calls_; - bridge::DatastoreSerializer serializer_bridge_; + DatastoreSerializer datastore_serializer_; }; } // namespace remote diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/datastore.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/datastore.mm deleted file mode 100644 index 05806c2..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/datastore.mm +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/remote/datastore.h" - -#include -#include - -#import "Firestore/Source/Remote/FSTSerializerBeta.h" - -#include "Firestore/core/include/firebase/firestore/firestore_errors.h" -#include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" -#include "Firestore/core/src/firebase/firestore/auth/token.h" -#include "Firestore/core/src/firebase/firestore/core/database_info.h" -#include "Firestore/core/src/firebase/firestore/model/database_id.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/remote/connectivity_monitor.h" -#include "Firestore/core/src/firebase/firestore/remote/grpc_completion.h" -#include "Firestore/core/src/firebase/firestore/remote/grpc_connection.h" -#include "Firestore/core/src/firebase/firestore/remote/grpc_stream.h" -#include "Firestore/core/src/firebase/firestore/remote/grpc_streaming_reader.h" -#include "Firestore/core/src/firebase/firestore/remote/grpc_unary_call.h" -#include "Firestore/core/src/firebase/firestore/util/async_queue.h" -#include "Firestore/core/src/firebase/firestore/util/error_apple.h" -#include "Firestore/core/src/firebase/firestore/util/executor_libdispatch.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/log.h" -#include "Firestore/core/src/firebase/firestore/util/statusor.h" -#include "absl/memory/memory.h" -#include "absl/strings/str_cat.h" - -namespace firebase { -namespace firestore { -namespace remote { - -using auth::CredentialsProvider; -using auth::Token; -using core::DatabaseInfo; -using model::DocumentKey; -using util::AsyncQueue; -using util::Status; -using util::StatusOr; -using util::Executor; -using util::ExecutorLibdispatch; - -namespace { - -const auto kRpcNameCommit = "/google.firestore.v1.Firestore/Commit"; -const auto kRpcNameLookup = "/google.firestore.v1.Firestore/BatchGetDocuments"; - -std::unique_ptr CreateExecutor() { - auto queue = dispatch_queue_create("com.google.firebase.firestore.rpc", - DISPATCH_QUEUE_SERIAL); - return absl::make_unique(queue); -} - -std::string MakeString(grpc::string_ref grpc_str) { - return {grpc_str.begin(), grpc_str.size()}; -} - -absl::string_view MakeStringView(grpc::string_ref grpc_str) { - return {grpc_str.begin(), grpc_str.size()}; -} - -void LogGrpcCallFinished(absl::string_view rpc_name, - GrpcCall* call, - const Status& status) { - LOG_DEBUG("RPC %s completed. Error: %s: %s", rpc_name, status.code(), - status.error_message()); - if (bridge::IsLoggingEnabled()) { - auto headers = - Datastore::GetWhitelistedHeadersAsString(call->GetResponseHeaders()); - LOG_DEBUG("RPC %s returned headers (whitelisted): %s", rpc_name, headers); - } -} - -} // namespace - -Datastore::Datastore(const DatabaseInfo& database_info, - AsyncQueue* worker_queue, - CredentialsProvider* credentials) - : Datastore{database_info, worker_queue, credentials, - ConnectivityMonitor::Create(worker_queue)} { -} - -Datastore::Datastore(const DatabaseInfo& database_info, - AsyncQueue* worker_queue, - CredentialsProvider* credentials, - std::unique_ptr connectivity_monitor) - : worker_queue_{NOT_NULL(worker_queue)}, - credentials_{credentials}, - rpc_executor_{CreateExecutor()}, - connectivity_monitor_{std::move(connectivity_monitor)}, - grpc_connection_{database_info, worker_queue, &grpc_queue_, - connectivity_monitor_.get()}, - serializer_bridge_{database_info} { - if (!database_info.ssl_enabled()) { - GrpcConnection::UseInsecureChannel(database_info.host()); - } -} - -void Datastore::Start() { - rpc_executor_->Execute([this] { PollGrpcQueue(); }); -} - -void Datastore::Shutdown() { - is_shut_down_ = true; - - // Order matters here: shutting down `grpc_connection_`, which will quickly - // finish any pending gRPC calls, must happen before shutting down the gRPC - // queue. - grpc_connection_.Shutdown(); - - // `grpc::CompletionQueue::Next` will only return `false` once `Shutdown` has - // been called and all submitted tags have been extracted. Without this call, - // `rpc_executor_` will never finish. - grpc_queue_.Shutdown(); - // Drain the executor to make sure it extracted all the operations from gRPC - // completion queue. - rpc_executor_->ExecuteBlocking([] {}); -} - -void Datastore::PollGrpcQueue() { - HARD_ASSERT(rpc_executor_->IsCurrentExecutor(), - "PollGrpcQueue should only be called on the " - "dedicated Datastore executor"); - - void* tag = nullptr; - bool ok = false; - while (grpc_queue_.Next(&tag, &ok)) { - auto completion = static_cast(tag); - // While it's valid in principle, we never deliberately pass a null pointer - // to gRPC completion queue and expect it back. This assertion might be - // relaxed if necessary. - HARD_ASSERT(tag, "gRPC queue returned a null tag"); - completion->Complete(ok); - } -} - -std::shared_ptr Datastore::CreateWatchStream( - WatchStreamCallback* callback) { - return std::make_shared(worker_queue_, credentials_, - serializer_bridge_.GetSerializer(), - &grpc_connection_, callback); -} - -std::shared_ptr Datastore::CreateWriteStream( - WriteStreamCallback* callback) { - return std::make_shared(worker_queue_, credentials_, - serializer_bridge_.GetSerializer(), - &grpc_connection_, callback); -} - -void Datastore::CommitMutations(const std::vector& mutations, - CommitCallback&& callback) { - ResumeRpcWithCredentials( - // TODO(c++14): move into lambda. - [this, mutations, - callback](const StatusOr& maybe_credentials) mutable { - if (!maybe_credentials.ok()) { - callback(maybe_credentials.status()); - return; - } - CommitMutationsWithCredentials(maybe_credentials.ValueOrDie(), - mutations, std::move(callback)); - }); -} - -void Datastore::CommitMutationsWithCredentials( - const Token& token, - const std::vector& mutations, - CommitCallback&& callback) { - grpc::ByteBuffer message = serializer_bridge_.ToByteBuffer( - serializer_bridge_.CreateCommitRequest(mutations)); - - std::unique_ptr call_owning = grpc_connection_.CreateUnaryCall( - kRpcNameCommit, token, std::move(message)); - GrpcUnaryCall* call = call_owning.get(); - active_calls_.push_back(std::move(call_owning)); - - call->Start( - // TODO(c++14): move into lambda. - [this, call, callback](const StatusOr& result) { - LogGrpcCallFinished("CommitRequest", call, result.status()); - HandleCallStatus(result.status()); - - // Response is deliberately ignored - callback(result.status()); - - RemoveGrpcCall(call); - }); -} - -void Datastore::LookupDocuments(const std::vector& keys, - LookupCallback&& callback) { - ResumeRpcWithCredentials( - // TODO(c++14): move into lambda. - [this, keys, callback](const StatusOr& maybe_credentials) mutable { - if (!maybe_credentials.ok()) { - callback({}, maybe_credentials.status()); - return; - } - LookupDocumentsWithCredentials(maybe_credentials.ValueOrDie(), keys, - std::move(callback)); - }); -} - -void Datastore::LookupDocumentsWithCredentials( - const Token& token, - const std::vector& keys, - LookupCallback&& callback) { - grpc::ByteBuffer message = serializer_bridge_.ToByteBuffer( - serializer_bridge_.CreateLookupRequest(keys)); - - std::unique_ptr call_owning = - grpc_connection_.CreateStreamingReader(kRpcNameLookup, token, - std::move(message)); - GrpcStreamingReader* call = call_owning.get(); - active_calls_.push_back(std::move(call_owning)); - - // TODO(c++14): move into lambda. - call->Start([this, call, callback]( - const StatusOr>& result) { - LogGrpcCallFinished("BatchGetDocuments", call, result.status()); - HandleCallStatus(result.status()); - - OnLookupDocumentsResponse(result, callback); - - RemoveGrpcCall(call); - }); -} - -void Datastore::OnLookupDocumentsResponse( - const StatusOr>& result, - const LookupCallback& callback) { - if (!result.ok()) { - callback({}, result.status()); - return; - } - - Status parse_status; - std::vector responses = std::move(result).ValueOrDie(); - std::vector docs = - serializer_bridge_.MergeLookupResponses(responses, &parse_status); - callback(docs, parse_status); -} - -void Datastore::ResumeRpcWithCredentials(const OnCredentials& on_credentials) { - // Auth may outlive Firestore - std::weak_ptr weak_this{shared_from_this()}; - - credentials_->GetToken( - [weak_this, on_credentials](const StatusOr& result) { - auto strong_this = weak_this.lock(); - if (!strong_this) { - return; - } - - strong_this->worker_queue_->EnqueueRelaxed( - [weak_this, result, on_credentials] { - auto strong_this = weak_this.lock(); - if (!strong_this) { - return; - } - // In case Auth callback is invoked after Datastore has been shut - // down. - if (strong_this->is_shut_down_) { - return; - } - - on_credentials(result); - }); - }); -} - -void Datastore::HandleCallStatus(const Status& status) { - if (status.code() == FirestoreErrorCode::Unauthenticated) { - credentials_->InvalidateToken(); - } -} - -void Datastore::RemoveGrpcCall(GrpcCall* to_remove) { - auto found = std::find_if(active_calls_.begin(), active_calls_.end(), - [to_remove](const std::unique_ptr& call) { - return call.get() == to_remove; - }); - HARD_ASSERT(found != active_calls_.end(), "Missing gRPC call"); - active_calls_.erase(found); -} - -bool Datastore::IsAbortedError(const Status& error) { - return error.code() == FirestoreErrorCode::Aborted; -} - -bool Datastore::IsPermanentError(const Status& error) { - switch (error.code()) { - case FirestoreErrorCode::Ok: - HARD_FAIL("Treated status OK as error"); - case FirestoreErrorCode::Cancelled: - case FirestoreErrorCode::Unknown: - case FirestoreErrorCode::DeadlineExceeded: - case FirestoreErrorCode::ResourceExhausted: - case FirestoreErrorCode::Internal: - case FirestoreErrorCode::Unavailable: - // Unauthenticated means something went wrong with our token and we need - // to retry with new credentials which will happen automatically. - case FirestoreErrorCode::Unauthenticated: - return false; - case FirestoreErrorCode::InvalidArgument: - case FirestoreErrorCode::NotFound: - case FirestoreErrorCode::AlreadyExists: - case FirestoreErrorCode::PermissionDenied: - case FirestoreErrorCode::FailedPrecondition: - case FirestoreErrorCode::Aborted: - // Aborted might be retried in some scenarios, but that is dependant on - // the context and should handled individually by the calling code. - // See https://cloud.google.com/apis/design/errors - case FirestoreErrorCode::OutOfRange: - case FirestoreErrorCode::Unimplemented: - case FirestoreErrorCode::DataLoss: - return true; - } - - HARD_FAIL("Unknown status code: %s", error.code()); -} - -bool Datastore::IsPermanentWriteError(const Status& error) { - return IsPermanentError(error) && !IsAbortedError(error); -} - -std::string Datastore::GetWhitelistedHeadersAsString( - const GrpcCall::Metadata& headers) { - static std::unordered_set whitelist = { - "date", "x-google-backends", "x-google-netmon-label", "x-google-service", - "x-google-gfe-request-trace"}; - - std::string result; - for (const auto& kv : headers) { - if (whitelist.find(MakeString(kv.first)) != whitelist.end()) { - absl::StrAppend(&result, MakeStringView(kv.first), ": ", - MakeStringView(kv.second), "\n"); - } - } - return result; -} - -} // namespace remote -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/exponential_backoff.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/exponential_backoff.cc index d93d081..7239df9 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/exponential_backoff.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/exponential_backoff.cc @@ -17,6 +17,7 @@ #include "Firestore/core/src/firebase/firestore/remote/exponential_backoff.h" #include +#include #include #include @@ -26,12 +27,27 @@ namespace firebase { namespace firestore { namespace remote { +namespace { using firebase::firestore::util::AsyncQueue; using firebase::firestore::util::TimerId; +using Milliseconds = util::AsyncQueue::Milliseconds; namespace chr = std::chrono; -ExponentialBackoff::ExponentialBackoff(AsyncQueue* queue, +/** + * Initial backoff time in milliseconds after an error. Set to 1s according to + * https://cloud.google.com/apis/design/errors. + */ +constexpr Milliseconds kDefaultBackoffInitialDelay = Milliseconds(1000); + +constexpr double kDefaultBackoffFactor = 1.5; + +/** Maximum backoff time in milliseconds. */ +constexpr Milliseconds kDefaultBackoffMaxDelay = Milliseconds(60 * 1000); + +} // namespace + +ExponentialBackoff::ExponentialBackoff(const std::shared_ptr& queue, TimerId timer_id, double backoff_factor, Milliseconds initial_delay, @@ -52,6 +68,15 @@ ExponentialBackoff::ExponentialBackoff(AsyncQueue* queue, "Initial delay can't be greater than max delay"); } +ExponentialBackoff::ExponentialBackoff(const std::shared_ptr& queue, + TimerId timer_id) + : ExponentialBackoff(queue, + timer_id, + kDefaultBackoffFactor, + kDefaultBackoffInitialDelay, + kDefaultBackoffMaxDelay) { +} + void ExponentialBackoff::BackoffAndRun(AsyncQueue::Operation&& operation) { Cancel(); @@ -88,15 +113,14 @@ void ExponentialBackoff::BackoffAndRun(AsyncQueue::Operation&& operation) { chr::duration_cast(current_base_ * backoff_factor_)); } -ExponentialBackoff::Milliseconds ExponentialBackoff::GetDelayWithJitter() { +Milliseconds ExponentialBackoff::GetDelayWithJitter() { std::uniform_real_distribution distribution; double random_double = distribution(secure_random_); return chr::duration_cast((random_double - 0.5) * current_base_); } -ExponentialBackoff::Milliseconds ExponentialBackoff::ClampDelay( - Milliseconds delay) const { +Milliseconds ExponentialBackoff::ClampDelay(Milliseconds delay) const { if (delay < initial_delay_) { return initial_delay_; } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/exponential_backoff.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/exponential_backoff.h index de2418c..f4c1e92 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/exponential_backoff.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/exponential_backoff.h @@ -18,6 +18,7 @@ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_EXPONENTIAL_BACKOFF_H_ #include // NOLINT(build/c++11) +#include #include "Firestore/core/src/firebase/firestore/util/async_queue.h" #include "Firestore/core/src/firebase/firestore/util/secure_random.h" @@ -54,16 +55,22 @@ class ExponentialBackoff { * performed. Note that jitter will still be applied, so the actual delay * could be as much as `1.5*max_delay`. */ - ExponentialBackoff(util::AsyncQueue* queue, + ExponentialBackoff(const std::shared_ptr& queue, util::TimerId timer_id, double backoff_factor, util::AsyncQueue::Milliseconds initial_delay, util::AsyncQueue::Milliseconds max_delay); + /** + * Instantiates the exponential backoff with the default values. + */ + ExponentialBackoff(const std::shared_ptr& queue, + util::TimerId timer_id); + /** * Resets the backoff delay. * - * The very next `backoffAndRun` will have no delay. If it is called again + * The very next `BackoffAndRun` will have no delay. If it is called again * (i.e. due to an error), `initial_delay` (plus jitter) will be used, and * subsequent ones will increase according to the `backoff_factor`. */ @@ -93,12 +100,11 @@ class ExponentialBackoff { private: using Milliseconds = util::AsyncQueue::Milliseconds; - // Returns a random value in the range [-current_base_/2, current_base_/2]. Milliseconds GetDelayWithJitter(); Milliseconds ClampDelay(Milliseconds delay) const; - util::AsyncQueue* const queue_; + std::shared_ptr queue_; const util::TimerId timer_id_; util::DelayedOperation delayed_operation_; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_call.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_call.h index 6cd0c33..8c2b38e 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_call.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_call.h @@ -19,7 +19,7 @@ #include -#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "grpcpp/client_context.h" #include "grpcpp/support/string_ref.h" diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_completion.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_completion.cc index 18574aa..815dbc4 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_completion.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_completion.cc @@ -16,6 +16,7 @@ #include "Firestore/core/src/firebase/firestore/remote/grpc_completion.h" +#include #include namespace firebase { @@ -24,22 +25,44 @@ namespace remote { using util::AsyncQueue; -GrpcCompletion::GrpcCompletion(Type type, - AsyncQueue* worker_queue, - Callback&& callback) +std::shared_ptr GrpcCompletion::Create( + Type type, + const std::shared_ptr& worker_queue, + Callback&& callback) { + // Construct in two steps to use the private constructor. + GrpcCompletion partial(type, worker_queue, std::move(callback)); + auto completion = std::make_shared(std::move(partial)); + + // Prepare the `GrpcCompletion` for submission to gRPC. + // + // Note: this is done in a separate step because `shared_from_this` cannot be + // called in a constructor. + completion->grpc_ownership_ = completion; + + return completion; +} + +GrpcCompletion::GrpcCompletion( + Type type, + const std::shared_ptr& worker_queue, + Callback&& callback) : worker_queue_{worker_queue}, callback_{std::move(callback)}, type_{type} { } void GrpcCompletion::Cancel() { worker_queue_->VerifyIsCurrentQueue(); callback_ = {}; + + // Does not release grpc_ownership_. If gRPC still holds this completion it + // must remain valid to avoid a use-after-free once Complete is actually + // called. } void GrpcCompletion::WaitUntilOffQueue() { worker_queue_->VerifyIsCurrentQueue(); EnsureValidFuture(); - return off_queue_future_.wait(); + off_queue_future_.wait(); } std::future_status GrpcCompletion::WaitUntilOffQueue( @@ -62,12 +85,21 @@ void GrpcCompletion::Complete(bool ok) { // objects to be valid). off_queue_.set_value(); - worker_queue_->Enqueue([this, ok] { - if (callback_) { - callback_(ok, this); + // The queued operation needs to also retain this completion. It's possible + // for Complete to fire, shutdown to start, and then have this queued + // operation run. If this weren't a retain that ordering would have the + // callback use after free. + auto shared_this = grpc_ownership_; + worker_queue_->Enqueue([shared_this, ok] { + if (shared_this->callback_) { + shared_this->callback_(ok, shared_this); } - delete this; }); + + // Having called Complete, gRPC has released its ownership interest in this + // object. Once the queued operation completes the `GrpcCompletion` will be + // deleted. + grpc_ownership_.reset(); } } // namespace remote diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_completion.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_completion.h index 17641ba..3bf280c 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_completion.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_completion.h @@ -20,10 +20,11 @@ #include // NOLINT(build/c++11) #include #include // NOLINT(build/c++11) +#include #include #include "Firestore/core/src/firebase/firestore/util/async_queue.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "grpcpp/support/byte_buffer.h" namespace firebase { @@ -47,14 +48,16 @@ namespace remote { * operation). The buffer and/or the status may be unused by the corresponding * gRPC operation. * - * `GrpcCompletion` is "self-owned"; `GrpcCompletion` deletes itself in its - * `Complete` method. + * `GrpcCompletion` has shared ownership. While it has been submitted as a tag + * to a gRPC operation, gRPC owns it. Callers also potentially own the + * `GrpcCompletion` if they retain it. Once all interested parties have released + * their shared_ptrs, the `GrpcCompletion` is deleted. * * `GrpcCompletion` expects all gRPC objects pertaining to the current stream to * remain valid until the `GrpcCompletion` comes back from the gRPC completion * queue. */ -class GrpcCompletion { +class GrpcCompletion : public std::enable_shared_from_this { public: /** * This is only to aid debugging and testing; type allows easily @@ -68,11 +71,13 @@ class GrpcCompletion { * * The `GrpcCompletion` pointer will always point to `this`. */ - using Callback = std::function; + using Callback = + std::function&)>; - GrpcCompletion(Type type, - util::AsyncQueue* firestore_queue, - Callback&& callback); + static std::shared_ptr Create( + Type type, + const std::shared_ptr& worker_queue, + Callback&& callback); /** * Marks the `GrpcCompletion` as having come back from the gRPC completion @@ -114,11 +119,31 @@ class GrpcCompletion { } private: - util::AsyncQueue* worker_queue_ = nullptr; - Callback callback_; + GrpcCompletion(Type type, + const std::shared_ptr& worker_queue, + Callback&& callback); void EnsureValidFuture(); + std::shared_ptr worker_queue_; + Callback callback_; + + // Ownership of the GrpcCompletion is shared between the Firestore gRPC + // wrapper object that initiated the operation (e.g., a `GrpcStream`) and gRPC + // itself, for as long as the completion is on the gRPC completion queue. + // While most of the time a completion gets removed from the gRPC completion + // queue first and then destroyed by the wrapper, during shutdown the gRPC + // wrapper can be destroyed first so in that case the completion needs to + // delete itself. + // + // To handle these two cases, `GrpcCompletion` is held by shared_ptr, and one + // shared_ptr is held here, within the `GrpcCompletion` itself to model gRPC's + // ownership. This works around a limitation in the gRPC API where it only + // accepts raw pointers for tag objects. Once this completion is completed, + // the grpc_ownership_ shared_ptr is reset, which models gRPC releasing its + // interest in the completion. + std::shared_ptr grpc_ownership_; + // Note that even though `grpc::GenericClientAsyncReaderWriter::Write` takes // the byte buffer by const reference, it expects the buffer's lifetime to // extend beyond `Write` (the buffer must be valid until the completion queue diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_connection.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_connection.cc index 55ee82b..f46f641 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_connection.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_connection.cc @@ -17,6 +17,7 @@ #include "Firestore/core/src/firebase/firestore/remote/grpc_connection.h" #include +#include // NOLINT(build/c++11) #include #include @@ -28,6 +29,7 @@ #include "Firestore/core/src/firebase/firestore/util/filesystem.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/statusor.h" #include "Firestore/core/src/firebase/firestore/util/string_format.h" #include "absl/memory/memory.h" #include "grpcpp/create_channel.h" @@ -39,6 +41,7 @@ namespace remote { using auth::Token; using core::DatabaseInfo; using model::DatabaseId; +using util::Filesystem; using util::Path; using util::Status; using util::StatusOr; @@ -66,23 +69,64 @@ struct HostConfig { bool use_insecure_channel = false; }; -using ConfigByHost = std::unordered_map; +class HostConfigMap { + using ConfigByHost = std::unordered_map; + using Guard = std::lock_guard; + + public: + /** + * Returns a pointer to the HostConfig entry for the given host or `nullptr` + * if there's no entry. + */ + const HostConfig* find(const std::string& host) const { + Guard guard{mutex_}; + auto iter = map_.find(host); + if (iter == map_.end()) { + return nullptr; + } else { + return &(iter->second); + } + } -ConfigByHost& Config() { - static ConfigByHost config_by_host_; - return config_by_host_; -} + void UseTestCertificate(const std::string& host, + const Path& certificate_path, + const std::string& target_name) { + HARD_ASSERT(!host.empty(), "Empty host name"); + HARD_ASSERT(!certificate_path.native_value().empty(), + "Empty path to test certificate"); + HARD_ASSERT(!target_name.empty(), "Empty SSL target name"); + + Guard guard(mutex_); + HostConfig& host_config = map_[host]; + host_config.certificate_path = certificate_path; + host_config.target_name = target_name; + } -bool HasSpecialConfig(const std::string& host) { - return Config().find(host) != Config().end(); + void UseInsecureChannel(const std::string& host) { + HARD_ASSERT(!host.empty(), "Empty host name"); + + Guard guard(mutex_); + HostConfig& host_config = map_[host]; + host_config.use_insecure_channel = true; + } + + private: + ConfigByHost map_; + mutable std::mutex mutex_; +}; + +HostConfigMap& Config() { + static HostConfigMap config_by_host_; + return config_by_host_; } } // namespace -GrpcConnection::GrpcConnection(const DatabaseInfo& database_info, - util::AsyncQueue* worker_queue, - grpc::CompletionQueue* grpc_queue, - ConnectivityMonitor* connectivity_monitor) +GrpcConnection::GrpcConnection( + const DatabaseInfo& database_info, + const std::shared_ptr& worker_queue, + grpc::CompletionQueue* grpc_queue, + ConnectivityMonitor* connectivity_monitor) : database_info_{&database_info}, worker_queue_{NOT_NULL(worker_queue)}, grpc_queue_{NOT_NULL(grpc_queue)}, @@ -144,23 +188,30 @@ void GrpcConnection::EnsureActiveStub() { std::shared_ptr GrpcConnection::CreateChannel() const { const std::string& host = database_info_->host(); - if (!HasSpecialConfig(host)) { + grpc::ChannelArguments args; + // Ensure gRPC recovers from a dead connection. (Not typically necessary, as + // the OS will usually notify gRPC when a connection dies. But not always. + // This acts as a failsafe.) + args.SetInt(GRPC_ARG_KEEPALIVE_TIME_MS, 30 * 1000); + + const HostConfig* host_config = Config().find(host); + if (!host_config) { std::string root_certificate = LoadGrpcRootCertificate(); - return grpc::CreateChannel(host, CreateSslCredentials(root_certificate)); + return grpc::CreateCustomChannel( + host, CreateSslCredentials(root_certificate), args); } - const HostConfig& host_config = Config()[host]; - - // For the case when `Settings.sslEnabled == false`. - if (host_config.use_insecure_channel) { - return grpc::CreateChannel(host, grpc::InsecureChannelCredentials()); + // For the case when `Settings.set_ssl_enabled(false)`. + if (host_config->use_insecure_channel) { + return grpc::CreateCustomChannel(host, grpc::InsecureChannelCredentials(), + args); } // For tests only - grpc::ChannelArguments args; - args.SetSslTargetNameOverride(host_config.target_name); - Path path = host_config.certificate_path; - StatusOr test_certificate = ReadFile(path); + auto* fs = Filesystem::Default(); + args.SetSslTargetNameOverride(host_config->target_name); + Path path = host_config->certificate_path; + StatusOr test_certificate = fs->ReadFile(path); HARD_ASSERT(test_certificate.ok(), StringFormat("Unable to open root certificates at file path %s", path.ToUtf8String()) @@ -216,8 +267,8 @@ void GrpcConnection::RegisterConnectivityMonitor() { auto calls = active_calls_; for (GrpcCall* call : calls) { // This will trigger the observers. - call->FinishAndNotify(Status{FirestoreErrorCode::Unavailable, - "Network connectivity changed"}); + call->FinishAndNotify( + Status{Error::Unavailable, "Network connectivity changed"}); } // The old channel may hang for a long time trying to reestablish // connection before eventually failing. Note that gRPC Objective-C @@ -241,21 +292,11 @@ void GrpcConnection::Unregister(GrpcCall* call) { const std::string& host, const Path& certificate_path, const std::string& target_name) { - HARD_ASSERT(!host.empty(), "Empty host name"); - HARD_ASSERT(!certificate_path.native_value().empty(), - "Empty path to test certificate"); - HARD_ASSERT(!target_name.empty(), "Empty SSL target name"); - - HostConfig& host_config = Config()[host]; - host_config.certificate_path = certificate_path; - host_config.target_name = target_name; + Config().UseTestCertificate(host, certificate_path, target_name); } /*static*/ void GrpcConnection::UseInsecureChannel(const std::string& host) { - HARD_ASSERT(!host.empty(), "Empty host name"); - - HostConfig& host_config = Config()[host]; - host_config.use_insecure_channel = true; + Config().UseInsecureChannel(host); } } // namespace remote diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_connection.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_connection.h index 8d201f4..694e06a 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_connection.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_connection.h @@ -56,7 +56,7 @@ namespace remote { class GrpcConnection { public: GrpcConnection(const core::DatabaseInfo& database_info, - util::AsyncQueue* worker_queue, + const std::shared_ptr& worker_queue, grpc::CompletionQueue* grpc_queue, ConnectivityMonitor* connectivity_monitor); @@ -108,7 +108,7 @@ class GrpcConnection { void RegisterConnectivityMonitor(); const core::DatabaseInfo* database_info_ = nullptr; - util::AsyncQueue* worker_queue_ = nullptr; + std::shared_ptr worker_queue_; grpc::CompletionQueue* grpc_queue_ = nullptr; std::shared_ptr grpc_channel_; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_nanopb.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_nanopb.cc new file mode 100644 index 0000000..2cab002 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_nanopb.cc @@ -0,0 +1,92 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/remote/grpc_nanopb.h" + +#include + +#include "Firestore/core/include/firebase/firestore/firestore_errors.h" +#include "Firestore/core/src/firebase/firestore/nanopb/writer.h" +#include "Firestore/core/src/firebase/firestore/remote/grpc_util.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "grpcpp/support/status.h" + +namespace firebase { +namespace firestore { +namespace remote { + +using nanopb::ByteString; +using nanopb::ByteStringWriter; +using util::Status; + +ByteBufferReader::ByteBufferReader(const grpc::ByteBuffer& buffer) { + std::vector slices; + grpc::Status status = buffer.Dump(&slices); + // Conversion may fail if compression is used and gRPC tries to decompress an + // ill-formed buffer. + if (!status.ok()) { + Status error{Error::Internal, + "Trying to convert an invalid grpc::ByteBuffer"}; + error.CausedBy(ConvertStatus(status)); + set_status(error); + return; + } + + ByteStringWriter writer; + writer.Reserve(buffer.Length()); + for (const auto& slice : slices) { + writer.Append(slice.begin(), slice.size()); + } + + bytes_ = writer.Release(); + stream_ = pb_istream_from_buffer(bytes_.data(), bytes_.size()); +} + +void ByteBufferReader::Read(const pb_field_t* fields, void* dest_struct) { + if (!ok()) return; + + if (!pb_decode(&stream_, fields, dest_struct)) { + Fail(PB_GET_ERROR(&stream_)); + } +} + +namespace { + +bool AppendToGrpcBuffer(pb_ostream_t* stream, + const pb_byte_t* buf, + size_t count) { + auto buffer = static_cast*>(stream->state); + buffer->emplace_back(buf, count); + return true; +} + +} // namespace + +ByteBufferWriter::ByteBufferWriter() { + stream_.callback = AppendToGrpcBuffer; + stream_.state = &buffer_; + stream_.max_size = SIZE_MAX; +} + +grpc::ByteBuffer ByteBufferWriter::Release() { + grpc::ByteBuffer result{buffer_.data(), buffer_.size()}; + buffer_.clear(); + return result; +} + +} // namespace remote +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_nanopb.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_nanopb.h new file mode 100644 index 0000000..89abbe2 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_nanopb.h @@ -0,0 +1,79 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_GRPC_NANOPB_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_GRPC_NANOPB_H_ + +#include +#include + +#include + +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" +#include "Firestore/core/src/firebase/firestore/nanopb/message.h" +#include "Firestore/core/src/firebase/firestore/nanopb/reader.h" +#include "Firestore/core/src/firebase/firestore/nanopb/writer.h" +#include "grpcpp/support/byte_buffer.h" + +namespace firebase { +namespace firestore { +namespace remote { + +/** A `Reader` that reads from the given `grpc::ByteBuffer`. */ +class ByteBufferReader : public nanopb::Reader { + public: + /** + * Copies the given `buffer` and associates the resulting stream with this + * `ByteBufferReader`. + */ + // TODO(varconst): avoid copying the buffer. + explicit ByteBufferReader(const grpc::ByteBuffer& buffer); + + void Read(const pb_field_t* fields, void* dest_struct) override; + + private: + nanopb::ByteString bytes_; + pb_istream_t stream_{}; +}; + +/** A `Writer` that writes into a `grpc::ByteBuffer`. */ +class ByteBufferWriter : public nanopb::Writer { + public: + ByteBufferWriter(); + + grpc::ByteBuffer Release(); + + private: + std::vector buffer_; +}; + +/** + * Serializes the given `message` into a `grpc::ByteBuffer`. + * + * The lifetime of the return value is entirely independent of the `message`. + */ +template +grpc::ByteBuffer MakeByteBuffer(const nanopb::Message& message) { + ByteBufferWriter writer; + writer.Write(message.fields(), message.get()); + return writer.Release(); +} + +} // namespace remote +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_GRPC_NANOPB_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder_apple.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder_apple.mm deleted file mode 100644 index b7e0db4..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder_apple.mm +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder.h" - -#import - -#include - -#include "Firestore/core/src/firebase/firestore/util/filesystem.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/log.h" -#include "Firestore/core/src/firebase/firestore/util/statusor.h" -#include "absl/strings/str_cat.h" - -namespace firebase { -namespace firestore { -namespace remote { - -using util::Path; -using util::ReadFile; -using util::StatusOr; -using util::StringFormat; - -namespace { - -/** - * Finds the roots.pem certificate file in the given resource bundle and logs - * the outcome. - * - * @param bundle The bundle to check. Can be a nested bundle in Resources or - * an app or framework bundle to look in directly. - * @param parent The parent bundle of the bundle to search. Used for logging. - */ -NSString* _Nullable FindCertFileInResourceBundle(NSBundle* _Nullable bundle, - NSBundle* _Nullable parent) { - if (!bundle) return nil; - - NSString* path = [bundle pathForResource:@"roots" ofType:@"pem"]; - if (util::LogIsDebugEnabled()) { - std::string message = - absl::StrCat("roots.pem ", path ? "found " : "not found ", "in bundle ", - util::MakeString([bundle bundleIdentifier])); - if (parent) { - absl::StrAppend(&message, " (in parent ", - util::MakeString([parent bundleIdentifier]), ")"); - } - LOG_DEBUG("%s", message); - } - - return path; -} - -/** - * Finds gRPCCertificates.bundle inside the given parent, if it exists. - * - * This function exists mostly to handle differences in platforms. - * On iOS, resources are nested directly within the top-level of the parent - * bundle, but on macOS this will actually be in Contents/Resources. - * - * @param parent A framework or app bundle to check. - * @return The nested gRPCCertificates.bundle if found, otherwise nil. - */ -NSBundle* _Nullable FindCertBundleInParent(NSBundle* _Nullable parent) { - if (!parent) return nil; - - NSString* path = [parent pathForResource:@"gRPCCertificates" - ofType:@"bundle"]; - if (!path) return nil; - - return [[NSBundle alloc] initWithPath:path]; -} - -NSBundle* _Nullable FindFirestoreFrameworkBundle() { - // Load FIRFirestore reflectively to avoid a circular reference at build time. - Class firestore_class = objc_getClass("FIRFirestore"); - if (!firestore_class) return nil; - - return [NSBundle bundleForClass:firestore_class]; -} - -/** - * Finds the path to the roots.pem certificates file, wherever it may be. - * - * Carthage users will find roots.pem inside gRPCCertificates.bundle in - * the main bundle. - * - * There have been enough variations and workarounds posted on this that - * this also accepts the roots.pem file outside gRPCCertificates.bundle. - */ -NSString* FindPathToCertificatesFile() { - // Certificates file might be present in either the gRPC-C++ framework or (for - // some projects) in the main bundle. - NSBundle* bundles[] = { - // CocoaPods: try to load from the gRPC-C++ Framework. - [NSBundle bundleWithIdentifier:@"org.cocoapods.grpcpp"], - - // Carthage: try to load from the FirebaseFirestore.framework - FindFirestoreFrameworkBundle(), - - // Carthage and manual projects: users manually adding resources to the - // project may add the certificate to the main application bundle. Note - // that `mainBundle` is nil for unit tests of library projects. - [NSBundle mainBundle], - }; - - NSString* path = nil; - - for (NSBundle* parent : bundles) { - if (!parent) continue; - - NSBundle* certs_bundle = FindCertBundleInParent(parent); - path = FindCertFileInResourceBundle(certs_bundle, parent); - if (path) break; - - path = FindCertFileInResourceBundle(parent, nil); - if (path) break; - } - - return path; -} - -} // namespace - -std::string LoadGrpcRootCertificate() { - NSString* path = FindPathToCertificatesFile(); - HARD_ASSERT( - path, - "Could not load root certificates from the bundle. SSL cannot work."); - - StatusOr certificate = ReadFile(Path::FromNSString(path)); - HARD_ASSERT( - certificate.ok(), - StringFormat("Unable to open root certificates at file path %s", path) - .c_str()); - return certificate.ValueOrDie(); -} - -} // namespace remote -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder_generated.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder_generated.cc new file mode 100644 index 0000000..e4b48a0 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder_generated.cc @@ -0,0 +1,38 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +/** + * This implementation presumes that `roots.pem` has been embedded into the + * binary during the build and is accessible as a char array named + * `grpc_root_certificates`. + */ + +#include "Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder.h" + +#include "Firestore/core/src/firebase/firestore/remote/grpc_root_certificates_generated.h" + +namespace firebase { +namespace firestore { +namespace remote { + +std::string LoadGrpcRootCertificate() { + return {reinterpret_cast(grpc_root_certificates_generated_data), + grpc_root_certificates_generated_size}; +} + +} // namespace remote +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_root_certificates_generated.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_root_certificates_generated.cc new file mode 100644 index 0000000..51b2861 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_root_certificates_generated.cc @@ -0,0 +1,23967 @@ +// Copyright 2019 Google Inc. All Rights Reserved. + +#include + +#include "Firestore/core/src/firebase/firestore/remote/grpc_root_certificates_generated.h" + +namespace firebase { +namespace firestore { +namespace remote { + +extern const size_t grpc_root_certificates_generated_size; +extern const char roots_filename[]; +extern const unsigned char grpc_root_certificates_generated_data[]; + +const unsigned char grpc_root_certificates_generated_data[] = { + 0x23, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x20, 0x43, 0x6f, 0x64, 0x65, 0x20, 0x46, 0x6f, 0x72, 0x6d, 0x20, + 0x69, 0x73, 0x20, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, + 0x6c, 0x61, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x0a, 0x23, 0x20, + 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, 0x20, 0x76, 0x2e, 0x20, + 0x32, 0x2e, 0x30, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x61, 0x20, 0x63, 0x6f, + 0x70, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x50, + 0x4c, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x69, + 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x74, 0x68, 0x69, 0x73, 0x0a, 0x23, 0x20, 0x66, 0x69, + 0x6c, 0x65, 0x2c, 0x20, 0x59, 0x6f, 0x75, 0x20, 0x63, 0x61, 0x6e, 0x20, + 0x6f, 0x62, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x61, + 0x74, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6d, 0x6f, 0x7a, + 0x69, 0x6c, 0x6c, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x4d, 0x50, 0x4c, + 0x2f, 0x32, 0x2e, 0x30, 0x2f, 0x2e, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, 0x20, 0x4f, + 0x55, 0x3d, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x0a, 0x23, 0x20, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x47, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, + 0x61, 0x20, 0x4f, 0x55, 0x3d, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x34, 0x38, 0x33, 0x35, 0x37, 0x30, 0x33, + 0x32, 0x37, 0x38, 0x34, 0x35, 0x39, 0x37, 0x30, 0x37, 0x36, 0x36, 0x39, + 0x30, 0x30, 0x35, 0x32, 0x30, 0x34, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x33, 0x65, 0x3a, 0x34, 0x35, 0x3a, 0x35, 0x32, 0x3a, 0x31, + 0x35, 0x3a, 0x30, 0x39, 0x3a, 0x35, 0x31, 0x3a, 0x39, 0x32, 0x3a, 0x65, + 0x31, 0x3a, 0x62, 0x37, 0x3a, 0x35, 0x64, 0x3a, 0x33, 0x37, 0x3a, 0x39, + 0x66, 0x3a, 0x62, 0x31, 0x3a, 0x38, 0x37, 0x3a, 0x32, 0x39, 0x3a, 0x38, + 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x31, + 0x3a, 0x62, 0x63, 0x3a, 0x39, 0x36, 0x3a, 0x38, 0x62, 0x3a, 0x64, 0x34, + 0x3a, 0x66, 0x34, 0x3a, 0x39, 0x64, 0x3a, 0x36, 0x32, 0x3a, 0x32, 0x61, + 0x3a, 0x61, 0x38, 0x3a, 0x39, 0x61, 0x3a, 0x38, 0x31, 0x3a, 0x66, 0x32, + 0x3a, 0x31, 0x35, 0x3a, 0x30, 0x31, 0x3a, 0x35, 0x32, 0x3a, 0x61, 0x34, + 0x3a, 0x31, 0x64, 0x3a, 0x38, 0x32, 0x3a, 0x39, 0x63, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x62, 0x3a, 0x64, + 0x34, 0x3a, 0x31, 0x30, 0x3a, 0x34, 0x30, 0x3a, 0x65, 0x34, 0x3a, 0x62, + 0x62, 0x3a, 0x33, 0x65, 0x3a, 0x63, 0x37, 0x3a, 0x34, 0x32, 0x3a, 0x63, + 0x39, 0x3a, 0x65, 0x33, 0x3a, 0x38, 0x31, 0x3a, 0x64, 0x33, 0x3a, 0x31, + 0x65, 0x3a, 0x66, 0x32, 0x3a, 0x61, 0x34, 0x3a, 0x31, 0x61, 0x3a, 0x34, + 0x38, 0x3a, 0x62, 0x36, 0x3a, 0x36, 0x38, 0x3a, 0x35, 0x63, 0x3a, 0x39, + 0x36, 0x3a, 0x65, 0x37, 0x3a, 0x63, 0x65, 0x3a, 0x66, 0x33, 0x3a, 0x63, + 0x31, 0x3a, 0x64, 0x66, 0x3a, 0x36, 0x63, 0x3a, 0x64, 0x34, 0x3a, 0x33, + 0x33, 0x3a, 0x31, 0x63, 0x3a, 0x39, 0x39, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x44, 0x64, 0x54, 0x43, 0x43, 0x41, 0x6c, 0x32, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x4c, 0x42, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x42, 0x46, 0x55, 0x74, 0x61, 0x77, 0x35, 0x51, 0x77, + 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, + 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x56, 0x7a, 0x45, 0x4c, + 0x4d, 0x41, 0x6b, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x51, 0x6b, 0x55, 0x78, 0x47, 0x54, 0x41, 0x58, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x54, 0x45, 0x45, 0x64, 0x73, 0x62, 0x32, 0x4a, + 0x68, 0x62, 0x46, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x67, 0x62, 0x6e, 0x59, + 0x74, 0x63, 0x32, 0x45, 0x78, 0x45, 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x73, 0x54, 0x42, 0x31, 0x4a, 0x76, 0x0a, 0x62, 0x33, + 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x45, 0x6b, 0x64, 0x73, 0x62, 0x32, + 0x4a, 0x68, 0x62, 0x46, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x67, 0x55, 0x6d, + 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x54, 0x41, 0x65, 0x46, 0x77, + 0x30, 0x35, 0x4f, 0x44, 0x41, 0x35, 0x4d, 0x44, 0x45, 0x78, 0x4d, 0x6a, + 0x41, 0x77, 0x0a, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, 0x79, 0x4f, + 0x44, 0x41, 0x78, 0x4d, 0x6a, 0x67, 0x78, 0x4d, 0x6a, 0x41, 0x77, 0x4d, + 0x44, 0x42, 0x61, 0x4d, 0x46, 0x63, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x4a, 0x46, 0x4d, + 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, + 0x78, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, 0x0a, 0x59, 0x57, 0x78, 0x54, + 0x61, 0x57, 0x64, 0x75, 0x49, 0x47, 0x35, 0x32, 0x4c, 0x58, 0x4e, 0x68, + 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, + 0x45, 0x77, 0x64, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, + 0x4d, 0x52, 0x73, 0x77, 0x47, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, + 0x45, 0x78, 0x4a, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x78, 0x54, + 0x0a, 0x61, 0x57, 0x64, 0x75, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, + 0x67, 0x51, 0x30, 0x45, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4d, 0x41, 0x30, + 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, + 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77, 0x41, + 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x44, + 0x61, 0x44, 0x75, 0x61, 0x5a, 0x0a, 0x6a, 0x63, 0x36, 0x6a, 0x34, 0x30, + 0x2b, 0x4b, 0x66, 0x76, 0x76, 0x78, 0x69, 0x34, 0x4d, 0x6c, 0x61, 0x2b, + 0x70, 0x49, 0x48, 0x2f, 0x45, 0x71, 0x73, 0x4c, 0x6d, 0x56, 0x45, 0x51, + 0x53, 0x39, 0x38, 0x47, 0x50, 0x52, 0x34, 0x6d, 0x64, 0x6d, 0x7a, 0x78, + 0x7a, 0x64, 0x7a, 0x78, 0x74, 0x49, 0x4b, 0x2b, 0x36, 0x4e, 0x69, 0x59, + 0x36, 0x61, 0x72, 0x79, 0x6d, 0x41, 0x5a, 0x61, 0x76, 0x70, 0x0a, 0x78, + 0x79, 0x30, 0x53, 0x79, 0x36, 0x73, 0x63, 0x54, 0x48, 0x41, 0x48, 0x6f, + 0x54, 0x30, 0x4b, 0x4d, 0x4d, 0x30, 0x56, 0x6a, 0x55, 0x2f, 0x34, 0x33, + 0x64, 0x53, 0x4d, 0x55, 0x42, 0x55, 0x63, 0x37, 0x31, 0x44, 0x75, 0x78, + 0x43, 0x37, 0x33, 0x2f, 0x4f, 0x6c, 0x53, 0x38, 0x70, 0x46, 0x39, 0x34, + 0x47, 0x33, 0x56, 0x4e, 0x54, 0x43, 0x4f, 0x58, 0x6b, 0x4e, 0x7a, 0x38, + 0x6b, 0x48, 0x70, 0x0a, 0x31, 0x57, 0x72, 0x6a, 0x73, 0x6f, 0x6b, 0x36, + 0x56, 0x6a, 0x6b, 0x34, 0x62, 0x77, 0x59, 0x38, 0x69, 0x47, 0x6c, 0x62, + 0x4b, 0x6b, 0x33, 0x46, 0x70, 0x31, 0x53, 0x34, 0x62, 0x49, 0x6e, 0x4d, + 0x6d, 0x2f, 0x6b, 0x38, 0x79, 0x75, 0x58, 0x39, 0x69, 0x66, 0x55, 0x53, + 0x50, 0x4a, 0x4a, 0x34, 0x6c, 0x74, 0x62, 0x63, 0x64, 0x47, 0x36, 0x54, + 0x52, 0x47, 0x48, 0x52, 0x6a, 0x63, 0x64, 0x47, 0x0a, 0x73, 0x6e, 0x55, + 0x4f, 0x68, 0x75, 0x67, 0x5a, 0x69, 0x74, 0x56, 0x74, 0x62, 0x4e, 0x56, + 0x34, 0x46, 0x70, 0x57, 0x69, 0x36, 0x63, 0x67, 0x4b, 0x4f, 0x4f, 0x76, + 0x79, 0x4a, 0x42, 0x4e, 0x50, 0x63, 0x31, 0x53, 0x54, 0x45, 0x34, 0x55, + 0x36, 0x47, 0x37, 0x77, 0x65, 0x4e, 0x4c, 0x57, 0x4c, 0x42, 0x59, 0x79, + 0x35, 0x64, 0x34, 0x75, 0x78, 0x32, 0x78, 0x38, 0x67, 0x6b, 0x61, 0x73, + 0x4a, 0x0a, 0x55, 0x32, 0x36, 0x51, 0x7a, 0x6e, 0x73, 0x33, 0x64, 0x4c, + 0x6c, 0x77, 0x52, 0x35, 0x45, 0x69, 0x55, 0x57, 0x4d, 0x57, 0x65, 0x61, + 0x36, 0x78, 0x72, 0x6b, 0x45, 0x6d, 0x43, 0x4d, 0x67, 0x5a, 0x4b, 0x39, + 0x46, 0x47, 0x71, 0x6b, 0x6a, 0x57, 0x5a, 0x43, 0x72, 0x58, 0x67, 0x7a, + 0x54, 0x2f, 0x4c, 0x43, 0x72, 0x42, 0x62, 0x42, 0x6c, 0x44, 0x53, 0x67, + 0x65, 0x46, 0x35, 0x39, 0x4e, 0x38, 0x0a, 0x39, 0x69, 0x46, 0x6f, 0x37, + 0x2b, 0x72, 0x79, 0x55, 0x70, 0x39, 0x2f, 0x6b, 0x35, 0x44, 0x50, 0x41, + 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x4d, + 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, + 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x50, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x0a, + 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x42, 0x30, 0x47, + 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x52, 0x67, + 0x65, 0x32, 0x59, 0x61, 0x52, 0x51, 0x32, 0x58, 0x79, 0x6f, 0x6c, 0x51, + 0x4c, 0x33, 0x30, 0x45, 0x7a, 0x54, 0x53, 0x6f, 0x2f, 0x2f, 0x7a, 0x39, + 0x53, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, + 0x39, 0x77, 0x30, 0x42, 0x0a, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, + 0x43, 0x41, 0x51, 0x45, 0x41, 0x31, 0x6e, 0x50, 0x6e, 0x66, 0x45, 0x39, + 0x32, 0x30, 0x49, 0x32, 0x2f, 0x37, 0x4c, 0x71, 0x69, 0x76, 0x6a, 0x54, + 0x46, 0x4b, 0x44, 0x4b, 0x31, 0x66, 0x50, 0x78, 0x73, 0x6e, 0x43, 0x77, + 0x72, 0x76, 0x51, 0x6d, 0x65, 0x55, 0x37, 0x39, 0x72, 0x58, 0x71, 0x6f, + 0x52, 0x53, 0x4c, 0x62, 0x6c, 0x43, 0x4b, 0x4f, 0x7a, 0x0a, 0x79, 0x6a, + 0x31, 0x68, 0x54, 0x64, 0x4e, 0x47, 0x43, 0x62, 0x4d, 0x2b, 0x77, 0x36, + 0x44, 0x6a, 0x59, 0x31, 0x55, 0x62, 0x38, 0x72, 0x72, 0x76, 0x72, 0x54, + 0x6e, 0x68, 0x51, 0x37, 0x6b, 0x34, 0x6f, 0x2b, 0x59, 0x76, 0x69, 0x69, + 0x59, 0x37, 0x37, 0x36, 0x42, 0x51, 0x56, 0x76, 0x6e, 0x47, 0x43, 0x76, + 0x30, 0x34, 0x7a, 0x63, 0x51, 0x4c, 0x63, 0x46, 0x47, 0x55, 0x6c, 0x35, + 0x67, 0x45, 0x0a, 0x33, 0x38, 0x4e, 0x66, 0x6c, 0x4e, 0x55, 0x56, 0x79, + 0x52, 0x52, 0x42, 0x6e, 0x4d, 0x52, 0x64, 0x64, 0x57, 0x51, 0x56, 0x44, + 0x66, 0x39, 0x56, 0x4d, 0x4f, 0x79, 0x47, 0x6a, 0x2f, 0x38, 0x4e, 0x37, + 0x79, 0x79, 0x35, 0x59, 0x30, 0x62, 0x32, 0x71, 0x76, 0x7a, 0x66, 0x76, + 0x47, 0x6e, 0x39, 0x4c, 0x68, 0x4a, 0x49, 0x5a, 0x4a, 0x72, 0x67, 0x6c, + 0x66, 0x43, 0x6d, 0x37, 0x79, 0x6d, 0x50, 0x0a, 0x41, 0x62, 0x45, 0x56, + 0x74, 0x51, 0x77, 0x64, 0x70, 0x66, 0x35, 0x70, 0x4c, 0x47, 0x6b, 0x6b, + 0x65, 0x42, 0x36, 0x7a, 0x70, 0x78, 0x78, 0x78, 0x59, 0x75, 0x37, 0x4b, + 0x79, 0x4a, 0x65, 0x73, 0x46, 0x31, 0x32, 0x4b, 0x77, 0x76, 0x68, 0x48, + 0x68, 0x6d, 0x34, 0x71, 0x78, 0x46, 0x59, 0x78, 0x6c, 0x64, 0x42, 0x6e, + 0x69, 0x59, 0x55, 0x72, 0x2b, 0x57, 0x79, 0x6d, 0x58, 0x55, 0x61, 0x64, + 0x0a, 0x44, 0x4b, 0x71, 0x43, 0x35, 0x4a, 0x6c, 0x52, 0x33, 0x58, 0x43, + 0x33, 0x32, 0x31, 0x59, 0x39, 0x59, 0x65, 0x52, 0x71, 0x34, 0x56, 0x7a, + 0x57, 0x39, 0x76, 0x34, 0x39, 0x33, 0x6b, 0x48, 0x4d, 0x42, 0x36, 0x35, + 0x6a, 0x55, 0x72, 0x39, 0x54, 0x55, 0x2f, 0x51, 0x72, 0x36, 0x63, 0x66, + 0x39, 0x74, 0x76, 0x65, 0x43, 0x58, 0x34, 0x58, 0x53, 0x51, 0x52, 0x6a, + 0x62, 0x67, 0x62, 0x4d, 0x45, 0x0a, 0x48, 0x4d, 0x55, 0x66, 0x70, 0x49, + 0x42, 0x76, 0x46, 0x53, 0x44, 0x4a, 0x33, 0x67, 0x79, 0x49, 0x43, 0x68, + 0x33, 0x57, 0x5a, 0x6c, 0x58, 0x69, 0x2f, 0x45, 0x6a, 0x4a, 0x4b, 0x53, + 0x5a, 0x70, 0x34, 0x41, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, + 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x3d, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, + 0x55, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, + 0x32, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, + 0x67, 0x6e, 0x20, 0x4f, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, + 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x55, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x20, 0x2d, 0x20, 0x52, 0x32, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, + 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, + 0x2d, 0x20, 0x52, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x34, 0x38, 0x33, 0x35, 0x37, 0x30, 0x33, 0x32, + 0x37, 0x38, 0x34, 0x35, 0x39, 0x36, 0x38, 0x32, 0x38, 0x38, 0x35, 0x36, + 0x35, 0x38, 0x31, 0x32, 0x35, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x39, 0x34, 0x3a, 0x31, 0x34, 0x3a, 0x37, 0x37, 0x3a, 0x37, 0x65, + 0x3a, 0x33, 0x65, 0x3a, 0x35, 0x65, 0x3a, 0x66, 0x64, 0x3a, 0x38, 0x66, + 0x3a, 0x33, 0x30, 0x3a, 0x62, 0x64, 0x3a, 0x34, 0x31, 0x3a, 0x62, 0x30, + 0x3a, 0x63, 0x66, 0x3a, 0x65, 0x37, 0x3a, 0x64, 0x30, 0x3a, 0x33, 0x30, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x35, 0x3a, + 0x65, 0x30, 0x3a, 0x61, 0x62, 0x3a, 0x62, 0x36, 0x3a, 0x31, 0x33, 0x3a, + 0x38, 0x35, 0x3a, 0x31, 0x32, 0x3a, 0x32, 0x37, 0x3a, 0x31, 0x63, 0x3a, + 0x30, 0x34, 0x3a, 0x66, 0x38, 0x3a, 0x35, 0x66, 0x3a, 0x64, 0x64, 0x3a, + 0x64, 0x65, 0x3a, 0x33, 0x38, 0x3a, 0x65, 0x34, 0x3a, 0x62, 0x37, 0x3a, + 0x32, 0x34, 0x3a, 0x32, 0x65, 0x3a, 0x66, 0x65, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x61, 0x3a, 0x34, 0x32, + 0x3a, 0x64, 0x64, 0x3a, 0x34, 0x31, 0x3a, 0x37, 0x34, 0x3a, 0x35, 0x66, + 0x3a, 0x64, 0x30, 0x3a, 0x62, 0x38, 0x3a, 0x31, 0x65, 0x3a, 0x62, 0x39, + 0x3a, 0x30, 0x32, 0x3a, 0x33, 0x36, 0x3a, 0x32, 0x63, 0x3a, 0x66, 0x39, + 0x3a, 0x64, 0x38, 0x3a, 0x62, 0x66, 0x3a, 0x37, 0x31, 0x3a, 0x39, 0x64, + 0x3a, 0x61, 0x31, 0x3a, 0x62, 0x64, 0x3a, 0x31, 0x62, 0x3a, 0x31, 0x65, + 0x3a, 0x66, 0x63, 0x3a, 0x39, 0x34, 0x3a, 0x36, 0x66, 0x3a, 0x35, 0x62, + 0x3a, 0x34, 0x63, 0x3a, 0x39, 0x39, 0x3a, 0x66, 0x34, 0x3a, 0x32, 0x63, + 0x3a, 0x31, 0x62, 0x3a, 0x39, 0x65, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x44, 0x75, 0x6a, 0x43, 0x43, 0x41, 0x71, 0x4b, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x4c, 0x42, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x42, 0x44, 0x34, 0x59, 0x6d, 0x35, 0x67, 0x30, 0x77, 0x44, + 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, + 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x54, 0x44, 0x45, 0x67, 0x4d, + 0x42, 0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x58, + 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, 0x55, 0x32, 0x6c, 0x6e, + 0x62, 0x69, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, + 0x49, 0x43, 0x30, 0x67, 0x55, 0x6a, 0x49, 0x78, 0x45, 0x7a, 0x41, 0x52, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x43, 0x6b, 0x64, 0x73, + 0x62, 0x32, 0x4a, 0x68, 0x62, 0x46, 0x4e, 0x70, 0x0a, 0x5a, 0x32, 0x34, + 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, + 0x54, 0x43, 0x6b, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62, 0x46, 0x4e, + 0x70, 0x5a, 0x32, 0x34, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x59, + 0x78, 0x4d, 0x6a, 0x45, 0x31, 0x4d, 0x44, 0x67, 0x77, 0x4d, 0x44, 0x41, + 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x45, 0x78, 0x4d, 0x6a, 0x45, + 0x31, 0x0a, 0x4d, 0x44, 0x67, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x6a, + 0x42, 0x4d, 0x4d, 0x53, 0x41, 0x77, 0x48, 0x67, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4c, 0x45, 0x78, 0x64, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, + 0x78, 0x54, 0x61, 0x57, 0x64, 0x75, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, + 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4c, 0x53, 0x42, 0x53, 0x4d, 0x6a, + 0x45, 0x54, 0x4d, 0x42, 0x45, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x68, 0x4d, 0x4b, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, 0x55, + 0x32, 0x6c, 0x6e, 0x62, 0x6a, 0x45, 0x54, 0x4d, 0x42, 0x45, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x4b, 0x52, 0x32, 0x78, 0x76, 0x59, + 0x6d, 0x46, 0x73, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x6a, 0x43, 0x43, 0x41, + 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x0a, + 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, + 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, + 0x67, 0x67, 0x45, 0x42, 0x41, 0x4b, 0x62, 0x50, 0x4a, 0x41, 0x36, 0x2b, + 0x4c, 0x6d, 0x38, 0x6f, 0x6d, 0x55, 0x56, 0x43, 0x78, 0x4b, 0x73, 0x2b, + 0x49, 0x56, 0x53, 0x62, 0x43, 0x39, 0x4e, 0x2f, 0x68, 0x48, 0x44, 0x36, + 0x45, 0x72, 0x50, 0x4c, 0x0a, 0x76, 0x34, 0x64, 0x66, 0x78, 0x6e, 0x2b, + 0x47, 0x30, 0x37, 0x49, 0x77, 0x58, 0x4e, 0x62, 0x39, 0x72, 0x66, 0x46, + 0x37, 0x33, 0x4f, 0x58, 0x34, 0x59, 0x4a, 0x59, 0x4a, 0x6b, 0x68, 0x44, + 0x31, 0x30, 0x46, 0x50, 0x65, 0x2b, 0x33, 0x74, 0x2b, 0x63, 0x34, 0x69, + 0x73, 0x55, 0x6f, 0x68, 0x37, 0x53, 0x71, 0x62, 0x4b, 0x53, 0x61, 0x5a, + 0x65, 0x71, 0x4b, 0x65, 0x4d, 0x57, 0x68, 0x47, 0x38, 0x0a, 0x65, 0x6f, + 0x4c, 0x72, 0x76, 0x6f, 0x7a, 0x70, 0x73, 0x36, 0x79, 0x57, 0x4a, 0x51, + 0x65, 0x58, 0x53, 0x70, 0x6b, 0x71, 0x42, 0x79, 0x2b, 0x30, 0x48, 0x6e, + 0x65, 0x2f, 0x69, 0x67, 0x2b, 0x31, 0x41, 0x6e, 0x77, 0x62, 0x6c, 0x72, + 0x6a, 0x46, 0x75, 0x54, 0x6f, 0x73, 0x76, 0x4e, 0x59, 0x53, 0x75, 0x65, + 0x74, 0x5a, 0x66, 0x65, 0x4c, 0x51, 0x42, 0x6f, 0x5a, 0x66, 0x58, 0x6b, + 0x6c, 0x71, 0x0a, 0x74, 0x54, 0x6c, 0x65, 0x69, 0x44, 0x54, 0x73, 0x76, + 0x48, 0x67, 0x4d, 0x43, 0x4a, 0x69, 0x45, 0x62, 0x4b, 0x6a, 0x4e, 0x53, + 0x37, 0x53, 0x67, 0x66, 0x51, 0x78, 0x35, 0x54, 0x66, 0x43, 0x34, 0x4c, + 0x63, 0x73, 0x68, 0x79, 0x74, 0x56, 0x73, 0x57, 0x33, 0x33, 0x68, 0x6f, + 0x43, 0x6d, 0x45, 0x6f, 0x66, 0x6e, 0x54, 0x6c, 0x45, 0x6e, 0x4c, 0x4a, + 0x47, 0x4b, 0x52, 0x49, 0x4c, 0x7a, 0x64, 0x0a, 0x43, 0x39, 0x58, 0x5a, + 0x7a, 0x50, 0x6e, 0x71, 0x4a, 0x77, 0x6f, 0x72, 0x63, 0x35, 0x48, 0x47, + 0x6e, 0x52, 0x75, 0x73, 0x79, 0x4d, 0x76, 0x6f, 0x34, 0x4b, 0x44, 0x30, + 0x4c, 0x35, 0x43, 0x4c, 0x54, 0x66, 0x75, 0x77, 0x4e, 0x68, 0x76, 0x32, + 0x47, 0x58, 0x71, 0x46, 0x34, 0x47, 0x33, 0x79, 0x59, 0x52, 0x4f, 0x49, + 0x58, 0x4a, 0x2f, 0x67, 0x6b, 0x77, 0x70, 0x52, 0x6c, 0x34, 0x70, 0x61, + 0x0a, 0x7a, 0x71, 0x2b, 0x72, 0x31, 0x66, 0x65, 0x71, 0x43, 0x61, 0x70, + 0x67, 0x76, 0x64, 0x7a, 0x5a, 0x58, 0x39, 0x39, 0x79, 0x71, 0x57, 0x41, + 0x54, 0x58, 0x67, 0x41, 0x42, 0x79, 0x55, 0x72, 0x36, 0x50, 0x36, 0x54, + 0x71, 0x42, 0x77, 0x4d, 0x68, 0x41, 0x6f, 0x36, 0x43, 0x79, 0x67, 0x50, + 0x43, 0x6d, 0x34, 0x38, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4f, + 0x42, 0x6e, 0x44, 0x43, 0x42, 0x0a, 0x6d, 0x54, 0x41, 0x4f, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, + 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, + 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, + 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, + 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x6d, 0x2b, 0x49, 0x48, 0x0a, 0x56, + 0x32, 0x63, 0x63, 0x48, 0x73, 0x42, 0x71, 0x42, 0x74, 0x35, 0x5a, 0x74, + 0x4a, 0x6f, 0x74, 0x33, 0x39, 0x77, 0x5a, 0x68, 0x69, 0x34, 0x77, 0x4e, + 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x66, 0x42, 0x43, 0x38, 0x77, 0x4c, + 0x54, 0x41, 0x72, 0x6f, 0x43, 0x6d, 0x67, 0x4a, 0x34, 0x59, 0x6c, 0x61, + 0x48, 0x52, 0x30, 0x63, 0x44, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x79, 0x62, + 0x43, 0x35, 0x6e, 0x0a, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x78, 0x7a, + 0x61, 0x57, 0x64, 0x75, 0x4c, 0x6d, 0x35, 0x6c, 0x64, 0x43, 0x39, 0x79, + 0x62, 0x32, 0x39, 0x30, 0x4c, 0x58, 0x49, 0x79, 0x4c, 0x6d, 0x4e, 0x79, + 0x62, 0x44, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, + 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x53, 0x62, 0x34, 0x67, 0x64, 0x58, + 0x5a, 0x78, 0x77, 0x65, 0x77, 0x47, 0x6f, 0x47, 0x0a, 0x33, 0x6c, 0x6d, + 0x30, 0x6d, 0x69, 0x33, 0x66, 0x33, 0x42, 0x6d, 0x47, 0x4c, 0x6a, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, + 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, + 0x41, 0x6d, 0x59, 0x46, 0x54, 0x68, 0x78, 0x78, 0x6f, 0x6c, 0x34, 0x61, + 0x52, 0x37, 0x4f, 0x42, 0x4b, 0x75, 0x45, 0x51, 0x4c, 0x71, 0x34, 0x47, + 0x73, 0x0a, 0x4a, 0x30, 0x2f, 0x57, 0x77, 0x62, 0x67, 0x63, 0x51, 0x33, + 0x69, 0x7a, 0x44, 0x4a, 0x72, 0x38, 0x36, 0x69, 0x77, 0x38, 0x62, 0x6d, + 0x45, 0x62, 0x54, 0x55, 0x73, 0x70, 0x39, 0x5a, 0x38, 0x46, 0x48, 0x53, + 0x62, 0x42, 0x75, 0x4f, 0x6d, 0x44, 0x41, 0x47, 0x4a, 0x46, 0x74, 0x71, + 0x6b, 0x49, 0x6b, 0x37, 0x6d, 0x70, 0x4d, 0x30, 0x73, 0x59, 0x6d, 0x73, + 0x4c, 0x34, 0x68, 0x34, 0x68, 0x4f, 0x0a, 0x32, 0x39, 0x31, 0x78, 0x4e, + 0x42, 0x72, 0x42, 0x56, 0x4e, 0x70, 0x47, 0x50, 0x2b, 0x44, 0x54, 0x4b, + 0x71, 0x74, 0x74, 0x56, 0x43, 0x4c, 0x31, 0x4f, 0x6d, 0x4c, 0x4e, 0x49, + 0x47, 0x2b, 0x36, 0x4b, 0x59, 0x6e, 0x58, 0x33, 0x5a, 0x48, 0x75, 0x30, + 0x31, 0x79, 0x69, 0x50, 0x71, 0x46, 0x62, 0x51, 0x66, 0x58, 0x66, 0x35, + 0x57, 0x52, 0x44, 0x4c, 0x65, 0x6e, 0x56, 0x4f, 0x61, 0x76, 0x53, 0x0a, + 0x6f, 0x74, 0x2b, 0x33, 0x69, 0x39, 0x44, 0x41, 0x67, 0x42, 0x6b, 0x63, + 0x52, 0x63, 0x41, 0x74, 0x6a, 0x4f, 0x6a, 0x34, 0x4c, 0x61, 0x52, 0x30, + 0x56, 0x6b, 0x6e, 0x46, 0x42, 0x62, 0x56, 0x50, 0x46, 0x64, 0x35, 0x75, + 0x52, 0x48, 0x67, 0x35, 0x68, 0x36, 0x68, 0x2b, 0x75, 0x2f, 0x4e, 0x35, + 0x47, 0x4a, 0x47, 0x37, 0x39, 0x47, 0x2b, 0x64, 0x77, 0x66, 0x43, 0x4d, + 0x4e, 0x59, 0x78, 0x64, 0x0a, 0x41, 0x66, 0x76, 0x44, 0x62, 0x62, 0x6e, + 0x76, 0x52, 0x47, 0x31, 0x35, 0x52, 0x6a, 0x46, 0x2b, 0x43, 0x76, 0x36, + 0x70, 0x67, 0x73, 0x48, 0x2f, 0x37, 0x36, 0x74, 0x75, 0x49, 0x4d, 0x52, + 0x51, 0x79, 0x56, 0x2b, 0x64, 0x54, 0x5a, 0x73, 0x58, 0x6a, 0x41, 0x7a, + 0x6c, 0x41, 0x63, 0x6d, 0x67, 0x51, 0x57, 0x70, 0x7a, 0x55, 0x2f, 0x71, + 0x6c, 0x55, 0x4c, 0x52, 0x75, 0x4a, 0x51, 0x2f, 0x37, 0x0a, 0x54, 0x42, + 0x6a, 0x30, 0x2f, 0x56, 0x4c, 0x5a, 0x6a, 0x6d, 0x6d, 0x78, 0x36, 0x42, + 0x45, 0x50, 0x33, 0x6f, 0x6a, 0x59, 0x2b, 0x78, 0x31, 0x4a, 0x39, 0x36, + 0x72, 0x65, 0x6c, 0x63, 0x38, 0x67, 0x65, 0x4d, 0x4a, 0x67, 0x45, 0x74, + 0x73, 0x6c, 0x51, 0x49, 0x78, 0x71, 0x2f, 0x48, 0x35, 0x43, 0x4f, 0x45, + 0x42, 0x6b, 0x45, 0x76, 0x65, 0x65, 0x67, 0x65, 0x47, 0x54, 0x4c, 0x67, + 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, + 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, + 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, + 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, + 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, + 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, + 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x56, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x20, + 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, + 0x20, 0x47, 0x33, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x32, 0x30, 0x36, 0x36, 0x38, 0x34, 0x36, 0x39, 0x36, + 0x32, 0x37, 0x39, 0x34, 0x37, 0x32, 0x33, 0x31, 0x30, 0x32, 0x35, 0x34, + 0x32, 0x37, 0x37, 0x38, 0x37, 0x30, 0x31, 0x38, 0x30, 0x39, 0x36, 0x36, + 0x37, 0x32, 0x33, 0x34, 0x31, 0x35, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x63, 0x64, 0x3a, 0x36, 0x38, 0x3a, 0x62, 0x36, 0x3a, 0x61, + 0x37, 0x3a, 0x63, 0x37, 0x3a, 0x63, 0x34, 0x3a, 0x63, 0x65, 0x3a, 0x37, + 0x35, 0x3a, 0x65, 0x30, 0x3a, 0x31, 0x64, 0x3a, 0x34, 0x66, 0x3a, 0x35, + 0x37, 0x3a, 0x34, 0x34, 0x3a, 0x36, 0x31, 0x3a, 0x39, 0x32, 0x3a, 0x30, + 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x33, + 0x3a, 0x32, 0x64, 0x3a, 0x30, 0x64, 0x3a, 0x34, 0x35, 0x3a, 0x35, 0x33, + 0x3a, 0x34, 0x62, 0x3a, 0x36, 0x39, 0x3a, 0x39, 0x37, 0x3a, 0x63, 0x64, + 0x3a, 0x62, 0x32, 0x3a, 0x64, 0x35, 0x3a, 0x63, 0x33, 0x3a, 0x33, 0x39, + 0x3a, 0x65, 0x32, 0x3a, 0x35, 0x35, 0x3a, 0x37, 0x36, 0x3a, 0x36, 0x30, + 0x3a, 0x39, 0x62, 0x3a, 0x35, 0x63, 0x3a, 0x63, 0x36, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x62, 0x3a, 0x30, + 0x34, 0x3a, 0x63, 0x66, 0x3a, 0x35, 0x65, 0x3a, 0x62, 0x31, 0x3a, 0x66, + 0x33, 0x3a, 0x39, 0x61, 0x3a, 0x66, 0x61, 0x3a, 0x37, 0x36, 0x3a, 0x32, + 0x66, 0x3a, 0x32, 0x62, 0x3a, 0x62, 0x31, 0x3a, 0x32, 0x30, 0x3a, 0x66, + 0x32, 0x3a, 0x39, 0x36, 0x3a, 0x63, 0x62, 0x3a, 0x61, 0x35, 0x3a, 0x32, + 0x30, 0x3a, 0x63, 0x31, 0x3a, 0x62, 0x39, 0x3a, 0x37, 0x64, 0x3a, 0x62, + 0x31, 0x3a, 0x35, 0x38, 0x3a, 0x39, 0x35, 0x3a, 0x36, 0x35, 0x3a, 0x62, + 0x38, 0x3a, 0x31, 0x63, 0x3a, 0x62, 0x39, 0x3a, 0x61, 0x31, 0x3a, 0x37, + 0x62, 0x3a, 0x37, 0x32, 0x3a, 0x34, 0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x45, 0x47, 0x6a, 0x43, 0x43, 0x41, 0x77, 0x49, 0x43, + 0x45, 0x51, 0x43, 0x62, 0x66, 0x67, 0x5a, 0x4a, 0x6f, 0x7a, 0x35, 0x69, + 0x75, 0x64, 0x58, 0x75, 0x6b, 0x45, 0x68, 0x78, 0x4b, 0x65, 0x39, 0x58, + 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, + 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x4d, 0x49, 0x48, 0x4b, + 0x4d, 0x51, 0x73, 0x77, 0x0a, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x58, 0x4d, 0x42, 0x55, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4f, 0x56, 0x6d, 0x56, + 0x79, 0x61, 0x56, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x73, 0x49, 0x45, 0x6c, + 0x75, 0x59, 0x79, 0x34, 0x78, 0x48, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x73, 0x54, 0x46, 0x6c, 0x5a, 0x6c, 0x0a, 0x63, 0x6d, + 0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, + 0x4e, 0x30, 0x49, 0x45, 0x35, 0x6c, 0x64, 0x48, 0x64, 0x76, 0x63, 0x6d, + 0x73, 0x78, 0x4f, 0x6a, 0x41, 0x34, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x73, 0x54, 0x4d, 0x53, 0x68, 0x6a, 0x4b, 0x53, 0x41, 0x78, 0x4f, 0x54, + 0x6b, 0x35, 0x49, 0x46, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, + 0x64, 0x75, 0x0a, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, + 0x43, 0x30, 0x67, 0x52, 0x6d, 0x39, 0x79, 0x49, 0x47, 0x46, 0x31, 0x64, + 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, + 0x58, 0x4e, 0x6c, 0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x52, + 0x54, 0x42, 0x44, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x50, + 0x46, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x0a, 0x61, 0x57, 0x64, 0x75, + 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44, 0x4d, 0x67, + 0x55, 0x48, 0x56, 0x69, 0x62, 0x47, 0x6c, 0x6a, 0x49, 0x46, 0x42, 0x79, + 0x61, 0x57, 0x31, 0x68, 0x63, 0x6e, 0x6b, 0x67, 0x51, 0x32, 0x56, 0x79, + 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, + 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, + 0x0a, 0x64, 0x48, 0x6b, 0x67, 0x4c, 0x53, 0x42, 0x48, 0x4d, 0x7a, 0x41, + 0x65, 0x46, 0x77, 0x30, 0x35, 0x4f, 0x54, 0x45, 0x77, 0x4d, 0x44, 0x45, + 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, + 0x7a, 0x4e, 0x6a, 0x41, 0x33, 0x4d, 0x54, 0x59, 0x79, 0x4d, 0x7a, 0x55, + 0x35, 0x4e, 0x54, 0x6c, 0x61, 0x4d, 0x49, 0x48, 0x4b, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, + 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4f, 0x56, 0x6d, 0x56, 0x79, 0x61, 0x56, + 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, + 0x34, 0x78, 0x48, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x73, 0x54, 0x46, 0x6c, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x0a, 0x61, + 0x57, 0x64, 0x75, 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, + 0x45, 0x35, 0x6c, 0x64, 0x48, 0x64, 0x76, 0x63, 0x6d, 0x73, 0x78, 0x4f, + 0x6a, 0x41, 0x34, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x4d, + 0x53, 0x68, 0x6a, 0x4b, 0x53, 0x41, 0x78, 0x4f, 0x54, 0x6b, 0x35, 0x49, + 0x46, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x4c, + 0x43, 0x42, 0x4a, 0x0a, 0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30, 0x67, + 0x52, 0x6d, 0x39, 0x79, 0x49, 0x47, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, + 0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, 0x58, 0x4e, 0x6c, + 0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x52, 0x54, 0x42, 0x44, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x50, 0x46, 0x5a, 0x6c, + 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x0a, 0x49, 0x45, 0x4e, + 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44, 0x4d, 0x67, 0x55, 0x48, 0x56, + 0x69, 0x62, 0x47, 0x6c, 0x6a, 0x49, 0x46, 0x42, 0x79, 0x61, 0x57, 0x31, + 0x68, 0x63, 0x6e, 0x6b, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, + 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, + 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, + 0x67, 0x0a, 0x4c, 0x53, 0x42, 0x48, 0x4d, 0x7a, 0x43, 0x43, 0x41, 0x53, + 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, + 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, + 0x45, 0x42, 0x41, 0x4d, 0x75, 0x36, 0x6e, 0x46, 0x4c, 0x38, 0x65, 0x42, + 0x38, 0x61, 0x48, 0x6d, 0x38, 0x62, 0x0a, 0x4e, 0x33, 0x4f, 0x39, 0x2b, + 0x4d, 0x6c, 0x72, 0x6c, 0x42, 0x49, 0x77, 0x54, 0x2f, 0x41, 0x32, 0x52, + 0x2f, 0x58, 0x51, 0x6b, 0x51, 0x72, 0x31, 0x46, 0x38, 0x69, 0x6c, 0x59, + 0x63, 0x45, 0x57, 0x51, 0x45, 0x33, 0x37, 0x69, 0x6d, 0x47, 0x51, 0x35, + 0x58, 0x59, 0x67, 0x77, 0x52, 0x45, 0x47, 0x66, 0x61, 0x73, 0x73, 0x62, + 0x71, 0x62, 0x31, 0x45, 0x55, 0x47, 0x4f, 0x2b, 0x69, 0x32, 0x74, 0x0a, + 0x4b, 0x6d, 0x46, 0x5a, 0x70, 0x47, 0x63, 0x6d, 0x54, 0x4e, 0x44, 0x6f, + 0x76, 0x46, 0x4a, 0x62, 0x63, 0x43, 0x41, 0x45, 0x57, 0x4e, 0x46, 0x36, + 0x79, 0x61, 0x52, 0x70, 0x76, 0x49, 0x4d, 0x58, 0x5a, 0x4b, 0x30, 0x46, + 0x69, 0x37, 0x7a, 0x51, 0x57, 0x4d, 0x36, 0x4e, 0x6a, 0x50, 0x58, 0x72, + 0x38, 0x45, 0x4a, 0x4a, 0x43, 0x35, 0x32, 0x58, 0x4a, 0x32, 0x63, 0x79, + 0x62, 0x75, 0x47, 0x75, 0x0a, 0x6b, 0x78, 0x55, 0x63, 0x63, 0x4c, 0x77, + 0x67, 0x54, 0x53, 0x38, 0x59, 0x33, 0x70, 0x4b, 0x49, 0x36, 0x47, 0x79, + 0x46, 0x56, 0x78, 0x45, 0x61, 0x36, 0x58, 0x37, 0x6a, 0x4a, 0x68, 0x46, + 0x55, 0x6f, 0x6b, 0x57, 0x57, 0x56, 0x59, 0x50, 0x4b, 0x4d, 0x49, 0x6e, + 0x6f, 0x33, 0x4e, 0x69, 0x6a, 0x37, 0x53, 0x71, 0x41, 0x50, 0x33, 0x39, + 0x35, 0x5a, 0x56, 0x63, 0x2b, 0x46, 0x53, 0x42, 0x6d, 0x0a, 0x43, 0x43, + 0x2b, 0x56, 0x6b, 0x37, 0x2b, 0x71, 0x52, 0x79, 0x2b, 0x6f, 0x52, 0x70, + 0x66, 0x77, 0x45, 0x75, 0x4c, 0x2b, 0x77, 0x67, 0x6f, 0x72, 0x55, 0x65, + 0x5a, 0x32, 0x35, 0x72, 0x64, 0x47, 0x74, 0x2b, 0x49, 0x4e, 0x70, 0x73, + 0x79, 0x6f, 0x77, 0x30, 0x78, 0x5a, 0x56, 0x59, 0x6e, 0x6d, 0x36, 0x46, + 0x4e, 0x63, 0x48, 0x4f, 0x71, 0x64, 0x38, 0x47, 0x49, 0x57, 0x43, 0x36, + 0x66, 0x4a, 0x0a, 0x58, 0x77, 0x7a, 0x77, 0x33, 0x73, 0x4a, 0x32, 0x7a, + 0x71, 0x2f, 0x33, 0x61, 0x76, 0x4c, 0x36, 0x51, 0x61, 0x61, 0x69, 0x4d, + 0x78, 0x54, 0x4a, 0x35, 0x58, 0x70, 0x6a, 0x30, 0x35, 0x35, 0x69, 0x4e, + 0x39, 0x57, 0x46, 0x5a, 0x5a, 0x34, 0x4f, 0x35, 0x6c, 0x4d, 0x6b, 0x64, + 0x42, 0x74, 0x65, 0x48, 0x52, 0x4a, 0x54, 0x57, 0x38, 0x63, 0x73, 0x35, + 0x34, 0x4e, 0x4a, 0x4f, 0x78, 0x57, 0x75, 0x0a, 0x69, 0x6d, 0x69, 0x35, + 0x56, 0x35, 0x63, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x54, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, + 0x45, 0x52, 0x53, 0x57, 0x77, 0x61, 0x75, 0x53, 0x43, 0x50, 0x63, 0x2f, + 0x4c, 0x38, 0x6d, 0x79, 0x2f, 0x75, 0x52, 0x61, 0x6e, 0x32, 0x54, 0x65, + 0x0a, 0x32, 0x79, 0x46, 0x50, 0x68, 0x70, 0x6b, 0x30, 0x64, 0x6a, 0x5a, + 0x58, 0x33, 0x64, 0x41, 0x56, 0x4c, 0x38, 0x57, 0x74, 0x66, 0x78, 0x55, + 0x66, 0x4e, 0x32, 0x4a, 0x7a, 0x50, 0x74, 0x54, 0x6e, 0x58, 0x38, 0x34, + 0x58, 0x41, 0x39, 0x73, 0x31, 0x2b, 0x69, 0x76, 0x62, 0x72, 0x6d, 0x41, + 0x4a, 0x58, 0x78, 0x35, 0x66, 0x6a, 0x32, 0x36, 0x37, 0x43, 0x7a, 0x33, + 0x71, 0x57, 0x68, 0x4d, 0x65, 0x0a, 0x44, 0x47, 0x42, 0x76, 0x74, 0x63, + 0x43, 0x31, 0x49, 0x79, 0x49, 0x75, 0x42, 0x77, 0x76, 0x4c, 0x71, 0x58, + 0x54, 0x4c, 0x52, 0x37, 0x73, 0x64, 0x77, 0x64, 0x65, 0x6c, 0x61, 0x38, + 0x77, 0x76, 0x30, 0x6b, 0x4c, 0x39, 0x53, 0x64, 0x32, 0x6e, 0x69, 0x63, + 0x39, 0x54, 0x75, 0x74, 0x6f, 0x41, 0x57, 0x69, 0x69, 0x2f, 0x67, 0x74, + 0x2f, 0x34, 0x75, 0x68, 0x4d, 0x64, 0x55, 0x49, 0x61, 0x43, 0x0a, 0x2f, + 0x59, 0x34, 0x77, 0x6a, 0x79, 0x6c, 0x47, 0x73, 0x42, 0x34, 0x39, 0x4e, + 0x64, 0x6f, 0x34, 0x59, 0x68, 0x59, 0x59, 0x53, 0x71, 0x33, 0x6d, 0x74, + 0x6c, 0x46, 0x73, 0x33, 0x71, 0x39, 0x69, 0x36, 0x77, 0x48, 0x51, 0x48, + 0x69, 0x54, 0x2b, 0x65, 0x6f, 0x38, 0x53, 0x47, 0x68, 0x4a, 0x6f, 0x75, + 0x50, 0x74, 0x6d, 0x6d, 0x52, 0x51, 0x55, 0x52, 0x56, 0x79, 0x75, 0x35, + 0x36, 0x35, 0x70, 0x0a, 0x46, 0x34, 0x45, 0x72, 0x57, 0x6a, 0x66, 0x4a, + 0x58, 0x69, 0x72, 0x30, 0x78, 0x75, 0x4b, 0x68, 0x58, 0x46, 0x53, 0x62, + 0x70, 0x6c, 0x51, 0x41, 0x7a, 0x2f, 0x44, 0x78, 0x77, 0x63, 0x65, 0x59, + 0x4d, 0x42, 0x6f, 0x37, 0x4e, 0x68, 0x62, 0x62, 0x6f, 0x32, 0x37, 0x71, + 0x2f, 0x61, 0x32, 0x79, 0x77, 0x74, 0x72, 0x76, 0x41, 0x6b, 0x63, 0x54, + 0x69, 0x73, 0x44, 0x78, 0x73, 0x7a, 0x47, 0x74, 0x0a, 0x54, 0x78, 0x7a, + 0x68, 0x54, 0x35, 0x79, 0x76, 0x44, 0x77, 0x79, 0x64, 0x39, 0x33, 0x67, + 0x4e, 0x32, 0x50, 0x51, 0x31, 0x56, 0x6f, 0x44, 0x61, 0x74, 0x32, 0x30, + 0x58, 0x6a, 0x35, 0x30, 0x65, 0x67, 0x57, 0x54, 0x68, 0x2f, 0x73, 0x56, + 0x46, 0x75, 0x71, 0x31, 0x72, 0x75, 0x51, 0x70, 0x36, 0x54, 0x6b, 0x39, + 0x4c, 0x68, 0x4f, 0x35, 0x4c, 0x38, 0x58, 0x33, 0x64, 0x45, 0x51, 0x3d, + 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x28, 0x32, 0x30, 0x34, 0x38, 0x29, + 0x20, 0x4f, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, + 0x65, 0x74, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, + 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, + 0x53, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72, + 0x70, 0x2e, 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, 0x66, 0x2e, 0x20, 0x28, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x20, 0x6c, 0x69, 0x61, 0x62, 0x2e, + 0x29, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x45, + 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45, 0x6e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x28, 0x32, 0x30, + 0x34, 0x38, 0x29, 0x20, 0x4f, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, + 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, + 0x2f, 0x43, 0x50, 0x53, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x20, 0x69, 0x6e, + 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, 0x66, + 0x2e, 0x20, 0x28, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x20, 0x6c, 0x69, + 0x61, 0x62, 0x2e, 0x29, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39, 0x39, + 0x39, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, + 0x74, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, 0x6e, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x50, 0x72, 0x65, 0x6d, + 0x69, 0x75, 0x6d, 0x20, 0x32, 0x30, 0x34, 0x38, 0x20, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, + 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x39, 0x34, 0x36, 0x30, 0x36, 0x39, 0x32, 0x34, 0x30, 0x0a, 0x23, + 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x65, 0x3a, 0x32, 0x39, 0x3a, + 0x33, 0x31, 0x3a, 0x62, 0x63, 0x3a, 0x33, 0x32, 0x3a, 0x37, 0x65, 0x3a, + 0x39, 0x61, 0x3a, 0x65, 0x36, 0x3a, 0x65, 0x38, 0x3a, 0x62, 0x35, 0x3a, + 0x66, 0x37, 0x3a, 0x35, 0x31, 0x3a, 0x62, 0x34, 0x3a, 0x33, 0x34, 0x3a, + 0x37, 0x31, 0x3a, 0x39, 0x30, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x35, 0x30, 0x3a, 0x33, 0x30, 0x3a, 0x30, 0x36, 0x3a, 0x30, + 0x39, 0x3a, 0x31, 0x64, 0x3a, 0x39, 0x37, 0x3a, 0x64, 0x34, 0x3a, 0x66, + 0x35, 0x3a, 0x61, 0x65, 0x3a, 0x33, 0x39, 0x3a, 0x66, 0x37, 0x3a, 0x63, + 0x62, 0x3a, 0x65, 0x37, 0x3a, 0x39, 0x32, 0x3a, 0x37, 0x64, 0x3a, 0x37, + 0x64, 0x3a, 0x36, 0x35, 0x3a, 0x32, 0x64, 0x3a, 0x33, 0x34, 0x3a, 0x33, + 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x36, 0x64, 0x3a, 0x63, 0x34, 0x3a, 0x37, 0x31, 0x3a, 0x37, 0x32, 0x3a, + 0x65, 0x30, 0x3a, 0x31, 0x63, 0x3a, 0x62, 0x63, 0x3a, 0x62, 0x30, 0x3a, + 0x62, 0x66, 0x3a, 0x36, 0x32, 0x3a, 0x35, 0x38, 0x3a, 0x30, 0x64, 0x3a, + 0x38, 0x39, 0x3a, 0x35, 0x66, 0x3a, 0x65, 0x32, 0x3a, 0x62, 0x38, 0x3a, + 0x61, 0x63, 0x3a, 0x39, 0x61, 0x3a, 0x64, 0x34, 0x3a, 0x66, 0x38, 0x3a, + 0x37, 0x33, 0x3a, 0x38, 0x30, 0x3a, 0x31, 0x65, 0x3a, 0x30, 0x63, 0x3a, + 0x31, 0x30, 0x3a, 0x62, 0x39, 0x3a, 0x63, 0x38, 0x3a, 0x33, 0x37, 0x3a, + 0x64, 0x32, 0x3a, 0x31, 0x65, 0x3a, 0x62, 0x31, 0x3a, 0x37, 0x37, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x4b, 0x6a, 0x43, 0x43, + 0x41, 0x78, 0x4b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x45, + 0x4f, 0x47, 0x50, 0x65, 0x2b, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, + 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, + 0x41, 0x44, 0x43, 0x42, 0x74, 0x44, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4c, 0x0a, 0x52, 0x57, 0x35, + 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x35, 0x75, 0x5a, 0x58, 0x51, + 0x78, 0x51, 0x44, 0x41, 0x2b, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, + 0x55, 0x4e, 0x33, 0x64, 0x33, 0x64, 0x79, 0x35, 0x6c, 0x62, 0x6e, 0x52, + 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4c, 0x6d, 0x35, 0x6c, 0x64, 0x43, 0x39, + 0x44, 0x55, 0x46, 0x4e, 0x66, 0x4d, 0x6a, 0x41, 0x30, 0x4f, 0x43, 0x42, + 0x70, 0x0a, 0x62, 0x6d, 0x4e, 0x76, 0x63, 0x6e, 0x41, 0x75, 0x49, 0x47, + 0x4a, 0x35, 0x49, 0x48, 0x4a, 0x6c, 0x5a, 0x69, 0x34, 0x67, 0x4b, 0x47, + 0x78, 0x70, 0x62, 0x57, 0x6c, 0x30, 0x63, 0x79, 0x42, 0x73, 0x61, 0x57, + 0x46, 0x69, 0x4c, 0x69, 0x6b, 0x78, 0x4a, 0x54, 0x41, 0x6a, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x48, 0x43, 0x68, 0x6a, 0x4b, 0x53, + 0x41, 0x78, 0x4f, 0x54, 0x6b, 0x35, 0x0a, 0x49, 0x45, 0x56, 0x75, 0x64, + 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x75, 0x62, 0x6d, 0x56, 0x30, 0x49, + 0x45, 0x78, 0x70, 0x62, 0x57, 0x6c, 0x30, 0x5a, 0x57, 0x51, 0x78, 0x4d, + 0x7a, 0x41, 0x78, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x4b, + 0x6b, 0x56, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x75, 0x62, + 0x6d, 0x56, 0x30, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x0a, + 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, + 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, + 0x49, 0x43, 0x67, 0x79, 0x4d, 0x44, 0x51, 0x34, 0x4b, 0x54, 0x41, 0x65, + 0x46, 0x77, 0x30, 0x35, 0x4f, 0x54, 0x45, 0x79, 0x4d, 0x6a, 0x51, 0x78, + 0x4e, 0x7a, 0x55, 0x77, 0x4e, 0x54, 0x46, 0x61, 0x46, 0x77, 0x30, 0x79, + 0x4f, 0x54, 0x41, 0x33, 0x0a, 0x4d, 0x6a, 0x51, 0x78, 0x4e, 0x44, 0x45, + 0x31, 0x4d, 0x54, 0x4a, 0x61, 0x4d, 0x49, 0x47, 0x30, 0x4d, 0x52, 0x51, + 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x74, + 0x46, 0x62, 0x6e, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4c, 0x6d, 0x35, + 0x6c, 0x64, 0x44, 0x46, 0x41, 0x4d, 0x44, 0x34, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x78, 0x51, 0x33, 0x64, 0x33, 0x64, 0x33, 0x0a, 0x4c, 0x6d, + 0x56, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x75, 0x62, 0x6d, + 0x56, 0x30, 0x4c, 0x30, 0x4e, 0x51, 0x55, 0x31, 0x38, 0x79, 0x4d, 0x44, + 0x51, 0x34, 0x49, 0x47, 0x6c, 0x75, 0x59, 0x32, 0x39, 0x79, 0x63, 0x43, + 0x34, 0x67, 0x59, 0x6e, 0x6b, 0x67, 0x63, 0x6d, 0x56, 0x6d, 0x4c, 0x69, + 0x41, 0x6f, 0x62, 0x47, 0x6c, 0x74, 0x61, 0x58, 0x52, 0x7a, 0x49, 0x47, + 0x78, 0x70, 0x0a, 0x59, 0x57, 0x49, 0x75, 0x4b, 0x54, 0x45, 0x6c, 0x4d, + 0x43, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x63, 0x4b, + 0x47, 0x4d, 0x70, 0x49, 0x44, 0x45, 0x35, 0x4f, 0x54, 0x6b, 0x67, 0x52, + 0x57, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x35, 0x75, 0x5a, + 0x58, 0x51, 0x67, 0x54, 0x47, 0x6c, 0x74, 0x61, 0x58, 0x52, 0x6c, 0x5a, + 0x44, 0x45, 0x7a, 0x4d, 0x44, 0x45, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, + 0x41, 0x78, 0x4d, 0x71, 0x52, 0x57, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, + 0x64, 0x43, 0x35, 0x75, 0x5a, 0x58, 0x51, 0x67, 0x51, 0x32, 0x56, 0x79, + 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, + 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, + 0x64, 0x48, 0x6b, 0x67, 0x4b, 0x44, 0x49, 0x77, 0x4e, 0x44, 0x67, 0x70, + 0x0a, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, + 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, + 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, + 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x72, 0x55, 0x31, + 0x4c, 0x71, 0x52, 0x4b, 0x47, 0x73, 0x75, 0x71, 0x6a, 0x49, 0x41, 0x63, + 0x56, 0x46, 0x6d, 0x51, 0x71, 0x0a, 0x4b, 0x30, 0x76, 0x52, 0x76, 0x77, + 0x74, 0x4b, 0x54, 0x59, 0x37, 0x74, 0x67, 0x48, 0x61, 0x6c, 0x5a, 0x37, + 0x64, 0x34, 0x51, 0x4d, 0x42, 0x7a, 0x51, 0x73, 0x68, 0x6f, 0x77, 0x4e, + 0x74, 0x54, 0x4b, 0x39, 0x31, 0x65, 0x75, 0x48, 0x61, 0x59, 0x4e, 0x5a, + 0x4f, 0x4c, 0x47, 0x70, 0x31, 0x38, 0x45, 0x7a, 0x6f, 0x4f, 0x48, 0x31, + 0x75, 0x33, 0x48, 0x73, 0x2f, 0x6c, 0x4a, 0x42, 0x51, 0x65, 0x0a, 0x73, + 0x59, 0x47, 0x70, 0x6a, 0x58, 0x32, 0x34, 0x7a, 0x47, 0x74, 0x4c, 0x41, + 0x2f, 0x45, 0x43, 0x44, 0x4e, 0x79, 0x72, 0x70, 0x55, 0x41, 0x6b, 0x41, + 0x48, 0x39, 0x30, 0x6c, 0x4b, 0x47, 0x64, 0x43, 0x43, 0x6d, 0x7a, 0x69, + 0x41, 0x76, 0x31, 0x68, 0x33, 0x65, 0x64, 0x56, 0x63, 0x33, 0x6b, 0x77, + 0x33, 0x37, 0x58, 0x61, 0x6d, 0x53, 0x72, 0x68, 0x52, 0x53, 0x47, 0x6c, + 0x56, 0x75, 0x58, 0x0a, 0x4d, 0x6c, 0x42, 0x76, 0x50, 0x63, 0x69, 0x36, + 0x5a, 0x67, 0x7a, 0x6a, 0x2f, 0x4c, 0x32, 0x34, 0x53, 0x63, 0x46, 0x32, + 0x69, 0x55, 0x6b, 0x5a, 0x2f, 0x63, 0x43, 0x6f, 0x76, 0x59, 0x6d, 0x6a, + 0x5a, 0x79, 0x2f, 0x47, 0x6e, 0x37, 0x78, 0x78, 0x47, 0x57, 0x43, 0x34, + 0x4c, 0x65, 0x6b, 0x73, 0x79, 0x5a, 0x42, 0x32, 0x5a, 0x6e, 0x75, 0x55, + 0x34, 0x71, 0x39, 0x34, 0x31, 0x6d, 0x56, 0x54, 0x0a, 0x58, 0x54, 0x7a, + 0x57, 0x6e, 0x4c, 0x4c, 0x50, 0x4b, 0x51, 0x50, 0x35, 0x4c, 0x36, 0x52, + 0x51, 0x73, 0x74, 0x52, 0x49, 0x7a, 0x67, 0x55, 0x79, 0x56, 0x59, 0x72, + 0x39, 0x73, 0x6d, 0x52, 0x4d, 0x44, 0x75, 0x53, 0x59, 0x42, 0x33, 0x58, + 0x62, 0x66, 0x39, 0x2b, 0x35, 0x43, 0x46, 0x56, 0x67, 0x68, 0x54, 0x41, + 0x70, 0x2b, 0x58, 0x74, 0x49, 0x70, 0x47, 0x6d, 0x47, 0x34, 0x7a, 0x55, + 0x2f, 0x0a, 0x48, 0x6f, 0x5a, 0x64, 0x65, 0x6e, 0x6f, 0x56, 0x76, 0x65, + 0x38, 0x41, 0x6a, 0x68, 0x55, 0x69, 0x56, 0x42, 0x63, 0x41, 0x6b, 0x43, + 0x61, 0x54, 0x76, 0x41, 0x35, 0x4a, 0x61, 0x4a, 0x47, 0x2f, 0x2b, 0x45, + 0x66, 0x54, 0x6e, 0x5a, 0x56, 0x43, 0x77, 0x51, 0x35, 0x4e, 0x33, 0x32, + 0x38, 0x6d, 0x7a, 0x38, 0x4d, 0x59, 0x49, 0x57, 0x4a, 0x6d, 0x51, 0x33, + 0x44, 0x57, 0x31, 0x63, 0x41, 0x48, 0x0a, 0x34, 0x51, 0x49, 0x44, 0x41, + 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x4f, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, + 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, + 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x0a, + 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x56, 0x65, 0x53, 0x42, + 0x30, 0x52, 0x47, 0x41, 0x76, 0x74, 0x69, 0x4a, 0x75, 0x51, 0x69, 0x6a, + 0x4d, 0x66, 0x6d, 0x68, 0x4a, 0x41, 0x6b, 0x57, 0x75, 0x58, 0x41, 0x77, + 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, + 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, + 0x41, 0x44, 0x75, 0x62, 0x0a, 0x6a, 0x31, 0x61, 0x62, 0x4d, 0x4f, 0x64, + 0x54, 0x6d, 0x58, 0x78, 0x36, 0x65, 0x61, 0x64, 0x4e, 0x6c, 0x39, 0x63, + 0x5a, 0x6c, 0x5a, 0x44, 0x37, 0x42, 0x68, 0x2f, 0x4b, 0x4d, 0x33, 0x78, + 0x47, 0x59, 0x34, 0x2b, 0x57, 0x5a, 0x69, 0x54, 0x36, 0x51, 0x42, 0x73, + 0x68, 0x4a, 0x38, 0x72, 0x6d, 0x63, 0x6e, 0x50, 0x79, 0x54, 0x2f, 0x34, + 0x78, 0x6d, 0x66, 0x33, 0x49, 0x44, 0x45, 0x78, 0x6f, 0x0a, 0x55, 0x38, + 0x61, 0x41, 0x67, 0x68, 0x4f, 0x59, 0x2b, 0x72, 0x61, 0x74, 0x32, 0x6c, + 0x30, 0x39, 0x38, 0x63, 0x35, 0x75, 0x39, 0x68, 0x55, 0x52, 0x6c, 0x49, + 0x49, 0x4d, 0x37, 0x6a, 0x2b, 0x56, 0x72, 0x78, 0x47, 0x72, 0x44, 0x39, + 0x63, 0x76, 0x33, 0x68, 0x38, 0x44, 0x6a, 0x31, 0x63, 0x73, 0x48, 0x73, + 0x6d, 0x37, 0x6d, 0x68, 0x70, 0x45, 0x6c, 0x65, 0x73, 0x59, 0x54, 0x36, + 0x59, 0x66, 0x0a, 0x7a, 0x58, 0x31, 0x58, 0x45, 0x43, 0x2b, 0x62, 0x42, + 0x41, 0x6c, 0x61, 0x68, 0x4c, 0x56, 0x75, 0x32, 0x42, 0x30, 0x36, 0x34, + 0x64, 0x61, 0x65, 0x30, 0x57, 0x78, 0x35, 0x58, 0x6e, 0x6b, 0x63, 0x46, + 0x4d, 0x58, 0x6a, 0x30, 0x45, 0x79, 0x54, 0x4f, 0x32, 0x55, 0x38, 0x37, + 0x64, 0x38, 0x39, 0x76, 0x71, 0x62, 0x6c, 0x6c, 0x52, 0x72, 0x44, 0x74, + 0x52, 0x6e, 0x44, 0x76, 0x56, 0x35, 0x62, 0x0a, 0x75, 0x2f, 0x38, 0x6a, + 0x37, 0x32, 0x67, 0x5a, 0x79, 0x78, 0x4b, 0x54, 0x4a, 0x31, 0x77, 0x44, + 0x4c, 0x57, 0x38, 0x77, 0x30, 0x42, 0x36, 0x32, 0x47, 0x71, 0x7a, 0x65, + 0x57, 0x76, 0x66, 0x52, 0x71, 0x71, 0x67, 0x6e, 0x70, 0x76, 0x35, 0x35, + 0x67, 0x63, 0x52, 0x35, 0x6d, 0x54, 0x4e, 0x58, 0x75, 0x68, 0x4b, 0x77, + 0x71, 0x65, 0x42, 0x43, 0x62, 0x4a, 0x50, 0x4b, 0x56, 0x74, 0x37, 0x2b, + 0x0a, 0x62, 0x59, 0x51, 0x4c, 0x43, 0x49, 0x74, 0x2b, 0x6a, 0x65, 0x72, + 0x58, 0x6d, 0x43, 0x48, 0x47, 0x38, 0x2b, 0x63, 0x38, 0x65, 0x53, 0x39, + 0x65, 0x6e, 0x4e, 0x46, 0x4d, 0x46, 0x59, 0x33, 0x68, 0x37, 0x43, 0x49, + 0x33, 0x7a, 0x4a, 0x70, 0x44, 0x43, 0x35, 0x66, 0x63, 0x67, 0x4a, 0x43, + 0x4e, 0x73, 0x32, 0x65, 0x62, 0x62, 0x30, 0x67, 0x49, 0x46, 0x56, 0x62, + 0x50, 0x76, 0x2f, 0x45, 0x72, 0x0a, 0x66, 0x46, 0x36, 0x61, 0x64, 0x75, + 0x6c, 0x5a, 0x6b, 0x4d, 0x56, 0x38, 0x67, 0x7a, 0x55, 0x52, 0x5a, 0x56, + 0x45, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x42, 0x61, 0x6c, 0x74, 0x69, + 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x42, + 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x4f, 0x55, 0x3d, + 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, + 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x43, + 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, + 0x72, 0x65, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, + 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x33, 0x33, 0x35, 0x35, 0x34, 0x36, 0x31, 0x37, + 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x63, 0x3a, 0x62, + 0x36, 0x3a, 0x39, 0x34, 0x3a, 0x61, 0x35, 0x3a, 0x39, 0x63, 0x3a, 0x31, + 0x37, 0x3a, 0x65, 0x30, 0x3a, 0x64, 0x37, 0x3a, 0x39, 0x31, 0x3a, 0x35, + 0x32, 0x3a, 0x39, 0x62, 0x3a, 0x62, 0x31, 0x3a, 0x39, 0x37, 0x3a, 0x30, + 0x36, 0x3a, 0x61, 0x36, 0x3a, 0x65, 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x34, 0x3a, 0x64, 0x65, 0x3a, 0x32, 0x30, + 0x3a, 0x64, 0x30, 0x3a, 0x35, 0x65, 0x3a, 0x36, 0x36, 0x3a, 0x66, 0x63, + 0x3a, 0x35, 0x33, 0x3a, 0x66, 0x65, 0x3a, 0x31, 0x61, 0x3a, 0x35, 0x30, + 0x3a, 0x38, 0x38, 0x3a, 0x32, 0x63, 0x3a, 0x37, 0x38, 0x3a, 0x64, 0x62, + 0x3a, 0x32, 0x38, 0x3a, 0x35, 0x32, 0x3a, 0x63, 0x61, 0x3a, 0x65, 0x34, + 0x3a, 0x37, 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x31, 0x36, 0x3a, 0x61, 0x66, 0x3a, 0x35, 0x37, 0x3a, 0x61, + 0x39, 0x3a, 0x66, 0x36, 0x3a, 0x37, 0x36, 0x3a, 0x62, 0x30, 0x3a, 0x61, + 0x62, 0x3a, 0x31, 0x32, 0x3a, 0x36, 0x30, 0x3a, 0x39, 0x35, 0x3a, 0x61, + 0x61, 0x3a, 0x35, 0x65, 0x3a, 0x62, 0x61, 0x3a, 0x64, 0x65, 0x3a, 0x66, + 0x32, 0x3a, 0x32, 0x61, 0x3a, 0x62, 0x33, 0x3a, 0x31, 0x31, 0x3a, 0x31, + 0x39, 0x3a, 0x64, 0x36, 0x3a, 0x34, 0x34, 0x3a, 0x61, 0x63, 0x3a, 0x39, + 0x35, 0x3a, 0x63, 0x64, 0x3a, 0x34, 0x62, 0x3a, 0x39, 0x33, 0x3a, 0x64, + 0x62, 0x3a, 0x66, 0x33, 0x3a, 0x66, 0x32, 0x3a, 0x36, 0x61, 0x3a, 0x65, + 0x62, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x64, 0x7a, + 0x43, 0x43, 0x41, 0x6c, 0x2b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, + 0x49, 0x45, 0x41, 0x67, 0x41, 0x41, 0x75, 0x54, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x55, 0x46, 0x41, 0x44, 0x42, 0x61, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x4a, 0x0a, 0x52, + 0x54, 0x45, 0x53, 0x4d, 0x42, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x68, 0x4d, 0x4a, 0x51, 0x6d, 0x46, 0x73, 0x64, 0x47, 0x6c, 0x74, 0x62, + 0x33, 0x4a, 0x6c, 0x4d, 0x52, 0x4d, 0x77, 0x45, 0x51, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x4c, 0x45, 0x77, 0x70, 0x44, 0x65, 0x57, 0x4a, 0x6c, 0x63, + 0x6c, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4d, 0x53, 0x49, 0x77, 0x49, + 0x41, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x6c, 0x43, + 0x59, 0x57, 0x78, 0x30, 0x61, 0x57, 0x31, 0x76, 0x63, 0x6d, 0x55, 0x67, + 0x51, 0x33, 0x6c, 0x69, 0x5a, 0x58, 0x4a, 0x55, 0x63, 0x6e, 0x56, 0x7a, + 0x64, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x4d, 0x42, 0x34, 0x58, + 0x44, 0x54, 0x41, 0x77, 0x4d, 0x44, 0x55, 0x78, 0x4d, 0x6a, 0x45, 0x34, + 0x4e, 0x44, 0x59, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x0a, 0x44, 0x54, 0x49, + 0x31, 0x4d, 0x44, 0x55, 0x78, 0x4d, 0x6a, 0x49, 0x7a, 0x4e, 0x54, 0x6b, + 0x77, 0x4d, 0x46, 0x6f, 0x77, 0x57, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x53, 0x55, 0x55, + 0x78, 0x45, 0x6a, 0x41, 0x51, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, + 0x54, 0x43, 0x55, 0x4a, 0x68, 0x62, 0x48, 0x52, 0x70, 0x62, 0x57, 0x39, + 0x79, 0x0a, 0x5a, 0x54, 0x45, 0x54, 0x4d, 0x42, 0x45, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x78, 0x4d, 0x4b, 0x51, 0x33, 0x6c, 0x69, 0x5a, 0x58, + 0x4a, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x44, 0x45, 0x69, 0x4d, 0x43, + 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x5a, 0x51, 0x6d, + 0x46, 0x73, 0x64, 0x47, 0x6c, 0x74, 0x62, 0x33, 0x4a, 0x6c, 0x49, 0x45, + 0x4e, 0x35, 0x59, 0x6d, 0x56, 0x79, 0x0a, 0x56, 0x48, 0x4a, 0x31, 0x63, + 0x33, 0x51, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x44, 0x43, 0x43, 0x41, + 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, + 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, + 0x67, 0x45, 0x42, 0x41, 0x4b, 0x4d, 0x45, 0x75, 0x79, 0x4b, 0x72, 0x0a, + 0x6d, 0x44, 0x31, 0x58, 0x36, 0x43, 0x5a, 0x79, 0x6d, 0x72, 0x56, 0x35, + 0x31, 0x43, 0x6e, 0x69, 0x34, 0x65, 0x69, 0x56, 0x67, 0x4c, 0x47, 0x77, + 0x34, 0x31, 0x75, 0x4f, 0x4b, 0x79, 0x6d, 0x61, 0x5a, 0x4e, 0x2b, 0x68, + 0x58, 0x65, 0x32, 0x77, 0x43, 0x51, 0x56, 0x74, 0x32, 0x79, 0x67, 0x75, + 0x7a, 0x6d, 0x4b, 0x69, 0x59, 0x76, 0x36, 0x30, 0x69, 0x4e, 0x6f, 0x53, + 0x36, 0x7a, 0x6a, 0x72, 0x0a, 0x49, 0x5a, 0x33, 0x41, 0x51, 0x53, 0x73, + 0x42, 0x55, 0x6e, 0x75, 0x49, 0x64, 0x39, 0x4d, 0x63, 0x6a, 0x38, 0x65, + 0x36, 0x75, 0x59, 0x69, 0x31, 0x61, 0x67, 0x6e, 0x6e, 0x63, 0x2b, 0x67, + 0x52, 0x51, 0x4b, 0x66, 0x52, 0x7a, 0x4d, 0x70, 0x69, 0x6a, 0x53, 0x33, + 0x6c, 0x6a, 0x77, 0x75, 0x6d, 0x55, 0x4e, 0x4b, 0x6f, 0x55, 0x4d, 0x4d, + 0x6f, 0x36, 0x76, 0x57, 0x72, 0x4a, 0x59, 0x65, 0x4b, 0x0a, 0x6d, 0x70, + 0x59, 0x63, 0x71, 0x57, 0x65, 0x34, 0x50, 0x77, 0x7a, 0x56, 0x39, 0x2f, + 0x6c, 0x53, 0x45, 0x79, 0x2f, 0x43, 0x47, 0x39, 0x56, 0x77, 0x63, 0x50, + 0x43, 0x50, 0x77, 0x42, 0x4c, 0x4b, 0x42, 0x73, 0x75, 0x61, 0x34, 0x64, + 0x6e, 0x4b, 0x4d, 0x33, 0x70, 0x33, 0x31, 0x76, 0x6a, 0x73, 0x75, 0x66, + 0x46, 0x6f, 0x52, 0x45, 0x4a, 0x49, 0x45, 0x39, 0x4c, 0x41, 0x77, 0x71, + 0x53, 0x75, 0x0a, 0x58, 0x6d, 0x44, 0x2b, 0x74, 0x71, 0x59, 0x46, 0x2f, + 0x4c, 0x54, 0x64, 0x42, 0x31, 0x6b, 0x43, 0x31, 0x46, 0x6b, 0x59, 0x6d, + 0x47, 0x50, 0x31, 0x70, 0x57, 0x50, 0x67, 0x6b, 0x41, 0x78, 0x39, 0x58, + 0x62, 0x49, 0x47, 0x65, 0x76, 0x4f, 0x46, 0x36, 0x75, 0x76, 0x55, 0x41, + 0x36, 0x35, 0x65, 0x68, 0x44, 0x35, 0x66, 0x2f, 0x78, 0x58, 0x74, 0x61, + 0x62, 0x7a, 0x35, 0x4f, 0x54, 0x5a, 0x79, 0x0a, 0x64, 0x63, 0x39, 0x33, + 0x55, 0x6b, 0x33, 0x7a, 0x79, 0x5a, 0x41, 0x73, 0x75, 0x54, 0x33, 0x6c, + 0x79, 0x53, 0x4e, 0x54, 0x50, 0x78, 0x38, 0x6b, 0x6d, 0x43, 0x46, 0x63, + 0x42, 0x35, 0x6b, 0x70, 0x76, 0x63, 0x59, 0x36, 0x37, 0x4f, 0x64, 0x75, + 0x68, 0x6a, 0x70, 0x72, 0x6c, 0x33, 0x52, 0x6a, 0x4d, 0x37, 0x31, 0x6f, + 0x47, 0x44, 0x48, 0x77, 0x65, 0x49, 0x31, 0x32, 0x76, 0x2f, 0x79, 0x65, + 0x0a, 0x6a, 0x6c, 0x30, 0x71, 0x68, 0x71, 0x64, 0x4e, 0x6b, 0x4e, 0x77, + 0x6e, 0x47, 0x6a, 0x6b, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, + 0x46, 0x4d, 0x45, 0x4d, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, + 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4f, 0x57, 0x64, 0x57, 0x54, 0x43, + 0x43, 0x52, 0x31, 0x6a, 0x4d, 0x72, 0x50, 0x6f, 0x49, 0x56, 0x44, 0x61, + 0x47, 0x65, 0x7a, 0x71, 0x31, 0x0a, 0x42, 0x45, 0x33, 0x77, 0x4d, 0x42, + 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, + 0x51, 0x49, 0x4d, 0x41, 0x59, 0x42, 0x41, 0x66, 0x38, 0x43, 0x41, 0x51, + 0x4d, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x41, + 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x0a, 0x44, + 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x41, + 0x51, 0x43, 0x46, 0x44, 0x46, 0x32, 0x4f, 0x35, 0x47, 0x39, 0x52, 0x61, + 0x45, 0x49, 0x46, 0x6f, 0x4e, 0x32, 0x37, 0x54, 0x79, 0x63, 0x6c, 0x68, + 0x41, 0x4f, 0x39, 0x39, 0x32, 0x54, 0x39, 0x4c, 0x64, 0x63, 0x77, 0x34, + 0x36, 0x51, 0x51, 0x46, 0x2b, 0x76, 0x61, 0x4b, 0x53, 0x6d, 0x32, 0x65, + 0x54, 0x39, 0x32, 0x0a, 0x39, 0x68, 0x6b, 0x54, 0x49, 0x37, 0x67, 0x51, + 0x43, 0x76, 0x6c, 0x59, 0x70, 0x4e, 0x52, 0x68, 0x63, 0x4c, 0x30, 0x45, + 0x59, 0x57, 0x6f, 0x53, 0x69, 0x68, 0x66, 0x56, 0x43, 0x72, 0x33, 0x46, + 0x76, 0x44, 0x42, 0x38, 0x31, 0x75, 0x6b, 0x4d, 0x4a, 0x59, 0x32, 0x47, + 0x51, 0x45, 0x2f, 0x73, 0x7a, 0x4b, 0x4e, 0x2b, 0x4f, 0x4d, 0x59, 0x33, + 0x45, 0x55, 0x2f, 0x74, 0x33, 0x57, 0x67, 0x78, 0x0a, 0x6a, 0x6b, 0x7a, + 0x53, 0x73, 0x77, 0x46, 0x30, 0x37, 0x72, 0x35, 0x31, 0x58, 0x67, 0x64, + 0x49, 0x47, 0x6e, 0x39, 0x77, 0x2f, 0x78, 0x5a, 0x63, 0x68, 0x4d, 0x42, + 0x35, 0x68, 0x62, 0x67, 0x46, 0x2f, 0x58, 0x2b, 0x2b, 0x5a, 0x52, 0x47, + 0x6a, 0x44, 0x38, 0x41, 0x43, 0x74, 0x50, 0x68, 0x53, 0x4e, 0x7a, 0x6b, + 0x45, 0x31, 0x61, 0x6b, 0x78, 0x65, 0x68, 0x69, 0x2f, 0x6f, 0x43, 0x72, + 0x30, 0x0a, 0x45, 0x70, 0x6e, 0x33, 0x6f, 0x30, 0x57, 0x43, 0x34, 0x7a, + 0x78, 0x65, 0x39, 0x5a, 0x32, 0x65, 0x74, 0x63, 0x69, 0x65, 0x66, 0x43, + 0x37, 0x49, 0x70, 0x4a, 0x35, 0x4f, 0x43, 0x42, 0x52, 0x4c, 0x62, 0x66, + 0x31, 0x77, 0x62, 0x57, 0x73, 0x61, 0x59, 0x37, 0x31, 0x6b, 0x35, 0x68, + 0x2b, 0x33, 0x7a, 0x76, 0x44, 0x79, 0x6e, 0x79, 0x36, 0x37, 0x47, 0x37, + 0x66, 0x79, 0x55, 0x49, 0x68, 0x7a, 0x0a, 0x6b, 0x73, 0x4c, 0x69, 0x34, + 0x78, 0x61, 0x4e, 0x6d, 0x6a, 0x49, 0x43, 0x71, 0x34, 0x34, 0x59, 0x33, + 0x65, 0x6b, 0x51, 0x45, 0x65, 0x35, 0x2b, 0x4e, 0x61, 0x75, 0x51, 0x72, + 0x7a, 0x34, 0x77, 0x6c, 0x48, 0x72, 0x51, 0x4d, 0x7a, 0x32, 0x6e, 0x5a, + 0x51, 0x2f, 0x31, 0x2f, 0x49, 0x36, 0x65, 0x59, 0x73, 0x39, 0x48, 0x52, + 0x43, 0x77, 0x42, 0x58, 0x62, 0x73, 0x64, 0x74, 0x54, 0x4c, 0x53, 0x0a, + 0x52, 0x39, 0x49, 0x34, 0x4c, 0x74, 0x44, 0x2b, 0x67, 0x64, 0x77, 0x79, + 0x61, 0x68, 0x36, 0x31, 0x37, 0x6a, 0x7a, 0x56, 0x2f, 0x4f, 0x65, 0x42, + 0x48, 0x52, 0x6e, 0x44, 0x4a, 0x45, 0x4c, 0x71, 0x59, 0x7a, 0x6d, 0x70, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x43, + 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x41, 0x64, 0x64, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, 0x42, 0x20, 0x4f, 0x55, 0x3d, + 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50, 0x20, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x64, 0x64, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x20, 0x43, 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d, + 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, 0x42, 0x20, + 0x4f, 0x55, 0x3d, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50, + 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, 0x64, 0x64, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x31, 0x64, 0x3a, 0x33, 0x35, 0x3a, 0x35, 0x34, 0x3a, 0x30, + 0x34, 0x3a, 0x38, 0x35, 0x3a, 0x37, 0x38, 0x3a, 0x62, 0x30, 0x3a, 0x33, + 0x66, 0x3a, 0x34, 0x32, 0x3a, 0x34, 0x32, 0x3a, 0x34, 0x64, 0x3a, 0x62, + 0x66, 0x3a, 0x32, 0x30, 0x3a, 0x37, 0x33, 0x3a, 0x30, 0x61, 0x3a, 0x33, + 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x32, + 0x3a, 0x66, 0x61, 0x3a, 0x66, 0x33, 0x3a, 0x65, 0x32, 0x3a, 0x39, 0x31, + 0x3a, 0x34, 0x33, 0x3a, 0x35, 0x34, 0x3a, 0x36, 0x38, 0x3a, 0x36, 0x30, + 0x3a, 0x37, 0x38, 0x3a, 0x35, 0x37, 0x3a, 0x36, 0x39, 0x3a, 0x34, 0x64, + 0x3a, 0x66, 0x35, 0x3a, 0x65, 0x34, 0x3a, 0x35, 0x62, 0x3a, 0x36, 0x38, + 0x3a, 0x38, 0x35, 0x3a, 0x31, 0x38, 0x3a, 0x36, 0x38, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x38, 0x3a, 0x37, + 0x66, 0x3a, 0x61, 0x34, 0x3a, 0x35, 0x31, 0x3a, 0x33, 0x38, 0x3a, 0x32, + 0x32, 0x3a, 0x37, 0x38, 0x3a, 0x66, 0x66, 0x3a, 0x66, 0x30, 0x3a, 0x63, + 0x38, 0x3a, 0x62, 0x31, 0x3a, 0x31, 0x66, 0x3a, 0x38, 0x64, 0x3a, 0x34, + 0x33, 0x3a, 0x64, 0x35, 0x3a, 0x37, 0x36, 0x3a, 0x36, 0x37, 0x3a, 0x31, + 0x63, 0x3a, 0x36, 0x65, 0x3a, 0x62, 0x32, 0x3a, 0x62, 0x63, 0x3a, 0x65, + 0x61, 0x3a, 0x62, 0x34, 0x3a, 0x31, 0x33, 0x3a, 0x66, 0x62, 0x3a, 0x38, + 0x33, 0x3a, 0x64, 0x39, 0x3a, 0x36, 0x35, 0x3a, 0x64, 0x30, 0x3a, 0x36, + 0x64, 0x3a, 0x32, 0x66, 0x3a, 0x66, 0x32, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x45, 0x4e, 0x6a, 0x43, 0x43, 0x41, 0x78, 0x36, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x76, 0x4d, 0x51, 0x73, 0x77, + 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x54, + 0x52, 0x54, 0x45, 0x55, 0x0a, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x68, 0x4d, 0x4c, 0x51, 0x57, 0x52, 0x6b, 0x56, 0x48, 0x4a, + 0x31, 0x63, 0x33, 0x51, 0x67, 0x51, 0x55, 0x49, 0x78, 0x4a, 0x6a, 0x41, + 0x6b, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x48, 0x55, 0x46, + 0x6b, 0x5a, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x56, + 0x34, 0x64, 0x47, 0x56, 0x79, 0x62, 0x6d, 0x46, 0x73, 0x0a, 0x49, 0x46, + 0x52, 0x55, 0x55, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33, + 0x4a, 0x72, 0x4d, 0x53, 0x49, 0x77, 0x49, 0x41, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x44, 0x45, 0x78, 0x6c, 0x42, 0x5a, 0x47, 0x52, 0x55, 0x63, 0x6e, + 0x56, 0x7a, 0x64, 0x43, 0x42, 0x46, 0x65, 0x48, 0x52, 0x6c, 0x63, 0x6d, + 0x35, 0x68, 0x62, 0x43, 0x42, 0x44, 0x51, 0x53, 0x42, 0x53, 0x62, 0x32, + 0x39, 0x30, 0x0a, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x77, 0x4d, + 0x44, 0x55, 0x7a, 0x4d, 0x44, 0x45, 0x77, 0x4e, 0x44, 0x67, 0x7a, 0x4f, + 0x46, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x77, 0x4d, 0x44, 0x55, 0x7a, 0x4d, + 0x44, 0x45, 0x77, 0x4e, 0x44, 0x67, 0x7a, 0x4f, 0x46, 0x6f, 0x77, 0x62, + 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x68, 0x4d, 0x43, 0x55, 0x30, 0x55, 0x78, 0x0a, 0x46, 0x44, 0x41, 0x53, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x43, 0x30, 0x46, 0x6b, + 0x5a, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x46, 0x43, + 0x4d, 0x53, 0x59, 0x77, 0x4a, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, + 0x45, 0x78, 0x31, 0x42, 0x5a, 0x47, 0x52, 0x55, 0x63, 0x6e, 0x56, 0x7a, + 0x64, 0x43, 0x42, 0x46, 0x65, 0x48, 0x52, 0x6c, 0x63, 0x6d, 0x35, 0x68, + 0x0a, 0x62, 0x43, 0x42, 0x55, 0x56, 0x46, 0x41, 0x67, 0x54, 0x6d, 0x56, + 0x30, 0x64, 0x32, 0x39, 0x79, 0x61, 0x7a, 0x45, 0x69, 0x4d, 0x43, 0x41, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x5a, 0x51, 0x57, 0x52, + 0x6b, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x52, 0x58, 0x68, + 0x30, 0x5a, 0x58, 0x4a, 0x75, 0x59, 0x57, 0x77, 0x67, 0x51, 0x30, 0x45, + 0x67, 0x55, 0x6d, 0x39, 0x76, 0x0a, 0x64, 0x44, 0x43, 0x43, 0x41, 0x53, + 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, + 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, + 0x45, 0x42, 0x41, 0x4c, 0x66, 0x33, 0x47, 0x6a, 0x50, 0x6d, 0x38, 0x67, + 0x41, 0x45, 0x4c, 0x54, 0x6e, 0x67, 0x54, 0x6c, 0x76, 0x74, 0x0a, 0x48, + 0x37, 0x78, 0x73, 0x44, 0x38, 0x32, 0x31, 0x2b, 0x69, 0x4f, 0x32, 0x7a, + 0x74, 0x36, 0x62, 0x45, 0x54, 0x4f, 0x58, 0x70, 0x43, 0x6c, 0x4d, 0x66, + 0x5a, 0x4f, 0x66, 0x76, 0x55, 0x71, 0x38, 0x6b, 0x2b, 0x30, 0x44, 0x47, + 0x75, 0x4f, 0x50, 0x7a, 0x2b, 0x56, 0x74, 0x55, 0x46, 0x72, 0x57, 0x6c, + 0x79, 0x6d, 0x55, 0x57, 0x6f, 0x43, 0x77, 0x53, 0x58, 0x72, 0x62, 0x4c, + 0x70, 0x58, 0x39, 0x0a, 0x75, 0x4d, 0x71, 0x2f, 0x4e, 0x7a, 0x67, 0x74, + 0x48, 0x6a, 0x36, 0x52, 0x51, 0x61, 0x31, 0x77, 0x56, 0x73, 0x66, 0x77, + 0x54, 0x7a, 0x2f, 0x6f, 0x4d, 0x70, 0x35, 0x30, 0x79, 0x73, 0x69, 0x51, + 0x56, 0x4f, 0x6e, 0x47, 0x58, 0x77, 0x39, 0x34, 0x6e, 0x5a, 0x70, 0x41, + 0x50, 0x41, 0x36, 0x73, 0x59, 0x61, 0x70, 0x65, 0x46, 0x49, 0x2b, 0x65, + 0x68, 0x36, 0x46, 0x71, 0x55, 0x4e, 0x7a, 0x58, 0x0a, 0x6d, 0x6b, 0x36, + 0x76, 0x42, 0x62, 0x4f, 0x6d, 0x63, 0x5a, 0x53, 0x63, 0x63, 0x62, 0x4e, + 0x51, 0x59, 0x41, 0x72, 0x48, 0x45, 0x35, 0x30, 0x34, 0x42, 0x34, 0x59, + 0x43, 0x71, 0x4f, 0x6d, 0x6f, 0x61, 0x53, 0x59, 0x59, 0x6b, 0x4b, 0x74, + 0x4d, 0x73, 0x45, 0x38, 0x6a, 0x71, 0x7a, 0x70, 0x50, 0x68, 0x4e, 0x6a, + 0x66, 0x7a, 0x70, 0x2f, 0x68, 0x61, 0x57, 0x2b, 0x37, 0x31, 0x30, 0x4c, + 0x58, 0x0a, 0x61, 0x30, 0x54, 0x6b, 0x78, 0x36, 0x33, 0x75, 0x62, 0x55, + 0x46, 0x66, 0x63, 0x6c, 0x70, 0x78, 0x43, 0x44, 0x65, 0x7a, 0x65, 0x57, + 0x57, 0x6b, 0x57, 0x61, 0x43, 0x55, 0x4e, 0x2f, 0x63, 0x41, 0x4c, 0x77, + 0x33, 0x43, 0x6b, 0x6e, 0x4c, 0x61, 0x30, 0x44, 0x68, 0x79, 0x32, 0x78, + 0x53, 0x6f, 0x52, 0x63, 0x52, 0x64, 0x4b, 0x6e, 0x32, 0x33, 0x74, 0x4e, + 0x62, 0x45, 0x37, 0x71, 0x7a, 0x4e, 0x0a, 0x45, 0x30, 0x53, 0x33, 0x79, + 0x53, 0x76, 0x64, 0x51, 0x77, 0x41, 0x6c, 0x2b, 0x6d, 0x47, 0x35, 0x61, + 0x57, 0x70, 0x59, 0x49, 0x78, 0x47, 0x33, 0x70, 0x7a, 0x4f, 0x50, 0x56, + 0x6e, 0x56, 0x5a, 0x39, 0x63, 0x30, 0x70, 0x31, 0x30, 0x61, 0x33, 0x43, + 0x69, 0x74, 0x6c, 0x74, 0x74, 0x4e, 0x43, 0x62, 0x78, 0x57, 0x79, 0x75, + 0x48, 0x76, 0x37, 0x37, 0x2b, 0x6c, 0x64, 0x55, 0x39, 0x55, 0x30, 0x0a, + 0x57, 0x69, 0x63, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4f, 0x42, + 0x33, 0x44, 0x43, 0x42, 0x32, 0x54, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x72, 0x62, 0x32, 0x59, + 0x65, 0x6a, 0x53, 0x30, 0x4a, 0x76, 0x66, 0x36, 0x78, 0x43, 0x5a, 0x55, + 0x37, 0x77, 0x4f, 0x39, 0x34, 0x43, 0x54, 0x4c, 0x56, 0x42, 0x6f, 0x77, + 0x43, 0x77, 0x59, 0x44, 0x0a, 0x56, 0x52, 0x30, 0x50, 0x42, 0x41, 0x51, + 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, + 0x42, 0x41, 0x66, 0x38, 0x77, 0x67, 0x5a, 0x6b, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x49, 0x77, 0x53, 0x42, 0x6b, 0x54, 0x43, 0x42, 0x6a, 0x6f, 0x41, + 0x55, 0x72, 0x62, 0x32, 0x59, 0x65, 0x6a, 0x53, 0x30, 0x0a, 0x4a, 0x76, + 0x66, 0x36, 0x78, 0x43, 0x5a, 0x55, 0x37, 0x77, 0x4f, 0x39, 0x34, 0x43, + 0x54, 0x4c, 0x56, 0x42, 0x71, 0x68, 0x63, 0x36, 0x52, 0x78, 0x4d, 0x47, + 0x38, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x59, 0x54, 0x41, 0x6c, 0x4e, 0x46, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x74, 0x42, 0x5a, 0x47, + 0x52, 0x55, 0x0a, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x42, 0x51, + 0x6a, 0x45, 0x6d, 0x4d, 0x43, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x78, 0x4d, 0x64, 0x51, 0x57, 0x52, 0x6b, 0x56, 0x48, 0x4a, 0x31, 0x63, + 0x33, 0x51, 0x67, 0x52, 0x58, 0x68, 0x30, 0x5a, 0x58, 0x4a, 0x75, 0x59, + 0x57, 0x77, 0x67, 0x56, 0x46, 0x52, 0x51, 0x49, 0x45, 0x35, 0x6c, 0x64, + 0x48, 0x64, 0x76, 0x63, 0x6d, 0x73, 0x78, 0x0a, 0x49, 0x6a, 0x41, 0x67, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x47, 0x55, 0x46, 0x6b, + 0x5a, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x56, 0x34, + 0x64, 0x47, 0x56, 0x79, 0x62, 0x6d, 0x46, 0x73, 0x49, 0x45, 0x4e, 0x42, + 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x53, 0x43, 0x41, 0x51, 0x45, 0x77, + 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, + 0x0a, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, + 0x42, 0x41, 0x4c, 0x43, 0x62, 0x34, 0x49, 0x55, 0x6c, 0x77, 0x74, 0x59, + 0x6a, 0x34, 0x67, 0x2b, 0x57, 0x42, 0x70, 0x4b, 0x64, 0x51, 0x5a, 0x69, + 0x63, 0x32, 0x59, 0x52, 0x35, 0x67, 0x64, 0x6b, 0x65, 0x57, 0x78, 0x51, + 0x48, 0x49, 0x7a, 0x5a, 0x6c, 0x6a, 0x37, 0x44, 0x59, 0x64, 0x37, 0x75, + 0x73, 0x51, 0x57, 0x78, 0x48, 0x0a, 0x59, 0x49, 0x4e, 0x52, 0x73, 0x50, + 0x6b, 0x79, 0x50, 0x65, 0x66, 0x38, 0x39, 0x69, 0x59, 0x54, 0x78, 0x34, + 0x41, 0x57, 0x70, 0x62, 0x39, 0x61, 0x2f, 0x49, 0x66, 0x50, 0x65, 0x48, + 0x6d, 0x4a, 0x49, 0x5a, 0x72, 0x69, 0x54, 0x41, 0x63, 0x4b, 0x68, 0x6a, + 0x57, 0x38, 0x38, 0x74, 0x35, 0x52, 0x78, 0x4e, 0x4b, 0x57, 0x74, 0x39, + 0x78, 0x2b, 0x54, 0x75, 0x35, 0x77, 0x2f, 0x52, 0x77, 0x35, 0x0a, 0x36, + 0x77, 0x77, 0x43, 0x55, 0x52, 0x51, 0x74, 0x6a, 0x72, 0x30, 0x57, 0x34, + 0x4d, 0x48, 0x66, 0x52, 0x6e, 0x58, 0x6e, 0x4a, 0x4b, 0x33, 0x73, 0x39, + 0x45, 0x4b, 0x30, 0x68, 0x5a, 0x4e, 0x77, 0x45, 0x47, 0x65, 0x36, 0x6e, + 0x51, 0x59, 0x31, 0x53, 0x68, 0x6a, 0x54, 0x4b, 0x33, 0x72, 0x4d, 0x55, + 0x55, 0x4b, 0x68, 0x65, 0x6d, 0x50, 0x52, 0x35, 0x72, 0x75, 0x68, 0x78, + 0x53, 0x76, 0x43, 0x0a, 0x4e, 0x72, 0x34, 0x54, 0x44, 0x65, 0x61, 0x39, + 0x59, 0x33, 0x35, 0x35, 0x65, 0x36, 0x63, 0x4a, 0x44, 0x55, 0x43, 0x72, + 0x61, 0x74, 0x32, 0x50, 0x69, 0x73, 0x50, 0x32, 0x39, 0x6f, 0x77, 0x61, + 0x51, 0x67, 0x56, 0x52, 0x31, 0x45, 0x58, 0x31, 0x6e, 0x36, 0x64, 0x69, + 0x49, 0x57, 0x67, 0x56, 0x49, 0x45, 0x4d, 0x38, 0x6d, 0x65, 0x64, 0x38, + 0x76, 0x53, 0x54, 0x59, 0x71, 0x5a, 0x45, 0x58, 0x0a, 0x63, 0x34, 0x67, + 0x2f, 0x56, 0x68, 0x73, 0x78, 0x4f, 0x42, 0x69, 0x30, 0x63, 0x51, 0x2b, + 0x61, 0x7a, 0x63, 0x67, 0x4f, 0x6e, 0x6f, 0x34, 0x75, 0x47, 0x2b, 0x47, + 0x4d, 0x6d, 0x49, 0x50, 0x4c, 0x48, 0x7a, 0x48, 0x78, 0x52, 0x45, 0x7a, + 0x47, 0x42, 0x48, 0x4e, 0x4a, 0x64, 0x6d, 0x41, 0x50, 0x78, 0x2f, 0x69, + 0x39, 0x46, 0x34, 0x42, 0x72, 0x4c, 0x75, 0x6e, 0x4d, 0x54, 0x41, 0x35, + 0x61, 0x0a, 0x6d, 0x6e, 0x6b, 0x50, 0x49, 0x41, 0x6f, 0x75, 0x31, 0x5a, + 0x35, 0x6a, 0x4a, 0x68, 0x35, 0x56, 0x6b, 0x70, 0x54, 0x59, 0x67, 0x68, + 0x64, 0x61, 0x65, 0x39, 0x43, 0x38, 0x78, 0x34, 0x39, 0x4f, 0x68, 0x67, + 0x51, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x45, 0x6e, + 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, + 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, 0x53, 0x20, 0x69, + 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, + 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, + 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x45, 0x6e, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, + 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, 0x53, 0x20, 0x69, 0x73, 0x20, + 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x45, + 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, + 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, + 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, + 0x31, 0x36, 0x34, 0x36, 0x36, 0x30, 0x38, 0x32, 0x30, 0x0a, 0x23, 0x20, + 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x36, 0x3a, 0x61, 0x35, 0x3a, 0x63, + 0x33, 0x3a, 0x65, 0x64, 0x3a, 0x35, 0x64, 0x3a, 0x64, 0x64, 0x3a, 0x33, + 0x65, 0x3a, 0x30, 0x30, 0x3a, 0x63, 0x31, 0x3a, 0x33, 0x64, 0x3a, 0x38, + 0x37, 0x3a, 0x39, 0x32, 0x3a, 0x31, 0x66, 0x3a, 0x31, 0x64, 0x3a, 0x33, + 0x66, 0x3a, 0x65, 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x62, 0x33, 0x3a, 0x31, 0x65, 0x3a, 0x62, 0x31, 0x3a, 0x62, 0x37, + 0x3a, 0x34, 0x30, 0x3a, 0x65, 0x33, 0x3a, 0x36, 0x63, 0x3a, 0x38, 0x34, + 0x3a, 0x30, 0x32, 0x3a, 0x64, 0x61, 0x3a, 0x64, 0x63, 0x3a, 0x33, 0x37, + 0x3a, 0x64, 0x34, 0x3a, 0x34, 0x64, 0x3a, 0x66, 0x35, 0x3a, 0x64, 0x34, + 0x3a, 0x36, 0x37, 0x3a, 0x34, 0x39, 0x3a, 0x35, 0x32, 0x3a, 0x66, 0x39, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, + 0x33, 0x3a, 0x63, 0x31, 0x3a, 0x37, 0x36, 0x3a, 0x34, 0x33, 0x3a, 0x34, + 0x66, 0x3a, 0x31, 0x62, 0x3a, 0x63, 0x36, 0x3a, 0x64, 0x35, 0x3a, 0x61, + 0x64, 0x3a, 0x66, 0x34, 0x3a, 0x35, 0x62, 0x3a, 0x30, 0x65, 0x3a, 0x37, + 0x36, 0x3a, 0x65, 0x37, 0x3a, 0x32, 0x37, 0x3a, 0x32, 0x38, 0x3a, 0x37, + 0x63, 0x3a, 0x38, 0x64, 0x3a, 0x65, 0x35, 0x3a, 0x37, 0x36, 0x3a, 0x31, + 0x36, 0x3a, 0x63, 0x31, 0x3a, 0x65, 0x36, 0x3a, 0x65, 0x36, 0x3a, 0x31, + 0x34, 0x3a, 0x31, 0x61, 0x3a, 0x32, 0x62, 0x3a, 0x32, 0x63, 0x3a, 0x62, + 0x63, 0x3a, 0x37, 0x64, 0x3a, 0x38, 0x65, 0x3a, 0x34, 0x63, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x6b, 0x54, 0x43, 0x43, 0x41, + 0x33, 0x6d, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x45, 0x52, + 0x57, 0x74, 0x51, 0x56, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, + 0x44, 0x43, 0x42, 0x73, 0x44, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x0a, 0x56, 0x56, 0x4d, 0x78, + 0x46, 0x6a, 0x41, 0x55, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, + 0x44, 0x55, 0x56, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x73, + 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x4f, 0x54, 0x41, 0x33, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x4d, 0x48, 0x64, 0x33, + 0x64, 0x79, 0x35, 0x6c, 0x62, 0x6e, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, + 0x0a, 0x4c, 0x6d, 0x35, 0x6c, 0x64, 0x43, 0x39, 0x44, 0x55, 0x46, 0x4d, + 0x67, 0x61, 0x58, 0x4d, 0x67, 0x61, 0x57, 0x35, 0x6a, 0x62, 0x33, 0x4a, + 0x77, 0x62, 0x33, 0x4a, 0x68, 0x64, 0x47, 0x56, 0x6b, 0x49, 0x47, 0x4a, + 0x35, 0x49, 0x48, 0x4a, 0x6c, 0x5a, 0x6d, 0x56, 0x79, 0x5a, 0x57, 0x35, + 0x6a, 0x5a, 0x54, 0x45, 0x66, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x78, 0x4d, 0x57, 0x0a, 0x4b, 0x47, 0x4d, 0x70, 0x49, 0x44, + 0x49, 0x77, 0x4d, 0x44, 0x59, 0x67, 0x52, 0x57, 0x35, 0x30, 0x63, 0x6e, + 0x56, 0x7a, 0x64, 0x43, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, + 0x45, 0x74, 0x4d, 0x43, 0x73, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, + 0x4d, 0x6b, 0x52, 0x57, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, + 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x6c, 0x0a, 0x63, + 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, + 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, + 0x58, 0x52, 0x35, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x32, 0x4d, + 0x54, 0x45, 0x79, 0x4e, 0x7a, 0x49, 0x77, 0x4d, 0x6a, 0x4d, 0x30, 0x4d, + 0x6c, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x32, 0x4d, 0x54, 0x45, 0x79, 0x4e, + 0x7a, 0x49, 0x77, 0x0a, 0x4e, 0x54, 0x4d, 0x30, 0x4d, 0x6c, 0x6f, 0x77, + 0x67, 0x62, 0x41, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x52, 0x59, 0x77, + 0x46, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x31, 0x46, + 0x62, 0x6e, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4c, 0x43, 0x42, 0x4a, + 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x54, 0x6b, 0x77, 0x0a, 0x4e, 0x77, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x7a, 0x42, 0x33, 0x64, 0x33, 0x63, + 0x75, 0x5a, 0x57, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x35, + 0x75, 0x5a, 0x58, 0x51, 0x76, 0x51, 0x31, 0x42, 0x54, 0x49, 0x47, 0x6c, + 0x7a, 0x49, 0x47, 0x6c, 0x75, 0x59, 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, + 0x79, 0x59, 0x58, 0x52, 0x6c, 0x5a, 0x43, 0x42, 0x69, 0x65, 0x53, 0x42, + 0x79, 0x0a, 0x5a, 0x57, 0x5a, 0x6c, 0x63, 0x6d, 0x56, 0x75, 0x59, 0x32, + 0x55, 0x78, 0x48, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x73, 0x54, 0x46, 0x69, 0x68, 0x6a, 0x4b, 0x53, 0x41, 0x79, 0x4d, 0x44, + 0x41, 0x32, 0x49, 0x45, 0x56, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, + 0x51, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x4c, 0x54, + 0x41, 0x72, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x4d, 0x54, 0x4a, + 0x45, 0x56, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x55, + 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, + 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, + 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, + 0x54, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x0a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, + 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, + 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4c, 0x61, 0x56, + 0x74, 0x6b, 0x4e, 0x43, 0x2b, 0x73, 0x5a, 0x74, 0x4b, 0x6d, 0x39, 0x49, + 0x33, 0x35, 0x52, 0x4d, 0x4f, 0x56, 0x63, 0x46, 0x37, 0x73, 0x4e, 0x35, + 0x45, 0x55, 0x46, 0x6f, 0x0a, 0x4e, 0x75, 0x33, 0x73, 0x2f, 0x70, 0x6f, + 0x42, 0x6a, 0x36, 0x45, 0x34, 0x4b, 0x50, 0x7a, 0x33, 0x45, 0x45, 0x5a, + 0x6d, 0x4c, 0x6b, 0x30, 0x65, 0x47, 0x72, 0x45, 0x61, 0x54, 0x73, 0x62, + 0x52, 0x77, 0x4a, 0x57, 0x49, 0x73, 0x4d, 0x6e, 0x2f, 0x4d, 0x59, 0x73, + 0x7a, 0x41, 0x39, 0x75, 0x33, 0x67, 0x33, 0x73, 0x2b, 0x49, 0x49, 0x52, + 0x65, 0x37, 0x62, 0x4a, 0x57, 0x4b, 0x4b, 0x66, 0x34, 0x0a, 0x34, 0x4c, + 0x6c, 0x41, 0x63, 0x54, 0x66, 0x46, 0x79, 0x30, 0x63, 0x4f, 0x6c, 0x79, + 0x70, 0x6f, 0x77, 0x43, 0x4b, 0x56, 0x59, 0x68, 0x58, 0x62, 0x52, 0x39, + 0x6e, 0x31, 0x30, 0x43, 0x76, 0x2f, 0x67, 0x6b, 0x76, 0x4a, 0x72, 0x54, + 0x37, 0x65, 0x54, 0x4e, 0x75, 0x51, 0x67, 0x46, 0x41, 0x2f, 0x43, 0x59, + 0x71, 0x45, 0x41, 0x4f, 0x77, 0x77, 0x43, 0x6a, 0x30, 0x59, 0x7a, 0x66, + 0x76, 0x39, 0x0a, 0x4b, 0x6c, 0x6d, 0x61, 0x49, 0x35, 0x55, 0x58, 0x4c, + 0x45, 0x57, 0x65, 0x48, 0x32, 0x35, 0x44, 0x65, 0x57, 0x30, 0x4d, 0x58, + 0x4a, 0x6a, 0x2b, 0x53, 0x4b, 0x66, 0x46, 0x49, 0x30, 0x64, 0x63, 0x58, + 0x76, 0x31, 0x75, 0x35, 0x78, 0x36, 0x30, 0x39, 0x6d, 0x68, 0x46, 0x30, + 0x59, 0x61, 0x44, 0x57, 0x36, 0x4b, 0x4b, 0x6a, 0x62, 0x48, 0x6a, 0x4b, + 0x59, 0x44, 0x2b, 0x4a, 0x58, 0x47, 0x49, 0x0a, 0x72, 0x62, 0x36, 0x38, + 0x6a, 0x36, 0x78, 0x53, 0x6c, 0x6b, 0x75, 0x71, 0x55, 0x59, 0x33, 0x6b, + 0x45, 0x7a, 0x45, 0x5a, 0x36, 0x45, 0x35, 0x4e, 0x6e, 0x39, 0x75, 0x73, + 0x73, 0x32, 0x72, 0x56, 0x76, 0x44, 0x6c, 0x55, 0x63, 0x63, 0x70, 0x36, + 0x65, 0x6e, 0x2b, 0x51, 0x33, 0x58, 0x30, 0x64, 0x67, 0x4e, 0x6d, 0x42, + 0x75, 0x31, 0x6b, 0x6d, 0x77, 0x68, 0x48, 0x2b, 0x35, 0x70, 0x50, 0x69, + 0x0a, 0x39, 0x34, 0x44, 0x6b, 0x5a, 0x66, 0x73, 0x30, 0x4e, 0x77, 0x34, + 0x70, 0x67, 0x48, 0x42, 0x4e, 0x72, 0x7a, 0x69, 0x47, 0x4c, 0x70, 0x35, + 0x2f, 0x56, 0x36, 0x2b, 0x65, 0x46, 0x36, 0x37, 0x72, 0x48, 0x4d, 0x73, + 0x6f, 0x49, 0x56, 0x2b, 0x32, 0x48, 0x4e, 0x6a, 0x6e, 0x6f, 0x67, 0x51, + 0x69, 0x2b, 0x64, 0x50, 0x61, 0x32, 0x4d, 0x73, 0x43, 0x41, 0x77, 0x45, + 0x41, 0x41, 0x61, 0x4f, 0x42, 0x0a, 0x73, 0x44, 0x43, 0x42, 0x72, 0x54, + 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, + 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x44, 0x77, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, + 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x72, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x41, 0x45, 0x4a, 0x44, 0x41, 0x69, 0x0a, 0x67, + 0x41, 0x38, 0x79, 0x4d, 0x44, 0x41, 0x32, 0x4d, 0x54, 0x45, 0x79, 0x4e, + 0x7a, 0x49, 0x77, 0x4d, 0x6a, 0x4d, 0x30, 0x4d, 0x6c, 0x71, 0x42, 0x44, + 0x7a, 0x49, 0x77, 0x4d, 0x6a, 0x59, 0x78, 0x4d, 0x54, 0x49, 0x33, 0x4d, + 0x6a, 0x41, 0x31, 0x4d, 0x7a, 0x51, 0x79, 0x57, 0x6a, 0x41, 0x66, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, + 0x42, 0x52, 0x6f, 0x0a, 0x6b, 0x4f, 0x52, 0x6e, 0x70, 0x4b, 0x5a, 0x54, + 0x67, 0x4d, 0x65, 0x47, 0x5a, 0x71, 0x54, 0x78, 0x39, 0x30, 0x74, 0x44, + 0x2b, 0x34, 0x53, 0x39, 0x62, 0x54, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x61, 0x4a, 0x44, 0x6b, + 0x5a, 0x36, 0x53, 0x6d, 0x55, 0x34, 0x44, 0x48, 0x68, 0x6d, 0x61, 0x6b, + 0x38, 0x66, 0x64, 0x4c, 0x51, 0x2f, 0x75, 0x45, 0x0a, 0x76, 0x57, 0x30, + 0x77, 0x48, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x5a, + 0x39, 0x42, 0x30, 0x45, 0x41, 0x42, 0x42, 0x41, 0x77, 0x44, 0x68, 0x73, + 0x49, 0x56, 0x6a, 0x63, 0x75, 0x4d, 0x54, 0x6f, 0x30, 0x4c, 0x6a, 0x41, + 0x44, 0x41, 0x67, 0x53, 0x51, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, + 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, + 0x41, 0x0a, 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x43, 0x54, 0x31, 0x44, + 0x43, 0x77, 0x31, 0x77, 0x4d, 0x67, 0x4b, 0x74, 0x44, 0x35, 0x59, 0x2b, + 0x69, 0x52, 0x44, 0x41, 0x55, 0x67, 0x71, 0x56, 0x38, 0x5a, 0x79, 0x6e, + 0x74, 0x79, 0x54, 0x74, 0x53, 0x78, 0x32, 0x39, 0x43, 0x57, 0x2b, 0x31, + 0x52, 0x61, 0x47, 0x53, 0x77, 0x4d, 0x43, 0x50, 0x65, 0x79, 0x76, 0x49, + 0x57, 0x6f, 0x6e, 0x58, 0x39, 0x74, 0x0a, 0x4f, 0x31, 0x4b, 0x7a, 0x4b, + 0x74, 0x76, 0x6e, 0x31, 0x49, 0x53, 0x4d, 0x59, 0x2f, 0x59, 0x50, 0x79, + 0x79, 0x59, 0x42, 0x6b, 0x56, 0x42, 0x73, 0x39, 0x46, 0x38, 0x55, 0x34, + 0x70, 0x4e, 0x30, 0x77, 0x42, 0x4f, 0x65, 0x4d, 0x44, 0x70, 0x51, 0x34, + 0x37, 0x52, 0x67, 0x78, 0x52, 0x7a, 0x77, 0x49, 0x6b, 0x53, 0x4e, 0x63, + 0x55, 0x65, 0x73, 0x79, 0x42, 0x72, 0x4a, 0x36, 0x5a, 0x75, 0x61, 0x0a, + 0x41, 0x47, 0x41, 0x54, 0x2f, 0x33, 0x42, 0x2b, 0x58, 0x78, 0x46, 0x4e, + 0x53, 0x52, 0x75, 0x7a, 0x46, 0x56, 0x4a, 0x37, 0x79, 0x56, 0x54, 0x61, + 0x76, 0x35, 0x32, 0x56, 0x72, 0x32, 0x75, 0x61, 0x32, 0x4a, 0x37, 0x70, + 0x38, 0x65, 0x52, 0x44, 0x6a, 0x65, 0x49, 0x52, 0x52, 0x44, 0x71, 0x2f, + 0x72, 0x37, 0x32, 0x44, 0x51, 0x6e, 0x4e, 0x53, 0x69, 0x36, 0x71, 0x37, + 0x70, 0x79, 0x6e, 0x50, 0x0a, 0x39, 0x57, 0x51, 0x63, 0x43, 0x6b, 0x33, + 0x52, 0x76, 0x4b, 0x71, 0x73, 0x6e, 0x79, 0x72, 0x51, 0x2f, 0x33, 0x39, + 0x2f, 0x32, 0x6e, 0x33, 0x71, 0x73, 0x65, 0x30, 0x77, 0x4a, 0x63, 0x47, + 0x45, 0x32, 0x6a, 0x54, 0x53, 0x57, 0x33, 0x69, 0x44, 0x56, 0x75, 0x79, + 0x63, 0x4e, 0x73, 0x4d, 0x6d, 0x34, 0x68, 0x48, 0x32, 0x5a, 0x30, 0x6b, + 0x64, 0x6b, 0x71, 0x75, 0x4d, 0x2b, 0x2b, 0x76, 0x2f, 0x0a, 0x65, 0x75, + 0x36, 0x46, 0x53, 0x71, 0x64, 0x51, 0x67, 0x50, 0x43, 0x6e, 0x58, 0x45, + 0x71, 0x55, 0x4c, 0x6c, 0x38, 0x46, 0x6d, 0x54, 0x78, 0x53, 0x51, 0x65, + 0x44, 0x4e, 0x74, 0x47, 0x50, 0x50, 0x41, 0x55, 0x4f, 0x36, 0x6e, 0x49, + 0x50, 0x63, 0x6a, 0x32, 0x41, 0x37, 0x38, 0x31, 0x71, 0x30, 0x74, 0x48, + 0x75, 0x75, 0x32, 0x67, 0x75, 0x51, 0x4f, 0x48, 0x58, 0x76, 0x67, 0x52, + 0x31, 0x6d, 0x0a, 0x30, 0x76, 0x64, 0x58, 0x63, 0x44, 0x61, 0x7a, 0x76, + 0x2f, 0x77, 0x6f, 0x72, 0x33, 0x45, 0x6c, 0x68, 0x56, 0x73, 0x54, 0x2f, + 0x68, 0x35, 0x2f, 0x57, 0x72, 0x51, 0x38, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, + 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, + 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x47, 0x65, + 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, + 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x65, + 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x34, 0x34, 0x34, 0x37, 0x30, 0x0a, 0x23, + 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x66, 0x37, 0x3a, 0x37, 0x35, 0x3a, + 0x61, 0x62, 0x3a, 0x32, 0x39, 0x3a, 0x66, 0x62, 0x3a, 0x35, 0x31, 0x3a, + 0x34, 0x65, 0x3a, 0x62, 0x37, 0x3a, 0x37, 0x37, 0x3a, 0x35, 0x65, 0x3a, + 0x66, 0x66, 0x3a, 0x30, 0x35, 0x3a, 0x33, 0x63, 0x3a, 0x39, 0x39, 0x3a, + 0x38, 0x65, 0x3a, 0x66, 0x35, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x64, 0x65, 0x3a, 0x32, 0x38, 0x3a, 0x66, 0x34, 0x3a, 0x61, + 0x34, 0x3a, 0x66, 0x66, 0x3a, 0x65, 0x35, 0x3a, 0x62, 0x39, 0x3a, 0x32, + 0x66, 0x3a, 0x61, 0x33, 0x3a, 0x63, 0x35, 0x3a, 0x30, 0x33, 0x3a, 0x64, + 0x31, 0x3a, 0x61, 0x33, 0x3a, 0x34, 0x39, 0x3a, 0x61, 0x37, 0x3a, 0x66, + 0x39, 0x3a, 0x39, 0x36, 0x3a, 0x32, 0x61, 0x3a, 0x38, 0x32, 0x3a, 0x31, + 0x32, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x66, 0x66, 0x3a, 0x38, 0x35, 0x3a, 0x36, 0x61, 0x3a, 0x32, 0x64, 0x3a, + 0x32, 0x35, 0x3a, 0x31, 0x64, 0x3a, 0x63, 0x64, 0x3a, 0x38, 0x38, 0x3a, + 0x64, 0x33, 0x3a, 0x36, 0x36, 0x3a, 0x35, 0x36, 0x3a, 0x66, 0x34, 0x3a, + 0x35, 0x30, 0x3a, 0x31, 0x32, 0x3a, 0x36, 0x37, 0x3a, 0x39, 0x38, 0x3a, + 0x63, 0x66, 0x3a, 0x61, 0x62, 0x3a, 0x61, 0x61, 0x3a, 0x64, 0x65, 0x3a, + 0x34, 0x30, 0x3a, 0x37, 0x39, 0x3a, 0x39, 0x63, 0x3a, 0x37, 0x32, 0x3a, + 0x32, 0x64, 0x3a, 0x65, 0x34, 0x3a, 0x64, 0x32, 0x3a, 0x62, 0x35, 0x3a, + 0x64, 0x62, 0x3a, 0x33, 0x36, 0x3a, 0x61, 0x37, 0x3a, 0x33, 0x61, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x56, 0x44, 0x43, 0x43, + 0x41, 0x6a, 0x79, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x44, + 0x41, 0x6a, 0x52, 0x57, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, + 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, + 0x4d, 0x45, 0x49, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x0a, 0x4d, 0x52, 0x59, + 0x77, 0x46, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x31, + 0x48, 0x5a, 0x57, 0x39, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, + 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x52, 0x73, 0x77, 0x47, 0x51, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x4a, 0x48, 0x5a, 0x57, 0x39, + 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x48, 0x62, 0x47, 0x39, + 0x69, 0x0a, 0x59, 0x57, 0x77, 0x67, 0x51, 0x30, 0x45, 0x77, 0x48, 0x68, + 0x63, 0x4e, 0x4d, 0x44, 0x49, 0x77, 0x4e, 0x54, 0x49, 0x78, 0x4d, 0x44, + 0x51, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, + 0x49, 0x77, 0x4e, 0x54, 0x49, 0x78, 0x4d, 0x44, 0x51, 0x77, 0x4d, 0x44, + 0x41, 0x77, 0x57, 0x6a, 0x42, 0x43, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x0a, 0x45, 0x77, 0x4a, 0x56, 0x55, + 0x7a, 0x45, 0x57, 0x4d, 0x42, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x68, 0x4d, 0x4e, 0x52, 0x32, 0x56, 0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, + 0x33, 0x51, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x62, 0x4d, + 0x42, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x53, 0x52, + 0x32, 0x56, 0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x0a, + 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, 0x49, 0x45, 0x4e, 0x42, + 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, + 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, + 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, + 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x32, 0x73, 0x77, 0x59, + 0x59, 0x7a, 0x44, 0x39, 0x0a, 0x39, 0x42, 0x63, 0x6a, 0x47, 0x6c, 0x5a, + 0x2b, 0x57, 0x39, 0x38, 0x38, 0x62, 0x44, 0x6a, 0x6b, 0x63, 0x62, 0x64, + 0x34, 0x6b, 0x64, 0x53, 0x38, 0x6f, 0x64, 0x68, 0x4d, 0x2b, 0x4b, 0x68, + 0x44, 0x74, 0x67, 0x50, 0x70, 0x54, 0x53, 0x45, 0x48, 0x43, 0x49, 0x6a, + 0x61, 0x57, 0x43, 0x39, 0x6d, 0x4f, 0x53, 0x6d, 0x39, 0x42, 0x58, 0x69, + 0x4c, 0x6e, 0x54, 0x6a, 0x6f, 0x42, 0x62, 0x64, 0x71, 0x0a, 0x66, 0x6e, + 0x47, 0x6b, 0x35, 0x73, 0x52, 0x67, 0x70, 0x72, 0x44, 0x76, 0x67, 0x4f, + 0x53, 0x4a, 0x4b, 0x41, 0x2b, 0x65, 0x4a, 0x64, 0x62, 0x74, 0x67, 0x2f, + 0x4f, 0x74, 0x70, 0x70, 0x48, 0x48, 0x6d, 0x4d, 0x6c, 0x43, 0x47, 0x44, + 0x55, 0x55, 0x6e, 0x61, 0x32, 0x59, 0x52, 0x70, 0x49, 0x75, 0x54, 0x38, + 0x72, 0x78, 0x68, 0x30, 0x50, 0x42, 0x46, 0x70, 0x56, 0x58, 0x4c, 0x56, + 0x44, 0x76, 0x0a, 0x69, 0x53, 0x32, 0x41, 0x65, 0x6c, 0x65, 0x74, 0x38, + 0x75, 0x35, 0x66, 0x61, 0x39, 0x49, 0x41, 0x6a, 0x62, 0x6b, 0x55, 0x2b, + 0x42, 0x51, 0x56, 0x4e, 0x64, 0x6e, 0x41, 0x52, 0x71, 0x4e, 0x37, 0x63, + 0x73, 0x69, 0x52, 0x76, 0x38, 0x6c, 0x56, 0x4b, 0x38, 0x33, 0x51, 0x6c, + 0x7a, 0x36, 0x63, 0x4a, 0x6d, 0x54, 0x4d, 0x33, 0x38, 0x36, 0x44, 0x47, + 0x58, 0x48, 0x4b, 0x54, 0x75, 0x62, 0x55, 0x0a, 0x31, 0x58, 0x75, 0x70, + 0x47, 0x63, 0x31, 0x56, 0x33, 0x73, 0x6a, 0x73, 0x30, 0x6c, 0x34, 0x34, + 0x55, 0x2b, 0x56, 0x63, 0x54, 0x34, 0x77, 0x74, 0x2f, 0x6c, 0x41, 0x6a, + 0x4e, 0x76, 0x78, 0x6d, 0x35, 0x73, 0x75, 0x4f, 0x70, 0x44, 0x6b, 0x5a, + 0x41, 0x4c, 0x65, 0x56, 0x41, 0x6a, 0x6d, 0x52, 0x43, 0x77, 0x37, 0x2b, + 0x4f, 0x43, 0x37, 0x52, 0x48, 0x51, 0x57, 0x61, 0x39, 0x6b, 0x30, 0x2b, + 0x0a, 0x62, 0x77, 0x38, 0x48, 0x48, 0x61, 0x38, 0x73, 0x48, 0x6f, 0x39, + 0x67, 0x4f, 0x65, 0x4c, 0x36, 0x4e, 0x6c, 0x4d, 0x54, 0x4f, 0x64, 0x52, + 0x65, 0x4a, 0x69, 0x76, 0x62, 0x50, 0x61, 0x67, 0x55, 0x76, 0x54, 0x4c, + 0x72, 0x47, 0x41, 0x4d, 0x6f, 0x55, 0x67, 0x52, 0x78, 0x35, 0x61, 0x73, + 0x7a, 0x50, 0x65, 0x45, 0x34, 0x75, 0x77, 0x63, 0x32, 0x68, 0x47, 0x4b, + 0x63, 0x65, 0x65, 0x6f, 0x57, 0x0a, 0x4d, 0x50, 0x52, 0x66, 0x77, 0x43, + 0x76, 0x6f, 0x63, 0x57, 0x76, 0x6b, 0x2b, 0x51, 0x49, 0x44, 0x41, 0x51, + 0x41, 0x42, 0x6f, 0x31, 0x4d, 0x77, 0x55, 0x54, 0x41, 0x50, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, + 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x54, 0x41, 0x0a, 0x65, + 0x70, 0x68, 0x6f, 0x6a, 0x59, 0x6e, 0x37, 0x71, 0x77, 0x56, 0x6b, 0x44, + 0x42, 0x46, 0x39, 0x71, 0x6e, 0x31, 0x6c, 0x75, 0x4d, 0x72, 0x4d, 0x54, + 0x6a, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, + 0x44, 0x41, 0x57, 0x67, 0x42, 0x54, 0x41, 0x65, 0x70, 0x68, 0x6f, 0x6a, + 0x59, 0x6e, 0x37, 0x71, 0x77, 0x56, 0x6b, 0x44, 0x42, 0x46, 0x39, 0x71, + 0x6e, 0x31, 0x6c, 0x0a, 0x75, 0x4d, 0x72, 0x4d, 0x54, 0x6a, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, + 0x4e, 0x65, 0x4d, 0x70, 0x61, 0x75, 0x55, 0x76, 0x58, 0x56, 0x53, 0x4f, + 0x4b, 0x56, 0x43, 0x55, 0x6e, 0x35, 0x6b, 0x61, 0x46, 0x4f, 0x53, 0x50, + 0x65, 0x43, 0x70, 0x69, 0x6c, 0x4b, 0x49, 0x6e, 0x0a, 0x5a, 0x35, 0x37, + 0x51, 0x7a, 0x78, 0x70, 0x65, 0x52, 0x2b, 0x6e, 0x42, 0x73, 0x71, 0x54, + 0x50, 0x33, 0x55, 0x45, 0x61, 0x42, 0x55, 0x36, 0x62, 0x53, 0x2b, 0x35, + 0x4b, 0x62, 0x31, 0x56, 0x53, 0x73, 0x79, 0x53, 0x68, 0x4e, 0x77, 0x72, + 0x72, 0x5a, 0x48, 0x59, 0x71, 0x4c, 0x69, 0x7a, 0x7a, 0x2f, 0x54, 0x74, + 0x31, 0x6b, 0x4c, 0x2f, 0x36, 0x63, 0x64, 0x6a, 0x48, 0x50, 0x54, 0x66, + 0x53, 0x0a, 0x74, 0x51, 0x57, 0x56, 0x59, 0x72, 0x6d, 0x6d, 0x33, 0x6f, + 0x6b, 0x39, 0x4e, 0x6e, 0x73, 0x34, 0x64, 0x30, 0x69, 0x58, 0x72, 0x4b, + 0x59, 0x67, 0x6a, 0x79, 0x36, 0x6d, 0x79, 0x51, 0x7a, 0x43, 0x73, 0x70, + 0x6c, 0x46, 0x41, 0x4d, 0x66, 0x4f, 0x45, 0x56, 0x45, 0x69, 0x49, 0x75, + 0x43, 0x6c, 0x36, 0x72, 0x59, 0x56, 0x53, 0x41, 0x6c, 0x6b, 0x36, 0x6c, + 0x35, 0x50, 0x64, 0x50, 0x63, 0x46, 0x0a, 0x50, 0x73, 0x65, 0x4b, 0x55, + 0x67, 0x7a, 0x62, 0x46, 0x62, 0x53, 0x39, 0x62, 0x5a, 0x76, 0x6c, 0x78, + 0x72, 0x46, 0x55, 0x61, 0x4b, 0x6e, 0x6a, 0x61, 0x5a, 0x43, 0x32, 0x6d, + 0x71, 0x55, 0x50, 0x75, 0x4c, 0x6b, 0x2f, 0x49, 0x48, 0x32, 0x75, 0x53, + 0x72, 0x57, 0x34, 0x6e, 0x4f, 0x51, 0x64, 0x74, 0x71, 0x76, 0x6d, 0x6c, + 0x4b, 0x58, 0x42, 0x78, 0x34, 0x4f, 0x74, 0x32, 0x2f, 0x55, 0x6e, 0x0a, + 0x68, 0x77, 0x34, 0x45, 0x62, 0x4e, 0x58, 0x2f, 0x33, 0x61, 0x42, 0x64, + 0x37, 0x59, 0x64, 0x53, 0x74, 0x79, 0x73, 0x56, 0x41, 0x71, 0x34, 0x35, + 0x70, 0x6d, 0x70, 0x30, 0x36, 0x64, 0x72, 0x45, 0x35, 0x37, 0x78, 0x4e, + 0x4e, 0x42, 0x36, 0x70, 0x58, 0x45, 0x30, 0x7a, 0x58, 0x35, 0x49, 0x4a, + 0x4c, 0x34, 0x68, 0x6d, 0x58, 0x58, 0x65, 0x58, 0x78, 0x78, 0x31, 0x32, + 0x45, 0x36, 0x6e, 0x56, 0x0a, 0x35, 0x66, 0x45, 0x57, 0x43, 0x52, 0x45, + 0x31, 0x31, 0x61, 0x7a, 0x62, 0x4a, 0x48, 0x46, 0x77, 0x4c, 0x4a, 0x68, + 0x57, 0x43, 0x39, 0x6b, 0x58, 0x74, 0x4e, 0x48, 0x6a, 0x55, 0x53, 0x74, + 0x65, 0x64, 0x65, 0x6a, 0x56, 0x30, 0x4e, 0x78, 0x50, 0x4e, 0x4f, 0x33, + 0x43, 0x42, 0x57, 0x61, 0x41, 0x6f, 0x63, 0x76, 0x6d, 0x4d, 0x77, 0x3d, + 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, + 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65, + 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, + 0x72, 0x73, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x47, 0x65, + 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, + 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x65, + 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, + 0x72, 0x73, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23, 0x20, 0x4d, + 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x32, 0x3a, 0x36, 0x35, 0x3a, 0x35, 0x38, + 0x3a, 0x38, 0x62, 0x3a, 0x61, 0x32, 0x3a, 0x31, 0x61, 0x3a, 0x33, 0x31, + 0x3a, 0x37, 0x32, 0x3a, 0x37, 0x33, 0x3a, 0x36, 0x38, 0x3a, 0x35, 0x63, + 0x3a, 0x62, 0x34, 0x3a, 0x61, 0x35, 0x3a, 0x37, 0x61, 0x3a, 0x30, 0x37, + 0x3a, 0x34, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x65, 0x36, 0x3a, 0x32, 0x31, 0x3a, 0x66, 0x33, 0x3a, 0x33, 0x35, 0x3a, + 0x34, 0x33, 0x3a, 0x37, 0x39, 0x3a, 0x30, 0x35, 0x3a, 0x39, 0x61, 0x3a, + 0x34, 0x62, 0x3a, 0x36, 0x38, 0x3a, 0x33, 0x30, 0x3a, 0x39, 0x64, 0x3a, + 0x38, 0x61, 0x3a, 0x32, 0x66, 0x3a, 0x37, 0x34, 0x3a, 0x32, 0x32, 0x3a, + 0x31, 0x35, 0x3a, 0x38, 0x37, 0x3a, 0x65, 0x63, 0x3a, 0x37, 0x39, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x30, + 0x3a, 0x34, 0x35, 0x3a, 0x39, 0x62, 0x3a, 0x39, 0x66, 0x3a, 0x36, 0x33, + 0x3a, 0x62, 0x32, 0x3a, 0x32, 0x35, 0x3a, 0x35, 0x39, 0x3a, 0x66, 0x35, + 0x3a, 0x66, 0x61, 0x3a, 0x35, 0x64, 0x3a, 0x34, 0x63, 0x3a, 0x36, 0x64, + 0x3a, 0x62, 0x33, 0x3a, 0x66, 0x39, 0x3a, 0x66, 0x37, 0x3a, 0x32, 0x66, + 0x3a, 0x66, 0x31, 0x3a, 0x39, 0x33, 0x3a, 0x34, 0x32, 0x3a, 0x30, 0x33, + 0x3a, 0x33, 0x35, 0x3a, 0x37, 0x38, 0x3a, 0x66, 0x30, 0x3a, 0x37, 0x33, + 0x3a, 0x62, 0x66, 0x3a, 0x31, 0x64, 0x3a, 0x31, 0x62, 0x3a, 0x34, 0x36, + 0x3a, 0x63, 0x62, 0x3a, 0x62, 0x39, 0x3a, 0x31, 0x32, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x61, 0x44, 0x43, 0x43, 0x41, 0x31, + 0x43, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x54, + 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, + 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x46, 0x4d, 0x51, + 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, + 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x57, 0x0a, 0x4d, 0x42, 0x51, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4e, 0x52, 0x32, 0x56, 0x76, 0x56, + 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, + 0x6a, 0x45, 0x65, 0x4d, 0x42, 0x77, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, + 0x78, 0x4d, 0x56, 0x52, 0x32, 0x56, 0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, + 0x33, 0x51, 0x67, 0x56, 0x57, 0x35, 0x70, 0x64, 0x6d, 0x56, 0x79, 0x0a, + 0x63, 0x32, 0x46, 0x73, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x42, 0x34, 0x58, + 0x44, 0x54, 0x41, 0x30, 0x4d, 0x44, 0x4d, 0x77, 0x4e, 0x44, 0x41, 0x31, + 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x35, + 0x4d, 0x44, 0x4d, 0x77, 0x4e, 0x44, 0x41, 0x31, 0x4d, 0x44, 0x41, 0x77, + 0x4d, 0x46, 0x6f, 0x77, 0x52, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x0a, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, + 0x78, 0x46, 0x6a, 0x41, 0x55, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, + 0x54, 0x44, 0x55, 0x64, 0x6c, 0x62, 0x31, 0x52, 0x79, 0x64, 0x58, 0x4e, + 0x30, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x48, 0x6a, 0x41, + 0x63, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x46, 0x55, 0x64, + 0x6c, 0x62, 0x31, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x0a, 0x49, 0x46, + 0x56, 0x75, 0x61, 0x58, 0x5a, 0x6c, 0x63, 0x6e, 0x4e, 0x68, 0x62, 0x43, + 0x42, 0x44, 0x51, 0x54, 0x43, 0x43, 0x41, 0x69, 0x49, 0x77, 0x44, 0x51, + 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, + 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x50, 0x41, 0x44, + 0x43, 0x43, 0x41, 0x67, 0x6f, 0x43, 0x67, 0x67, 0x49, 0x42, 0x41, 0x4b, + 0x59, 0x56, 0x0a, 0x56, 0x61, 0x43, 0x6a, 0x78, 0x75, 0x41, 0x66, 0x6a, + 0x4a, 0x30, 0x68, 0x55, 0x4e, 0x66, 0x42, 0x76, 0x69, 0x74, 0x62, 0x74, + 0x61, 0x53, 0x65, 0x6f, 0x64, 0x6c, 0x79, 0x57, 0x4c, 0x30, 0x41, 0x47, + 0x30, 0x79, 0x2f, 0x59, 0x63, 0x6b, 0x55, 0x48, 0x55, 0x57, 0x43, 0x71, + 0x38, 0x59, 0x64, 0x67, 0x4e, 0x59, 0x39, 0x36, 0x78, 0x43, 0x63, 0x4f, + 0x71, 0x39, 0x74, 0x4a, 0x50, 0x69, 0x38, 0x0a, 0x63, 0x51, 0x47, 0x65, + 0x42, 0x76, 0x56, 0x38, 0x58, 0x78, 0x37, 0x42, 0x44, 0x6c, 0x58, 0x4b, + 0x67, 0x35, 0x70, 0x5a, 0x4d, 0x4b, 0x34, 0x5a, 0x79, 0x7a, 0x42, 0x49, + 0x6c, 0x65, 0x30, 0x69, 0x4e, 0x34, 0x33, 0x30, 0x53, 0x70, 0x70, 0x79, + 0x5a, 0x6a, 0x36, 0x74, 0x6c, 0x63, 0x44, 0x67, 0x46, 0x67, 0x44, 0x67, + 0x45, 0x42, 0x38, 0x72, 0x4d, 0x51, 0x37, 0x58, 0x6c, 0x46, 0x54, 0x54, + 0x0a, 0x51, 0x6a, 0x4f, 0x67, 0x4e, 0x42, 0x30, 0x65, 0x52, 0x58, 0x62, + 0x64, 0x54, 0x38, 0x6f, 0x59, 0x4e, 0x2b, 0x79, 0x46, 0x46, 0x58, 0x6f, + 0x5a, 0x43, 0x50, 0x7a, 0x56, 0x78, 0x35, 0x7a, 0x77, 0x38, 0x71, 0x6b, + 0x75, 0x45, 0x4b, 0x6d, 0x53, 0x35, 0x6a, 0x31, 0x59, 0x50, 0x61, 0x6b, + 0x57, 0x61, 0x44, 0x77, 0x76, 0x64, 0x53, 0x45, 0x59, 0x66, 0x79, 0x68, + 0x33, 0x70, 0x65, 0x46, 0x68, 0x0a, 0x46, 0x37, 0x65, 0x6d, 0x36, 0x66, + 0x67, 0x65, 0x6d, 0x64, 0x74, 0x7a, 0x62, 0x76, 0x51, 0x4b, 0x6f, 0x69, + 0x46, 0x73, 0x37, 0x74, 0x71, 0x71, 0x68, 0x5a, 0x4a, 0x6d, 0x72, 0x2f, + 0x5a, 0x36, 0x61, 0x34, 0x4c, 0x61, 0x75, 0x69, 0x49, 0x49, 0x4e, 0x51, + 0x2f, 0x50, 0x51, 0x76, 0x45, 0x31, 0x2b, 0x6d, 0x72, 0x75, 0x66, 0x69, + 0x73, 0x6c, 0x7a, 0x44, 0x6f, 0x52, 0x35, 0x47, 0x32, 0x76, 0x0a, 0x63, + 0x37, 0x4a, 0x32, 0x48, 0x61, 0x33, 0x51, 0x73, 0x6e, 0x68, 0x6e, 0x47, + 0x71, 0x51, 0x35, 0x48, 0x46, 0x45, 0x4c, 0x5a, 0x31, 0x61, 0x44, 0x2f, + 0x54, 0x68, 0x64, 0x44, 0x63, 0x37, 0x64, 0x38, 0x4c, 0x73, 0x72, 0x6c, + 0x68, 0x2f, 0x65, 0x65, 0x7a, 0x4a, 0x53, 0x2f, 0x52, 0x32, 0x37, 0x74, + 0x51, 0x61, 0x68, 0x73, 0x69, 0x46, 0x65, 0x70, 0x64, 0x61, 0x56, 0x61, + 0x48, 0x2f, 0x77, 0x0a, 0x6d, 0x5a, 0x37, 0x63, 0x52, 0x51, 0x67, 0x2b, + 0x35, 0x39, 0x49, 0x4a, 0x44, 0x54, 0x57, 0x55, 0x33, 0x59, 0x42, 0x4f, + 0x55, 0x35, 0x66, 0x58, 0x74, 0x51, 0x6c, 0x45, 0x49, 0x47, 0x51, 0x57, + 0x46, 0x77, 0x4d, 0x43, 0x54, 0x46, 0x4d, 0x4e, 0x61, 0x4e, 0x37, 0x56, + 0x71, 0x6e, 0x4a, 0x4e, 0x6b, 0x32, 0x32, 0x43, 0x44, 0x74, 0x75, 0x63, + 0x76, 0x63, 0x2b, 0x30, 0x38, 0x31, 0x78, 0x64, 0x0a, 0x56, 0x48, 0x70, + 0x70, 0x43, 0x5a, 0x62, 0x57, 0x32, 0x78, 0x48, 0x42, 0x6a, 0x58, 0x57, + 0x6f, 0x74, 0x4d, 0x38, 0x35, 0x79, 0x4d, 0x34, 0x38, 0x76, 0x43, 0x52, + 0x38, 0x35, 0x6d, 0x4c, 0x4b, 0x34, 0x62, 0x31, 0x39, 0x70, 0x37, 0x31, + 0x58, 0x5a, 0x51, 0x76, 0x6b, 0x2f, 0x69, 0x58, 0x74, 0x74, 0x6d, 0x6b, + 0x51, 0x33, 0x43, 0x67, 0x61, 0x52, 0x72, 0x30, 0x42, 0x48, 0x64, 0x43, + 0x58, 0x0a, 0x74, 0x65, 0x47, 0x59, 0x4f, 0x38, 0x41, 0x33, 0x5a, 0x4e, + 0x59, 0x39, 0x6c, 0x4f, 0x34, 0x4c, 0x34, 0x66, 0x55, 0x6f, 0x72, 0x67, + 0x74, 0x57, 0x76, 0x33, 0x47, 0x4c, 0x49, 0x79, 0x6c, 0x42, 0x6a, 0x6f, + 0x62, 0x46, 0x53, 0x31, 0x4a, 0x37, 0x32, 0x48, 0x47, 0x72, 0x48, 0x34, + 0x6f, 0x56, 0x70, 0x6a, 0x75, 0x44, 0x57, 0x74, 0x64, 0x59, 0x41, 0x56, + 0x48, 0x47, 0x54, 0x45, 0x48, 0x5a, 0x0a, 0x66, 0x39, 0x68, 0x42, 0x5a, + 0x33, 0x4b, 0x69, 0x4b, 0x4e, 0x39, 0x67, 0x67, 0x36, 0x6d, 0x65, 0x79, + 0x48, 0x76, 0x38, 0x55, 0x33, 0x4e, 0x79, 0x57, 0x66, 0x57, 0x54, 0x65, + 0x68, 0x64, 0x32, 0x44, 0x73, 0x37, 0x33, 0x35, 0x56, 0x7a, 0x5a, 0x43, + 0x31, 0x55, 0x30, 0x6f, 0x71, 0x70, 0x62, 0x74, 0x57, 0x70, 0x55, 0x35, + 0x78, 0x50, 0x4b, 0x56, 0x2b, 0x79, 0x58, 0x62, 0x66, 0x52, 0x65, 0x0a, + 0x42, 0x69, 0x39, 0x46, 0x69, 0x31, 0x6a, 0x55, 0x49, 0x78, 0x61, 0x53, + 0x35, 0x42, 0x5a, 0x75, 0x4b, 0x47, 0x4e, 0x5a, 0x4d, 0x4e, 0x39, 0x51, + 0x41, 0x5a, 0x78, 0x6a, 0x69, 0x52, 0x71, 0x66, 0x32, 0x78, 0x65, 0x55, + 0x67, 0x6e, 0x41, 0x33, 0x77, 0x79, 0x53, 0x65, 0x6d, 0x6b, 0x66, 0x57, + 0x57, 0x73, 0x70, 0x4f, 0x71, 0x47, 0x6d, 0x4a, 0x63, 0x68, 0x2b, 0x52, + 0x62, 0x4e, 0x74, 0x2b, 0x0a, 0x6e, 0x68, 0x75, 0x74, 0x78, 0x78, 0x39, + 0x7a, 0x33, 0x53, 0x78, 0x50, 0x47, 0x57, 0x58, 0x39, 0x66, 0x35, 0x4e, + 0x41, 0x45, 0x43, 0x37, 0x53, 0x38, 0x4f, 0x30, 0x38, 0x6e, 0x69, 0x34, + 0x6f, 0x50, 0x6d, 0x6b, 0x6d, 0x4d, 0x38, 0x56, 0x37, 0x41, 0x67, 0x4d, + 0x42, 0x41, 0x41, 0x47, 0x6a, 0x59, 0x7a, 0x42, 0x68, 0x4d, 0x41, 0x38, + 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x0a, 0x2f, 0x77, + 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x48, 0x51, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4e, + 0x71, 0x37, 0x4c, 0x71, 0x71, 0x77, 0x44, 0x4c, 0x69, 0x49, 0x4a, 0x6c, + 0x46, 0x30, 0x58, 0x47, 0x30, 0x44, 0x30, 0x38, 0x44, 0x59, 0x6a, 0x33, + 0x72, 0x57, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x49, 0x77, + 0x51, 0x59, 0x0a, 0x4d, 0x42, 0x61, 0x41, 0x46, 0x4e, 0x71, 0x37, 0x4c, + 0x71, 0x71, 0x77, 0x44, 0x4c, 0x69, 0x49, 0x4a, 0x6c, 0x46, 0x30, 0x58, + 0x47, 0x30, 0x44, 0x30, 0x38, 0x44, 0x59, 0x6a, 0x33, 0x72, 0x57, 0x4d, + 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, + 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x68, 0x6a, 0x41, 0x4e, 0x42, + 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x0a, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, + 0x4d, 0x58, 0x6a, 0x6d, 0x78, 0x37, 0x58, 0x66, 0x75, 0x4a, 0x52, 0x41, + 0x79, 0x58, 0x48, 0x45, 0x71, 0x44, 0x58, 0x73, 0x52, 0x68, 0x33, 0x43, + 0x68, 0x66, 0x4d, 0x6f, 0x57, 0x49, 0x61, 0x77, 0x43, 0x2f, 0x79, 0x4f, + 0x73, 0x6a, 0x6d, 0x50, 0x52, 0x46, 0x57, 0x72, 0x5a, 0x49, 0x52, 0x63, + 0x0a, 0x61, 0x61, 0x6e, 0x51, 0x6d, 0x6a, 0x67, 0x38, 0x2b, 0x75, 0x55, + 0x66, 0x4e, 0x65, 0x56, 0x45, 0x34, 0x34, 0x42, 0x35, 0x6c, 0x47, 0x69, + 0x6b, 0x75, 0x38, 0x53, 0x66, 0x50, 0x65, 0x45, 0x30, 0x7a, 0x54, 0x42, + 0x47, 0x69, 0x31, 0x51, 0x72, 0x6c, 0x61, 0x58, 0x76, 0x39, 0x7a, 0x2b, + 0x5a, 0x68, 0x50, 0x30, 0x31, 0x35, 0x73, 0x38, 0x78, 0x78, 0x74, 0x78, + 0x71, 0x76, 0x36, 0x66, 0x58, 0x0a, 0x49, 0x77, 0x6a, 0x68, 0x6d, 0x46, + 0x37, 0x44, 0x57, 0x67, 0x68, 0x32, 0x71, 0x61, 0x61, 0x76, 0x64, 0x79, + 0x2b, 0x33, 0x59, 0x4c, 0x31, 0x45, 0x52, 0x6d, 0x72, 0x76, 0x6c, 0x2f, + 0x39, 0x7a, 0x6c, 0x63, 0x47, 0x4f, 0x36, 0x4a, 0x50, 0x37, 0x2f, 0x54, + 0x47, 0x33, 0x37, 0x46, 0x63, 0x52, 0x45, 0x55, 0x57, 0x62, 0x4d, 0x50, + 0x45, 0x61, 0x69, 0x44, 0x6e, 0x42, 0x54, 0x7a, 0x79, 0x6e, 0x0a, 0x41, + 0x4e, 0x58, 0x48, 0x2f, 0x4b, 0x74, 0x74, 0x67, 0x43, 0x4a, 0x77, 0x70, + 0x51, 0x7a, 0x67, 0x58, 0x51, 0x51, 0x70, 0x41, 0x76, 0x76, 0x4c, 0x6f, + 0x4a, 0x48, 0x52, 0x66, 0x4e, 0x62, 0x44, 0x66, 0x6c, 0x44, 0x56, 0x6e, + 0x56, 0x69, 0x2b, 0x51, 0x54, 0x6a, 0x72, 0x75, 0x58, 0x55, 0x38, 0x46, + 0x64, 0x6d, 0x62, 0x79, 0x55, 0x71, 0x44, 0x57, 0x63, 0x44, 0x61, 0x55, + 0x2f, 0x30, 0x7a, 0x0a, 0x75, 0x7a, 0x59, 0x59, 0x6d, 0x34, 0x55, 0x50, + 0x46, 0x64, 0x33, 0x75, 0x4c, 0x61, 0x78, 0x32, 0x6b, 0x37, 0x6e, 0x5a, + 0x41, 0x59, 0x31, 0x49, 0x45, 0x4b, 0x6a, 0x37, 0x39, 0x54, 0x69, 0x47, + 0x38, 0x64, 0x73, 0x4b, 0x78, 0x72, 0x32, 0x45, 0x6f, 0x79, 0x4e, 0x42, + 0x33, 0x74, 0x5a, 0x33, 0x62, 0x34, 0x58, 0x55, 0x68, 0x52, 0x78, 0x51, + 0x34, 0x4b, 0x35, 0x52, 0x69, 0x72, 0x71, 0x4e, 0x0a, 0x50, 0x6e, 0x62, + 0x69, 0x75, 0x63, 0x6f, 0x6e, 0x38, 0x6c, 0x2b, 0x66, 0x37, 0x32, 0x35, + 0x5a, 0x44, 0x51, 0x62, 0x59, 0x4b, 0x78, 0x65, 0x6b, 0x30, 0x6e, 0x78, + 0x72, 0x75, 0x31, 0x38, 0x55, 0x47, 0x6b, 0x69, 0x50, 0x47, 0x6b, 0x7a, + 0x6e, 0x73, 0x30, 0x63, 0x63, 0x6a, 0x6b, 0x78, 0x46, 0x4b, 0x79, 0x44, + 0x75, 0x53, 0x4e, 0x2f, 0x6e, 0x33, 0x51, 0x6d, 0x4f, 0x47, 0x4b, 0x6a, + 0x61, 0x0a, 0x51, 0x49, 0x32, 0x53, 0x4a, 0x68, 0x46, 0x54, 0x59, 0x58, + 0x4e, 0x64, 0x36, 0x37, 0x33, 0x6e, 0x78, 0x45, 0x30, 0x70, 0x4e, 0x32, + 0x48, 0x72, 0x72, 0x44, 0x6b, 0x74, 0x5a, 0x79, 0x34, 0x57, 0x31, 0x76, + 0x55, 0x41, 0x67, 0x34, 0x57, 0x68, 0x7a, 0x48, 0x39, 0x32, 0x78, 0x48, + 0x33, 0x6b, 0x74, 0x30, 0x74, 0x6d, 0x37, 0x77, 0x4e, 0x46, 0x59, 0x47, + 0x6d, 0x32, 0x44, 0x46, 0x4b, 0x57, 0x0a, 0x6b, 0x6f, 0x52, 0x65, 0x70, + 0x71, 0x4f, 0x31, 0x70, 0x44, 0x34, 0x72, 0x32, 0x63, 0x7a, 0x59, 0x47, + 0x30, 0x65, 0x71, 0x38, 0x6b, 0x54, 0x61, 0x54, 0x2f, 0x6b, 0x44, 0x36, + 0x50, 0x41, 0x55, 0x79, 0x7a, 0x2f, 0x7a, 0x67, 0x39, 0x37, 0x51, 0x77, + 0x56, 0x54, 0x6a, 0x74, 0x2b, 0x67, 0x4b, 0x4e, 0x30, 0x32, 0x4c, 0x49, + 0x46, 0x6b, 0x44, 0x4d, 0x42, 0x6d, 0x68, 0x4c, 0x4d, 0x69, 0x39, 0x0a, + 0x45, 0x52, 0x2f, 0x66, 0x72, 0x73, 0x6c, 0x4b, 0x78, 0x66, 0x4d, 0x6e, + 0x5a, 0x6d, 0x61, 0x47, 0x72, 0x47, 0x69, 0x52, 0x2f, 0x39, 0x6e, 0x6d, + 0x55, 0x78, 0x77, 0x50, 0x69, 0x31, 0x78, 0x70, 0x5a, 0x51, 0x6f, 0x6d, + 0x79, 0x42, 0x34, 0x30, 0x77, 0x31, 0x31, 0x52, 0x65, 0x39, 0x65, 0x70, + 0x6e, 0x41, 0x61, 0x68, 0x4e, 0x74, 0x33, 0x56, 0x69, 0x5a, 0x53, 0x38, + 0x32, 0x65, 0x51, 0x74, 0x0a, 0x44, 0x46, 0x34, 0x4a, 0x62, 0x41, 0x69, + 0x58, 0x66, 0x4b, 0x4d, 0x39, 0x66, 0x4a, 0x50, 0x2f, 0x50, 0x36, 0x45, + 0x55, 0x70, 0x38, 0x2b, 0x31, 0x58, 0x65, 0x76, 0x62, 0x32, 0x78, 0x7a, + 0x45, 0x64, 0x74, 0x2b, 0x49, 0x75, 0x62, 0x31, 0x46, 0x42, 0x5a, 0x55, + 0x62, 0x72, 0x76, 0x78, 0x47, 0x61, 0x6b, 0x79, 0x76, 0x53, 0x4f, 0x50, + 0x4f, 0x72, 0x67, 0x2f, 0x53, 0x66, 0x75, 0x76, 0x6d, 0x0a, 0x62, 0x4a, + 0x78, 0x50, 0x67, 0x57, 0x70, 0x36, 0x5a, 0x4b, 0x79, 0x37, 0x50, 0x74, + 0x58, 0x6e, 0x79, 0x33, 0x59, 0x75, 0x78, 0x61, 0x64, 0x49, 0x77, 0x56, + 0x79, 0x51, 0x44, 0x38, 0x76, 0x49, 0x50, 0x2f, 0x72, 0x6d, 0x4d, 0x75, + 0x47, 0x4e, 0x47, 0x32, 0x2b, 0x6b, 0x35, 0x6f, 0x37, 0x59, 0x2b, 0x53, + 0x6c, 0x49, 0x69, 0x73, 0x35, 0x7a, 0x2f, 0x69, 0x77, 0x3d, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x43, 0x41, + 0x20, 0x32, 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, + 0x73, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x32, 0x20, 0x4f, 0x3d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x55, 0x6e, 0x69, 0x76, + 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x32, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, + 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x34, 0x3a, 0x66, 0x63, + 0x3a, 0x62, 0x38, 0x3a, 0x64, 0x30, 0x3a, 0x33, 0x36, 0x3a, 0x64, 0x62, + 0x3a, 0x39, 0x65, 0x3a, 0x31, 0x34, 0x3a, 0x62, 0x33, 0x3a, 0x63, 0x32, + 0x3a, 0x66, 0x32, 0x3a, 0x64, 0x62, 0x3a, 0x38, 0x66, 0x3a, 0x65, 0x34, + 0x3a, 0x39, 0x34, 0x3a, 0x63, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x33, 0x37, 0x3a, 0x39, 0x61, 0x3a, 0x31, 0x39, 0x3a, + 0x37, 0x62, 0x3a, 0x34, 0x31, 0x3a, 0x38, 0x35, 0x3a, 0x34, 0x35, 0x3a, + 0x33, 0x35, 0x3a, 0x30, 0x63, 0x3a, 0x61, 0x36, 0x3a, 0x30, 0x33, 0x3a, + 0x36, 0x39, 0x3a, 0x66, 0x33, 0x3a, 0x33, 0x63, 0x3a, 0x32, 0x65, 0x3a, + 0x61, 0x66, 0x3a, 0x34, 0x37, 0x3a, 0x34, 0x66, 0x3a, 0x32, 0x30, 0x3a, + 0x37, 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x61, 0x30, 0x3a, 0x32, 0x33, 0x3a, 0x34, 0x66, 0x3a, 0x33, 0x62, + 0x3a, 0x63, 0x38, 0x3a, 0x35, 0x32, 0x3a, 0x37, 0x63, 0x3a, 0x61, 0x35, + 0x3a, 0x36, 0x32, 0x3a, 0x38, 0x65, 0x3a, 0x65, 0x63, 0x3a, 0x38, 0x31, + 0x3a, 0x61, 0x64, 0x3a, 0x35, 0x64, 0x3a, 0x36, 0x39, 0x3a, 0x38, 0x39, + 0x3a, 0x35, 0x64, 0x3a, 0x61, 0x35, 0x3a, 0x36, 0x38, 0x3a, 0x30, 0x64, + 0x3a, 0x63, 0x39, 0x3a, 0x31, 0x64, 0x3a, 0x31, 0x63, 0x3a, 0x62, 0x38, + 0x3a, 0x34, 0x37, 0x3a, 0x37, 0x66, 0x3a, 0x33, 0x33, 0x3a, 0x66, 0x38, + 0x3a, 0x37, 0x38, 0x3a, 0x62, 0x39, 0x3a, 0x35, 0x62, 0x3a, 0x30, 0x62, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x62, 0x44, 0x43, + 0x43, 0x41, 0x31, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, + 0x48, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x57, 0x0a, 0x4d, 0x42, + 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4e, 0x52, 0x32, + 0x56, 0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x53, 0x57, + 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x67, 0x4d, 0x42, 0x34, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x41, 0x78, 0x4d, 0x58, 0x52, 0x32, 0x56, 0x76, 0x56, 0x48, + 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x56, 0x57, 0x35, 0x70, 0x64, 0x6d, + 0x56, 0x79, 0x0a, 0x63, 0x32, 0x46, 0x73, 0x49, 0x45, 0x4e, 0x42, 0x49, + 0x44, 0x49, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x51, 0x77, 0x4d, + 0x7a, 0x41, 0x30, 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, + 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x6b, 0x77, 0x4d, 0x7a, 0x41, 0x30, 0x4d, + 0x44, 0x55, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x6a, 0x42, 0x48, 0x4d, + 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, 0x47, + 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x57, 0x4d, 0x42, 0x51, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4e, 0x52, 0x32, 0x56, 0x76, + 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x53, 0x57, 0x35, 0x6a, + 0x4c, 0x6a, 0x45, 0x67, 0x4d, 0x42, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x41, 0x78, 0x4d, 0x58, 0x52, 0x32, 0x56, 0x76, 0x56, 0x48, 0x4a, 0x31, + 0x0a, 0x63, 0x33, 0x51, 0x67, 0x56, 0x57, 0x35, 0x70, 0x64, 0x6d, 0x56, + 0x79, 0x63, 0x32, 0x46, 0x73, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x44, 0x49, + 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, + 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, + 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, + 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x0a, 0x41, 0x51, 0x43, 0x7a, 0x56, 0x46, + 0x4c, 0x42, 0x79, 0x54, 0x37, 0x79, 0x32, 0x64, 0x79, 0x78, 0x55, 0x78, + 0x70, 0x5a, 0x4b, 0x65, 0x65, 0x78, 0x77, 0x30, 0x55, 0x6f, 0x35, 0x64, + 0x66, 0x52, 0x37, 0x63, 0x58, 0x46, 0x53, 0x36, 0x47, 0x71, 0x64, 0x48, + 0x74, 0x58, 0x72, 0x30, 0x6f, 0x6d, 0x2f, 0x4e, 0x6a, 0x31, 0x58, 0x71, + 0x64, 0x75, 0x47, 0x64, 0x74, 0x30, 0x44, 0x45, 0x38, 0x31, 0x0a, 0x57, + 0x7a, 0x49, 0x4c, 0x41, 0x65, 0x50, 0x62, 0x36, 0x33, 0x70, 0x33, 0x4e, + 0x65, 0x71, 0x71, 0x57, 0x75, 0x44, 0x57, 0x36, 0x4b, 0x46, 0x58, 0x6c, + 0x50, 0x43, 0x51, 0x6f, 0x33, 0x52, 0x57, 0x6c, 0x45, 0x51, 0x77, 0x41, + 0x78, 0x35, 0x63, 0x54, 0x69, 0x75, 0x46, 0x4a, 0x6e, 0x53, 0x43, 0x65, + 0x67, 0x78, 0x32, 0x6f, 0x47, 0x39, 0x4e, 0x7a, 0x6b, 0x45, 0x74, 0x6f, + 0x42, 0x55, 0x47, 0x0a, 0x46, 0x46, 0x2b, 0x33, 0x51, 0x73, 0x31, 0x37, + 0x6a, 0x31, 0x68, 0x68, 0x4e, 0x4e, 0x77, 0x71, 0x43, 0x50, 0x6b, 0x75, + 0x77, 0x77, 0x47, 0x6d, 0x49, 0x6b, 0x51, 0x63, 0x54, 0x41, 0x65, 0x43, + 0x35, 0x6c, 0x76, 0x4f, 0x30, 0x45, 0x70, 0x38, 0x42, 0x4e, 0x4d, 0x5a, + 0x63, 0x79, 0x66, 0x77, 0x71, 0x70, 0x68, 0x2f, 0x4c, 0x71, 0x39, 0x4f, + 0x36, 0x34, 0x63, 0x65, 0x4a, 0x48, 0x64, 0x71, 0x0a, 0x58, 0x62, 0x62, + 0x6f, 0x57, 0x30, 0x57, 0x36, 0x33, 0x4d, 0x4f, 0x68, 0x42, 0x57, 0x39, + 0x57, 0x6a, 0x6f, 0x38, 0x51, 0x4a, 0x71, 0x56, 0x4a, 0x77, 0x79, 0x37, + 0x58, 0x51, 0x59, 0x63, 0x69, 0x34, 0x45, 0x2b, 0x47, 0x79, 0x6d, 0x43, + 0x31, 0x36, 0x71, 0x46, 0x6a, 0x77, 0x41, 0x47, 0x58, 0x45, 0x48, 0x6d, + 0x39, 0x41, 0x44, 0x77, 0x53, 0x62, 0x53, 0x73, 0x56, 0x73, 0x61, 0x78, + 0x4c, 0x0a, 0x73, 0x65, 0x34, 0x59, 0x75, 0x55, 0x36, 0x57, 0x33, 0x4e, + 0x78, 0x32, 0x2f, 0x7a, 0x75, 0x2b, 0x7a, 0x31, 0x38, 0x44, 0x77, 0x50, + 0x77, 0x37, 0x36, 0x4c, 0x35, 0x47, 0x47, 0x2f, 0x2f, 0x61, 0x51, 0x4d, + 0x4a, 0x53, 0x39, 0x2f, 0x37, 0x6a, 0x4f, 0x76, 0x64, 0x71, 0x64, 0x7a, + 0x58, 0x51, 0x32, 0x6f, 0x33, 0x72, 0x58, 0x68, 0x68, 0x71, 0x4d, 0x63, + 0x63, 0x65, 0x75, 0x6a, 0x77, 0x62, 0x0a, 0x4b, 0x4e, 0x5a, 0x72, 0x56, + 0x4d, 0x61, 0x71, 0x57, 0x39, 0x65, 0x69, 0x4c, 0x42, 0x73, 0x5a, 0x7a, + 0x4b, 0x49, 0x43, 0x39, 0x70, 0x74, 0x5a, 0x76, 0x54, 0x64, 0x72, 0x68, + 0x72, 0x56, 0x74, 0x67, 0x72, 0x72, 0x59, 0x36, 0x73, 0x6c, 0x57, 0x76, + 0x4b, 0x6b, 0x32, 0x57, 0x50, 0x30, 0x2b, 0x47, 0x66, 0x50, 0x74, 0x44, + 0x43, 0x61, 0x70, 0x6b, 0x7a, 0x6a, 0x34, 0x54, 0x38, 0x46, 0x64, 0x0a, + 0x49, 0x67, 0x62, 0x51, 0x6c, 0x2b, 0x72, 0x68, 0x72, 0x63, 0x5a, 0x56, + 0x34, 0x49, 0x45, 0x72, 0x4b, 0x49, 0x4d, 0x36, 0x2b, 0x76, 0x52, 0x37, + 0x49, 0x56, 0x45, 0x41, 0x76, 0x6c, 0x49, 0x34, 0x7a, 0x73, 0x31, 0x6d, + 0x65, 0x61, 0x6a, 0x30, 0x67, 0x56, 0x62, 0x69, 0x30, 0x49, 0x4d, 0x4a, + 0x52, 0x31, 0x46, 0x62, 0x55, 0x47, 0x72, 0x50, 0x32, 0x30, 0x67, 0x61, + 0x58, 0x54, 0x37, 0x33, 0x0a, 0x79, 0x2f, 0x5a, 0x6c, 0x39, 0x32, 0x7a, + 0x78, 0x6c, 0x66, 0x67, 0x43, 0x4f, 0x7a, 0x4a, 0x57, 0x67, 0x6a, 0x6c, + 0x36, 0x57, 0x37, 0x30, 0x76, 0x69, 0x52, 0x75, 0x2f, 0x6f, 0x62, 0x54, + 0x6f, 0x2f, 0x33, 0x2b, 0x4e, 0x6a, 0x4e, 0x38, 0x44, 0x38, 0x57, 0x42, + 0x4f, 0x57, 0x42, 0x46, 0x4d, 0x36, 0x36, 0x4d, 0x2f, 0x45, 0x43, 0x75, + 0x44, 0x6d, 0x67, 0x46, 0x7a, 0x32, 0x5a, 0x52, 0x74, 0x0a, 0x68, 0x41, + 0x41, 0x6e, 0x5a, 0x71, 0x7a, 0x77, 0x63, 0x45, 0x41, 0x4a, 0x51, 0x70, + 0x4b, 0x74, 0x54, 0x35, 0x4d, 0x4e, 0x59, 0x51, 0x6c, 0x52, 0x4a, 0x4e, + 0x69, 0x53, 0x31, 0x51, 0x75, 0x55, 0x59, 0x62, 0x4b, 0x48, 0x73, 0x75, + 0x33, 0x2f, 0x6d, 0x6a, 0x58, 0x2f, 0x68, 0x56, 0x54, 0x4b, 0x37, 0x55, + 0x52, 0x44, 0x72, 0x42, 0x73, 0x38, 0x46, 0x6d, 0x74, 0x49, 0x53, 0x67, + 0x6f, 0x63, 0x0a, 0x51, 0x49, 0x67, 0x66, 0x6b, 0x73, 0x49, 0x4c, 0x41, + 0x41, 0x58, 0x2f, 0x38, 0x73, 0x67, 0x43, 0x53, 0x71, 0x53, 0x71, 0x71, + 0x63, 0x79, 0x5a, 0x6c, 0x70, 0x77, 0x76, 0x57, 0x4f, 0x42, 0x39, 0x34, + 0x62, 0x36, 0x37, 0x42, 0x39, 0x78, 0x66, 0x42, 0x48, 0x4a, 0x63, 0x4d, + 0x54, 0x54, 0x44, 0x37, 0x46, 0x38, 0x74, 0x34, 0x44, 0x31, 0x6b, 0x6b, + 0x43, 0x4c, 0x6d, 0x30, 0x65, 0x79, 0x34, 0x0a, 0x4c, 0x74, 0x31, 0x5a, + 0x72, 0x74, 0x6d, 0x68, 0x4e, 0x37, 0x39, 0x55, 0x4e, 0x64, 0x78, 0x7a, + 0x4d, 0x6b, 0x2b, 0x4d, 0x42, 0x42, 0x34, 0x7a, 0x73, 0x73, 0x6c, 0x47, + 0x38, 0x64, 0x68, 0x63, 0x79, 0x46, 0x56, 0x51, 0x79, 0x57, 0x69, 0x39, + 0x71, 0x4c, 0x6f, 0x32, 0x43, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, + 0x6f, 0x32, 0x4d, 0x77, 0x59, 0x54, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, + 0x0a, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, + 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x52, 0x32, 0x38, 0x31, 0x58, + 0x68, 0x2b, 0x71, 0x51, 0x32, 0x2b, 0x2f, 0x43, 0x66, 0x58, 0x47, 0x4a, + 0x78, 0x37, 0x54, 0x7a, 0x30, 0x52, 0x7a, 0x67, 0x51, 0x4b, 0x7a, 0x41, + 0x66, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, + 0x41, 0x57, 0x67, 0x42, 0x52, 0x32, 0x38, 0x31, 0x58, 0x68, 0x2b, 0x71, + 0x51, 0x32, 0x2b, 0x2f, 0x43, 0x66, 0x58, 0x47, 0x4a, 0x78, 0x37, 0x54, + 0x7a, 0x30, 0x52, 0x7a, 0x67, 0x51, 0x4b, 0x7a, 0x41, 0x4f, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, + 0x4d, 0x43, 0x41, 0x59, 0x59, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x0a, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, + 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x42, 0x41, 0x47, 0x62, 0x42, 0x78, + 0x69, 0x50, 0x7a, 0x32, 0x65, 0x41, 0x75, 0x62, 0x6c, 0x2f, 0x6f, 0x7a, + 0x36, 0x36, 0x77, 0x73, 0x43, 0x56, 0x4e, 0x4b, 0x2f, 0x67, 0x37, 0x57, + 0x4a, 0x74, 0x41, 0x4a, 0x44, 0x64, 0x61, 0x79, 0x36, 0x73, 0x57, 0x53, + 0x66, 0x2b, 0x7a, 0x0a, 0x64, 0x58, 0x6b, 0x7a, 0x6f, 0x53, 0x39, 0x74, + 0x63, 0x42, 0x63, 0x30, 0x6b, 0x66, 0x35, 0x6e, 0x66, 0x6f, 0x2f, 0x73, + 0x6d, 0x2b, 0x56, 0x65, 0x67, 0x71, 0x6c, 0x56, 0x48, 0x79, 0x2f, 0x63, + 0x31, 0x46, 0x45, 0x48, 0x45, 0x76, 0x36, 0x73, 0x46, 0x6a, 0x34, 0x73, + 0x4e, 0x63, 0x5a, 0x6a, 0x2f, 0x4e, 0x77, 0x51, 0x36, 0x77, 0x32, 0x6a, + 0x71, 0x74, 0x42, 0x38, 0x7a, 0x4e, 0x48, 0x51, 0x0a, 0x4c, 0x31, 0x45, + 0x75, 0x78, 0x42, 0x52, 0x61, 0x33, 0x75, 0x67, 0x5a, 0x34, 0x54, 0x37, + 0x47, 0x7a, 0x4b, 0x51, 0x70, 0x35, 0x79, 0x36, 0x45, 0x71, 0x67, 0x59, + 0x77, 0x65, 0x48, 0x5a, 0x55, 0x63, 0x79, 0x69, 0x59, 0x57, 0x54, 0x6a, + 0x67, 0x41, 0x41, 0x31, 0x69, 0x30, 0x30, 0x4a, 0x39, 0x49, 0x5a, 0x2b, + 0x75, 0x50, 0x54, 0x71, 0x4d, 0x31, 0x66, 0x70, 0x33, 0x44, 0x52, 0x67, + 0x72, 0x0a, 0x46, 0x67, 0x35, 0x66, 0x4e, 0x75, 0x48, 0x38, 0x4b, 0x72, + 0x55, 0x77, 0x4a, 0x4d, 0x2f, 0x67, 0x59, 0x77, 0x78, 0x37, 0x57, 0x42, + 0x72, 0x2b, 0x6d, 0x62, 0x70, 0x43, 0x45, 0x72, 0x47, 0x52, 0x39, 0x48, + 0x78, 0x6f, 0x34, 0x73, 0x6a, 0x6f, 0x72, 0x79, 0x7a, 0x71, 0x79, 0x58, + 0x36, 0x75, 0x75, 0x79, 0x6f, 0x39, 0x44, 0x52, 0x58, 0x63, 0x4e, 0x4a, + 0x57, 0x32, 0x47, 0x48, 0x53, 0x6f, 0x0a, 0x61, 0x67, 0x2f, 0x48, 0x74, + 0x50, 0x51, 0x54, 0x78, 0x4f, 0x52, 0x62, 0x37, 0x51, 0x72, 0x53, 0x70, + 0x4a, 0x64, 0x4d, 0x4b, 0x75, 0x30, 0x76, 0x62, 0x42, 0x4b, 0x4a, 0x50, + 0x66, 0x45, 0x6e, 0x63, 0x4b, 0x70, 0x71, 0x41, 0x31, 0x49, 0x68, 0x6e, + 0x30, 0x43, 0x6f, 0x5a, 0x31, 0x44, 0x79, 0x38, 0x31, 0x6f, 0x66, 0x33, + 0x39, 0x38, 0x6a, 0x39, 0x74, 0x78, 0x34, 0x54, 0x75, 0x61, 0x59, 0x0a, + 0x54, 0x31, 0x55, 0x36, 0x55, 0x2b, 0x50, 0x76, 0x38, 0x76, 0x53, 0x66, + 0x78, 0x33, 0x7a, 0x59, 0x57, 0x4b, 0x38, 0x70, 0x49, 0x70, 0x65, 0x34, + 0x34, 0x4c, 0x32, 0x52, 0x4c, 0x72, 0x42, 0x32, 0x37, 0x46, 0x63, 0x52, + 0x7a, 0x2b, 0x38, 0x70, 0x52, 0x50, 0x50, 0x70, 0x68, 0x58, 0x70, 0x67, + 0x59, 0x2b, 0x52, 0x64, 0x4d, 0x34, 0x6b, 0x58, 0x32, 0x54, 0x47, 0x71, + 0x32, 0x74, 0x62, 0x7a, 0x0a, 0x47, 0x44, 0x56, 0x79, 0x7a, 0x34, 0x63, + 0x72, 0x4c, 0x32, 0x4d, 0x6a, 0x68, 0x46, 0x32, 0x45, 0x6a, 0x44, 0x39, + 0x58, 0x6f, 0x49, 0x6a, 0x38, 0x6d, 0x5a, 0x45, 0x6f, 0x4a, 0x6d, 0x6d, + 0x5a, 0x31, 0x49, 0x2b, 0x58, 0x52, 0x4c, 0x36, 0x4f, 0x31, 0x55, 0x69, + 0x78, 0x70, 0x43, 0x67, 0x70, 0x38, 0x52, 0x57, 0x30, 0x34, 0x65, 0x57, + 0x65, 0x33, 0x66, 0x69, 0x50, 0x70, 0x6d, 0x38, 0x6d, 0x0a, 0x31, 0x77, + 0x6b, 0x38, 0x4f, 0x68, 0x77, 0x52, 0x44, 0x71, 0x5a, 0x73, 0x4e, 0x2f, + 0x65, 0x74, 0x52, 0x49, 0x63, 0x73, 0x4b, 0x4d, 0x66, 0x59, 0x64, 0x49, + 0x4b, 0x7a, 0x30, 0x47, 0x39, 0x4b, 0x56, 0x37, 0x73, 0x31, 0x4b, 0x53, + 0x65, 0x67, 0x69, 0x2b, 0x67, 0x68, 0x70, 0x34, 0x64, 0x6b, 0x4e, 0x6c, + 0x33, 0x4d, 0x32, 0x42, 0x61, 0x73, 0x78, 0x37, 0x49, 0x6e, 0x51, 0x4a, + 0x4a, 0x56, 0x0a, 0x4f, 0x43, 0x69, 0x4e, 0x55, 0x57, 0x37, 0x64, 0x46, + 0x47, 0x64, 0x54, 0x62, 0x48, 0x46, 0x63, 0x4a, 0x6f, 0x52, 0x4e, 0x64, + 0x56, 0x71, 0x32, 0x66, 0x6d, 0x42, 0x57, 0x71, 0x55, 0x32, 0x74, 0x2b, + 0x35, 0x73, 0x65, 0x6c, 0x2f, 0x4d, 0x4e, 0x32, 0x64, 0x4b, 0x58, 0x56, + 0x48, 0x66, 0x61, 0x50, 0x52, 0x4b, 0x33, 0x34, 0x42, 0x37, 0x76, 0x43, + 0x41, 0x61, 0x73, 0x2b, 0x59, 0x57, 0x48, 0x0a, 0x36, 0x61, 0x4c, 0x63, + 0x72, 0x33, 0x34, 0x59, 0x45, 0x6f, 0x50, 0x39, 0x56, 0x68, 0x64, 0x42, + 0x4c, 0x74, 0x55, 0x70, 0x67, 0x6e, 0x32, 0x5a, 0x39, 0x44, 0x48, 0x32, + 0x63, 0x61, 0x6e, 0x50, 0x4c, 0x41, 0x45, 0x6e, 0x70, 0x51, 0x57, 0x35, + 0x71, 0x72, 0x4a, 0x49, 0x54, 0x69, 0x72, 0x76, 0x6e, 0x35, 0x4e, 0x53, + 0x55, 0x5a, 0x55, 0x38, 0x55, 0x6e, 0x4f, 0x4f, 0x56, 0x6b, 0x77, 0x58, + 0x0a, 0x51, 0x4d, 0x41, 0x4a, 0x4b, 0x4f, 0x53, 0x4c, 0x61, 0x6b, 0x68, + 0x54, 0x32, 0x2b, 0x7a, 0x4e, 0x56, 0x56, 0x58, 0x78, 0x78, 0x76, 0x6a, + 0x70, 0x6f, 0x69, 0x78, 0x4d, 0x70, 0x74, 0x45, 0x6d, 0x58, 0x33, 0x36, + 0x76, 0x57, 0x6b, 0x7a, 0x61, 0x48, 0x36, 0x62, 0x79, 0x48, 0x43, 0x78, + 0x2b, 0x72, 0x67, 0x49, 0x57, 0x30, 0x6c, 0x62, 0x51, 0x4c, 0x31, 0x64, + 0x54, 0x52, 0x2b, 0x69, 0x53, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x41, + 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x4f, + 0x3d, 0x43, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x20, 0x43, 0x41, 0x20, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x41, 0x41, + 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x4f, 0x3d, + 0x43, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x20, 0x41, + 0x41, 0x41, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, + 0x72, 0x6f, 0x6f, 0x74, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x34, 0x39, 0x3a, 0x37, 0x39, 0x3a, 0x30, 0x34, 0x3a, 0x62, 0x30, + 0x3a, 0x65, 0x62, 0x3a, 0x38, 0x37, 0x3a, 0x31, 0x39, 0x3a, 0x61, 0x63, + 0x3a, 0x34, 0x37, 0x3a, 0x62, 0x30, 0x3a, 0x62, 0x63, 0x3a, 0x31, 0x31, + 0x3a, 0x35, 0x31, 0x3a, 0x39, 0x62, 0x3a, 0x37, 0x34, 0x3a, 0x64, 0x30, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x31, 0x3a, + 0x65, 0x62, 0x3a, 0x32, 0x33, 0x3a, 0x61, 0x34, 0x3a, 0x36, 0x64, 0x3a, + 0x31, 0x37, 0x3a, 0x64, 0x36, 0x3a, 0x38, 0x66, 0x3a, 0x64, 0x39, 0x3a, + 0x32, 0x35, 0x3a, 0x36, 0x34, 0x3a, 0x63, 0x32, 0x3a, 0x66, 0x31, 0x3a, + 0x66, 0x31, 0x3a, 0x36, 0x30, 0x3a, 0x31, 0x37, 0x3a, 0x36, 0x34, 0x3a, + 0x64, 0x38, 0x3a, 0x65, 0x33, 0x3a, 0x34, 0x39, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x37, 0x3a, 0x61, 0x37, + 0x3a, 0x61, 0x30, 0x3a, 0x66, 0x62, 0x3a, 0x35, 0x64, 0x3a, 0x37, 0x65, + 0x3a, 0x32, 0x37, 0x3a, 0x33, 0x31, 0x3a, 0x64, 0x37, 0x3a, 0x37, 0x31, + 0x3a, 0x65, 0x39, 0x3a, 0x34, 0x38, 0x3a, 0x34, 0x65, 0x3a, 0x62, 0x63, + 0x3a, 0x64, 0x65, 0x3a, 0x66, 0x37, 0x3a, 0x31, 0x64, 0x3a, 0x35, 0x66, + 0x3a, 0x30, 0x63, 0x3a, 0x33, 0x65, 0x3a, 0x30, 0x61, 0x3a, 0x32, 0x39, + 0x3a, 0x34, 0x38, 0x3a, 0x37, 0x38, 0x3a, 0x32, 0x62, 0x3a, 0x63, 0x38, + 0x3a, 0x33, 0x65, 0x3a, 0x65, 0x30, 0x3a, 0x65, 0x61, 0x3a, 0x36, 0x39, + 0x3a, 0x39, 0x65, 0x3a, 0x66, 0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x45, 0x4d, 0x6a, 0x43, 0x43, 0x41, 0x78, 0x71, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, + 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, + 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x37, 0x4d, 0x51, 0x73, 0x77, 0x43, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x48, 0x51, + 0x6a, 0x45, 0x62, 0x0a, 0x4d, 0x42, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x41, 0x77, 0x53, 0x52, 0x33, 0x4a, 0x6c, 0x59, 0x58, 0x52, 0x6c, + 0x63, 0x69, 0x42, 0x4e, 0x59, 0x57, 0x35, 0x6a, 0x61, 0x47, 0x56, 0x7a, + 0x64, 0x47, 0x56, 0x79, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x64, 0x54, 0x59, 0x57, 0x78, 0x6d, + 0x62, 0x33, 0x4a, 0x6b, 0x4d, 0x52, 0x6f, 0x77, 0x0a, 0x47, 0x41, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x46, 0x44, 0x62, 0x32, 0x31, + 0x76, 0x5a, 0x47, 0x38, 0x67, 0x51, 0x30, 0x45, 0x67, 0x54, 0x47, 0x6c, + 0x74, 0x61, 0x58, 0x52, 0x6c, 0x5a, 0x44, 0x45, 0x68, 0x4d, 0x42, 0x38, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x59, 0x51, 0x55, 0x46, + 0x42, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, + 0x6a, 0x0a, 0x59, 0x58, 0x52, 0x6c, 0x49, 0x46, 0x4e, 0x6c, 0x63, 0x6e, + 0x5a, 0x70, 0x59, 0x32, 0x56, 0x7a, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, + 0x41, 0x30, 0x4d, 0x44, 0x45, 0x77, 0x4d, 0x54, 0x41, 0x77, 0x4d, 0x44, + 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x34, 0x4d, 0x54, + 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31, 0x4f, 0x56, + 0x6f, 0x77, 0x65, 0x7a, 0x45, 0x4c, 0x0a, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x30, 0x49, 0x78, 0x47, + 0x7a, 0x41, 0x5a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x4d, 0x45, + 0x6b, 0x64, 0x79, 0x5a, 0x57, 0x46, 0x30, 0x5a, 0x58, 0x49, 0x67, 0x54, + 0x57, 0x46, 0x75, 0x59, 0x32, 0x68, 0x6c, 0x63, 0x33, 0x52, 0x6c, 0x63, + 0x6a, 0x45, 0x51, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, + 0x42, 0x77, 0x77, 0x48, 0x55, 0x32, 0x46, 0x73, 0x5a, 0x6d, 0x39, 0x79, + 0x5a, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x67, 0x77, 0x52, 0x51, 0x32, 0x39, 0x74, 0x62, 0x32, 0x52, 0x76, + 0x49, 0x45, 0x4e, 0x42, 0x49, 0x45, 0x78, 0x70, 0x62, 0x57, 0x6c, 0x30, + 0x5a, 0x57, 0x51, 0x78, 0x49, 0x54, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x4d, 0x4d, 0x0a, 0x47, 0x45, 0x46, 0x42, 0x51, 0x53, 0x42, + 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, + 0x30, 0x5a, 0x53, 0x42, 0x54, 0x5a, 0x58, 0x4a, 0x32, 0x61, 0x57, 0x4e, + 0x6c, 0x63, 0x7a, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, + 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, + 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x0a, 0x41, 0x44, + 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4c, + 0x35, 0x41, 0x6e, 0x66, 0x52, 0x75, 0x34, 0x65, 0x70, 0x32, 0x68, 0x78, + 0x78, 0x4e, 0x52, 0x55, 0x53, 0x4f, 0x76, 0x6b, 0x62, 0x49, 0x67, 0x77, + 0x61, 0x64, 0x77, 0x53, 0x72, 0x2b, 0x47, 0x42, 0x2b, 0x4f, 0x35, 0x41, + 0x4c, 0x36, 0x38, 0x36, 0x74, 0x64, 0x55, 0x49, 0x6f, 0x57, 0x4d, 0x51, + 0x75, 0x61, 0x0a, 0x42, 0x74, 0x44, 0x46, 0x63, 0x43, 0x4c, 0x4e, 0x53, + 0x53, 0x31, 0x55, 0x59, 0x38, 0x79, 0x32, 0x62, 0x6d, 0x68, 0x47, 0x43, + 0x31, 0x50, 0x71, 0x79, 0x30, 0x77, 0x6b, 0x77, 0x4c, 0x78, 0x79, 0x54, + 0x75, 0x72, 0x78, 0x46, 0x61, 0x37, 0x30, 0x56, 0x4a, 0x6f, 0x53, 0x43, + 0x73, 0x4e, 0x36, 0x73, 0x6a, 0x4e, 0x67, 0x34, 0x74, 0x71, 0x4a, 0x56, + 0x66, 0x4d, 0x69, 0x57, 0x50, 0x50, 0x65, 0x0a, 0x33, 0x4d, 0x2f, 0x76, + 0x67, 0x34, 0x61, 0x69, 0x6a, 0x4a, 0x52, 0x50, 0x6e, 0x32, 0x6a, 0x79, + 0x6d, 0x4a, 0x42, 0x47, 0x68, 0x43, 0x66, 0x48, 0x64, 0x72, 0x2f, 0x6a, + 0x7a, 0x44, 0x55, 0x73, 0x69, 0x31, 0x34, 0x48, 0x5a, 0x47, 0x57, 0x43, + 0x77, 0x45, 0x69, 0x77, 0x71, 0x4a, 0x48, 0x35, 0x59, 0x5a, 0x39, 0x32, + 0x49, 0x46, 0x43, 0x6f, 0x6b, 0x63, 0x64, 0x6d, 0x74, 0x65, 0x74, 0x34, + 0x0a, 0x59, 0x67, 0x4e, 0x57, 0x38, 0x49, 0x6f, 0x61, 0x45, 0x2b, 0x6f, + 0x78, 0x6f, 0x78, 0x36, 0x67, 0x6d, 0x66, 0x30, 0x34, 0x39, 0x76, 0x59, + 0x6e, 0x4d, 0x6c, 0x68, 0x76, 0x42, 0x2f, 0x56, 0x72, 0x75, 0x50, 0x73, + 0x55, 0x4b, 0x36, 0x2b, 0x33, 0x71, 0x73, 0x7a, 0x57, 0x59, 0x31, 0x39, + 0x7a, 0x6a, 0x4e, 0x6f, 0x46, 0x6d, 0x61, 0x67, 0x34, 0x71, 0x4d, 0x73, + 0x58, 0x65, 0x44, 0x5a, 0x52, 0x0a, 0x72, 0x4f, 0x6d, 0x65, 0x39, 0x48, + 0x67, 0x36, 0x6a, 0x63, 0x38, 0x50, 0x32, 0x55, 0x4c, 0x69, 0x6d, 0x41, + 0x79, 0x72, 0x4c, 0x35, 0x38, 0x4f, 0x41, 0x64, 0x37, 0x76, 0x6e, 0x35, + 0x6c, 0x4a, 0x38, 0x53, 0x33, 0x66, 0x72, 0x48, 0x52, 0x4e, 0x47, 0x35, + 0x69, 0x31, 0x52, 0x38, 0x58, 0x6c, 0x4b, 0x64, 0x48, 0x35, 0x6b, 0x42, + 0x6a, 0x48, 0x59, 0x70, 0x79, 0x2b, 0x67, 0x38, 0x63, 0x6d, 0x0a, 0x65, + 0x7a, 0x36, 0x4b, 0x4a, 0x63, 0x66, 0x41, 0x33, 0x5a, 0x33, 0x6d, 0x4e, + 0x57, 0x67, 0x51, 0x49, 0x4a, 0x32, 0x50, 0x32, 0x4e, 0x37, 0x53, 0x77, + 0x34, 0x53, 0x63, 0x44, 0x56, 0x37, 0x6f, 0x4c, 0x38, 0x6b, 0x43, 0x41, + 0x77, 0x45, 0x41, 0x41, 0x61, 0x4f, 0x42, 0x77, 0x44, 0x43, 0x42, 0x76, + 0x54, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, + 0x67, 0x51, 0x55, 0x0a, 0x6f, 0x42, 0x45, 0x4b, 0x49, 0x7a, 0x36, 0x57, + 0x38, 0x51, 0x66, 0x73, 0x34, 0x71, 0x38, 0x70, 0x37, 0x34, 0x4b, 0x6c, + 0x66, 0x39, 0x41, 0x77, 0x70, 0x4c, 0x51, 0x77, 0x44, 0x67, 0x59, 0x44, + 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, + 0x41, 0x67, 0x45, 0x47, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x0a, 0x4d, 0x41, 0x4d, + 0x42, 0x41, 0x66, 0x38, 0x77, 0x65, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, + 0x66, 0x42, 0x48, 0x51, 0x77, 0x63, 0x6a, 0x41, 0x34, 0x6f, 0x44, 0x61, + 0x67, 0x4e, 0x49, 0x59, 0x79, 0x61, 0x48, 0x52, 0x30, 0x63, 0x44, 0x6f, + 0x76, 0x4c, 0x32, 0x4e, 0x79, 0x62, 0x43, 0x35, 0x6a, 0x62, 0x32, 0x31, + 0x76, 0x5a, 0x47, 0x39, 0x6a, 0x59, 0x53, 0x35, 0x6a, 0x62, 0x32, 0x30, + 0x76, 0x0a, 0x51, 0x55, 0x46, 0x42, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, + 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x56, 0x54, 0x5a, 0x58, + 0x4a, 0x32, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x79, 0x35, 0x6a, 0x63, 0x6d, + 0x77, 0x77, 0x4e, 0x71, 0x41, 0x30, 0x6f, 0x44, 0x4b, 0x47, 0x4d, 0x47, + 0x68, 0x30, 0x64, 0x48, 0x41, 0x36, 0x4c, 0x79, 0x39, 0x6a, 0x63, 0x6d, + 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x0a, 0x62, 0x32, 0x52, 0x76, 0x4c, + 0x6d, 0x35, 0x6c, 0x64, 0x43, 0x39, 0x42, 0x51, 0x55, 0x46, 0x44, 0x5a, + 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, + 0x56, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, 0x7a, 0x4c, + 0x6d, 0x4e, 0x79, 0x62, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x0a, + 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x43, 0x46, 0x62, 0x38, + 0x41, 0x76, 0x43, 0x62, 0x36, 0x50, 0x2b, 0x6b, 0x2b, 0x74, 0x5a, 0x37, + 0x78, 0x6b, 0x53, 0x41, 0x7a, 0x6b, 0x2f, 0x45, 0x78, 0x66, 0x59, 0x41, + 0x57, 0x4d, 0x79, 0x6d, 0x74, 0x72, 0x77, 0x55, 0x53, 0x57, 0x67, 0x45, + 0x64, 0x75, 0x6a, 0x6d, 0x37, 0x6c, 0x33, 0x73, 0x41, 0x67, 0x39, 0x67, + 0x31, 0x6f, 0x31, 0x51, 0x0a, 0x47, 0x45, 0x38, 0x6d, 0x54, 0x67, 0x48, + 0x6a, 0x35, 0x72, 0x43, 0x6c, 0x37, 0x72, 0x2b, 0x38, 0x64, 0x46, 0x52, + 0x42, 0x76, 0x2f, 0x33, 0x38, 0x45, 0x72, 0x6a, 0x48, 0x54, 0x31, 0x72, + 0x30, 0x69, 0x57, 0x41, 0x46, 0x66, 0x32, 0x43, 0x33, 0x42, 0x55, 0x72, + 0x7a, 0x39, 0x76, 0x48, 0x43, 0x76, 0x38, 0x53, 0x35, 0x64, 0x49, 0x61, + 0x32, 0x4c, 0x58, 0x31, 0x72, 0x7a, 0x4e, 0x4c, 0x7a, 0x0a, 0x52, 0x74, + 0x30, 0x76, 0x78, 0x75, 0x42, 0x71, 0x77, 0x38, 0x4d, 0x30, 0x41, 0x79, + 0x78, 0x39, 0x6c, 0x74, 0x31, 0x61, 0x77, 0x67, 0x36, 0x6e, 0x43, 0x70, + 0x6e, 0x42, 0x42, 0x59, 0x75, 0x72, 0x44, 0x43, 0x2f, 0x7a, 0x58, 0x44, + 0x72, 0x50, 0x62, 0x44, 0x64, 0x56, 0x43, 0x59, 0x66, 0x65, 0x55, 0x30, + 0x42, 0x73, 0x57, 0x4f, 0x2f, 0x38, 0x74, 0x71, 0x74, 0x6c, 0x62, 0x67, + 0x54, 0x32, 0x0a, 0x47, 0x39, 0x77, 0x38, 0x34, 0x46, 0x6f, 0x56, 0x78, + 0x70, 0x37, 0x5a, 0x38, 0x56, 0x6c, 0x49, 0x4d, 0x43, 0x46, 0x6c, 0x41, + 0x32, 0x7a, 0x73, 0x36, 0x53, 0x46, 0x7a, 0x37, 0x4a, 0x73, 0x44, 0x6f, + 0x65, 0x41, 0x33, 0x72, 0x61, 0x41, 0x56, 0x47, 0x49, 0x2f, 0x36, 0x75, + 0x67, 0x4c, 0x4f, 0x70, 0x79, 0x79, 0x70, 0x45, 0x42, 0x4d, 0x73, 0x31, + 0x4f, 0x55, 0x49, 0x4a, 0x71, 0x73, 0x69, 0x0a, 0x6c, 0x32, 0x44, 0x34, + 0x6b, 0x46, 0x35, 0x30, 0x31, 0x4b, 0x4b, 0x61, 0x55, 0x37, 0x33, 0x79, + 0x71, 0x57, 0x6a, 0x67, 0x6f, 0x6d, 0x37, 0x43, 0x31, 0x32, 0x79, 0x78, + 0x6f, 0x77, 0x2b, 0x65, 0x76, 0x2b, 0x74, 0x6f, 0x35, 0x31, 0x62, 0x79, + 0x72, 0x76, 0x4c, 0x6a, 0x4b, 0x7a, 0x67, 0x36, 0x43, 0x59, 0x47, 0x31, + 0x61, 0x34, 0x58, 0x58, 0x76, 0x69, 0x33, 0x74, 0x50, 0x78, 0x71, 0x33, + 0x0a, 0x73, 0x6d, 0x50, 0x69, 0x39, 0x57, 0x49, 0x73, 0x67, 0x74, 0x52, + 0x71, 0x41, 0x45, 0x46, 0x51, 0x38, 0x54, 0x6d, 0x44, 0x6e, 0x35, 0x58, + 0x70, 0x4e, 0x70, 0x61, 0x59, 0x62, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, + 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x20, 0x4f, + 0x55, 0x3d, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x51, 0x75, 0x6f, + 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, + 0x3d, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x65, 0x64, 0x20, 0x4f, 0x55, 0x3d, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x39, 0x38, 0x35, 0x30, 0x32, 0x36, 0x36, 0x39, + 0x39, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x37, 0x3a, + 0x64, 0x65, 0x3a, 0x33, 0x36, 0x3a, 0x66, 0x65, 0x3a, 0x37, 0x32, 0x3a, + 0x62, 0x37, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x33, 0x3a, 0x30, 0x30, 0x3a, + 0x39, 0x64, 0x3a, 0x66, 0x34, 0x3a, 0x66, 0x30, 0x3a, 0x31, 0x65, 0x3a, + 0x36, 0x63, 0x3a, 0x30, 0x34, 0x3a, 0x32, 0x34, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x65, 0x3a, 0x33, 0x66, 0x3a, 0x34, + 0x30, 0x3a, 0x62, 0x64, 0x3a, 0x35, 0x30, 0x3a, 0x39, 0x33, 0x3a, 0x64, + 0x33, 0x3a, 0x39, 0x62, 0x3a, 0x36, 0x63, 0x3a, 0x36, 0x30, 0x3a, 0x66, + 0x36, 0x3a, 0x64, 0x61, 0x3a, 0x62, 0x63, 0x3a, 0x30, 0x37, 0x3a, 0x36, + 0x32, 0x3a, 0x30, 0x31, 0x3a, 0x30, 0x30, 0x3a, 0x38, 0x39, 0x3a, 0x37, + 0x36, 0x3a, 0x63, 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, + 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x61, 0x34, 0x3a, 0x35, 0x65, 0x3a, 0x64, 0x65, 0x3a, + 0x33, 0x62, 0x3a, 0x62, 0x62, 0x3a, 0x66, 0x30, 0x3a, 0x39, 0x63, 0x3a, + 0x38, 0x61, 0x3a, 0x65, 0x31, 0x3a, 0x35, 0x63, 0x3a, 0x37, 0x32, 0x3a, + 0x65, 0x66, 0x3a, 0x63, 0x30, 0x3a, 0x37, 0x32, 0x3a, 0x36, 0x38, 0x3a, + 0x64, 0x36, 0x3a, 0x39, 0x33, 0x3a, 0x61, 0x32, 0x3a, 0x31, 0x63, 0x3a, + 0x39, 0x39, 0x3a, 0x36, 0x66, 0x3a, 0x64, 0x35, 0x3a, 0x31, 0x65, 0x3a, + 0x36, 0x37, 0x3a, 0x63, 0x61, 0x3a, 0x30, 0x37, 0x3a, 0x39, 0x34, 0x3a, + 0x36, 0x30, 0x3a, 0x66, 0x64, 0x3a, 0x36, 0x64, 0x3a, 0x38, 0x38, 0x3a, + 0x37, 0x33, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, + 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x30, + 0x44, 0x43, 0x43, 0x42, 0x4c, 0x69, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, + 0x67, 0x49, 0x45, 0x4f, 0x72, 0x5a, 0x51, 0x69, 0x7a, 0x41, 0x4e, 0x42, + 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, + 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x2f, 0x4d, 0x51, 0x73, 0x77, 0x43, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x43, 0x0a, + 0x54, 0x54, 0x45, 0x5a, 0x4d, 0x42, 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x68, 0x4d, 0x51, 0x55, 0x58, 0x56, 0x76, 0x56, 0x6d, 0x46, 0x6b, + 0x61, 0x58, 0x4d, 0x67, 0x54, 0x47, 0x6c, 0x74, 0x61, 0x58, 0x52, 0x6c, + 0x5a, 0x44, 0x45, 0x6c, 0x4d, 0x43, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x78, 0x4d, 0x63, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, + 0x5a, 0x58, 0x4a, 0x30, 0x0a, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, + 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, + 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, 0x45, 0x75, 0x4d, 0x43, 0x77, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x6c, 0x55, 0x58, 0x56, + 0x76, 0x56, 0x6d, 0x46, 0x6b, 0x61, 0x58, 0x4d, 0x67, 0x55, 0x6d, 0x39, + 0x76, 0x64, 0x43, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x0a, 0x61, 0x57, + 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, + 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, + 0x41, 0x65, 0x46, 0x77, 0x30, 0x77, 0x4d, 0x54, 0x41, 0x7a, 0x4d, 0x54, + 0x6b, 0x78, 0x4f, 0x44, 0x4d, 0x7a, 0x4d, 0x7a, 0x4e, 0x61, 0x46, 0x77, + 0x30, 0x79, 0x4d, 0x54, 0x41, 0x7a, 0x4d, 0x54, 0x63, 0x78, 0x4f, 0x44, + 0x4d, 0x7a, 0x0a, 0x4d, 0x7a, 0x4e, 0x61, 0x4d, 0x48, 0x38, 0x78, 0x43, + 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, + 0x6b, 0x4a, 0x4e, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x4b, 0x45, 0x78, 0x42, 0x52, 0x64, 0x57, 0x39, 0x57, 0x59, + 0x57, 0x52, 0x70, 0x63, 0x79, 0x42, 0x4d, 0x61, 0x57, 0x31, 0x70, 0x64, + 0x47, 0x56, 0x6b, 0x4d, 0x53, 0x55, 0x77, 0x0a, 0x49, 0x77, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x78, 0x53, 0x62, 0x32, 0x39, 0x30, + 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, + 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, + 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x53, 0x34, 0x77, + 0x4c, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x79, 0x56, 0x52, + 0x0a, 0x64, 0x57, 0x39, 0x57, 0x59, 0x57, 0x52, 0x70, 0x63, 0x79, 0x42, + 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, + 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, + 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, + 0x35, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, + 0x71, 0x68, 0x6b, 0x69, 0x47, 0x0a, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, + 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x76, 0x32, + 0x47, 0x31, 0x6c, 0x56, 0x4f, 0x36, 0x56, 0x2f, 0x7a, 0x36, 0x38, 0x6d, + 0x63, 0x4c, 0x4f, 0x68, 0x72, 0x66, 0x45, 0x59, 0x42, 0x6b, 0x6c, 0x62, + 0x54, 0x52, 0x76, 0x4d, 0x31, 0x36, 0x7a, 0x2f, 0x59, 0x70, 0x0a, 0x6c, + 0x69, 0x34, 0x6b, 0x56, 0x45, 0x41, 0x6b, 0x4f, 0x50, 0x63, 0x61, 0x68, + 0x64, 0x78, 0x59, 0x54, 0x4d, 0x75, 0x6b, 0x4a, 0x30, 0x4b, 0x58, 0x30, + 0x4a, 0x2b, 0x44, 0x69, 0x73, 0x50, 0x6b, 0x42, 0x67, 0x4e, 0x62, 0x41, + 0x4b, 0x56, 0x52, 0x48, 0x6e, 0x41, 0x45, 0x64, 0x4f, 0x4c, 0x42, 0x31, + 0x44, 0x71, 0x72, 0x31, 0x36, 0x30, 0x37, 0x42, 0x78, 0x67, 0x46, 0x6a, + 0x76, 0x32, 0x44, 0x0a, 0x72, 0x4f, 0x70, 0x6d, 0x32, 0x52, 0x67, 0x62, + 0x61, 0x49, 0x72, 0x31, 0x56, 0x78, 0x71, 0x59, 0x75, 0x76, 0x58, 0x74, + 0x64, 0x6a, 0x31, 0x38, 0x32, 0x64, 0x36, 0x55, 0x61, 0x6a, 0x74, 0x4c, + 0x46, 0x38, 0x48, 0x56, 0x6a, 0x37, 0x31, 0x6c, 0x4f, 0x44, 0x71, 0x56, + 0x30, 0x44, 0x31, 0x56, 0x4e, 0x6b, 0x37, 0x66, 0x65, 0x56, 0x63, 0x78, + 0x4b, 0x68, 0x37, 0x59, 0x57, 0x57, 0x56, 0x4a, 0x0a, 0x57, 0x43, 0x43, + 0x59, 0x66, 0x71, 0x74, 0x66, 0x66, 0x70, 0x2f, 0x70, 0x31, 0x6b, 0x33, + 0x73, 0x67, 0x33, 0x53, 0x70, 0x78, 0x32, 0x7a, 0x59, 0x37, 0x69, 0x6c, + 0x4b, 0x68, 0x53, 0x6f, 0x47, 0x46, 0x50, 0x6c, 0x55, 0x35, 0x74, 0x50, + 0x61, 0x5a, 0x51, 0x65, 0x4c, 0x59, 0x7a, 0x63, 0x53, 0x31, 0x39, 0x44, + 0x73, 0x77, 0x33, 0x73, 0x67, 0x51, 0x55, 0x53, 0x6a, 0x37, 0x63, 0x75, + 0x67, 0x0a, 0x46, 0x2b, 0x46, 0x78, 0x5a, 0x63, 0x34, 0x64, 0x5a, 0x6a, + 0x48, 0x33, 0x64, 0x67, 0x45, 0x5a, 0x79, 0x48, 0x30, 0x44, 0x57, 0x4c, + 0x61, 0x56, 0x53, 0x52, 0x32, 0x6d, 0x45, 0x69, 0x62, 0x6f, 0x78, 0x67, + 0x78, 0x32, 0x34, 0x4f, 0x4e, 0x6d, 0x79, 0x2b, 0x70, 0x64, 0x70, 0x69, + 0x62, 0x75, 0x35, 0x63, 0x78, 0x66, 0x76, 0x57, 0x65, 0x6e, 0x41, 0x53, + 0x63, 0x4f, 0x6f, 0x73, 0x70, 0x55, 0x0a, 0x78, 0x62, 0x46, 0x36, 0x6c, + 0x52, 0x31, 0x78, 0x48, 0x6b, 0x6f, 0x70, 0x69, 0x67, 0x50, 0x63, 0x61, + 0x6b, 0x58, 0x42, 0x70, 0x42, 0x6c, 0x65, 0x62, 0x7a, 0x62, 0x4e, 0x77, + 0x36, 0x4b, 0x77, 0x74, 0x2f, 0x35, 0x63, 0x4f, 0x4f, 0x4a, 0x53, 0x76, + 0x50, 0x68, 0x45, 0x51, 0x2b, 0x61, 0x51, 0x75, 0x77, 0x49, 0x44, 0x41, + 0x51, 0x41, 0x42, 0x6f, 0x34, 0x49, 0x43, 0x55, 0x6a, 0x43, 0x43, 0x0a, + 0x41, 0x6b, 0x34, 0x77, 0x50, 0x51, 0x59, 0x49, 0x4b, 0x77, 0x59, 0x42, + 0x42, 0x51, 0x55, 0x48, 0x41, 0x51, 0x45, 0x45, 0x4d, 0x54, 0x41, 0x76, + 0x4d, 0x43, 0x30, 0x47, 0x43, 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, + 0x42, 0x7a, 0x41, 0x42, 0x68, 0x69, 0x46, 0x6f, 0x64, 0x48, 0x52, 0x77, + 0x63, 0x7a, 0x6f, 0x76, 0x4c, 0x32, 0x39, 0x6a, 0x63, 0x33, 0x41, 0x75, + 0x63, 0x58, 0x56, 0x76, 0x0a, 0x64, 0x6d, 0x46, 0x6b, 0x61, 0x58, 0x4e, + 0x76, 0x5a, 0x6d, 0x5a, 0x7a, 0x61, 0x47, 0x39, 0x79, 0x5a, 0x53, 0x35, + 0x6a, 0x62, 0x32, 0x30, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, + 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, + 0x42, 0x2f, 0x7a, 0x43, 0x43, 0x41, 0x52, 0x6f, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x49, 0x41, 0x53, 0x43, 0x41, 0x52, 0x45, 0x77, 0x0a, 0x67, 0x67, + 0x45, 0x4e, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x51, 0x59, 0x4a, 0x4b, 0x77, + 0x59, 0x42, 0x42, 0x41, 0x47, 0x2b, 0x57, 0x41, 0x41, 0x42, 0x4d, 0x49, + 0x48, 0x37, 0x4d, 0x49, 0x48, 0x55, 0x42, 0x67, 0x67, 0x72, 0x42, 0x67, + 0x45, 0x46, 0x42, 0x51, 0x63, 0x43, 0x41, 0x6a, 0x43, 0x42, 0x78, 0x78, + 0x71, 0x42, 0x78, 0x46, 0x4a, 0x6c, 0x62, 0x47, 0x6c, 0x68, 0x62, 0x6d, + 0x4e, 0x6c, 0x0a, 0x49, 0x47, 0x39, 0x75, 0x49, 0x48, 0x52, 0x6f, 0x5a, + 0x53, 0x42, 0x52, 0x64, 0x57, 0x39, 0x57, 0x59, 0x57, 0x52, 0x70, 0x63, + 0x79, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x6c, 0x63, + 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x49, + 0x47, 0x4a, 0x35, 0x49, 0x47, 0x46, 0x75, 0x65, 0x53, 0x42, 0x77, 0x59, + 0x58, 0x4a, 0x30, 0x65, 0x53, 0x42, 0x68, 0x0a, 0x63, 0x33, 0x4e, 0x31, + 0x62, 0x57, 0x56, 0x7a, 0x49, 0x47, 0x46, 0x6a, 0x59, 0x32, 0x56, 0x77, + 0x64, 0x47, 0x46, 0x75, 0x59, 0x32, 0x55, 0x67, 0x62, 0x32, 0x59, 0x67, + 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x52, 0x6f, 0x5a, 0x57, 0x34, 0x67, + 0x59, 0x58, 0x42, 0x77, 0x62, 0x47, 0x6c, 0x6a, 0x59, 0x57, 0x4a, 0x73, + 0x5a, 0x53, 0x42, 0x7a, 0x64, 0x47, 0x46, 0x75, 0x5a, 0x47, 0x46, 0x79, + 0x0a, 0x5a, 0x43, 0x42, 0x30, 0x5a, 0x58, 0x4a, 0x74, 0x63, 0x79, 0x42, + 0x68, 0x62, 0x6d, 0x51, 0x67, 0x59, 0x32, 0x39, 0x75, 0x5a, 0x47, 0x6c, + 0x30, 0x61, 0x57, 0x39, 0x75, 0x63, 0x79, 0x42, 0x76, 0x5a, 0x69, 0x42, + 0x31, 0x63, 0x32, 0x55, 0x73, 0x49, 0x47, 0x4e, 0x6c, 0x63, 0x6e, 0x52, + 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, + 0x67, 0x63, 0x48, 0x4a, 0x68, 0x0a, 0x59, 0x33, 0x52, 0x70, 0x59, 0x32, + 0x56, 0x7a, 0x4c, 0x43, 0x42, 0x68, 0x62, 0x6d, 0x51, 0x67, 0x64, 0x47, + 0x68, 0x6c, 0x49, 0x46, 0x46, 0x31, 0x62, 0x31, 0x5a, 0x68, 0x5a, 0x47, + 0x6c, 0x7a, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, + 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x49, 0x46, 0x42, 0x76, 0x62, 0x47, + 0x6c, 0x6a, 0x65, 0x53, 0x34, 0x77, 0x49, 0x67, 0x59, 0x49, 0x0a, 0x4b, + 0x77, 0x59, 0x42, 0x42, 0x51, 0x55, 0x48, 0x41, 0x67, 0x45, 0x57, 0x46, + 0x6d, 0x68, 0x30, 0x64, 0x48, 0x41, 0x36, 0x4c, 0x79, 0x39, 0x33, 0x64, + 0x33, 0x63, 0x75, 0x63, 0x58, 0x56, 0x76, 0x64, 0x6d, 0x46, 0x6b, 0x61, + 0x58, 0x4d, 0x75, 0x59, 0x6d, 0x30, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x49, 0x74, 0x4c, 0x62, + 0x65, 0x33, 0x54, 0x0a, 0x4b, 0x62, 0x6b, 0x47, 0x47, 0x65, 0x77, 0x35, + 0x4f, 0x61, 0x6e, 0x77, 0x6c, 0x34, 0x52, 0x71, 0x79, 0x2b, 0x2f, 0x66, + 0x4d, 0x49, 0x47, 0x75, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, + 0x67, 0x61, 0x59, 0x77, 0x67, 0x61, 0x4f, 0x41, 0x46, 0x49, 0x74, 0x4c, + 0x62, 0x65, 0x33, 0x54, 0x4b, 0x62, 0x6b, 0x47, 0x47, 0x65, 0x77, 0x35, + 0x4f, 0x61, 0x6e, 0x77, 0x6c, 0x34, 0x52, 0x71, 0x0a, 0x79, 0x2b, 0x2f, + 0x66, 0x6f, 0x59, 0x47, 0x45, 0x70, 0x49, 0x47, 0x42, 0x4d, 0x48, 0x38, + 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, + 0x54, 0x41, 0x6b, 0x4a, 0x4e, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x42, 0x52, 0x64, 0x57, 0x39, + 0x57, 0x59, 0x57, 0x52, 0x70, 0x63, 0x79, 0x42, 0x4d, 0x61, 0x57, 0x31, + 0x70, 0x0a, 0x64, 0x47, 0x56, 0x6b, 0x4d, 0x53, 0x55, 0x77, 0x49, 0x77, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x78, 0x53, 0x62, 0x32, + 0x39, 0x30, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, + 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, + 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x53, + 0x34, 0x77, 0x4c, 0x41, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, 0x44, 0x45, + 0x79, 0x56, 0x52, 0x64, 0x57, 0x39, 0x57, 0x59, 0x57, 0x52, 0x70, 0x63, + 0x79, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x6c, 0x63, + 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, + 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, + 0x58, 0x52, 0x35, 0x67, 0x67, 0x51, 0x36, 0x74, 0x6c, 0x43, 0x4c, 0x0a, + 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, + 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, + 0x69, 0x74, 0x51, 0x55, 0x74, 0x66, 0x37, 0x30, 0x6d, 0x70, 0x4b, 0x6e, + 0x47, 0x64, 0x53, 0x6b, 0x0a, 0x66, 0x6e, 0x49, 0x59, 0x6a, 0x39, 0x6c, + 0x6f, 0x66, 0x46, 0x49, 0x6b, 0x33, 0x57, 0x64, 0x76, 0x4f, 0x58, 0x72, + 0x45, 0x71, 0x6c, 0x34, 0x39, 0x34, 0x6c, 0x69, 0x77, 0x54, 0x58, 0x43, + 0x59, 0x68, 0x47, 0x48, 0x6f, 0x47, 0x2b, 0x4e, 0x70, 0x47, 0x41, 0x37, + 0x4f, 0x2b, 0x30, 0x64, 0x51, 0x6f, 0x45, 0x37, 0x2f, 0x38, 0x43, 0x51, + 0x66, 0x76, 0x62, 0x4c, 0x4f, 0x39, 0x53, 0x66, 0x38, 0x0a, 0x37, 0x43, + 0x39, 0x54, 0x71, 0x6e, 0x4e, 0x37, 0x41, 0x7a, 0x31, 0x30, 0x62, 0x75, + 0x59, 0x57, 0x6e, 0x75, 0x75, 0x6c, 0x4c, 0x73, 0x53, 0x2f, 0x56, 0x69, + 0x64, 0x51, 0x4b, 0x32, 0x4b, 0x36, 0x76, 0x6b, 0x73, 0x63, 0x50, 0x46, + 0x56, 0x63, 0x51, 0x52, 0x30, 0x6b, 0x76, 0x6f, 0x49, 0x67, 0x52, 0x31, + 0x33, 0x56, 0x52, 0x48, 0x35, 0x36, 0x46, 0x6d, 0x6a, 0x66, 0x66, 0x55, + 0x31, 0x52, 0x0a, 0x63, 0x48, 0x68, 0x58, 0x48, 0x54, 0x4d, 0x65, 0x2f, + 0x51, 0x4b, 0x5a, 0x6e, 0x41, 0x7a, 0x4e, 0x43, 0x67, 0x56, 0x50, 0x78, + 0x37, 0x75, 0x4f, 0x70, 0x48, 0x58, 0x36, 0x53, 0x6d, 0x32, 0x78, 0x67, + 0x49, 0x34, 0x4a, 0x56, 0x72, 0x6d, 0x63, 0x47, 0x6d, 0x44, 0x2b, 0x58, + 0x63, 0x48, 0x58, 0x65, 0x74, 0x77, 0x52, 0x65, 0x4e, 0x44, 0x57, 0x58, + 0x63, 0x47, 0x33, 0x31, 0x61, 0x30, 0x79, 0x0a, 0x6d, 0x51, 0x4d, 0x36, + 0x69, 0x73, 0x78, 0x55, 0x4a, 0x54, 0x6b, 0x78, 0x67, 0x58, 0x73, 0x54, + 0x49, 0x6c, 0x47, 0x36, 0x52, 0x6d, 0x79, 0x68, 0x75, 0x35, 0x37, 0x36, + 0x42, 0x47, 0x78, 0x4a, 0x4a, 0x6e, 0x53, 0x50, 0x30, 0x6e, 0x50, 0x72, + 0x7a, 0x44, 0x43, 0x69, 0x35, 0x75, 0x70, 0x5a, 0x49, 0x6f, 0x66, 0x34, + 0x6c, 0x2f, 0x55, 0x4f, 0x2f, 0x65, 0x72, 0x4d, 0x6b, 0x71, 0x51, 0x57, + 0x0a, 0x78, 0x46, 0x49, 0x59, 0x36, 0x69, 0x48, 0x4f, 0x73, 0x66, 0x48, + 0x6d, 0x68, 0x49, 0x48, 0x6c, 0x75, 0x71, 0x6d, 0x47, 0x4b, 0x50, 0x4a, + 0x44, 0x57, 0x6c, 0x30, 0x53, 0x6e, 0x61, 0x77, 0x65, 0x32, 0x61, 0x6a, + 0x6c, 0x43, 0x6d, 0x71, 0x6e, 0x66, 0x36, 0x43, 0x48, 0x4b, 0x63, 0x2f, + 0x79, 0x69, 0x55, 0x33, 0x55, 0x37, 0x4d, 0x58, 0x69, 0x35, 0x6e, 0x72, + 0x51, 0x4e, 0x69, 0x4f, 0x4b, 0x0a, 0x53, 0x6e, 0x51, 0x32, 0x2b, 0x51, + 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x51, 0x75, 0x6f, 0x56, 0x61, + 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, + 0x32, 0x20, 0x4f, 0x3d, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, + 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x51, + 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x32, 0x20, 0x4f, 0x3d, 0x51, 0x75, 0x6f, 0x56, + 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, + 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x51, + 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x32, 0x38, 0x39, 0x0a, 0x23, 0x20, + 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x65, 0x3a, 0x33, 0x39, 0x3a, 0x37, + 0x62, 0x3a, 0x64, 0x64, 0x3a, 0x66, 0x38, 0x3a, 0x62, 0x61, 0x3a, 0x65, + 0x63, 0x3a, 0x38, 0x32, 0x3a, 0x65, 0x39, 0x3a, 0x61, 0x63, 0x3a, 0x36, + 0x32, 0x3a, 0x62, 0x61, 0x3a, 0x30, 0x63, 0x3a, 0x35, 0x34, 0x3a, 0x30, + 0x30, 0x3a, 0x32, 0x62, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x63, 0x61, 0x3a, 0x33, 0x61, 0x3a, 0x66, 0x62, 0x3a, 0x63, 0x66, + 0x3a, 0x31, 0x32, 0x3a, 0x34, 0x30, 0x3a, 0x33, 0x36, 0x3a, 0x34, 0x62, + 0x3a, 0x34, 0x34, 0x3a, 0x62, 0x32, 0x3a, 0x31, 0x36, 0x3a, 0x32, 0x30, + 0x3a, 0x38, 0x38, 0x3a, 0x38, 0x30, 0x3a, 0x34, 0x38, 0x3a, 0x33, 0x39, + 0x3a, 0x31, 0x39, 0x3a, 0x39, 0x33, 0x3a, 0x37, 0x63, 0x3a, 0x66, 0x37, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, + 0x35, 0x3a, 0x61, 0x30, 0x3a, 0x64, 0x64, 0x3a, 0x37, 0x64, 0x3a, 0x64, + 0x37, 0x3a, 0x32, 0x30, 0x3a, 0x61, 0x64, 0x3a, 0x62, 0x37, 0x3a, 0x66, + 0x66, 0x3a, 0x30, 0x35, 0x3a, 0x66, 0x38, 0x3a, 0x33, 0x64, 0x3a, 0x35, + 0x34, 0x3a, 0x32, 0x62, 0x3a, 0x32, 0x30, 0x3a, 0x39, 0x64, 0x3a, 0x63, + 0x37, 0x3a, 0x66, 0x66, 0x3a, 0x34, 0x35, 0x3a, 0x32, 0x38, 0x3a, 0x66, + 0x37, 0x3a, 0x64, 0x36, 0x3a, 0x37, 0x37, 0x3a, 0x62, 0x31, 0x3a, 0x38, + 0x33, 0x3a, 0x38, 0x39, 0x3a, 0x66, 0x65, 0x3a, 0x61, 0x35, 0x3a, 0x65, + 0x35, 0x3a, 0x63, 0x34, 0x3a, 0x39, 0x65, 0x3a, 0x38, 0x36, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x74, 0x7a, 0x43, 0x43, 0x41, + 0x35, 0x2b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x43, 0x42, + 0x51, 0x6b, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x52, + 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x68, 0x4d, 0x43, 0x51, 0x6b, 0x30, 0x78, 0x0a, 0x47, 0x54, 0x41, 0x58, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x45, 0x46, 0x46, 0x31, + 0x62, 0x31, 0x5a, 0x68, 0x5a, 0x47, 0x6c, 0x7a, 0x49, 0x45, 0x78, 0x70, + 0x62, 0x57, 0x6c, 0x30, 0x5a, 0x57, 0x51, 0x78, 0x47, 0x7a, 0x41, 0x5a, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x45, 0x6c, 0x46, 0x31, + 0x62, 0x31, 0x5a, 0x68, 0x5a, 0x47, 0x6c, 0x7a, 0x49, 0x46, 0x4a, 0x76, + 0x0a, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4d, 0x6a, 0x41, + 0x65, 0x46, 0x77, 0x30, 0x77, 0x4e, 0x6a, 0x45, 0x78, 0x4d, 0x6a, 0x51, + 0x78, 0x4f, 0x44, 0x49, 0x33, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, + 0x7a, 0x4d, 0x54, 0x45, 0x78, 0x4d, 0x6a, 0x51, 0x78, 0x4f, 0x44, 0x49, + 0x7a, 0x4d, 0x7a, 0x4e, 0x61, 0x4d, 0x45, 0x55, 0x78, 0x43, 0x7a, 0x41, + 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, + 0x4a, 0x4e, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4b, 0x45, 0x78, 0x42, 0x52, 0x64, 0x57, 0x39, 0x57, 0x59, 0x57, + 0x52, 0x70, 0x63, 0x79, 0x42, 0x4d, 0x61, 0x57, 0x31, 0x70, 0x64, 0x47, + 0x56, 0x6b, 0x4d, 0x52, 0x73, 0x77, 0x47, 0x51, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x44, 0x45, 0x78, 0x4a, 0x52, 0x64, 0x57, 0x39, 0x57, 0x0a, 0x59, + 0x57, 0x52, 0x70, 0x63, 0x79, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, + 0x45, 0x4e, 0x42, 0x49, 0x44, 0x49, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, + 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, + 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, + 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x41, + 0x51, 0x43, 0x61, 0x0a, 0x47, 0x4d, 0x70, 0x4c, 0x6c, 0x41, 0x30, 0x41, + 0x4c, 0x61, 0x38, 0x44, 0x4b, 0x59, 0x72, 0x77, 0x44, 0x34, 0x48, 0x49, + 0x72, 0x6b, 0x77, 0x5a, 0x68, 0x52, 0x30, 0x49, 0x6e, 0x36, 0x73, 0x70, + 0x52, 0x49, 0x58, 0x7a, 0x4c, 0x34, 0x47, 0x74, 0x4d, 0x68, 0x36, 0x51, + 0x52, 0x72, 0x2b, 0x6a, 0x68, 0x69, 0x59, 0x61, 0x48, 0x76, 0x35, 0x2b, + 0x48, 0x42, 0x67, 0x36, 0x58, 0x4a, 0x78, 0x67, 0x0a, 0x46, 0x79, 0x6f, + 0x36, 0x64, 0x49, 0x4d, 0x7a, 0x4d, 0x48, 0x31, 0x68, 0x56, 0x42, 0x48, + 0x4c, 0x37, 0x61, 0x76, 0x67, 0x35, 0x74, 0x4b, 0x69, 0x66, 0x76, 0x56, + 0x72, 0x62, 0x78, 0x69, 0x33, 0x43, 0x67, 0x73, 0x74, 0x2f, 0x65, 0x6b, + 0x2b, 0x37, 0x77, 0x72, 0x47, 0x73, 0x78, 0x44, 0x70, 0x33, 0x4d, 0x4a, + 0x47, 0x46, 0x2f, 0x68, 0x64, 0x2f, 0x61, 0x54, 0x61, 0x2f, 0x35, 0x35, + 0x4a, 0x0a, 0x57, 0x70, 0x7a, 0x6d, 0x4d, 0x2b, 0x59, 0x6b, 0x6c, 0x76, + 0x63, 0x2f, 0x75, 0x6c, 0x73, 0x72, 0x48, 0x48, 0x6f, 0x31, 0x77, 0x74, + 0x5a, 0x6e, 0x2f, 0x71, 0x74, 0x6d, 0x55, 0x49, 0x74, 0x74, 0x4b, 0x47, + 0x41, 0x72, 0x37, 0x39, 0x64, 0x67, 0x77, 0x38, 0x65, 0x54, 0x76, 0x49, + 0x30, 0x32, 0x6b, 0x66, 0x4e, 0x2f, 0x2b, 0x4e, 0x73, 0x52, 0x45, 0x38, + 0x53, 0x63, 0x64, 0x33, 0x62, 0x42, 0x0a, 0x72, 0x72, 0x63, 0x43, 0x61, + 0x6f, 0x46, 0x36, 0x71, 0x55, 0x57, 0x44, 0x34, 0x67, 0x58, 0x6d, 0x75, + 0x56, 0x62, 0x42, 0x6c, 0x44, 0x65, 0x50, 0x53, 0x48, 0x46, 0x6a, 0x49, + 0x75, 0x77, 0x58, 0x5a, 0x51, 0x65, 0x56, 0x69, 0x6b, 0x76, 0x66, 0x6a, + 0x38, 0x5a, 0x61, 0x43, 0x75, 0x57, 0x77, 0x34, 0x31, 0x39, 0x65, 0x61, + 0x78, 0x47, 0x72, 0x44, 0x50, 0x6d, 0x46, 0x36, 0x30, 0x54, 0x70, 0x0a, + 0x2b, 0x41, 0x52, 0x7a, 0x38, 0x75, 0x6e, 0x2b, 0x58, 0x4a, 0x69, 0x4d, + 0x39, 0x58, 0x4f, 0x76, 0x61, 0x37, 0x52, 0x2b, 0x7a, 0x64, 0x52, 0x63, + 0x41, 0x69, 0x74, 0x4d, 0x4f, 0x65, 0x47, 0x79, 0x6c, 0x5a, 0x55, 0x74, + 0x51, 0x6f, 0x66, 0x58, 0x31, 0x62, 0x4f, 0x51, 0x51, 0x37, 0x64, 0x73, + 0x45, 0x2f, 0x48, 0x65, 0x33, 0x66, 0x62, 0x45, 0x2b, 0x49, 0x6b, 0x2f, + 0x30, 0x58, 0x58, 0x31, 0x0a, 0x6b, 0x73, 0x4f, 0x52, 0x31, 0x59, 0x71, + 0x49, 0x30, 0x4a, 0x44, 0x73, 0x33, 0x47, 0x33, 0x65, 0x69, 0x63, 0x4a, + 0x6c, 0x63, 0x5a, 0x61, 0x4c, 0x44, 0x51, 0x50, 0x39, 0x6e, 0x4c, 0x39, + 0x62, 0x46, 0x71, 0x79, 0x53, 0x32, 0x2b, 0x72, 0x2b, 0x65, 0x58, 0x79, + 0x74, 0x36, 0x36, 0x2f, 0x33, 0x46, 0x73, 0x76, 0x62, 0x7a, 0x53, 0x55, + 0x72, 0x35, 0x52, 0x2f, 0x37, 0x6d, 0x70, 0x2f, 0x69, 0x0a, 0x55, 0x63, + 0x77, 0x36, 0x55, 0x77, 0x78, 0x49, 0x35, 0x67, 0x36, 0x39, 0x79, 0x62, + 0x52, 0x32, 0x42, 0x6c, 0x4c, 0x6d, 0x45, 0x52, 0x4f, 0x46, 0x63, 0x6d, + 0x4d, 0x44, 0x42, 0x4f, 0x41, 0x45, 0x4e, 0x69, 0x73, 0x67, 0x47, 0x51, + 0x4c, 0x6f, 0x64, 0x4b, 0x63, 0x66, 0x74, 0x73, 0x6c, 0x57, 0x5a, 0x76, + 0x42, 0x31, 0x4a, 0x64, 0x78, 0x6e, 0x77, 0x51, 0x35, 0x68, 0x59, 0x49, + 0x69, 0x7a, 0x0a, 0x50, 0x74, 0x47, 0x6f, 0x2f, 0x4b, 0x50, 0x61, 0x48, + 0x62, 0x44, 0x52, 0x73, 0x53, 0x4e, 0x55, 0x33, 0x30, 0x52, 0x32, 0x62, + 0x65, 0x31, 0x42, 0x32, 0x4d, 0x47, 0x79, 0x49, 0x72, 0x5a, 0x54, 0x48, + 0x4e, 0x38, 0x31, 0x48, 0x64, 0x79, 0x68, 0x64, 0x79, 0x6f, 0x78, 0x35, + 0x43, 0x33, 0x31, 0x35, 0x65, 0x58, 0x62, 0x79, 0x4f, 0x44, 0x2f, 0x35, + 0x59, 0x44, 0x58, 0x43, 0x32, 0x4f, 0x67, 0x0a, 0x2f, 0x7a, 0x4f, 0x68, + 0x44, 0x37, 0x6f, 0x73, 0x46, 0x52, 0x58, 0x71, 0x6c, 0x37, 0x50, 0x53, + 0x6f, 0x72, 0x57, 0x2b, 0x38, 0x6f, 0x79, 0x57, 0x48, 0x68, 0x71, 0x50, + 0x48, 0x57, 0x79, 0x6b, 0x59, 0x54, 0x65, 0x35, 0x68, 0x6e, 0x4d, 0x7a, + 0x31, 0x35, 0x65, 0x57, 0x6e, 0x69, 0x4e, 0x39, 0x67, 0x71, 0x52, 0x4d, + 0x67, 0x65, 0x4b, 0x68, 0x30, 0x62, 0x70, 0x6e, 0x58, 0x35, 0x55, 0x48, + 0x0a, 0x6f, 0x79, 0x63, 0x52, 0x37, 0x68, 0x59, 0x51, 0x65, 0x37, 0x78, + 0x46, 0x53, 0x6b, 0x79, 0x79, 0x42, 0x4e, 0x4b, 0x72, 0x37, 0x39, 0x58, + 0x39, 0x44, 0x46, 0x48, 0x4f, 0x55, 0x47, 0x6f, 0x49, 0x4d, 0x66, 0x6d, + 0x52, 0x32, 0x67, 0x79, 0x50, 0x5a, 0x46, 0x77, 0x44, 0x77, 0x7a, 0x71, + 0x4c, 0x49, 0x44, 0x39, 0x75, 0x6a, 0x57, 0x63, 0x39, 0x4f, 0x74, 0x62, + 0x2b, 0x66, 0x56, 0x75, 0x49, 0x0a, 0x79, 0x56, 0x37, 0x37, 0x7a, 0x47, + 0x48, 0x63, 0x69, 0x7a, 0x4e, 0x33, 0x30, 0x30, 0x51, 0x79, 0x4e, 0x51, + 0x6c, 0x69, 0x42, 0x4a, 0x49, 0x57, 0x45, 0x4e, 0x69, 0x65, 0x4a, 0x30, + 0x66, 0x37, 0x4f, 0x79, 0x48, 0x6a, 0x2b, 0x4f, 0x73, 0x64, 0x57, 0x77, + 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x34, 0x47, 0x77, 0x4d, 0x49, + 0x47, 0x74, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x0a, 0x45, + 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, + 0x66, 0x38, 0x77, 0x43, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x42, + 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x30, 0x47, 0x41, + 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x51, 0x61, 0x68, + 0x47, 0x4b, 0x38, 0x53, 0x45, 0x77, 0x7a, 0x4a, 0x51, 0x54, 0x55, 0x37, + 0x74, 0x44, 0x32, 0x0a, 0x41, 0x38, 0x51, 0x5a, 0x52, 0x74, 0x47, 0x55, + 0x61, 0x7a, 0x42, 0x75, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, + 0x5a, 0x7a, 0x42, 0x6c, 0x67, 0x42, 0x51, 0x61, 0x68, 0x47, 0x4b, 0x38, + 0x53, 0x45, 0x77, 0x7a, 0x4a, 0x51, 0x54, 0x55, 0x37, 0x74, 0x44, 0x32, + 0x41, 0x38, 0x51, 0x5a, 0x52, 0x74, 0x47, 0x55, 0x61, 0x36, 0x46, 0x4a, + 0x70, 0x45, 0x63, 0x77, 0x52, 0x54, 0x45, 0x4c, 0x0a, 0x4d, 0x41, 0x6b, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x51, 0x6b, 0x30, + 0x78, 0x47, 0x54, 0x41, 0x58, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, + 0x54, 0x45, 0x46, 0x46, 0x31, 0x62, 0x31, 0x5a, 0x68, 0x5a, 0x47, 0x6c, + 0x7a, 0x49, 0x45, 0x78, 0x70, 0x62, 0x57, 0x6c, 0x30, 0x5a, 0x57, 0x51, + 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, + 0x54, 0x0a, 0x45, 0x6c, 0x46, 0x31, 0x62, 0x31, 0x5a, 0x68, 0x5a, 0x47, + 0x6c, 0x7a, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, + 0x45, 0x67, 0x4d, 0x6f, 0x49, 0x43, 0x42, 0x51, 0x6b, 0x77, 0x44, 0x51, + 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, + 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x42, 0x41, 0x44, + 0x34, 0x4b, 0x46, 0x6b, 0x32, 0x66, 0x0a, 0x42, 0x6c, 0x75, 0x6f, 0x72, + 0x6e, 0x46, 0x64, 0x4c, 0x77, 0x55, 0x76, 0x5a, 0x2b, 0x59, 0x54, 0x52, + 0x59, 0x50, 0x45, 0x4e, 0x76, 0x62, 0x7a, 0x77, 0x43, 0x59, 0x4d, 0x44, + 0x62, 0x56, 0x48, 0x5a, 0x46, 0x33, 0x34, 0x74, 0x48, 0x4c, 0x4a, 0x52, + 0x71, 0x55, 0x44, 0x47, 0x43, 0x64, 0x56, 0x69, 0x58, 0x68, 0x39, 0x64, + 0x75, 0x71, 0x57, 0x4e, 0x49, 0x41, 0x58, 0x49, 0x4e, 0x7a, 0x6e, 0x0a, + 0x67, 0x2f, 0x69, 0x4e, 0x2f, 0x41, 0x65, 0x34, 0x32, 0x6c, 0x39, 0x4e, + 0x4c, 0x6d, 0x65, 0x79, 0x68, 0x50, 0x33, 0x5a, 0x52, 0x50, 0x78, 0x33, + 0x55, 0x49, 0x48, 0x6d, 0x66, 0x4c, 0x54, 0x4a, 0x44, 0x51, 0x74, 0x79, + 0x55, 0x2f, 0x68, 0x32, 0x42, 0x77, 0x64, 0x42, 0x52, 0x35, 0x59, 0x4d, + 0x2b, 0x2b, 0x43, 0x43, 0x4a, 0x70, 0x4e, 0x56, 0x6a, 0x50, 0x34, 0x69, + 0x48, 0x32, 0x42, 0x6c, 0x0a, 0x66, 0x46, 0x2f, 0x6e, 0x4a, 0x72, 0x50, + 0x33, 0x4d, 0x70, 0x43, 0x59, 0x55, 0x4e, 0x51, 0x33, 0x63, 0x56, 0x58, + 0x32, 0x6b, 0x69, 0x46, 0x34, 0x39, 0x35, 0x56, 0x35, 0x2b, 0x76, 0x67, + 0x74, 0x4a, 0x6f, 0x64, 0x6d, 0x56, 0x6a, 0x42, 0x33, 0x70, 0x6a, 0x64, + 0x34, 0x4d, 0x31, 0x49, 0x51, 0x57, 0x4b, 0x34, 0x2f, 0x59, 0x59, 0x37, + 0x79, 0x61, 0x72, 0x48, 0x76, 0x47, 0x48, 0x35, 0x4b, 0x0a, 0x57, 0x57, + 0x50, 0x4b, 0x6a, 0x61, 0x4a, 0x57, 0x31, 0x61, 0x63, 0x76, 0x76, 0x46, + 0x59, 0x66, 0x7a, 0x7a, 0x6e, 0x42, 0x34, 0x76, 0x73, 0x4b, 0x71, 0x42, + 0x55, 0x73, 0x66, 0x55, 0x31, 0x36, 0x59, 0x38, 0x5a, 0x73, 0x6c, 0x30, + 0x51, 0x38, 0x30, 0x6d, 0x2f, 0x44, 0x53, 0x68, 0x63, 0x4b, 0x2b, 0x4a, + 0x44, 0x53, 0x56, 0x36, 0x49, 0x5a, 0x55, 0x61, 0x55, 0x74, 0x6c, 0x30, + 0x48, 0x61, 0x0a, 0x42, 0x30, 0x2b, 0x70, 0x55, 0x4e, 0x71, 0x51, 0x6a, + 0x5a, 0x52, 0x47, 0x34, 0x54, 0x37, 0x77, 0x6c, 0x50, 0x30, 0x51, 0x41, + 0x44, 0x6a, 0x31, 0x4f, 0x2b, 0x68, 0x41, 0x34, 0x62, 0x52, 0x75, 0x56, + 0x68, 0x6f, 0x67, 0x7a, 0x47, 0x39, 0x59, 0x6a, 0x65, 0x30, 0x75, 0x52, + 0x59, 0x2f, 0x57, 0x36, 0x5a, 0x4d, 0x2f, 0x35, 0x37, 0x45, 0x73, 0x33, + 0x7a, 0x72, 0x57, 0x49, 0x6f, 0x7a, 0x63, 0x0a, 0x68, 0x4c, 0x73, 0x69, + 0x62, 0x39, 0x44, 0x34, 0x35, 0x4d, 0x59, 0x35, 0x36, 0x51, 0x53, 0x49, + 0x50, 0x4d, 0x4f, 0x36, 0x36, 0x31, 0x56, 0x36, 0x62, 0x59, 0x43, 0x5a, + 0x4a, 0x50, 0x56, 0x73, 0x41, 0x66, 0x76, 0x34, 0x6c, 0x37, 0x43, 0x55, + 0x57, 0x2b, 0x76, 0x39, 0x30, 0x6d, 0x2f, 0x78, 0x64, 0x32, 0x67, 0x4e, + 0x4e, 0x57, 0x51, 0x6a, 0x72, 0x4c, 0x68, 0x56, 0x6f, 0x51, 0x50, 0x52, + 0x0a, 0x54, 0x55, 0x49, 0x5a, 0x33, 0x50, 0x68, 0x31, 0x57, 0x56, 0x61, + 0x6a, 0x2b, 0x61, 0x68, 0x4a, 0x65, 0x66, 0x69, 0x76, 0x44, 0x72, 0x6b, + 0x52, 0x6f, 0x48, 0x79, 0x33, 0x61, 0x75, 0x30, 0x30, 0x30, 0x4c, 0x59, + 0x6d, 0x59, 0x6a, 0x67, 0x61, 0x68, 0x77, 0x7a, 0x34, 0x36, 0x50, 0x30, + 0x75, 0x30, 0x35, 0x42, 0x2f, 0x42, 0x35, 0x45, 0x71, 0x48, 0x64, 0x5a, + 0x2b, 0x58, 0x49, 0x57, 0x44, 0x0a, 0x6d, 0x62, 0x41, 0x34, 0x43, 0x44, + 0x2f, 0x70, 0x58, 0x76, 0x6b, 0x31, 0x42, 0x2b, 0x54, 0x4a, 0x59, 0x6d, + 0x35, 0x58, 0x66, 0x36, 0x64, 0x51, 0x6c, 0x66, 0x65, 0x36, 0x79, 0x4a, + 0x76, 0x6d, 0x6a, 0x71, 0x49, 0x42, 0x78, 0x64, 0x5a, 0x6d, 0x76, 0x33, + 0x6c, 0x68, 0x38, 0x7a, 0x77, 0x63, 0x34, 0x62, 0x6d, 0x43, 0x58, 0x46, + 0x32, 0x67, 0x77, 0x2b, 0x6e, 0x59, 0x53, 0x4c, 0x30, 0x5a, 0x0a, 0x6f, + 0x68, 0x45, 0x55, 0x47, 0x57, 0x36, 0x79, 0x68, 0x68, 0x74, 0x6f, 0x50, + 0x6b, 0x67, 0x33, 0x47, 0x6f, 0x69, 0x33, 0x58, 0x5a, 0x5a, 0x65, 0x6e, + 0x4d, 0x66, 0x76, 0x4a, 0x32, 0x49, 0x49, 0x34, 0x70, 0x45, 0x5a, 0x58, + 0x4e, 0x4c, 0x78, 0x49, 0x64, 0x32, 0x36, 0x46, 0x30, 0x4b, 0x43, 0x6c, + 0x33, 0x47, 0x42, 0x55, 0x7a, 0x47, 0x70, 0x6e, 0x2f, 0x5a, 0x39, 0x59, + 0x72, 0x39, 0x79, 0x0a, 0x34, 0x61, 0x4f, 0x54, 0x48, 0x63, 0x79, 0x4b, + 0x4a, 0x6c, 0x6f, 0x4a, 0x4f, 0x4e, 0x44, 0x4f, 0x31, 0x77, 0x32, 0x41, + 0x46, 0x72, 0x52, 0x34, 0x70, 0x54, 0x71, 0x48, 0x54, 0x49, 0x32, 0x4b, + 0x70, 0x64, 0x56, 0x47, 0x6c, 0x2f, 0x49, 0x73, 0x45, 0x4c, 0x6d, 0x38, + 0x56, 0x43, 0x4c, 0x41, 0x41, 0x56, 0x42, 0x70, 0x51, 0x35, 0x37, 0x30, + 0x73, 0x75, 0x39, 0x74, 0x2b, 0x4f, 0x7a, 0x61, 0x0a, 0x38, 0x65, 0x4f, + 0x78, 0x37, 0x39, 0x2b, 0x52, 0x6a, 0x31, 0x51, 0x71, 0x43, 0x79, 0x58, + 0x42, 0x4a, 0x68, 0x6e, 0x45, 0x55, 0x68, 0x41, 0x46, 0x5a, 0x64, 0x57, + 0x43, 0x45, 0x4f, 0x72, 0x43, 0x4d, 0x63, 0x30, 0x75, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, 0x20, 0x4f, 0x3d, 0x51, + 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, + 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, + 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, + 0x20, 0x4f, 0x3d, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, + 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, + 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, + 0x31, 0x34, 0x37, 0x38, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x33, 0x31, 0x3a, 0x38, 0x35, 0x3a, 0x33, 0x63, 0x3a, 0x36, 0x32, 0x3a, + 0x39, 0x34, 0x3a, 0x39, 0x37, 0x3a, 0x36, 0x33, 0x3a, 0x62, 0x39, 0x3a, + 0x61, 0x61, 0x3a, 0x66, 0x64, 0x3a, 0x38, 0x39, 0x3a, 0x34, 0x65, 0x3a, + 0x61, 0x66, 0x3a, 0x36, 0x66, 0x3a, 0x65, 0x30, 0x3a, 0x63, 0x66, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x66, 0x3a, 0x34, + 0x39, 0x3a, 0x31, 0x34, 0x3a, 0x66, 0x37, 0x3a, 0x64, 0x38, 0x3a, 0x37, + 0x34, 0x3a, 0x39, 0x35, 0x3a, 0x31, 0x64, 0x3a, 0x64, 0x64, 0x3a, 0x61, + 0x65, 0x3a, 0x30, 0x32, 0x3a, 0x63, 0x30, 0x3a, 0x62, 0x65, 0x3a, 0x66, + 0x64, 0x3a, 0x33, 0x61, 0x3a, 0x32, 0x64, 0x3a, 0x38, 0x32, 0x3a, 0x37, + 0x35, 0x3a, 0x35, 0x31, 0x3a, 0x38, 0x35, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x38, 0x3a, 0x66, 0x31, 0x3a, + 0x66, 0x63, 0x3a, 0x37, 0x66, 0x3a, 0x32, 0x30, 0x3a, 0x35, 0x64, 0x3a, + 0x66, 0x38, 0x3a, 0x61, 0x64, 0x3a, 0x64, 0x64, 0x3a, 0x65, 0x62, 0x3a, + 0x37, 0x66, 0x3a, 0x65, 0x30, 0x3a, 0x30, 0x37, 0x3a, 0x64, 0x64, 0x3a, + 0x35, 0x37, 0x3a, 0x65, 0x33, 0x3a, 0x61, 0x66, 0x3a, 0x33, 0x37, 0x3a, + 0x35, 0x61, 0x3a, 0x39, 0x63, 0x3a, 0x34, 0x64, 0x3a, 0x38, 0x64, 0x3a, + 0x37, 0x33, 0x3a, 0x35, 0x34, 0x3a, 0x36, 0x62, 0x3a, 0x66, 0x34, 0x3a, + 0x66, 0x31, 0x3a, 0x66, 0x65, 0x3a, 0x64, 0x31, 0x3a, 0x65, 0x31, 0x3a, + 0x38, 0x64, 0x3a, 0x33, 0x35, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, + 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, + 0x49, 0x47, 0x6e, 0x54, 0x43, 0x43, 0x42, 0x49, 0x57, 0x67, 0x41, 0x77, + 0x49, 0x42, 0x41, 0x67, 0x49, 0x43, 0x42, 0x63, 0x59, 0x77, 0x44, 0x51, + 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, + 0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x52, 0x54, 0x45, 0x4c, 0x4d, 0x41, + 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x51, 0x6b, + 0x30, 0x78, 0x0a, 0x47, 0x54, 0x41, 0x58, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x6f, 0x54, 0x45, 0x46, 0x46, 0x31, 0x62, 0x31, 0x5a, 0x68, 0x5a, + 0x47, 0x6c, 0x7a, 0x49, 0x45, 0x78, 0x70, 0x62, 0x57, 0x6c, 0x30, 0x5a, + 0x57, 0x51, 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x4d, 0x54, 0x45, 0x6c, 0x46, 0x31, 0x62, 0x31, 0x5a, 0x68, 0x5a, + 0x47, 0x6c, 0x7a, 0x49, 0x46, 0x4a, 0x76, 0x0a, 0x62, 0x33, 0x51, 0x67, + 0x51, 0x30, 0x45, 0x67, 0x4d, 0x7a, 0x41, 0x65, 0x46, 0x77, 0x30, 0x77, + 0x4e, 0x6a, 0x45, 0x78, 0x4d, 0x6a, 0x51, 0x78, 0x4f, 0x54, 0x45, 0x78, + 0x4d, 0x6a, 0x4e, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4d, 0x54, 0x45, 0x78, + 0x4d, 0x6a, 0x51, 0x78, 0x4f, 0x54, 0x41, 0x32, 0x4e, 0x44, 0x52, 0x61, + 0x4d, 0x45, 0x55, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, + 0x0a, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x4a, 0x4e, 0x4d, 0x52, 0x6b, + 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x42, + 0x52, 0x64, 0x57, 0x39, 0x57, 0x59, 0x57, 0x52, 0x70, 0x63, 0x79, 0x42, + 0x4d, 0x61, 0x57, 0x31, 0x70, 0x64, 0x47, 0x56, 0x6b, 0x4d, 0x52, 0x73, + 0x77, 0x47, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x4a, + 0x52, 0x64, 0x57, 0x39, 0x57, 0x0a, 0x59, 0x57, 0x52, 0x70, 0x63, 0x79, + 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x44, + 0x4d, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, + 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, + 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, + 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51, 0x44, 0x4d, 0x0a, 0x56, + 0x30, 0x49, 0x57, 0x56, 0x4a, 0x7a, 0x6d, 0x6d, 0x4e, 0x50, 0x54, 0x54, + 0x65, 0x37, 0x2b, 0x37, 0x63, 0x65, 0x66, 0x51, 0x7a, 0x6c, 0x4b, 0x5a, + 0x62, 0x50, 0x6f, 0x46, 0x6f, 0x67, 0x30, 0x32, 0x77, 0x31, 0x5a, 0x6b, + 0x58, 0x54, 0x50, 0x6b, 0x72, 0x67, 0x45, 0x51, 0x4b, 0x30, 0x43, 0x53, + 0x7a, 0x47, 0x72, 0x76, 0x49, 0x32, 0x52, 0x61, 0x4e, 0x67, 0x67, 0x44, + 0x68, 0x6f, 0x42, 0x0a, 0x34, 0x68, 0x70, 0x37, 0x54, 0x68, 0x64, 0x64, + 0x34, 0x6f, 0x71, 0x33, 0x50, 0x35, 0x6b, 0x61, 0x7a, 0x65, 0x74, 0x68, + 0x71, 0x38, 0x4a, 0x6c, 0x70, 0x68, 0x2b, 0x33, 0x74, 0x37, 0x32, 0x33, + 0x6a, 0x2f, 0x7a, 0x39, 0x63, 0x49, 0x38, 0x4c, 0x6f, 0x47, 0x65, 0x2b, + 0x41, 0x61, 0x4a, 0x5a, 0x7a, 0x33, 0x48, 0x6d, 0x44, 0x79, 0x6c, 0x32, + 0x2f, 0x37, 0x46, 0x57, 0x65, 0x55, 0x55, 0x72, 0x0a, 0x48, 0x35, 0x35, + 0x36, 0x56, 0x4f, 0x69, 0x6a, 0x4b, 0x54, 0x56, 0x6f, 0x70, 0x41, 0x46, + 0x50, 0x44, 0x36, 0x51, 0x75, 0x4e, 0x2b, 0x38, 0x62, 0x76, 0x2b, 0x4f, + 0x50, 0x45, 0x4b, 0x68, 0x79, 0x71, 0x31, 0x68, 0x58, 0x35, 0x31, 0x53, + 0x47, 0x79, 0x4d, 0x6e, 0x7a, 0x57, 0x39, 0x6f, 0x73, 0x32, 0x6c, 0x32, + 0x4f, 0x62, 0x6a, 0x79, 0x6a, 0x50, 0x74, 0x72, 0x37, 0x67, 0x75, 0x58, + 0x64, 0x0a, 0x38, 0x6c, 0x79, 0x79, 0x42, 0x54, 0x4e, 0x76, 0x69, 0x6a, + 0x62, 0x4f, 0x30, 0x42, 0x4e, 0x4f, 0x2f, 0x37, 0x39, 0x4b, 0x44, 0x44, + 0x52, 0x4d, 0x70, 0x73, 0x4d, 0x68, 0x76, 0x56, 0x41, 0x45, 0x56, 0x65, + 0x75, 0x78, 0x75, 0x35, 0x33, 0x37, 0x52, 0x52, 0x35, 0x6b, 0x46, 0x64, + 0x35, 0x56, 0x41, 0x59, 0x77, 0x43, 0x64, 0x72, 0x58, 0x4c, 0x6f, 0x54, + 0x39, 0x43, 0x61, 0x62, 0x77, 0x76, 0x0a, 0x76, 0x57, 0x68, 0x44, 0x46, + 0x6c, 0x61, 0x4a, 0x4b, 0x6a, 0x64, 0x68, 0x6b, 0x66, 0x32, 0x6d, 0x72, + 0x6b, 0x37, 0x41, 0x79, 0x78, 0x52, 0x6c, 0x6c, 0x44, 0x64, 0x4c, 0x6b, + 0x67, 0x62, 0x76, 0x42, 0x4e, 0x44, 0x49, 0x6e, 0x49, 0x6a, 0x62, 0x43, + 0x33, 0x75, 0x42, 0x72, 0x37, 0x45, 0x39, 0x4b, 0x73, 0x52, 0x6c, 0x4f, + 0x6e, 0x69, 0x32, 0x37, 0x74, 0x79, 0x41, 0x73, 0x64, 0x4c, 0x54, 0x0a, + 0x6d, 0x5a, 0x77, 0x36, 0x37, 0x6d, 0x74, 0x61, 0x61, 0x37, 0x4f, 0x4e, + 0x74, 0x39, 0x58, 0x4f, 0x6e, 0x4d, 0x4b, 0x2b, 0x70, 0x55, 0x73, 0x76, + 0x46, 0x72, 0x47, 0x65, 0x61, 0x44, 0x73, 0x47, 0x62, 0x36, 0x35, 0x39, + 0x6e, 0x2f, 0x6a, 0x65, 0x37, 0x4d, 0x77, 0x70, 0x70, 0x35, 0x69, 0x6a, + 0x4a, 0x55, 0x4d, 0x76, 0x37, 0x2f, 0x46, 0x66, 0x4a, 0x75, 0x47, 0x49, + 0x54, 0x66, 0x68, 0x65, 0x0a, 0x62, 0x74, 0x66, 0x5a, 0x46, 0x47, 0x34, + 0x5a, 0x4d, 0x32, 0x6d, 0x6e, 0x4f, 0x34, 0x53, 0x4a, 0x6b, 0x38, 0x52, + 0x54, 0x56, 0x52, 0x4f, 0x68, 0x55, 0x58, 0x68, 0x41, 0x2b, 0x4c, 0x6a, + 0x4a, 0x6f, 0x75, 0x35, 0x37, 0x75, 0x6c, 0x4a, 0x43, 0x67, 0x35, 0x34, + 0x55, 0x37, 0x51, 0x56, 0x53, 0x57, 0x6c, 0x6c, 0x57, 0x70, 0x35, 0x66, + 0x38, 0x6e, 0x54, 0x38, 0x4b, 0x4b, 0x64, 0x6a, 0x63, 0x0a, 0x54, 0x35, + 0x45, 0x4f, 0x45, 0x37, 0x7a, 0x65, 0x6c, 0x61, 0x54, 0x66, 0x69, 0x35, + 0x6d, 0x2b, 0x72, 0x4a, 0x73, 0x7a, 0x69, 0x4f, 0x2b, 0x31, 0x67, 0x61, + 0x38, 0x62, 0x78, 0x69, 0x4a, 0x54, 0x79, 0x50, 0x62, 0x48, 0x37, 0x70, + 0x63, 0x55, 0x73, 0x4d, 0x56, 0x38, 0x65, 0x46, 0x4c, 0x49, 0x38, 0x4d, + 0x35, 0x75, 0x64, 0x32, 0x43, 0x45, 0x70, 0x75, 0x6b, 0x71, 0x64, 0x69, + 0x44, 0x74, 0x0a, 0x57, 0x41, 0x45, 0x58, 0x4d, 0x4a, 0x50, 0x70, 0x47, + 0x6f, 0x76, 0x67, 0x63, 0x32, 0x50, 0x5a, 0x61, 0x70, 0x4b, 0x55, 0x53, + 0x55, 0x36, 0x30, 0x72, 0x55, 0x71, 0x46, 0x78, 0x4b, 0x4d, 0x69, 0x4d, + 0x50, 0x77, 0x4a, 0x37, 0x57, 0x67, 0x69, 0x63, 0x36, 0x61, 0x49, 0x44, + 0x46, 0x55, 0x68, 0x57, 0x4d, 0x58, 0x68, 0x4f, 0x70, 0x38, 0x71, 0x33, + 0x63, 0x72, 0x68, 0x6b, 0x4f, 0x44, 0x5a, 0x0a, 0x63, 0x36, 0x74, 0x73, + 0x67, 0x4c, 0x6a, 0x6f, 0x43, 0x32, 0x53, 0x54, 0x6f, 0x4a, 0x79, 0x4d, + 0x47, 0x66, 0x2b, 0x7a, 0x30, 0x67, 0x7a, 0x73, 0x6b, 0x53, 0x61, 0x48, + 0x69, 0x72, 0x4f, 0x69, 0x34, 0x58, 0x43, 0x50, 0x4c, 0x41, 0x72, 0x6c, + 0x7a, 0x57, 0x31, 0x6f, 0x55, 0x65, 0x76, 0x61, 0x50, 0x77, 0x56, 0x2f, + 0x69, 0x7a, 0x4c, 0x6d, 0x45, 0x31, 0x78, 0x72, 0x2f, 0x6c, 0x39, 0x41, + 0x0a, 0x34, 0x69, 0x4c, 0x49, 0x74, 0x4c, 0x52, 0x6b, 0x54, 0x39, 0x61, + 0x36, 0x66, 0x55, 0x67, 0x2b, 0x71, 0x47, 0x6b, 0x4d, 0x31, 0x37, 0x75, + 0x47, 0x63, 0x63, 0x6c, 0x7a, 0x75, 0x44, 0x38, 0x37, 0x6e, 0x53, 0x56, + 0x4c, 0x32, 0x76, 0x39, 0x41, 0x36, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, + 0x42, 0x6f, 0x34, 0x49, 0x42, 0x6c, 0x54, 0x43, 0x43, 0x41, 0x5a, 0x45, + 0x77, 0x44, 0x77, 0x59, 0x44, 0x0a, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, + 0x43, 0x42, 0x34, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x67, 0x42, 0x49, + 0x48, 0x5a, 0x4d, 0x49, 0x48, 0x57, 0x4d, 0x49, 0x48, 0x54, 0x42, 0x67, + 0x6b, 0x72, 0x42, 0x67, 0x45, 0x45, 0x41, 0x62, 0x35, 0x59, 0x41, 0x41, + 0x4d, 0x77, 0x67, 0x63, 0x55, 0x77, 0x67, 0x5a, 0x4d, 0x47, 0x0a, 0x43, + 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x77, 0x49, 0x43, 0x4d, + 0x49, 0x47, 0x47, 0x47, 0x6f, 0x47, 0x44, 0x51, 0x57, 0x35, 0x35, 0x49, + 0x48, 0x56, 0x7a, 0x5a, 0x53, 0x42, 0x76, 0x5a, 0x69, 0x42, 0x30, 0x61, + 0x47, 0x6c, 0x7a, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, + 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x49, 0x47, 0x4e, 0x76, 0x62, + 0x6e, 0x4e, 0x30, 0x0a, 0x61, 0x58, 0x52, 0x31, 0x64, 0x47, 0x56, 0x7a, + 0x49, 0x47, 0x46, 0x6a, 0x59, 0x32, 0x56, 0x77, 0x64, 0x47, 0x46, 0x75, + 0x59, 0x32, 0x55, 0x67, 0x62, 0x32, 0x59, 0x67, 0x64, 0x47, 0x68, 0x6c, + 0x49, 0x46, 0x46, 0x31, 0x62, 0x31, 0x5a, 0x68, 0x5a, 0x47, 0x6c, 0x7a, + 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, + 0x4d, 0x79, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x0a, 0x61, 0x57, 0x5a, + 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, 0x53, 0x42, 0x51, 0x62, 0x32, 0x78, + 0x70, 0x59, 0x33, 0x6b, 0x67, 0x4c, 0x79, 0x42, 0x44, 0x5a, 0x58, 0x4a, + 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, + 0x75, 0x49, 0x46, 0x42, 0x79, 0x59, 0x57, 0x4e, 0x30, 0x61, 0x57, 0x4e, + 0x6c, 0x49, 0x46, 0x4e, 0x30, 0x59, 0x58, 0x52, 0x6c, 0x62, 0x57, 0x56, + 0x75, 0x0a, 0x64, 0x43, 0x34, 0x77, 0x4c, 0x51, 0x59, 0x49, 0x4b, 0x77, + 0x59, 0x42, 0x42, 0x51, 0x55, 0x48, 0x41, 0x67, 0x45, 0x57, 0x49, 0x57, + 0x68, 0x30, 0x64, 0x48, 0x41, 0x36, 0x4c, 0x79, 0x39, 0x33, 0x64, 0x33, + 0x63, 0x75, 0x63, 0x58, 0x56, 0x76, 0x64, 0x6d, 0x46, 0x6b, 0x61, 0x58, + 0x4e, 0x6e, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x77, 0x75, 0x59, 0x32, + 0x39, 0x74, 0x4c, 0x32, 0x4e, 0x77, 0x0a, 0x63, 0x7a, 0x41, 0x4c, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, + 0x51, 0x59, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, + 0x42, 0x59, 0x45, 0x46, 0x50, 0x4c, 0x41, 0x45, 0x2b, 0x43, 0x43, 0x51, + 0x7a, 0x37, 0x37, 0x37, 0x69, 0x39, 0x6e, 0x4d, 0x70, 0x59, 0x31, 0x58, + 0x4e, 0x75, 0x34, 0x79, 0x77, 0x4c, 0x51, 0x4d, 0x47, 0x34, 0x47, 0x0a, + 0x41, 0x31, 0x55, 0x64, 0x49, 0x77, 0x52, 0x6e, 0x4d, 0x47, 0x57, 0x41, + 0x46, 0x50, 0x4c, 0x41, 0x45, 0x2b, 0x43, 0x43, 0x51, 0x7a, 0x37, 0x37, + 0x37, 0x69, 0x39, 0x6e, 0x4d, 0x70, 0x59, 0x31, 0x58, 0x4e, 0x75, 0x34, + 0x79, 0x77, 0x4c, 0x51, 0x6f, 0x55, 0x6d, 0x6b, 0x52, 0x7a, 0x42, 0x46, + 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, + 0x45, 0x77, 0x4a, 0x43, 0x0a, 0x54, 0x54, 0x45, 0x5a, 0x4d, 0x42, 0x63, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x51, 0x55, 0x58, 0x56, + 0x76, 0x56, 0x6d, 0x46, 0x6b, 0x61, 0x58, 0x4d, 0x67, 0x54, 0x47, 0x6c, + 0x74, 0x61, 0x58, 0x52, 0x6c, 0x5a, 0x44, 0x45, 0x62, 0x4d, 0x42, 0x6b, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x53, 0x55, 0x58, 0x56, + 0x76, 0x56, 0x6d, 0x46, 0x6b, 0x61, 0x58, 0x4d, 0x67, 0x0a, 0x55, 0x6d, + 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x53, 0x41, 0x7a, 0x67, 0x67, + 0x49, 0x46, 0x78, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, + 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, + 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, 0x54, 0x36, 0x32, 0x67, 0x4c, 0x45, + 0x7a, 0x36, 0x77, 0x50, 0x4a, 0x76, 0x39, 0x32, 0x5a, 0x56, 0x71, 0x79, + 0x4d, 0x30, 0x0a, 0x37, 0x75, 0x63, 0x70, 0x32, 0x73, 0x4e, 0x62, 0x74, + 0x72, 0x43, 0x44, 0x32, 0x64, 0x44, 0x51, 0x34, 0x69, 0x48, 0x37, 0x38, + 0x32, 0x43, 0x6e, 0x4f, 0x31, 0x31, 0x67, 0x55, 0x79, 0x65, 0x69, 0x6d, + 0x2f, 0x59, 0x49, 0x49, 0x69, 0x72, 0x6e, 0x76, 0x36, 0x42, 0x79, 0x35, + 0x5a, 0x77, 0x6b, 0x61, 0x6a, 0x47, 0x78, 0x6b, 0x48, 0x6f, 0x6e, 0x32, + 0x34, 0x51, 0x52, 0x69, 0x53, 0x65, 0x6d, 0x0a, 0x64, 0x31, 0x6f, 0x34, + 0x31, 0x37, 0x2b, 0x73, 0x68, 0x76, 0x7a, 0x75, 0x58, 0x59, 0x4f, 0x38, + 0x42, 0x73, 0x62, 0x52, 0x64, 0x32, 0x73, 0x50, 0x62, 0x53, 0x51, 0x76, + 0x53, 0x33, 0x70, 0x73, 0x70, 0x77, 0x65, 0x57, 0x79, 0x75, 0x4f, 0x45, + 0x6e, 0x36, 0x32, 0x49, 0x69, 0x78, 0x32, 0x72, 0x46, 0x6f, 0x31, 0x62, + 0x5a, 0x68, 0x66, 0x5a, 0x46, 0x76, 0x53, 0x4c, 0x67, 0x4e, 0x4c, 0x64, + 0x0a, 0x2b, 0x4c, 0x4a, 0x32, 0x77, 0x2f, 0x77, 0x34, 0x45, 0x36, 0x6f, + 0x4d, 0x33, 0x6b, 0x4a, 0x70, 0x4b, 0x32, 0x37, 0x7a, 0x50, 0x4f, 0x75, + 0x41, 0x4a, 0x39, 0x76, 0x31, 0x70, 0x6b, 0x51, 0x4e, 0x6e, 0x31, 0x70, + 0x56, 0x57, 0x51, 0x76, 0x56, 0x44, 0x56, 0x4a, 0x49, 0x78, 0x61, 0x36, + 0x66, 0x38, 0x69, 0x2b, 0x41, 0x78, 0x65, 0x6f, 0x79, 0x55, 0x44, 0x55, + 0x53, 0x6c, 0x79, 0x37, 0x42, 0x0a, 0x34, 0x66, 0x2f, 0x78, 0x49, 0x34, + 0x68, 0x52, 0x4f, 0x4a, 0x2f, 0x79, 0x5a, 0x6c, 0x5a, 0x32, 0x35, 0x77, + 0x39, 0x52, 0x6c, 0x36, 0x56, 0x53, 0x44, 0x45, 0x31, 0x4a, 0x55, 0x5a, + 0x55, 0x32, 0x50, 0x62, 0x2b, 0x69, 0x53, 0x77, 0x77, 0x51, 0x48, 0x59, + 0x61, 0x5a, 0x54, 0x4b, 0x72, 0x7a, 0x63, 0x68, 0x47, 0x54, 0x35, 0x4f, + 0x72, 0x32, 0x6d, 0x39, 0x71, 0x6f, 0x58, 0x61, 0x64, 0x4e, 0x0a, 0x74, + 0x35, 0x34, 0x43, 0x72, 0x6e, 0x4d, 0x41, 0x79, 0x4e, 0x6f, 0x6a, 0x41, + 0x2b, 0x6a, 0x35, 0x36, 0x68, 0x6c, 0x30, 0x59, 0x67, 0x43, 0x55, 0x79, + 0x79, 0x49, 0x67, 0x76, 0x70, 0x53, 0x6e, 0x57, 0x62, 0x57, 0x43, 0x61, + 0x72, 0x36, 0x5a, 0x65, 0x58, 0x71, 0x70, 0x38, 0x6b, 0x6f, 0x6b, 0x55, + 0x76, 0x64, 0x30, 0x2f, 0x62, 0x70, 0x4f, 0x35, 0x71, 0x67, 0x64, 0x41, + 0x6d, 0x36, 0x78, 0x0a, 0x44, 0x59, 0x42, 0x45, 0x77, 0x61, 0x37, 0x54, + 0x49, 0x7a, 0x64, 0x66, 0x75, 0x34, 0x56, 0x38, 0x4b, 0x35, 0x49, 0x75, + 0x36, 0x48, 0x36, 0x6c, 0x69, 0x39, 0x32, 0x5a, 0x34, 0x62, 0x38, 0x6e, + 0x62, 0x79, 0x31, 0x64, 0x71, 0x6e, 0x75, 0x48, 0x2f, 0x67, 0x72, 0x64, + 0x53, 0x2f, 0x79, 0x4f, 0x39, 0x53, 0x62, 0x6b, 0x62, 0x6e, 0x42, 0x43, + 0x62, 0x6a, 0x50, 0x73, 0x4d, 0x5a, 0x35, 0x37, 0x0a, 0x6b, 0x38, 0x48, + 0x6b, 0x79, 0x57, 0x6b, 0x61, 0x50, 0x63, 0x42, 0x72, 0x54, 0x69, 0x4a, + 0x74, 0x37, 0x71, 0x74, 0x59, 0x54, 0x63, 0x62, 0x51, 0x51, 0x63, 0x45, + 0x72, 0x36, 0x6b, 0x38, 0x53, 0x68, 0x31, 0x37, 0x72, 0x52, 0x64, 0x68, + 0x73, 0x39, 0x5a, 0x67, 0x43, 0x30, 0x36, 0x44, 0x59, 0x56, 0x59, 0x6f, + 0x47, 0x6d, 0x52, 0x6d, 0x69, 0x6f, 0x48, 0x66, 0x52, 0x4d, 0x4a, 0x36, + 0x73, 0x0a, 0x7a, 0x48, 0x58, 0x75, 0x67, 0x2f, 0x57, 0x77, 0x59, 0x6a, + 0x6e, 0x50, 0x62, 0x46, 0x66, 0x69, 0x54, 0x4e, 0x4b, 0x52, 0x43, 0x77, + 0x35, 0x31, 0x4b, 0x42, 0x75, 0x61, 0x76, 0x2f, 0x30, 0x61, 0x51, 0x2f, + 0x48, 0x4b, 0x64, 0x2f, 0x73, 0x37, 0x6a, 0x32, 0x47, 0x34, 0x61, 0x53, + 0x67, 0x57, 0x51, 0x67, 0x52, 0x65, 0x63, 0x43, 0x6f, 0x63, 0x49, 0x64, + 0x69, 0x50, 0x34, 0x62, 0x30, 0x6a, 0x0a, 0x57, 0x79, 0x31, 0x30, 0x51, + 0x4a, 0x4c, 0x5a, 0x59, 0x78, 0x6b, 0x4e, 0x63, 0x39, 0x31, 0x70, 0x76, + 0x47, 0x4a, 0x48, 0x76, 0x4f, 0x42, 0x30, 0x4b, 0x37, 0x4c, 0x72, 0x66, + 0x62, 0x35, 0x42, 0x47, 0x37, 0x58, 0x41, 0x52, 0x73, 0x57, 0x68, 0x49, + 0x73, 0x74, 0x66, 0x54, 0x73, 0x45, 0x6f, 0x6b, 0x74, 0x34, 0x59, 0x75, + 0x74, 0x55, 0x71, 0x4b, 0x4c, 0x73, 0x52, 0x69, 0x78, 0x65, 0x54, 0x0a, + 0x6d, 0x4a, 0x6c, 0x67, 0x6c, 0x46, 0x77, 0x6a, 0x7a, 0x31, 0x6f, 0x6e, + 0x6c, 0x31, 0x34, 0x4c, 0x42, 0x51, 0x61, 0x54, 0x4e, 0x78, 0x34, 0x37, + 0x61, 0x54, 0x62, 0x72, 0x71, 0x5a, 0x35, 0x68, 0x48, 0x59, 0x38, 0x79, + 0x32, 0x6f, 0x34, 0x4d, 0x31, 0x6e, 0x51, 0x2b, 0x65, 0x77, 0x6b, 0x6b, + 0x32, 0x67, 0x46, 0x33, 0x52, 0x38, 0x51, 0x37, 0x7a, 0x54, 0x53, 0x4d, + 0x6d, 0x66, 0x58, 0x4b, 0x0a, 0x34, 0x53, 0x56, 0x68, 0x4d, 0x37, 0x4a, + 0x5a, 0x47, 0x2b, 0x4a, 0x75, 0x31, 0x7a, 0x64, 0x58, 0x74, 0x67, 0x32, + 0x70, 0x45, 0x74, 0x6f, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x4f, 0x3d, 0x53, 0x45, 0x43, + 0x4f, 0x4d, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, + 0x20, 0x4f, 0x55, 0x3d, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, + 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x31, 0x0a, 0x23, + 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x4f, 0x3d, + 0x53, 0x45, 0x43, 0x4f, 0x4d, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x6e, 0x65, 0x74, 0x20, 0x4f, 0x55, 0x3d, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, + 0x31, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x43, 0x6f, 0x6d, + 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, + 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x66, 0x31, 0x3a, 0x62, 0x63, 0x3a, 0x36, 0x33, 0x3a, + 0x36, 0x61, 0x3a, 0x35, 0x34, 0x3a, 0x65, 0x30, 0x3a, 0x62, 0x35, 0x3a, + 0x32, 0x37, 0x3a, 0x66, 0x35, 0x3a, 0x63, 0x64, 0x3a, 0x65, 0x37, 0x3a, + 0x31, 0x61, 0x3a, 0x65, 0x33, 0x3a, 0x34, 0x64, 0x3a, 0x36, 0x65, 0x3a, + 0x34, 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, + 0x36, 0x3a, 0x62, 0x31, 0x3a, 0x32, 0x62, 0x3a, 0x34, 0x39, 0x3a, 0x66, + 0x39, 0x3a, 0x38, 0x31, 0x3a, 0x39, 0x65, 0x3a, 0x64, 0x37, 0x3a, 0x34, + 0x63, 0x3a, 0x39, 0x65, 0x3a, 0x62, 0x63, 0x3a, 0x33, 0x38, 0x3a, 0x30, + 0x66, 0x3a, 0x63, 0x36, 0x3a, 0x35, 0x36, 0x3a, 0x38, 0x66, 0x3a, 0x35, + 0x64, 0x3a, 0x61, 0x63, 0x3a, 0x62, 0x32, 0x3a, 0x66, 0x37, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x37, 0x3a, + 0x35, 0x65, 0x3a, 0x37, 0x32, 0x3a, 0x65, 0x64, 0x3a, 0x39, 0x66, 0x3a, + 0x35, 0x36, 0x3a, 0x30, 0x65, 0x3a, 0x65, 0x63, 0x3a, 0x36, 0x65, 0x3a, + 0x62, 0x34, 0x3a, 0x38, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x37, 0x33, 0x3a, + 0x61, 0x34, 0x3a, 0x33, 0x66, 0x3a, 0x63, 0x33, 0x3a, 0x61, 0x64, 0x3a, + 0x31, 0x39, 0x3a, 0x31, 0x39, 0x3a, 0x35, 0x61, 0x3a, 0x33, 0x39, 0x3a, + 0x32, 0x32, 0x3a, 0x38, 0x32, 0x3a, 0x30, 0x31, 0x3a, 0x37, 0x38, 0x3a, + 0x39, 0x35, 0x3a, 0x39, 0x37, 0x3a, 0x34, 0x61, 0x3a, 0x39, 0x39, 0x3a, + 0x30, 0x32, 0x3a, 0x36, 0x62, 0x3a, 0x36, 0x63, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x57, 0x6a, 0x43, 0x43, 0x41, 0x6b, 0x4b, + 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x44, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, + 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x51, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, + 0x4b, 0x55, 0x44, 0x45, 0x59, 0x0a, 0x4d, 0x42, 0x59, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x68, 0x4d, 0x50, 0x55, 0x30, 0x56, 0x44, 0x54, 0x30, + 0x30, 0x67, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x75, 0x62, 0x6d, + 0x56, 0x30, 0x4d, 0x53, 0x63, 0x77, 0x4a, 0x51, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4c, 0x45, 0x78, 0x35, 0x54, 0x5a, 0x57, 0x4e, 0x31, 0x63, 0x6d, + 0x6c, 0x30, 0x65, 0x53, 0x42, 0x44, 0x62, 0x32, 0x31, 0x74, 0x0a, 0x64, + 0x57, 0x35, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, + 0x46, 0x4a, 0x76, 0x62, 0x33, 0x52, 0x44, 0x51, 0x54, 0x45, 0x77, 0x48, + 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x4d, 0x77, 0x4f, 0x54, 0x4d, 0x77, 0x4d, + 0x44, 0x51, 0x79, 0x4d, 0x44, 0x51, 0x35, 0x57, 0x68, 0x63, 0x4e, 0x4d, + 0x6a, 0x4d, 0x77, 0x4f, 0x54, 0x4d, 0x77, 0x4d, 0x44, 0x51, 0x79, 0x4d, + 0x44, 0x51, 0x35, 0x0a, 0x57, 0x6a, 0x42, 0x51, 0x4d, 0x51, 0x73, 0x77, + 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x4b, + 0x55, 0x44, 0x45, 0x59, 0x4d, 0x42, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x68, 0x4d, 0x50, 0x55, 0x30, 0x56, 0x44, 0x54, 0x30, 0x30, 0x67, + 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x75, 0x62, 0x6d, 0x56, 0x30, + 0x4d, 0x53, 0x63, 0x77, 0x4a, 0x51, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, + 0x4c, 0x45, 0x78, 0x35, 0x54, 0x5a, 0x57, 0x4e, 0x31, 0x63, 0x6d, 0x6c, + 0x30, 0x65, 0x53, 0x42, 0x44, 0x62, 0x32, 0x31, 0x74, 0x64, 0x57, 0x35, + 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x46, 0x4a, + 0x76, 0x62, 0x33, 0x52, 0x44, 0x51, 0x54, 0x45, 0x77, 0x67, 0x67, 0x45, + 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x33, 0x0a, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, + 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, + 0x49, 0x42, 0x41, 0x51, 0x43, 0x7a, 0x73, 0x2f, 0x35, 0x2f, 0x30, 0x32, + 0x32, 0x78, 0x37, 0x78, 0x5a, 0x38, 0x56, 0x36, 0x55, 0x4d, 0x62, 0x58, + 0x61, 0x4b, 0x4c, 0x30, 0x75, 0x2f, 0x5a, 0x50, 0x74, 0x4d, 0x37, 0x6f, + 0x72, 0x77, 0x38, 0x79, 0x6c, 0x38, 0x0a, 0x39, 0x66, 0x2f, 0x75, 0x4b, + 0x75, 0x44, 0x70, 0x36, 0x62, 0x70, 0x62, 0x5a, 0x43, 0x4b, 0x61, 0x6d, + 0x6d, 0x38, 0x73, 0x4f, 0x69, 0x5a, 0x70, 0x55, 0x51, 0x57, 0x5a, 0x4a, + 0x74, 0x7a, 0x56, 0x48, 0x47, 0x70, 0x78, 0x78, 0x70, 0x70, 0x39, 0x48, + 0x70, 0x33, 0x64, 0x66, 0x47, 0x7a, 0x47, 0x6a, 0x47, 0x64, 0x6e, 0x53, + 0x6a, 0x37, 0x34, 0x63, 0x62, 0x41, 0x5a, 0x4a, 0x36, 0x6b, 0x4a, 0x0a, + 0x44, 0x4b, 0x61, 0x56, 0x76, 0x30, 0x75, 0x4d, 0x44, 0x50, 0x70, 0x56, + 0x6d, 0x44, 0x76, 0x59, 0x36, 0x43, 0x4b, 0x68, 0x53, 0x33, 0x45, 0x34, + 0x65, 0x61, 0x79, 0x58, 0x6b, 0x6d, 0x6d, 0x7a, 0x69, 0x58, 0x37, 0x71, + 0x49, 0x57, 0x67, 0x47, 0x6d, 0x42, 0x53, 0x57, 0x68, 0x39, 0x4a, 0x68, + 0x4e, 0x72, 0x78, 0x74, 0x4a, 0x31, 0x61, 0x65, 0x56, 0x2b, 0x37, 0x41, + 0x77, 0x46, 0x62, 0x39, 0x0a, 0x4d, 0x73, 0x2b, 0x6b, 0x32, 0x59, 0x37, + 0x43, 0x49, 0x39, 0x65, 0x4e, 0x71, 0x50, 0x50, 0x59, 0x4a, 0x61, 0x79, + 0x58, 0x35, 0x48, 0x41, 0x34, 0x39, 0x4c, 0x59, 0x36, 0x74, 0x4a, 0x30, + 0x37, 0x6c, 0x79, 0x5a, 0x44, 0x6f, 0x36, 0x47, 0x38, 0x53, 0x56, 0x6c, + 0x79, 0x54, 0x43, 0x4d, 0x77, 0x68, 0x77, 0x46, 0x59, 0x39, 0x6b, 0x36, + 0x2b, 0x48, 0x47, 0x68, 0x57, 0x5a, 0x71, 0x2f, 0x4e, 0x0a, 0x51, 0x56, + 0x33, 0x49, 0x73, 0x30, 0x30, 0x71, 0x56, 0x55, 0x61, 0x72, 0x48, 0x39, + 0x6f, 0x65, 0x34, 0x6b, 0x41, 0x39, 0x32, 0x38, 0x31, 0x39, 0x75, 0x5a, + 0x4b, 0x41, 0x6e, 0x44, 0x66, 0x64, 0x44, 0x4a, 0x5a, 0x6b, 0x6e, 0x64, + 0x77, 0x69, 0x39, 0x32, 0x53, 0x4c, 0x33, 0x32, 0x48, 0x65, 0x46, 0x5a, + 0x52, 0x53, 0x46, 0x61, 0x42, 0x39, 0x55, 0x73, 0x6c, 0x4c, 0x71, 0x43, + 0x48, 0x4a, 0x0a, 0x78, 0x72, 0x48, 0x74, 0x79, 0x38, 0x4f, 0x56, 0x59, + 0x4e, 0x45, 0x50, 0x38, 0x4b, 0x74, 0x77, 0x2b, 0x4e, 0x2f, 0x4c, 0x54, + 0x58, 0x37, 0x73, 0x31, 0x76, 0x71, 0x72, 0x32, 0x62, 0x31, 0x2f, 0x56, + 0x50, 0x4b, 0x6c, 0x36, 0x58, 0x6e, 0x36, 0x32, 0x64, 0x5a, 0x32, 0x4a, + 0x43, 0x68, 0x7a, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x50, + 0x7a, 0x41, 0x39, 0x4d, 0x42, 0x30, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x64, + 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x53, 0x67, 0x63, 0x30, 0x6d, 0x5a, + 0x61, 0x4e, 0x79, 0x46, 0x57, 0x32, 0x58, 0x6a, 0x6d, 0x79, 0x67, 0x76, + 0x56, 0x35, 0x2b, 0x39, 0x4d, 0x37, 0x77, 0x48, 0x53, 0x44, 0x41, 0x4c, + 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, + 0x41, 0x51, 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, + 0x0a, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, + 0x42, 0x2f, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, + 0x43, 0x41, 0x51, 0x45, 0x41, 0x61, 0x45, 0x43, 0x70, 0x71, 0x4c, 0x76, + 0x6b, 0x54, 0x31, 0x31, 0x35, 0x73, 0x77, 0x57, 0x31, 0x46, 0x37, 0x4e, + 0x67, 0x45, 0x2b, 0x76, 0x47, 0x0a, 0x6b, 0x6c, 0x33, 0x67, 0x30, 0x64, + 0x4e, 0x71, 0x2f, 0x76, 0x75, 0x2b, 0x6d, 0x32, 0x32, 0x2f, 0x78, 0x77, + 0x56, 0x74, 0x57, 0x53, 0x44, 0x45, 0x48, 0x50, 0x43, 0x33, 0x32, 0x6f, + 0x52, 0x59, 0x41, 0x6d, 0x50, 0x36, 0x53, 0x42, 0x62, 0x76, 0x54, 0x36, + 0x55, 0x4c, 0x39, 0x30, 0x71, 0x59, 0x38, 0x6a, 0x2b, 0x65, 0x47, 0x36, + 0x31, 0x48, 0x61, 0x32, 0x50, 0x4f, 0x43, 0x45, 0x66, 0x72, 0x0a, 0x55, + 0x6a, 0x39, 0x34, 0x6e, 0x4b, 0x39, 0x4e, 0x72, 0x76, 0x6a, 0x56, 0x54, + 0x38, 0x2b, 0x61, 0x6d, 0x43, 0x6f, 0x51, 0x51, 0x54, 0x6c, 0x53, 0x78, + 0x4e, 0x33, 0x5a, 0x6d, 0x77, 0x37, 0x76, 0x6b, 0x77, 0x47, 0x75, 0x73, + 0x69, 0x37, 0x4b, 0x61, 0x45, 0x49, 0x6b, 0x51, 0x6d, 0x79, 0x77, 0x73, + 0x7a, 0x6f, 0x2b, 0x7a, 0x65, 0x6e, 0x61, 0x53, 0x4d, 0x51, 0x56, 0x79, + 0x2b, 0x6e, 0x35, 0x0a, 0x42, 0x77, 0x2b, 0x53, 0x55, 0x45, 0x6d, 0x4b, + 0x33, 0x54, 0x47, 0x58, 0x58, 0x38, 0x6e, 0x70, 0x4e, 0x36, 0x6f, 0x37, + 0x57, 0x57, 0x57, 0x58, 0x6c, 0x44, 0x4c, 0x4a, 0x73, 0x35, 0x38, 0x2b, + 0x4f, 0x6d, 0x4a, 0x59, 0x78, 0x55, 0x6d, 0x74, 0x59, 0x67, 0x35, 0x78, + 0x70, 0x54, 0x4b, 0x71, 0x4c, 0x38, 0x61, 0x4a, 0x64, 0x6b, 0x4e, 0x41, + 0x45, 0x78, 0x4e, 0x6e, 0x50, 0x61, 0x4a, 0x55, 0x0a, 0x4a, 0x52, 0x44, + 0x4c, 0x38, 0x54, 0x72, 0x79, 0x32, 0x66, 0x72, 0x62, 0x53, 0x56, 0x61, + 0x37, 0x70, 0x76, 0x36, 0x6e, 0x51, 0x54, 0x58, 0x44, 0x34, 0x49, 0x68, + 0x68, 0x79, 0x59, 0x6a, 0x48, 0x33, 0x7a, 0x59, 0x51, 0x49, 0x70, 0x68, + 0x5a, 0x36, 0x72, 0x42, 0x4b, 0x2b, 0x31, 0x59, 0x57, 0x63, 0x32, 0x36, + 0x73, 0x54, 0x66, 0x63, 0x69, 0x6f, 0x55, 0x2b, 0x74, 0x48, 0x58, 0x6f, + 0x74, 0x0a, 0x52, 0x53, 0x66, 0x6c, 0x4d, 0x4d, 0x46, 0x65, 0x38, 0x74, + 0x6f, 0x54, 0x79, 0x79, 0x56, 0x43, 0x55, 0x5a, 0x56, 0x48, 0x41, 0x34, + 0x78, 0x73, 0x49, 0x63, 0x78, 0x30, 0x51, 0x75, 0x31, 0x54, 0x2f, 0x7a, + 0x4f, 0x4c, 0x6a, 0x77, 0x39, 0x58, 0x41, 0x52, 0x59, 0x76, 0x7a, 0x36, + 0x62, 0x75, 0x79, 0x58, 0x41, 0x69, 0x46, 0x4c, 0x33, 0x39, 0x76, 0x6d, + 0x77, 0x4c, 0x41, 0x77, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, + 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, + 0x6f, 0x6e, 0x65, 0x72, 0x61, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x32, + 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x53, 0x6f, 0x6e, 0x65, 0x72, 0x61, + 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x53, 0x6f, 0x6e, 0x65, 0x72, 0x61, 0x20, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x32, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x53, 0x6f, + 0x6e, 0x65, 0x72, 0x61, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x53, 0x6f, 0x6e, 0x65, 0x72, 0x61, 0x20, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x32, 0x39, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, + 0x33, 0x3a, 0x65, 0x63, 0x3a, 0x37, 0x35, 0x3a, 0x30, 0x66, 0x3a, 0x32, + 0x65, 0x3a, 0x38, 0x38, 0x3a, 0x64, 0x66, 0x3a, 0x66, 0x61, 0x3a, 0x34, + 0x38, 0x3a, 0x30, 0x31, 0x3a, 0x34, 0x65, 0x3a, 0x30, 0x62, 0x3a, 0x35, + 0x63, 0x3a, 0x34, 0x38, 0x3a, 0x36, 0x66, 0x3a, 0x66, 0x62, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x37, 0x3a, 0x66, 0x37, + 0x3a, 0x36, 0x64, 0x3a, 0x65, 0x36, 0x3a, 0x30, 0x37, 0x3a, 0x37, 0x63, + 0x3a, 0x39, 0x30, 0x3a, 0x63, 0x35, 0x3a, 0x62, 0x31, 0x3a, 0x33, 0x65, + 0x3a, 0x39, 0x33, 0x3a, 0x31, 0x61, 0x3a, 0x62, 0x37, 0x3a, 0x34, 0x31, + 0x3a, 0x31, 0x30, 0x3a, 0x62, 0x34, 0x3a, 0x66, 0x32, 0x3a, 0x65, 0x34, + 0x3a, 0x39, 0x61, 0x3a, 0x32, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x39, 0x3a, 0x30, 0x38, 0x3a, 0x62, + 0x34, 0x3a, 0x30, 0x33, 0x3a, 0x31, 0x34, 0x3a, 0x63, 0x31, 0x3a, 0x33, + 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x30, 0x62, 0x3a, 0x35, 0x31, 0x3a, 0x38, + 0x64, 0x3a, 0x30, 0x37, 0x3a, 0x33, 0x35, 0x3a, 0x38, 0x30, 0x3a, 0x37, + 0x66, 0x3a, 0x66, 0x62, 0x3a, 0x66, 0x63, 0x3a, 0x66, 0x38, 0x3a, 0x35, + 0x31, 0x3a, 0x38, 0x61, 0x3a, 0x30, 0x30, 0x3a, 0x39, 0x35, 0x3a, 0x33, + 0x33, 0x3a, 0x37, 0x31, 0x3a, 0x30, 0x35, 0x3a, 0x62, 0x61, 0x3a, 0x33, + 0x38, 0x3a, 0x36, 0x62, 0x3a, 0x31, 0x35, 0x3a, 0x33, 0x64, 0x3a, 0x64, + 0x39, 0x3a, 0x32, 0x37, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x44, 0x49, 0x44, 0x43, 0x43, 0x41, 0x67, 0x69, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x42, 0x48, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, + 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, + 0x46, 0x41, 0x44, 0x41, 0x35, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x47, 0x53, 0x54, 0x45, + 0x50, 0x0a, 0x4d, 0x41, 0x30, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, + 0x4d, 0x47, 0x55, 0x32, 0x39, 0x75, 0x5a, 0x58, 0x4a, 0x68, 0x4d, 0x52, + 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, + 0x42, 0x54, 0x62, 0x32, 0x35, 0x6c, 0x63, 0x6d, 0x45, 0x67, 0x51, 0x32, + 0x78, 0x68, 0x63, 0x33, 0x4d, 0x79, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x42, + 0x34, 0x58, 0x44, 0x54, 0x41, 0x78, 0x0a, 0x4d, 0x44, 0x51, 0x77, 0x4e, + 0x6a, 0x41, 0x33, 0x4d, 0x6a, 0x6b, 0x30, 0x4d, 0x46, 0x6f, 0x58, 0x44, + 0x54, 0x49, 0x78, 0x4d, 0x44, 0x51, 0x77, 0x4e, 0x6a, 0x41, 0x33, 0x4d, + 0x6a, 0x6b, 0x30, 0x4d, 0x46, 0x6f, 0x77, 0x4f, 0x54, 0x45, 0x4c, 0x4d, + 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, + 0x6b, 0x6b, 0x78, 0x44, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x4e, 0x56, 0x0a, + 0x42, 0x41, 0x6f, 0x54, 0x42, 0x6c, 0x4e, 0x76, 0x62, 0x6d, 0x56, 0x79, + 0x59, 0x54, 0x45, 0x5a, 0x4d, 0x42, 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x41, 0x78, 0x4d, 0x51, 0x55, 0x32, 0x39, 0x75, 0x5a, 0x58, 0x4a, 0x68, + 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x4d, 0x69, 0x42, 0x44, + 0x51, 0x54, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, + 0x4b, 0x6f, 0x5a, 0x49, 0x0a, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, + 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, + 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4a, 0x41, + 0x58, 0x53, 0x6a, 0x57, 0x64, 0x79, 0x76, 0x41, 0x4e, 0x6c, 0x73, 0x64, + 0x45, 0x2b, 0x68, 0x59, 0x33, 0x2f, 0x45, 0x69, 0x39, 0x76, 0x58, 0x2b, + 0x41, 0x4c, 0x54, 0x55, 0x37, 0x34, 0x57, 0x2b, 0x6f, 0x0a, 0x5a, 0x36, + 0x6d, 0x2f, 0x41, 0x78, 0x78, 0x4e, 0x6a, 0x47, 0x38, 0x79, 0x52, 0x39, + 0x56, 0x42, 0x61, 0x4b, 0x51, 0x54, 0x42, 0x4d, 0x45, 0x31, 0x44, 0x4a, + 0x71, 0x45, 0x51, 0x2f, 0x78, 0x63, 0x48, 0x66, 0x2b, 0x4a, 0x73, 0x2b, + 0x67, 0x58, 0x47, 0x4d, 0x32, 0x52, 0x58, 0x2f, 0x75, 0x4a, 0x34, 0x2b, + 0x71, 0x2f, 0x54, 0x6c, 0x31, 0x38, 0x47, 0x79, 0x62, 0x54, 0x64, 0x58, + 0x6e, 0x74, 0x0a, 0x35, 0x6f, 0x54, 0x6a, 0x56, 0x2b, 0x57, 0x74, 0x4b, + 0x63, 0x54, 0x30, 0x4f, 0x69, 0x6a, 0x6e, 0x70, 0x58, 0x75, 0x45, 0x4e, + 0x6d, 0x6d, 0x7a, 0x2f, 0x56, 0x35, 0x32, 0x76, 0x61, 0x4d, 0x74, 0x6d, + 0x64, 0x4f, 0x51, 0x54, 0x69, 0x4d, 0x6f, 0x66, 0x52, 0x68, 0x6a, 0x38, + 0x56, 0x51, 0x37, 0x4a, 0x70, 0x31, 0x32, 0x57, 0x35, 0x64, 0x43, 0x73, + 0x76, 0x2b, 0x75, 0x38, 0x45, 0x37, 0x73, 0x0a, 0x33, 0x54, 0x6d, 0x56, + 0x54, 0x6f, 0x4d, 0x47, 0x66, 0x2b, 0x64, 0x4a, 0x51, 0x4d, 0x6a, 0x46, + 0x41, 0x62, 0x4a, 0x55, 0x57, 0x6d, 0x59, 0x64, 0x50, 0x66, 0x7a, 0x35, + 0x36, 0x54, 0x77, 0x4b, 0x6e, 0x6f, 0x47, 0x34, 0x63, 0x50, 0x41, 0x42, + 0x69, 0x2b, 0x51, 0x6a, 0x56, 0x48, 0x7a, 0x49, 0x72, 0x76, 0x69, 0x51, + 0x48, 0x67, 0x43, 0x57, 0x63, 0x74, 0x52, 0x55, 0x7a, 0x32, 0x45, 0x6a, + 0x0a, 0x76, 0x4f, 0x72, 0x37, 0x6e, 0x51, 0x4b, 0x56, 0x30, 0x62, 0x61, + 0x35, 0x63, 0x54, 0x70, 0x70, 0x43, 0x44, 0x38, 0x50, 0x74, 0x4f, 0x46, + 0x43, 0x78, 0x34, 0x6a, 0x31, 0x50, 0x35, 0x69, 0x6f, 0x70, 0x37, 0x6f, + 0x63, 0x34, 0x48, 0x46, 0x78, 0x37, 0x31, 0x68, 0x58, 0x67, 0x56, 0x42, + 0x36, 0x58, 0x47, 0x74, 0x30, 0x52, 0x67, 0x36, 0x44, 0x41, 0x35, 0x6a, + 0x44, 0x6a, 0x71, 0x68, 0x75, 0x0a, 0x38, 0x6e, 0x59, 0x79, 0x62, 0x69, + 0x65, 0x44, 0x77, 0x6e, 0x50, 0x7a, 0x33, 0x42, 0x6a, 0x6f, 0x74, 0x4a, + 0x50, 0x71, 0x64, 0x55, 0x52, 0x72, 0x42, 0x47, 0x41, 0x67, 0x63, 0x56, + 0x65, 0x48, 0x6e, 0x66, 0x4f, 0x2b, 0x6f, 0x4a, 0x41, 0x6a, 0x50, 0x59, + 0x6f, 0x6b, 0x34, 0x64, 0x6f, 0x68, 0x32, 0x38, 0x4d, 0x43, 0x41, 0x77, + 0x45, 0x41, 0x41, 0x61, 0x4d, 0x7a, 0x4d, 0x44, 0x45, 0x77, 0x0a, 0x44, + 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, + 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x52, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x43, 0x67, 0x51, 0x49, 0x53, + 0x71, 0x43, 0x71, 0x57, 0x49, 0x54, 0x54, 0x58, 0x6a, 0x77, 0x77, 0x43, + 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x42, 0x41, 0x51, 0x44, 0x41, + 0x67, 0x45, 0x47, 0x0a, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, + 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, + 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x42, 0x61, 0x7a, 0x6f, 0x66, 0x35, + 0x46, 0x6e, 0x49, 0x56, 0x56, 0x30, 0x73, 0x64, 0x32, 0x5a, 0x76, 0x6e, + 0x6f, 0x69, 0x59, 0x77, 0x37, 0x4a, 0x4e, 0x6e, 0x33, 0x39, 0x59, 0x74, + 0x30, 0x6a, 0x53, 0x76, 0x39, 0x7a, 0x69, 0x6c, 0x0a, 0x7a, 0x71, 0x73, + 0x57, 0x75, 0x61, 0x73, 0x76, 0x66, 0x44, 0x58, 0x4c, 0x72, 0x4e, 0x41, + 0x50, 0x74, 0x45, 0x77, 0x72, 0x2f, 0x49, 0x44, 0x76, 0x61, 0x34, 0x79, + 0x52, 0x58, 0x7a, 0x5a, 0x32, 0x39, 0x39, 0x75, 0x7a, 0x47, 0x78, 0x6e, + 0x71, 0x39, 0x4c, 0x49, 0x52, 0x2f, 0x57, 0x46, 0x78, 0x52, 0x4c, 0x38, + 0x6f, 0x73, 0x7a, 0x6f, 0x64, 0x76, 0x37, 0x4e, 0x44, 0x36, 0x4a, 0x2b, + 0x2f, 0x0a, 0x33, 0x44, 0x45, 0x49, 0x63, 0x62, 0x43, 0x64, 0x6a, 0x64, + 0x59, 0x30, 0x52, 0x7a, 0x4b, 0x51, 0x78, 0x6d, 0x55, 0x6b, 0x39, 0x36, + 0x42, 0x4b, 0x66, 0x41, 0x52, 0x7a, 0x6a, 0x7a, 0x6c, 0x76, 0x46, 0x34, + 0x78, 0x79, 0x74, 0x62, 0x31, 0x4c, 0x79, 0x48, 0x72, 0x34, 0x65, 0x34, + 0x50, 0x44, 0x4b, 0x45, 0x36, 0x63, 0x43, 0x65, 0x70, 0x6e, 0x50, 0x37, + 0x4a, 0x6e, 0x42, 0x42, 0x76, 0x44, 0x0a, 0x46, 0x4e, 0x72, 0x34, 0x35, + 0x30, 0x6b, 0x6b, 0x6b, 0x64, 0x41, 0x64, 0x61, 0x76, 0x70, 0x68, 0x4f, + 0x65, 0x39, 0x72, 0x35, 0x79, 0x46, 0x31, 0x42, 0x67, 0x66, 0x59, 0x45, + 0x72, 0x51, 0x68, 0x49, 0x48, 0x42, 0x43, 0x63, 0x59, 0x48, 0x61, 0x50, + 0x4a, 0x6f, 0x32, 0x76, 0x71, 0x5a, 0x62, 0x44, 0x57, 0x70, 0x73, 0x6d, + 0x68, 0x2b, 0x52, 0x65, 0x2f, 0x6e, 0x35, 0x37, 0x30, 0x4b, 0x36, 0x0a, + 0x54, 0x6b, 0x36, 0x65, 0x7a, 0x41, 0x79, 0x4e, 0x6c, 0x4e, 0x7a, 0x5a, + 0x52, 0x5a, 0x78, 0x65, 0x37, 0x45, 0x4a, 0x51, 0x59, 0x36, 0x37, 0x30, + 0x58, 0x63, 0x53, 0x78, 0x45, 0x74, 0x7a, 0x4b, 0x4f, 0x36, 0x67, 0x75, + 0x6e, 0x52, 0x52, 0x61, 0x42, 0x58, 0x57, 0x33, 0x37, 0x4e, 0x64, 0x6a, + 0x34, 0x72, 0x6f, 0x31, 0x74, 0x67, 0x51, 0x49, 0x6b, 0x65, 0x6a, 0x61, + 0x6e, 0x5a, 0x7a, 0x32, 0x0a, 0x5a, 0x72, 0x55, 0x59, 0x72, 0x41, 0x71, + 0x6d, 0x56, 0x43, 0x59, 0x30, 0x4d, 0x39, 0x49, 0x62, 0x77, 0x64, 0x52, + 0x2f, 0x47, 0x6a, 0x71, 0x4f, 0x43, 0x36, 0x6f, 0x79, 0x62, 0x74, 0x76, + 0x38, 0x54, 0x79, 0x57, 0x66, 0x32, 0x54, 0x4c, 0x48, 0x6c, 0x6c, 0x70, + 0x77, 0x72, 0x4e, 0x39, 0x4d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x58, 0x52, + 0x61, 0x6d, 0x70, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, + 0x3d, 0x58, 0x52, 0x61, 0x6d, 0x70, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, + 0x78, 0x72, 0x61, 0x6d, 0x70, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x58, 0x52, 0x61, 0x6d, + 0x70, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x58, + 0x52, 0x61, 0x6d, 0x70, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x49, + 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x78, 0x72, + 0x61, 0x6d, 0x70, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2e, + 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x58, 0x52, 0x61, 0x6d, 0x70, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x30, + 0x37, 0x31, 0x30, 0x38, 0x39, 0x30, 0x38, 0x38, 0x30, 0x33, 0x36, 0x35, + 0x31, 0x35, 0x30, 0x39, 0x36, 0x39, 0x32, 0x39, 0x38, 0x30, 0x31, 0x32, + 0x34, 0x32, 0x33, 0x33, 0x37, 0x34, 0x35, 0x30, 0x31, 0x34, 0x39, 0x35, + 0x37, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x31, 0x3a, + 0x30, 0x62, 0x3a, 0x34, 0x34, 0x3a, 0x62, 0x33, 0x3a, 0x63, 0x61, 0x3a, + 0x31, 0x30, 0x3a, 0x64, 0x38, 0x3a, 0x30, 0x30, 0x3a, 0x36, 0x65, 0x3a, + 0x39, 0x64, 0x3a, 0x30, 0x66, 0x3a, 0x64, 0x38, 0x3a, 0x30, 0x66, 0x3a, + 0x39, 0x32, 0x3a, 0x30, 0x61, 0x3a, 0x64, 0x31, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x38, 0x3a, 0x30, 0x31, 0x3a, 0x38, + 0x36, 0x3a, 0x64, 0x31, 0x3a, 0x65, 0x62, 0x3a, 0x39, 0x63, 0x3a, 0x38, + 0x36, 0x3a, 0x61, 0x35, 0x3a, 0x34, 0x31, 0x3a, 0x30, 0x34, 0x3a, 0x63, + 0x66, 0x3a, 0x33, 0x30, 0x3a, 0x35, 0x34, 0x3a, 0x66, 0x33, 0x3a, 0x34, + 0x63, 0x3a, 0x35, 0x32, 0x3a, 0x62, 0x37, 0x3a, 0x65, 0x35, 0x3a, 0x35, + 0x38, 0x3a, 0x63, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, + 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x63, 0x65, 0x3a, 0x63, 0x64, 0x3a, 0x64, 0x63, 0x3a, + 0x39, 0x30, 0x3a, 0x35, 0x30, 0x3a, 0x39, 0x39, 0x3a, 0x64, 0x38, 0x3a, + 0x64, 0x61, 0x3a, 0x64, 0x66, 0x3a, 0x63, 0x35, 0x3a, 0x62, 0x31, 0x3a, + 0x64, 0x32, 0x3a, 0x30, 0x39, 0x3a, 0x62, 0x37, 0x3a, 0x33, 0x37, 0x3a, + 0x63, 0x62, 0x3a, 0x65, 0x32, 0x3a, 0x63, 0x31, 0x3a, 0x38, 0x63, 0x3a, + 0x66, 0x62, 0x3a, 0x32, 0x63, 0x3a, 0x31, 0x30, 0x3a, 0x63, 0x30, 0x3a, + 0x66, 0x66, 0x3a, 0x30, 0x62, 0x3a, 0x63, 0x66, 0x3a, 0x30, 0x64, 0x3a, + 0x33, 0x32, 0x3a, 0x38, 0x36, 0x3a, 0x66, 0x63, 0x3a, 0x31, 0x61, 0x3a, + 0x61, 0x32, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, + 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x4d, + 0x44, 0x43, 0x43, 0x41, 0x78, 0x69, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, + 0x67, 0x49, 0x51, 0x55, 0x4a, 0x52, 0x73, 0x37, 0x42, 0x6a, 0x71, 0x31, + 0x5a, 0x78, 0x4e, 0x31, 0x5a, 0x66, 0x76, 0x64, 0x59, 0x2b, 0x67, 0x72, + 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, + 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, + 0x67, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x48, 0x6a, 0x41, 0x63, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x46, 0x58, 0x64, 0x33, + 0x64, 0x79, 0x35, 0x34, 0x63, 0x6d, 0x46, 0x74, 0x63, 0x48, 0x4e, 0x6c, + 0x59, 0x33, 0x56, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4c, 0x6d, 0x4e, 0x76, + 0x62, 0x54, 0x45, 0x6b, 0x0a, 0x4d, 0x43, 0x49, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x68, 0x4d, 0x62, 0x57, 0x46, 0x4a, 0x68, 0x62, 0x58, 0x41, + 0x67, 0x55, 0x32, 0x56, 0x6a, 0x64, 0x58, 0x4a, 0x70, 0x64, 0x48, 0x6b, + 0x67, 0x55, 0x32, 0x56, 0x79, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d, + 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d, 0x53, 0x30, 0x77, 0x4b, 0x77, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x79, 0x52, 0x59, 0x0a, 0x55, 0x6d, + 0x46, 0x74, 0x63, 0x43, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, + 0x77, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, + 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, + 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, 0x48, 0x68, + 0x63, 0x4e, 0x4d, 0x44, 0x51, 0x78, 0x4d, 0x54, 0x41, 0x78, 0x4d, 0x54, + 0x63, 0x78, 0x0a, 0x4e, 0x44, 0x41, 0x30, 0x57, 0x68, 0x63, 0x4e, 0x4d, + 0x7a, 0x55, 0x77, 0x4d, 0x54, 0x41, 0x78, 0x4d, 0x44, 0x55, 0x7a, 0x4e, + 0x7a, 0x45, 0x35, 0x57, 0x6a, 0x43, 0x42, 0x67, 0x6a, 0x45, 0x4c, 0x4d, + 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, + 0x56, 0x4d, 0x78, 0x48, 0x6a, 0x41, 0x63, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x73, 0x54, 0x46, 0x58, 0x64, 0x33, 0x0a, 0x64, 0x79, 0x35, 0x34, + 0x63, 0x6d, 0x46, 0x74, 0x63, 0x48, 0x4e, 0x6c, 0x59, 0x33, 0x56, 0x79, + 0x61, 0x58, 0x52, 0x35, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x54, 0x45, 0x6b, + 0x4d, 0x43, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x62, + 0x57, 0x46, 0x4a, 0x68, 0x62, 0x58, 0x41, 0x67, 0x55, 0x32, 0x56, 0x6a, + 0x64, 0x58, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x55, 0x32, 0x56, 0x79, + 0x0a, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d, 0x67, 0x53, 0x57, 0x35, + 0x6a, 0x4d, 0x53, 0x30, 0x77, 0x4b, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x44, 0x45, 0x79, 0x52, 0x59, 0x55, 0x6d, 0x46, 0x74, 0x63, 0x43, 0x42, + 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x77, 0x67, 0x51, 0x32, 0x56, + 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, + 0x76, 0x62, 0x69, 0x42, 0x42, 0x0a, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, + 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4d, 0x41, + 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, + 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77, + 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, + 0x43, 0x59, 0x4a, 0x42, 0x36, 0x39, 0x46, 0x62, 0x53, 0x36, 0x0a, 0x33, + 0x38, 0x65, 0x4d, 0x70, 0x53, 0x65, 0x32, 0x4f, 0x41, 0x74, 0x70, 0x38, + 0x37, 0x5a, 0x4f, 0x71, 0x43, 0x77, 0x75, 0x49, 0x52, 0x31, 0x63, 0x52, + 0x4e, 0x38, 0x68, 0x58, 0x58, 0x34, 0x6a, 0x64, 0x50, 0x35, 0x65, 0x66, + 0x72, 0x52, 0x4b, 0x74, 0x36, 0x61, 0x74, 0x48, 0x36, 0x37, 0x67, 0x42, + 0x68, 0x62, 0x69, 0x6d, 0x31, 0x76, 0x5a, 0x5a, 0x33, 0x52, 0x72, 0x58, + 0x59, 0x43, 0x50, 0x0a, 0x4b, 0x5a, 0x32, 0x47, 0x47, 0x39, 0x6d, 0x63, + 0x44, 0x5a, 0x68, 0x74, 0x64, 0x68, 0x41, 0x6f, 0x57, 0x4f, 0x52, 0x6c, + 0x73, 0x48, 0x39, 0x4b, 0x6d, 0x48, 0x6d, 0x66, 0x34, 0x4d, 0x4d, 0x78, + 0x66, 0x6f, 0x41, 0x72, 0x74, 0x59, 0x7a, 0x41, 0x51, 0x44, 0x73, 0x52, + 0x68, 0x74, 0x44, 0x4c, 0x6f, 0x6f, 0x59, 0x32, 0x59, 0x4b, 0x54, 0x56, + 0x4d, 0x49, 0x4a, 0x74, 0x32, 0x57, 0x37, 0x51, 0x0a, 0x44, 0x78, 0x49, + 0x45, 0x4d, 0x35, 0x64, 0x66, 0x54, 0x32, 0x46, 0x61, 0x38, 0x4f, 0x54, + 0x35, 0x6b, 0x61, 0x76, 0x6e, 0x48, 0x54, 0x75, 0x38, 0x36, 0x4d, 0x2f, + 0x30, 0x61, 0x79, 0x30, 0x30, 0x66, 0x4f, 0x4a, 0x49, 0x59, 0x52, 0x79, + 0x4f, 0x38, 0x32, 0x46, 0x45, 0x7a, 0x47, 0x2b, 0x67, 0x53, 0x71, 0x6d, + 0x55, 0x73, 0x45, 0x33, 0x61, 0x35, 0x36, 0x6b, 0x30, 0x65, 0x6e, 0x49, + 0x34, 0x0a, 0x71, 0x45, 0x48, 0x4d, 0x50, 0x4a, 0x51, 0x52, 0x66, 0x65, + 0x76, 0x49, 0x70, 0x6f, 0x79, 0x33, 0x68, 0x73, 0x76, 0x4b, 0x4d, 0x7a, + 0x76, 0x5a, 0x50, 0x54, 0x65, 0x4c, 0x2b, 0x33, 0x6f, 0x2b, 0x68, 0x69, + 0x7a, 0x6e, 0x63, 0x39, 0x63, 0x4b, 0x56, 0x36, 0x78, 0x6b, 0x6d, 0x78, + 0x6e, 0x72, 0x39, 0x41, 0x38, 0x45, 0x43, 0x49, 0x71, 0x73, 0x41, 0x78, + 0x63, 0x5a, 0x5a, 0x50, 0x52, 0x61, 0x0a, 0x4a, 0x53, 0x4b, 0x4e, 0x4e, + 0x43, 0x79, 0x79, 0x39, 0x6d, 0x67, 0x64, 0x45, 0x6d, 0x33, 0x54, 0x69, + 0x68, 0x34, 0x55, 0x32, 0x73, 0x53, 0x50, 0x70, 0x75, 0x49, 0x6a, 0x68, + 0x64, 0x56, 0x36, 0x44, 0x62, 0x31, 0x71, 0x34, 0x4f, 0x6e, 0x73, 0x37, + 0x42, 0x65, 0x37, 0x51, 0x68, 0x74, 0x6e, 0x71, 0x69, 0x58, 0x74, 0x52, + 0x59, 0x4d, 0x68, 0x2f, 0x4d, 0x48, 0x4a, 0x66, 0x4e, 0x56, 0x69, 0x0a, + 0x50, 0x76, 0x72, 0x79, 0x78, 0x53, 0x33, 0x54, 0x2f, 0x64, 0x52, 0x6c, + 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x67, 0x5a, 0x38, 0x77, + 0x67, 0x5a, 0x77, 0x77, 0x45, 0x77, 0x59, 0x4a, 0x4b, 0x77, 0x59, 0x42, + 0x42, 0x41, 0x47, 0x43, 0x4e, 0x78, 0x51, 0x43, 0x42, 0x41, 0x59, 0x65, + 0x42, 0x41, 0x42, 0x44, 0x41, 0x45, 0x45, 0x77, 0x43, 0x77, 0x59, 0x44, + 0x56, 0x52, 0x30, 0x50, 0x0a, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x47, + 0x47, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, + 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, + 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, + 0x45, 0x46, 0x4d, 0x5a, 0x50, 0x6f, 0x6a, 0x30, 0x47, 0x59, 0x34, 0x51, + 0x4a, 0x6e, 0x4d, 0x35, 0x69, 0x35, 0x41, 0x53, 0x73, 0x0a, 0x6a, 0x56, + 0x79, 0x31, 0x36, 0x62, 0x59, 0x62, 0x4d, 0x44, 0x59, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x48, 0x77, 0x51, 0x76, 0x4d, 0x43, 0x30, 0x77, 0x4b, 0x36, + 0x41, 0x70, 0x6f, 0x43, 0x65, 0x47, 0x4a, 0x57, 0x68, 0x30, 0x64, 0x48, + 0x41, 0x36, 0x4c, 0x79, 0x39, 0x6a, 0x63, 0x6d, 0x77, 0x75, 0x65, 0x48, + 0x4a, 0x68, 0x62, 0x58, 0x42, 0x7a, 0x5a, 0x57, 0x4e, 0x31, 0x63, 0x6d, + 0x6c, 0x30, 0x0a, 0x65, 0x53, 0x35, 0x6a, 0x62, 0x32, 0x30, 0x76, 0x57, + 0x45, 0x64, 0x44, 0x51, 0x53, 0x35, 0x6a, 0x63, 0x6d, 0x77, 0x77, 0x45, + 0x41, 0x59, 0x4a, 0x4b, 0x77, 0x59, 0x42, 0x42, 0x41, 0x47, 0x43, 0x4e, + 0x78, 0x55, 0x42, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x45, 0x77, 0x44, + 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, + 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x0a, 0x67, 0x67, 0x45, 0x42, + 0x41, 0x4a, 0x45, 0x56, 0x4f, 0x51, 0x4d, 0x42, 0x47, 0x32, 0x66, 0x37, + 0x53, 0x68, 0x7a, 0x35, 0x43, 0x6d, 0x42, 0x62, 0x6f, 0x64, 0x70, 0x4e, + 0x6c, 0x32, 0x4c, 0x35, 0x4a, 0x46, 0x4d, 0x6e, 0x31, 0x34, 0x4a, 0x6b, + 0x54, 0x70, 0x41, 0x75, 0x77, 0x30, 0x6b, 0x62, 0x4b, 0x35, 0x72, 0x63, + 0x2f, 0x4b, 0x68, 0x34, 0x5a, 0x7a, 0x58, 0x78, 0x48, 0x66, 0x41, 0x52, + 0x0a, 0x76, 0x62, 0x64, 0x49, 0x34, 0x78, 0x44, 0x32, 0x44, 0x64, 0x38, + 0x2f, 0x30, 0x73, 0x6d, 0x32, 0x71, 0x6c, 0x57, 0x6b, 0x53, 0x4c, 0x6f, + 0x43, 0x32, 0x39, 0x35, 0x5a, 0x4c, 0x68, 0x56, 0x62, 0x4f, 0x35, 0x30, + 0x57, 0x66, 0x55, 0x66, 0x58, 0x4e, 0x2b, 0x70, 0x66, 0x54, 0x58, 0x59, + 0x53, 0x4e, 0x72, 0x73, 0x66, 0x31, 0x36, 0x47, 0x42, 0x42, 0x45, 0x59, + 0x67, 0x6f, 0x79, 0x78, 0x74, 0x0a, 0x71, 0x5a, 0x34, 0x42, 0x66, 0x6a, + 0x38, 0x70, 0x7a, 0x67, 0x43, 0x54, 0x33, 0x2f, 0x33, 0x4a, 0x6b, 0x6e, + 0x4f, 0x4a, 0x69, 0x57, 0x53, 0x65, 0x35, 0x79, 0x76, 0x6b, 0x48, 0x4a, + 0x45, 0x73, 0x30, 0x72, 0x6e, 0x4f, 0x66, 0x63, 0x35, 0x76, 0x4d, 0x5a, + 0x6e, 0x54, 0x35, 0x72, 0x37, 0x53, 0x48, 0x70, 0x44, 0x77, 0x43, 0x52, + 0x52, 0x35, 0x58, 0x43, 0x4f, 0x72, 0x54, 0x64, 0x4c, 0x61, 0x0a, 0x49, + 0x52, 0x39, 0x4e, 0x6d, 0x58, 0x6d, 0x64, 0x34, 0x63, 0x38, 0x6e, 0x6e, + 0x78, 0x43, 0x62, 0x48, 0x49, 0x67, 0x4e, 0x73, 0x49, 0x70, 0x6b, 0x51, + 0x54, 0x47, 0x34, 0x44, 0x6d, 0x79, 0x51, 0x4a, 0x4b, 0x53, 0x62, 0x58, + 0x48, 0x47, 0x50, 0x75, 0x72, 0x74, 0x2b, 0x48, 0x42, 0x76, 0x62, 0x61, + 0x6f, 0x41, 0x50, 0x49, 0x62, 0x7a, 0x70, 0x32, 0x36, 0x61, 0x33, 0x51, + 0x50, 0x53, 0x79, 0x0a, 0x69, 0x36, 0x6d, 0x78, 0x35, 0x4f, 0x2b, 0x61, + 0x47, 0x74, 0x41, 0x39, 0x61, 0x5a, 0x6e, 0x75, 0x71, 0x43, 0x69, 0x6a, + 0x34, 0x54, 0x79, 0x7a, 0x38, 0x4c, 0x49, 0x52, 0x6e, 0x4d, 0x39, 0x38, + 0x51, 0x4f, 0x62, 0x64, 0x35, 0x30, 0x4e, 0x39, 0x6f, 0x74, 0x67, 0x36, + 0x74, 0x61, 0x6d, 0x4e, 0x38, 0x6a, 0x53, 0x5a, 0x78, 0x4e, 0x51, 0x51, + 0x34, 0x51, 0x62, 0x39, 0x43, 0x59, 0x51, 0x51, 0x0a, 0x4f, 0x2b, 0x37, + 0x45, 0x54, 0x50, 0x54, 0x73, 0x4a, 0x33, 0x78, 0x43, 0x77, 0x6e, 0x52, + 0x38, 0x67, 0x6f, 0x6f, 0x4a, 0x79, 0x62, 0x51, 0x44, 0x4a, 0x62, 0x77, + 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x4f, 0x3d, 0x54, 0x68, 0x65, 0x20, 0x47, 0x6f, 0x20, + 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2c, + 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x47, 0x6f, 0x20, + 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, + 0x32, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, + 0x20, 0x4f, 0x3d, 0x54, 0x68, 0x65, 0x20, 0x47, 0x6f, 0x20, 0x44, 0x61, + 0x64, 0x64, 0x79, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x47, 0x6f, 0x20, 0x44, 0x61, + 0x64, 0x64, 0x79, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, + 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x6f, + 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, + 0x20, 0x32, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x39, 0x31, 0x3a, 0x64, 0x65, 0x3a, 0x30, 0x36, 0x3a, 0x32, + 0x35, 0x3a, 0x61, 0x62, 0x3a, 0x64, 0x61, 0x3a, 0x66, 0x64, 0x3a, 0x33, + 0x32, 0x3a, 0x31, 0x37, 0x3a, 0x30, 0x63, 0x3a, 0x62, 0x62, 0x3a, 0x32, + 0x35, 0x3a, 0x31, 0x37, 0x3a, 0x32, 0x61, 0x3a, 0x38, 0x34, 0x3a, 0x36, + 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x37, + 0x3a, 0x39, 0x36, 0x3a, 0x62, 0x61, 0x3a, 0x65, 0x36, 0x3a, 0x33, 0x66, + 0x3a, 0x31, 0x38, 0x3a, 0x30, 0x31, 0x3a, 0x65, 0x32, 0x3a, 0x37, 0x37, + 0x3a, 0x32, 0x36, 0x3a, 0x31, 0x62, 0x3a, 0x61, 0x30, 0x3a, 0x64, 0x37, + 0x3a, 0x37, 0x37, 0x3a, 0x37, 0x30, 0x3a, 0x30, 0x32, 0x3a, 0x38, 0x66, + 0x3a, 0x32, 0x30, 0x3a, 0x65, 0x65, 0x3a, 0x65, 0x34, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x33, 0x3a, 0x38, + 0x34, 0x3a, 0x36, 0x62, 0x3a, 0x66, 0x32, 0x3a, 0x34, 0x62, 0x3a, 0x39, + 0x65, 0x3a, 0x39, 0x33, 0x3a, 0x63, 0x61, 0x3a, 0x36, 0x34, 0x3a, 0x32, + 0x37, 0x3a, 0x34, 0x63, 0x3a, 0x30, 0x65, 0x3a, 0x63, 0x36, 0x3a, 0x37, + 0x63, 0x3a, 0x31, 0x65, 0x3a, 0x63, 0x63, 0x3a, 0x35, 0x65, 0x3a, 0x30, + 0x32, 0x3a, 0x34, 0x66, 0x3a, 0x66, 0x63, 0x3a, 0x61, 0x63, 0x3a, 0x64, + 0x32, 0x3a, 0x64, 0x37, 0x3a, 0x34, 0x30, 0x3a, 0x31, 0x39, 0x3a, 0x33, + 0x35, 0x3a, 0x30, 0x65, 0x3a, 0x38, 0x31, 0x3a, 0x66, 0x65, 0x3a, 0x35, + 0x34, 0x3a, 0x36, 0x61, 0x3a, 0x65, 0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x45, 0x41, 0x44, 0x43, 0x43, 0x41, 0x75, 0x69, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x44, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x6a, 0x4d, 0x51, 0x73, 0x77, + 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, + 0x55, 0x7a, 0x45, 0x68, 0x0a, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x68, 0x4d, 0x59, 0x56, 0x47, 0x68, 0x6c, 0x49, 0x45, 0x64, + 0x76, 0x49, 0x45, 0x52, 0x68, 0x5a, 0x47, 0x52, 0x35, 0x49, 0x45, 0x64, + 0x79, 0x62, 0x33, 0x56, 0x77, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, + 0x75, 0x4d, 0x54, 0x45, 0x77, 0x4c, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x4c, 0x45, 0x79, 0x68, 0x48, 0x62, 0x79, 0x42, 0x45, 0x0a, 0x59, 0x57, + 0x52, 0x6b, 0x65, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, + 0x41, 0x79, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, + 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, + 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x42, + 0x34, 0x58, 0x44, 0x54, 0x41, 0x30, 0x4d, 0x44, 0x59, 0x79, 0x4f, 0x54, + 0x45, 0x33, 0x0a, 0x4d, 0x44, 0x59, 0x79, 0x4d, 0x46, 0x6f, 0x58, 0x44, + 0x54, 0x4d, 0x30, 0x4d, 0x44, 0x59, 0x79, 0x4f, 0x54, 0x45, 0x33, 0x4d, + 0x44, 0x59, 0x79, 0x4d, 0x46, 0x6f, 0x77, 0x59, 0x7a, 0x45, 0x4c, 0x4d, + 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, + 0x56, 0x4d, 0x78, 0x49, 0x54, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x6f, 0x54, 0x47, 0x46, 0x52, 0x6f, 0x0a, 0x5a, 0x53, 0x42, 0x48, + 0x62, 0x79, 0x42, 0x45, 0x59, 0x57, 0x52, 0x6b, 0x65, 0x53, 0x42, 0x48, + 0x63, 0x6d, 0x39, 0x31, 0x63, 0x43, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, + 0x4c, 0x6a, 0x45, 0x78, 0x4d, 0x43, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x78, 0x4d, 0x6f, 0x52, 0x32, 0x38, 0x67, 0x52, 0x47, 0x46, 0x6b, + 0x5a, 0x48, 0x6b, 0x67, 0x51, 0x32, 0x78, 0x68, 0x63, 0x33, 0x4d, 0x67, + 0x0a, 0x4d, 0x69, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, + 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, + 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, 0x43, + 0x43, 0x41, 0x53, 0x41, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, + 0x44, 0x67, 0x67, 0x45, 0x4e, 0x0a, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, + 0x67, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4e, 0x36, 0x64, 0x31, 0x2b, + 0x70, 0x58, 0x47, 0x45, 0x6d, 0x68, 0x57, 0x2b, 0x76, 0x58, 0x58, 0x30, + 0x69, 0x47, 0x36, 0x72, 0x37, 0x64, 0x2f, 0x2b, 0x54, 0x76, 0x5a, 0x78, + 0x7a, 0x30, 0x5a, 0x57, 0x69, 0x7a, 0x56, 0x33, 0x47, 0x67, 0x58, 0x6e, + 0x65, 0x37, 0x37, 0x5a, 0x74, 0x4a, 0x36, 0x58, 0x43, 0x41, 0x0a, 0x50, + 0x56, 0x59, 0x59, 0x59, 0x77, 0x68, 0x76, 0x32, 0x76, 0x4c, 0x4d, 0x30, + 0x44, 0x39, 0x2f, 0x41, 0x6c, 0x51, 0x69, 0x56, 0x42, 0x44, 0x59, 0x73, + 0x6f, 0x48, 0x55, 0x77, 0x48, 0x55, 0x39, 0x53, 0x33, 0x2f, 0x48, 0x64, + 0x38, 0x4d, 0x2b, 0x65, 0x4b, 0x73, 0x61, 0x41, 0x37, 0x55, 0x67, 0x61, + 0x79, 0x39, 0x71, 0x4b, 0x37, 0x48, 0x46, 0x69, 0x48, 0x37, 0x45, 0x75, + 0x78, 0x36, 0x77, 0x0a, 0x77, 0x64, 0x68, 0x46, 0x4a, 0x32, 0x2b, 0x71, + 0x4e, 0x31, 0x6a, 0x33, 0x68, 0x79, 0x62, 0x58, 0x32, 0x43, 0x33, 0x32, + 0x71, 0x52, 0x65, 0x33, 0x48, 0x33, 0x49, 0x32, 0x54, 0x71, 0x59, 0x58, + 0x50, 0x32, 0x57, 0x59, 0x6b, 0x74, 0x73, 0x71, 0x62, 0x6c, 0x32, 0x69, + 0x2f, 0x6f, 0x6a, 0x67, 0x43, 0x39, 0x35, 0x2f, 0x35, 0x59, 0x30, 0x56, + 0x34, 0x65, 0x76, 0x4c, 0x4f, 0x74, 0x58, 0x69, 0x0a, 0x45, 0x71, 0x49, + 0x54, 0x4c, 0x64, 0x69, 0x4f, 0x72, 0x31, 0x38, 0x53, 0x50, 0x61, 0x41, + 0x49, 0x42, 0x51, 0x69, 0x32, 0x58, 0x4b, 0x56, 0x6c, 0x4f, 0x41, 0x52, + 0x46, 0x6d, 0x52, 0x36, 0x6a, 0x59, 0x47, 0x42, 0x30, 0x78, 0x55, 0x47, + 0x6c, 0x63, 0x6d, 0x49, 0x62, 0x59, 0x73, 0x55, 0x66, 0x62, 0x31, 0x38, + 0x61, 0x51, 0x72, 0x34, 0x43, 0x55, 0x57, 0x57, 0x6f, 0x72, 0x69, 0x4d, + 0x59, 0x0a, 0x61, 0x76, 0x78, 0x34, 0x41, 0x36, 0x6c, 0x4e, 0x66, 0x34, + 0x44, 0x44, 0x2b, 0x71, 0x74, 0x61, 0x2f, 0x4b, 0x46, 0x41, 0x70, 0x4d, + 0x6f, 0x5a, 0x46, 0x76, 0x36, 0x79, 0x79, 0x4f, 0x39, 0x65, 0x63, 0x77, + 0x33, 0x75, 0x64, 0x37, 0x32, 0x61, 0x39, 0x6e, 0x6d, 0x59, 0x76, 0x4c, + 0x45, 0x48, 0x5a, 0x36, 0x49, 0x56, 0x44, 0x64, 0x32, 0x67, 0x57, 0x4d, + 0x5a, 0x45, 0x65, 0x77, 0x6f, 0x2b, 0x0a, 0x59, 0x69, 0x68, 0x66, 0x75, + 0x6b, 0x45, 0x48, 0x55, 0x31, 0x6a, 0x50, 0x45, 0x58, 0x34, 0x34, 0x64, + 0x4d, 0x58, 0x34, 0x2f, 0x37, 0x56, 0x70, 0x6b, 0x49, 0x2b, 0x45, 0x64, + 0x4f, 0x71, 0x58, 0x47, 0x36, 0x38, 0x43, 0x41, 0x51, 0x4f, 0x6a, 0x67, + 0x63, 0x41, 0x77, 0x67, 0x62, 0x30, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4e, 0x4c, 0x45, 0x0a, + 0x73, 0x4e, 0x4b, 0x52, 0x31, 0x45, 0x77, 0x52, 0x63, 0x62, 0x4e, 0x68, + 0x79, 0x7a, 0x32, 0x68, 0x2f, 0x74, 0x32, 0x6f, 0x61, 0x74, 0x54, 0x6a, + 0x4d, 0x49, 0x47, 0x4e, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, + 0x67, 0x59, 0x55, 0x77, 0x67, 0x59, 0x4b, 0x41, 0x46, 0x4e, 0x4c, 0x45, + 0x73, 0x4e, 0x4b, 0x52, 0x31, 0x45, 0x77, 0x52, 0x63, 0x62, 0x4e, 0x68, + 0x79, 0x7a, 0x32, 0x68, 0x0a, 0x2f, 0x74, 0x32, 0x6f, 0x61, 0x74, 0x54, + 0x6a, 0x6f, 0x57, 0x65, 0x6b, 0x5a, 0x54, 0x42, 0x6a, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, + 0x56, 0x55, 0x7a, 0x45, 0x68, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x68, 0x4d, 0x59, 0x56, 0x47, 0x68, 0x6c, 0x49, 0x45, 0x64, + 0x76, 0x49, 0x45, 0x52, 0x68, 0x5a, 0x47, 0x52, 0x35, 0x0a, 0x49, 0x45, + 0x64, 0x79, 0x62, 0x33, 0x56, 0x77, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, + 0x4d, 0x75, 0x4d, 0x54, 0x45, 0x77, 0x4c, 0x77, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4c, 0x45, 0x79, 0x68, 0x48, 0x62, 0x79, 0x42, 0x45, 0x59, 0x57, + 0x52, 0x6b, 0x65, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, + 0x41, 0x79, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, + 0x6c, 0x6a, 0x0a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, + 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x67, + 0x67, 0x45, 0x41, 0x4d, 0x41, 0x77, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, + 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x44, + 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, + 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x0a, 0x67, 0x67, 0x45, 0x42, + 0x41, 0x44, 0x4a, 0x4c, 0x38, 0x37, 0x4c, 0x4b, 0x50, 0x70, 0x48, 0x38, + 0x45, 0x73, 0x61, 0x68, 0x42, 0x34, 0x79, 0x4f, 0x64, 0x36, 0x41, 0x7a, + 0x42, 0x68, 0x52, 0x63, 0x6b, 0x42, 0x34, 0x59, 0x39, 0x77, 0x69, 0x6d, + 0x50, 0x51, 0x6f, 0x5a, 0x2b, 0x59, 0x65, 0x41, 0x45, 0x57, 0x35, 0x70, + 0x35, 0x4a, 0x59, 0x58, 0x4d, 0x50, 0x38, 0x30, 0x6b, 0x57, 0x4e, 0x79, + 0x0a, 0x4f, 0x4f, 0x37, 0x4d, 0x48, 0x41, 0x47, 0x6a, 0x48, 0x5a, 0x51, + 0x6f, 0x70, 0x44, 0x48, 0x32, 0x65, 0x73, 0x52, 0x55, 0x31, 0x2f, 0x62, + 0x6c, 0x4d, 0x56, 0x67, 0x44, 0x6f, 0x73, 0x7a, 0x4f, 0x59, 0x74, 0x75, + 0x55, 0x52, 0x58, 0x4f, 0x31, 0x76, 0x30, 0x58, 0x4a, 0x4a, 0x4c, 0x58, + 0x56, 0x67, 0x67, 0x4b, 0x74, 0x49, 0x33, 0x6c, 0x70, 0x6a, 0x62, 0x69, + 0x32, 0x54, 0x63, 0x37, 0x50, 0x0a, 0x54, 0x4d, 0x6f, 0x7a, 0x49, 0x2b, + 0x67, 0x63, 0x69, 0x4b, 0x71, 0x64, 0x69, 0x30, 0x46, 0x75, 0x46, 0x73, + 0x6b, 0x67, 0x35, 0x59, 0x6d, 0x65, 0x7a, 0x54, 0x76, 0x61, 0x63, 0x50, + 0x64, 0x2b, 0x6d, 0x53, 0x59, 0x67, 0x46, 0x46, 0x51, 0x6c, 0x71, 0x32, + 0x35, 0x7a, 0x68, 0x65, 0x61, 0x62, 0x49, 0x5a, 0x30, 0x4b, 0x62, 0x49, + 0x49, 0x4f, 0x71, 0x50, 0x6a, 0x43, 0x44, 0x50, 0x6f, 0x51, 0x0a, 0x48, + 0x6d, 0x79, 0x57, 0x37, 0x34, 0x63, 0x4e, 0x78, 0x41, 0x39, 0x68, 0x69, + 0x36, 0x33, 0x75, 0x67, 0x79, 0x75, 0x56, 0x2b, 0x49, 0x36, 0x53, 0x68, + 0x48, 0x49, 0x35, 0x36, 0x79, 0x44, 0x71, 0x67, 0x2b, 0x32, 0x44, 0x7a, + 0x5a, 0x64, 0x75, 0x43, 0x4c, 0x7a, 0x72, 0x54, 0x69, 0x61, 0x32, 0x63, + 0x79, 0x76, 0x6b, 0x30, 0x2f, 0x5a, 0x4d, 0x2f, 0x69, 0x5a, 0x78, 0x34, + 0x6d, 0x45, 0x52, 0x0a, 0x64, 0x45, 0x72, 0x2f, 0x56, 0x78, 0x71, 0x48, + 0x44, 0x33, 0x56, 0x49, 0x4c, 0x73, 0x39, 0x52, 0x61, 0x52, 0x65, 0x67, + 0x41, 0x68, 0x4a, 0x68, 0x6c, 0x64, 0x58, 0x52, 0x51, 0x4c, 0x49, 0x51, + 0x54, 0x4f, 0x37, 0x45, 0x72, 0x42, 0x42, 0x44, 0x70, 0x71, 0x57, 0x65, + 0x43, 0x74, 0x57, 0x56, 0x59, 0x70, 0x6f, 0x4e, 0x7a, 0x34, 0x69, 0x43, + 0x78, 0x54, 0x49, 0x4d, 0x35, 0x43, 0x75, 0x66, 0x0a, 0x52, 0x65, 0x59, + 0x4e, 0x6e, 0x79, 0x69, 0x63, 0x73, 0x62, 0x6b, 0x71, 0x57, 0x6c, 0x65, + 0x74, 0x4e, 0x77, 0x2b, 0x76, 0x48, 0x58, 0x2f, 0x62, 0x76, 0x5a, 0x38, + 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x4f, 0x3d, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, + 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, + 0x3d, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x43, + 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x4f, 0x3d, 0x53, 0x74, 0x61, 0x72, + 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, + 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x20, 0x4f, 0x55, 0x3d, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x53, 0x74, 0x61, 0x72, + 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, + 0x32, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x33, 0x32, 0x3a, 0x34, 0x61, 0x3a, 0x34, 0x62, 0x3a, 0x62, 0x62, + 0x3a, 0x63, 0x38, 0x3a, 0x36, 0x33, 0x3a, 0x36, 0x39, 0x3a, 0x39, 0x62, + 0x3a, 0x62, 0x65, 0x3a, 0x37, 0x34, 0x3a, 0x39, 0x61, 0x3a, 0x63, 0x36, + 0x3a, 0x64, 0x64, 0x3a, 0x31, 0x64, 0x3a, 0x34, 0x36, 0x3a, 0x32, 0x34, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x64, 0x3a, + 0x37, 0x65, 0x3a, 0x31, 0x63, 0x3a, 0x32, 0x38, 0x3a, 0x62, 0x30, 0x3a, + 0x36, 0x34, 0x3a, 0x65, 0x66, 0x3a, 0x38, 0x66, 0x3a, 0x36, 0x30, 0x3a, + 0x30, 0x33, 0x3a, 0x34, 0x30, 0x3a, 0x32, 0x30, 0x3a, 0x31, 0x34, 0x3a, + 0x63, 0x33, 0x3a, 0x64, 0x30, 0x3a, 0x65, 0x33, 0x3a, 0x33, 0x37, 0x3a, + 0x30, 0x65, 0x3a, 0x62, 0x35, 0x3a, 0x38, 0x61, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x34, 0x3a, 0x36, 0x35, + 0x3a, 0x66, 0x61, 0x3a, 0x32, 0x30, 0x3a, 0x35, 0x33, 0x3a, 0x39, 0x37, + 0x3a, 0x62, 0x38, 0x3a, 0x37, 0x36, 0x3a, 0x66, 0x61, 0x3a, 0x61, 0x36, + 0x3a, 0x66, 0x30, 0x3a, 0x61, 0x39, 0x3a, 0x39, 0x35, 0x3a, 0x38, 0x65, + 0x3a, 0x35, 0x35, 0x3a, 0x39, 0x30, 0x3a, 0x65, 0x34, 0x3a, 0x30, 0x66, + 0x3a, 0x63, 0x63, 0x3a, 0x37, 0x66, 0x3a, 0x61, 0x61, 0x3a, 0x34, 0x66, + 0x3a, 0x62, 0x37, 0x3a, 0x63, 0x32, 0x3a, 0x63, 0x38, 0x3a, 0x36, 0x37, + 0x3a, 0x37, 0x35, 0x3a, 0x32, 0x31, 0x3a, 0x66, 0x62, 0x3a, 0x35, 0x66, + 0x3a, 0x62, 0x36, 0x3a, 0x35, 0x38, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x45, 0x44, 0x7a, 0x43, 0x43, 0x41, 0x76, 0x65, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x44, 0x41, 0x4e, 0x42, + 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, + 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x6f, 0x4d, 0x51, 0x73, 0x77, 0x43, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, + 0x7a, 0x45, 0x6c, 0x0a, 0x4d, 0x43, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x68, 0x4d, 0x63, 0x55, 0x33, 0x52, 0x68, 0x63, 0x6d, 0x5a, 0x70, + 0x5a, 0x57, 0x78, 0x6b, 0x49, 0x46, 0x52, 0x6c, 0x59, 0x32, 0x68, 0x75, + 0x62, 0x32, 0x78, 0x76, 0x5a, 0x32, 0x6c, 0x6c, 0x63, 0x79, 0x77, 0x67, + 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x79, 0x4d, 0x44, 0x41, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x70, 0x0a, 0x55, 0x33, 0x52, + 0x68, 0x63, 0x6d, 0x5a, 0x70, 0x5a, 0x57, 0x78, 0x6b, 0x49, 0x45, 0x4e, + 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44, 0x49, 0x67, 0x51, 0x32, 0x56, + 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, + 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, + 0x70, 0x64, 0x48, 0x6b, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x51, + 0x77, 0x0a, 0x4e, 0x6a, 0x49, 0x35, 0x4d, 0x54, 0x63, 0x7a, 0x4f, 0x54, + 0x45, 0x32, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x51, 0x77, 0x4e, 0x6a, + 0x49, 0x35, 0x4d, 0x54, 0x63, 0x7a, 0x4f, 0x54, 0x45, 0x32, 0x57, 0x6a, + 0x42, 0x6f, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x6c, 0x4d, 0x43, + 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x43, 0x68, 0x4d, 0x63, 0x55, + 0x33, 0x52, 0x68, 0x63, 0x6d, 0x5a, 0x70, 0x5a, 0x57, 0x78, 0x6b, 0x49, + 0x46, 0x52, 0x6c, 0x59, 0x32, 0x68, 0x75, 0x62, 0x32, 0x78, 0x76, 0x5a, + 0x32, 0x6c, 0x6c, 0x63, 0x79, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, + 0x6a, 0x45, 0x79, 0x4d, 0x44, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x78, 0x4d, 0x70, 0x55, 0x33, 0x52, 0x68, 0x63, 0x6d, 0x5a, 0x70, 0x0a, + 0x5a, 0x57, 0x78, 0x6b, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a, + 0x49, 0x44, 0x49, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, + 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, + 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, + 0x67, 0x67, 0x45, 0x67, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, + 0x53, 0x49, 0x62, 0x33, 0x0a, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, + 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x51, 0x41, 0x77, 0x67, 0x67, 0x45, + 0x49, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x43, 0x33, 0x4d, 0x73, 0x6a, + 0x2b, 0x36, 0x58, 0x47, 0x6d, 0x42, 0x49, 0x57, 0x74, 0x44, 0x42, 0x46, + 0x6b, 0x33, 0x38, 0x35, 0x4e, 0x37, 0x38, 0x67, 0x44, 0x47, 0x49, 0x63, + 0x2f, 0x6f, 0x61, 0x76, 0x37, 0x50, 0x4b, 0x61, 0x66, 0x0a, 0x38, 0x4d, + 0x4f, 0x68, 0x32, 0x74, 0x54, 0x59, 0x62, 0x69, 0x74, 0x54, 0x6b, 0x50, + 0x73, 0x6b, 0x70, 0x44, 0x36, 0x45, 0x38, 0x4a, 0x37, 0x6f, 0x58, 0x2b, + 0x7a, 0x6c, 0x4a, 0x30, 0x54, 0x31, 0x4b, 0x4b, 0x59, 0x2f, 0x65, 0x39, + 0x37, 0x67, 0x4b, 0x76, 0x44, 0x49, 0x72, 0x31, 0x4d, 0x76, 0x6e, 0x73, + 0x6f, 0x46, 0x41, 0x5a, 0x4d, 0x65, 0x6a, 0x32, 0x59, 0x63, 0x4f, 0x61, + 0x64, 0x4e, 0x0a, 0x2b, 0x6c, 0x71, 0x32, 0x63, 0x77, 0x51, 0x6c, 0x5a, + 0x75, 0x74, 0x33, 0x66, 0x2b, 0x64, 0x5a, 0x78, 0x6b, 0x71, 0x5a, 0x4a, + 0x52, 0x52, 0x55, 0x36, 0x79, 0x62, 0x48, 0x38, 0x33, 0x38, 0x5a, 0x31, + 0x54, 0x42, 0x77, 0x6a, 0x36, 0x2b, 0x77, 0x52, 0x69, 0x72, 0x2f, 0x72, + 0x65, 0x73, 0x70, 0x37, 0x64, 0x65, 0x66, 0x71, 0x67, 0x53, 0x48, 0x6f, + 0x39, 0x54, 0x35, 0x69, 0x61, 0x55, 0x30, 0x0a, 0x58, 0x39, 0x74, 0x44, + 0x6b, 0x59, 0x49, 0x32, 0x32, 0x57, 0x59, 0x38, 0x73, 0x62, 0x69, 0x35, + 0x67, 0x76, 0x32, 0x63, 0x4f, 0x6a, 0x34, 0x51, 0x79, 0x44, 0x76, 0x76, + 0x42, 0x6d, 0x56, 0x6d, 0x65, 0x70, 0x73, 0x5a, 0x47, 0x44, 0x33, 0x2f, + 0x63, 0x56, 0x45, 0x38, 0x4d, 0x43, 0x35, 0x66, 0x76, 0x6a, 0x31, 0x33, + 0x63, 0x37, 0x4a, 0x64, 0x42, 0x6d, 0x7a, 0x44, 0x49, 0x31, 0x61, 0x61, + 0x0a, 0x4b, 0x34, 0x55, 0x6d, 0x6b, 0x68, 0x79, 0x6e, 0x41, 0x72, 0x50, + 0x6b, 0x50, 0x77, 0x32, 0x76, 0x43, 0x48, 0x6d, 0x43, 0x75, 0x44, 0x59, + 0x39, 0x36, 0x70, 0x7a, 0x54, 0x4e, 0x62, 0x4f, 0x38, 0x61, 0x63, 0x72, + 0x31, 0x7a, 0x4a, 0x33, 0x6f, 0x2f, 0x57, 0x53, 0x4e, 0x46, 0x34, 0x41, + 0x7a, 0x62, 0x6c, 0x35, 0x4b, 0x58, 0x5a, 0x6e, 0x4a, 0x48, 0x6f, 0x65, + 0x30, 0x6e, 0x52, 0x72, 0x41, 0x0a, 0x31, 0x57, 0x34, 0x54, 0x4e, 0x53, + 0x4e, 0x65, 0x33, 0x35, 0x74, 0x66, 0x50, 0x65, 0x2f, 0x57, 0x39, 0x33, + 0x62, 0x43, 0x36, 0x6a, 0x36, 0x37, 0x65, 0x41, 0x30, 0x63, 0x51, 0x6d, + 0x64, 0x72, 0x42, 0x4e, 0x6a, 0x34, 0x31, 0x74, 0x70, 0x76, 0x69, 0x2f, + 0x4a, 0x45, 0x6f, 0x41, 0x47, 0x72, 0x41, 0x67, 0x45, 0x44, 0x6f, 0x34, + 0x48, 0x46, 0x4d, 0x49, 0x48, 0x43, 0x4d, 0x42, 0x30, 0x47, 0x0a, 0x41, + 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x53, 0x2f, 0x58, + 0x37, 0x66, 0x52, 0x7a, 0x74, 0x30, 0x66, 0x68, 0x76, 0x52, 0x62, 0x56, + 0x61, 0x7a, 0x63, 0x31, 0x78, 0x44, 0x43, 0x44, 0x71, 0x6d, 0x49, 0x35, + 0x7a, 0x43, 0x42, 0x6b, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6a, 0x42, + 0x49, 0x47, 0x4b, 0x4d, 0x49, 0x47, 0x48, 0x67, 0x42, 0x53, 0x2f, 0x58, + 0x37, 0x66, 0x52, 0x0a, 0x7a, 0x74, 0x30, 0x66, 0x68, 0x76, 0x52, 0x62, + 0x56, 0x61, 0x7a, 0x63, 0x31, 0x78, 0x44, 0x43, 0x44, 0x71, 0x6d, 0x49, + 0x35, 0x36, 0x46, 0x73, 0x70, 0x47, 0x6f, 0x77, 0x61, 0x44, 0x45, 0x4c, + 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, + 0x56, 0x56, 0x4d, 0x78, 0x4a, 0x54, 0x41, 0x6a, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x6f, 0x54, 0x48, 0x46, 0x4e, 0x30, 0x0a, 0x59, 0x58, 0x4a, + 0x6d, 0x61, 0x57, 0x56, 0x73, 0x5a, 0x43, 0x42, 0x55, 0x5a, 0x57, 0x4e, + 0x6f, 0x62, 0x6d, 0x39, 0x73, 0x62, 0x32, 0x64, 0x70, 0x5a, 0x58, 0x4d, + 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x4d, 0x6a, 0x41, + 0x77, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x4b, 0x56, 0x4e, + 0x30, 0x59, 0x58, 0x4a, 0x6d, 0x61, 0x57, 0x56, 0x73, 0x5a, 0x43, 0x42, + 0x44, 0x0a, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, 0x41, 0x79, 0x49, 0x45, + 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, + 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, + 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x67, 0x67, 0x45, 0x41, 0x4d, 0x41, + 0x77, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x51, 0x46, 0x4d, 0x41, + 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x0a, 0x44, 0x51, 0x59, 0x4a, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, + 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x41, 0x57, 0x64, 0x50, + 0x34, 0x69, 0x64, 0x30, 0x63, 0x6b, 0x61, 0x56, 0x61, 0x47, 0x73, 0x61, + 0x66, 0x50, 0x7a, 0x57, 0x64, 0x71, 0x62, 0x41, 0x59, 0x63, 0x61, 0x54, + 0x31, 0x65, 0x70, 0x6f, 0x58, 0x6b, 0x4a, 0x4b, 0x74, 0x76, 0x33, 0x0a, + 0x4c, 0x37, 0x49, 0x65, 0x7a, 0x4d, 0x64, 0x65, 0x61, 0x74, 0x69, 0x44, + 0x68, 0x36, 0x47, 0x58, 0x37, 0x30, 0x6b, 0x31, 0x50, 0x6e, 0x63, 0x47, + 0x51, 0x56, 0x68, 0x69, 0x76, 0x34, 0x35, 0x59, 0x75, 0x41, 0x70, 0x6e, + 0x50, 0x2b, 0x79, 0x7a, 0x33, 0x53, 0x46, 0x6d, 0x48, 0x38, 0x6c, 0x55, + 0x2b, 0x6e, 0x4c, 0x4d, 0x50, 0x55, 0x78, 0x41, 0x32, 0x49, 0x47, 0x76, + 0x64, 0x35, 0x36, 0x44, 0x0a, 0x65, 0x72, 0x75, 0x69, 0x78, 0x2f, 0x55, + 0x30, 0x46, 0x34, 0x37, 0x5a, 0x45, 0x55, 0x44, 0x30, 0x2f, 0x43, 0x77, + 0x71, 0x54, 0x52, 0x56, 0x2f, 0x70, 0x32, 0x4a, 0x64, 0x4c, 0x69, 0x58, + 0x54, 0x41, 0x41, 0x73, 0x67, 0x47, 0x68, 0x31, 0x6f, 0x2b, 0x52, 0x65, + 0x34, 0x39, 0x4c, 0x32, 0x4c, 0x37, 0x53, 0x68, 0x5a, 0x33, 0x55, 0x30, + 0x57, 0x69, 0x78, 0x65, 0x44, 0x79, 0x4c, 0x4a, 0x6c, 0x0a, 0x78, 0x79, + 0x31, 0x36, 0x70, 0x61, 0x71, 0x38, 0x55, 0x34, 0x5a, 0x74, 0x33, 0x56, + 0x65, 0x6b, 0x79, 0x76, 0x67, 0x67, 0x51, 0x51, 0x74, 0x6f, 0x38, 0x50, + 0x54, 0x37, 0x64, 0x4c, 0x35, 0x57, 0x58, 0x58, 0x70, 0x35, 0x39, 0x66, + 0x6b, 0x64, 0x68, 0x65, 0x4d, 0x74, 0x6c, 0x62, 0x37, 0x31, 0x63, 0x5a, + 0x42, 0x44, 0x7a, 0x49, 0x30, 0x66, 0x6d, 0x67, 0x41, 0x4b, 0x68, 0x79, + 0x6e, 0x70, 0x0a, 0x56, 0x53, 0x4a, 0x59, 0x41, 0x43, 0x50, 0x71, 0x34, + 0x78, 0x4a, 0x44, 0x4b, 0x56, 0x74, 0x48, 0x43, 0x4e, 0x32, 0x4d, 0x51, + 0x57, 0x70, 0x6c, 0x42, 0x71, 0x6a, 0x6c, 0x49, 0x61, 0x70, 0x42, 0x74, + 0x4a, 0x55, 0x68, 0x6c, 0x62, 0x6c, 0x39, 0x30, 0x54, 0x53, 0x72, 0x45, + 0x39, 0x61, 0x74, 0x76, 0x4e, 0x7a, 0x69, 0x50, 0x54, 0x6e, 0x4e, 0x76, + 0x54, 0x35, 0x31, 0x63, 0x4b, 0x45, 0x59, 0x0a, 0x57, 0x51, 0x50, 0x4a, + 0x49, 0x72, 0x53, 0x50, 0x6e, 0x4e, 0x56, 0x65, 0x4b, 0x74, 0x65, 0x6c, + 0x74, 0x74, 0x51, 0x4b, 0x62, 0x66, 0x69, 0x33, 0x51, 0x42, 0x46, 0x47, + 0x6d, 0x68, 0x39, 0x35, 0x44, 0x6d, 0x4b, 0x2f, 0x44, 0x35, 0x66, 0x73, + 0x34, 0x43, 0x38, 0x66, 0x46, 0x35, 0x51, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, + 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x4f, 0x3d, + 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x3a, 0x20, 0x4f, 0x3d, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, + 0x65, 0x6e, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x54, 0x61, 0x69, 0x77, 0x61, + 0x6e, 0x20, 0x47, 0x52, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x34, 0x32, 0x30, 0x32, 0x33, 0x30, + 0x37, 0x30, 0x38, 0x30, 0x37, 0x37, 0x30, 0x38, 0x37, 0x32, 0x34, 0x31, + 0x35, 0x39, 0x39, 0x39, 0x31, 0x31, 0x34, 0x30, 0x35, 0x35, 0x36, 0x35, + 0x32, 0x37, 0x30, 0x36, 0x36, 0x38, 0x37, 0x30, 0x0a, 0x23, 0x20, 0x4d, + 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x37, 0x3a, 0x38, 0x35, 0x3a, 0x34, 0x34, + 0x3a, 0x35, 0x33, 0x3a, 0x33, 0x32, 0x3a, 0x34, 0x35, 0x3a, 0x31, 0x66, + 0x3a, 0x32, 0x30, 0x3a, 0x66, 0x30, 0x3a, 0x66, 0x33, 0x3a, 0x39, 0x35, + 0x3a, 0x65, 0x31, 0x3a, 0x32, 0x35, 0x3a, 0x63, 0x34, 0x3a, 0x34, 0x33, + 0x3a, 0x34, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x66, 0x34, 0x3a, 0x38, 0x62, 0x3a, 0x31, 0x31, 0x3a, 0x62, 0x66, 0x3a, + 0x64, 0x65, 0x3a, 0x61, 0x62, 0x3a, 0x62, 0x65, 0x3a, 0x39, 0x34, 0x3a, + 0x35, 0x34, 0x3a, 0x32, 0x30, 0x3a, 0x37, 0x31, 0x3a, 0x65, 0x36, 0x3a, + 0x34, 0x31, 0x3a, 0x64, 0x65, 0x3a, 0x36, 0x62, 0x3a, 0x62, 0x65, 0x3a, + 0x38, 0x38, 0x3a, 0x32, 0x62, 0x3a, 0x34, 0x30, 0x3a, 0x62, 0x39, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x36, + 0x3a, 0x30, 0x30, 0x3a, 0x32, 0x39, 0x3a, 0x35, 0x65, 0x3a, 0x65, 0x66, + 0x3a, 0x65, 0x38, 0x3a, 0x35, 0x62, 0x3a, 0x39, 0x65, 0x3a, 0x31, 0x66, + 0x3a, 0x64, 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x64, 0x62, 0x3a, 0x37, 0x36, + 0x3a, 0x30, 0x36, 0x3a, 0x32, 0x61, 0x3a, 0x61, 0x61, 0x3a, 0x61, 0x65, + 0x3a, 0x35, 0x39, 0x3a, 0x38, 0x31, 0x3a, 0x38, 0x61, 0x3a, 0x35, 0x34, + 0x3a, 0x64, 0x32, 0x3a, 0x37, 0x37, 0x3a, 0x34, 0x63, 0x3a, 0x64, 0x34, + 0x3a, 0x63, 0x30, 0x3a, 0x62, 0x32, 0x3a, 0x63, 0x30, 0x3a, 0x31, 0x31, + 0x3a, 0x33, 0x31, 0x3a, 0x65, 0x31, 0x3a, 0x62, 0x33, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x63, 0x6a, 0x43, 0x43, 0x41, 0x31, + 0x71, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x48, 0x35, + 0x31, 0x5a, 0x57, 0x74, 0x63, 0x76, 0x77, 0x67, 0x5a, 0x45, 0x70, 0x59, + 0x41, 0x49, 0x61, 0x65, 0x4e, 0x65, 0x39, 0x6a, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x55, 0x46, 0x41, 0x44, 0x41, 0x2f, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x55, 0x56, + 0x7a, 0x45, 0x77, 0x4d, 0x43, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x67, 0x77, 0x6e, 0x52, 0x32, 0x39, 0x32, 0x5a, 0x58, 0x4a, 0x75, 0x62, + 0x57, 0x56, 0x75, 0x64, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, + 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x0a, + 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, + 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x42, 0x34, 0x58, + 0x44, 0x54, 0x41, 0x79, 0x4d, 0x54, 0x49, 0x77, 0x4e, 0x54, 0x45, 0x7a, + 0x4d, 0x6a, 0x4d, 0x7a, 0x4d, 0x31, 0x6f, 0x58, 0x44, 0x54, 0x4d, 0x79, + 0x4d, 0x54, 0x49, 0x77, 0x4e, 0x54, 0x45, 0x7a, 0x4d, 0x6a, 0x4d, 0x7a, + 0x4d, 0x31, 0x6f, 0x77, 0x0a, 0x50, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x46, 0x63, + 0x78, 0x4d, 0x44, 0x41, 0x75, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, + 0x4d, 0x4a, 0x30, 0x64, 0x76, 0x64, 0x6d, 0x56, 0x79, 0x62, 0x6d, 0x31, + 0x6c, 0x62, 0x6e, 0x51, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, + 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x0a, 0x59, 0x32, + 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, + 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, 0x43, 0x43, 0x41, 0x69, + 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, + 0x49, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x67, 0x6f, 0x43, 0x67, 0x67, + 0x49, 0x42, 0x0a, 0x41, 0x4a, 0x6f, 0x6c, 0x75, 0x4f, 0x7a, 0x4d, 0x6f, + 0x6e, 0x57, 0x6f, 0x65, 0x2f, 0x66, 0x4f, 0x57, 0x31, 0x6d, 0x4b, 0x79, + 0x64, 0x47, 0x47, 0x45, 0x67, 0x68, 0x55, 0x37, 0x4a, 0x7a, 0x79, 0x35, + 0x30, 0x62, 0x32, 0x69, 0x50, 0x4e, 0x38, 0x36, 0x61, 0x58, 0x66, 0x54, + 0x45, 0x63, 0x32, 0x70, 0x42, 0x73, 0x42, 0x48, 0x48, 0x38, 0x65, 0x56, + 0x34, 0x71, 0x4e, 0x77, 0x38, 0x58, 0x52, 0x0a, 0x49, 0x65, 0x50, 0x61, + 0x4a, 0x44, 0x39, 0x49, 0x4b, 0x2f, 0x75, 0x66, 0x4c, 0x71, 0x47, 0x55, + 0x35, 0x79, 0x77, 0x63, 0x6b, 0x39, 0x47, 0x2f, 0x47, 0x77, 0x47, 0x48, + 0x55, 0x35, 0x6e, 0x4f, 0x70, 0x2f, 0x55, 0x4b, 0x49, 0x58, 0x5a, 0x33, + 0x2f, 0x36, 0x6d, 0x33, 0x78, 0x6e, 0x4f, 0x55, 0x54, 0x30, 0x62, 0x33, + 0x45, 0x45, 0x6b, 0x33, 0x2b, 0x71, 0x68, 0x5a, 0x53, 0x56, 0x31, 0x71, + 0x0a, 0x67, 0x51, 0x64, 0x57, 0x38, 0x6f, 0x72, 0x35, 0x42, 0x74, 0x44, + 0x33, 0x63, 0x43, 0x4a, 0x4e, 0x74, 0x4c, 0x64, 0x42, 0x75, 0x54, 0x4b, + 0x34, 0x73, 0x66, 0x43, 0x78, 0x77, 0x35, 0x77, 0x2f, 0x63, 0x50, 0x31, + 0x54, 0x33, 0x59, 0x47, 0x71, 0x32, 0x47, 0x4e, 0x34, 0x39, 0x74, 0x68, + 0x54, 0x62, 0x71, 0x47, 0x73, 0x61, 0x6f, 0x51, 0x6b, 0x63, 0x6c, 0x53, + 0x47, 0x78, 0x74, 0x4b, 0x79, 0x0a, 0x79, 0x68, 0x77, 0x4f, 0x65, 0x59, + 0x48, 0x57, 0x74, 0x58, 0x42, 0x69, 0x43, 0x41, 0x45, 0x75, 0x54, 0x6b, + 0x38, 0x4f, 0x31, 0x52, 0x47, 0x76, 0x71, 0x61, 0x2f, 0x6c, 0x6d, 0x72, + 0x2f, 0x63, 0x7a, 0x49, 0x64, 0x74, 0x4a, 0x75, 0x54, 0x4a, 0x56, 0x36, + 0x4c, 0x37, 0x6c, 0x76, 0x6e, 0x4d, 0x34, 0x54, 0x39, 0x54, 0x6a, 0x47, + 0x78, 0x4d, 0x66, 0x70, 0x74, 0x54, 0x43, 0x41, 0x74, 0x73, 0x0a, 0x46, + 0x2f, 0x74, 0x6e, 0x79, 0x4d, 0x4b, 0x74, 0x73, 0x63, 0x32, 0x41, 0x74, + 0x4a, 0x66, 0x63, 0x64, 0x67, 0x45, 0x57, 0x46, 0x65, 0x6c, 0x71, 0x31, + 0x36, 0x54, 0x68, 0x65, 0x45, 0x66, 0x4f, 0x68, 0x74, 0x58, 0x37, 0x4d, + 0x66, 0x50, 0x36, 0x4d, 0x62, 0x34, 0x30, 0x71, 0x69, 0x6a, 0x37, 0x63, + 0x45, 0x77, 0x64, 0x53, 0x63, 0x65, 0x76, 0x4c, 0x4a, 0x31, 0x74, 0x5a, + 0x71, 0x61, 0x32, 0x0a, 0x6a, 0x57, 0x52, 0x2b, 0x74, 0x53, 0x42, 0x71, + 0x6e, 0x54, 0x75, 0x42, 0x74, 0x6f, 0x39, 0x41, 0x41, 0x47, 0x64, 0x4c, + 0x69, 0x59, 0x61, 0x34, 0x7a, 0x47, 0x58, 0x2b, 0x46, 0x56, 0x50, 0x70, + 0x42, 0x4d, 0x48, 0x57, 0x58, 0x78, 0x31, 0x45, 0x31, 0x77, 0x6f, 0x76, + 0x4a, 0x35, 0x70, 0x47, 0x66, 0x61, 0x45, 0x4e, 0x64, 0x61, 0x31, 0x55, + 0x68, 0x68, 0x58, 0x63, 0x53, 0x54, 0x76, 0x78, 0x0a, 0x6c, 0x73, 0x34, + 0x50, 0x6d, 0x36, 0x44, 0x73, 0x6f, 0x33, 0x70, 0x64, 0x76, 0x74, 0x55, + 0x71, 0x64, 0x55, 0x4c, 0x6c, 0x65, 0x39, 0x36, 0x6c, 0x74, 0x71, 0x71, + 0x76, 0x4b, 0x4b, 0x79, 0x73, 0x6b, 0x4b, 0x77, 0x34, 0x74, 0x39, 0x56, + 0x6f, 0x4e, 0x53, 0x5a, 0x36, 0x33, 0x50, 0x63, 0x37, 0x38, 0x2f, 0x31, + 0x46, 0x6d, 0x39, 0x47, 0x37, 0x51, 0x33, 0x68, 0x75, 0x62, 0x2f, 0x46, + 0x43, 0x0a, 0x56, 0x47, 0x71, 0x59, 0x38, 0x41, 0x32, 0x74, 0x6c, 0x2b, + 0x6c, 0x53, 0x58, 0x75, 0x6e, 0x56, 0x61, 0x6e, 0x4c, 0x65, 0x61, 0x76, + 0x63, 0x62, 0x59, 0x42, 0x54, 0x30, 0x70, 0x65, 0x53, 0x32, 0x63, 0x57, + 0x65, 0x71, 0x48, 0x2b, 0x72, 0x69, 0x54, 0x63, 0x46, 0x43, 0x51, 0x50, + 0x35, 0x6e, 0x52, 0x68, 0x63, 0x34, 0x4c, 0x30, 0x63, 0x2f, 0x63, 0x5a, + 0x79, 0x75, 0x35, 0x53, 0x48, 0x4b, 0x0a, 0x59, 0x53, 0x31, 0x74, 0x42, + 0x36, 0x69, 0x45, 0x66, 0x43, 0x33, 0x75, 0x55, 0x53, 0x58, 0x78, 0x59, + 0x35, 0x43, 0x65, 0x2f, 0x65, 0x46, 0x58, 0x69, 0x47, 0x76, 0x76, 0x69, + 0x69, 0x4e, 0x74, 0x73, 0x65, 0x61, 0x39, 0x50, 0x36, 0x33, 0x52, 0x50, + 0x5a, 0x59, 0x4c, 0x68, 0x59, 0x33, 0x4e, 0x61, 0x79, 0x65, 0x37, 0x74, + 0x77, 0x57, 0x62, 0x37, 0x4c, 0x75, 0x52, 0x71, 0x51, 0x6f, 0x48, 0x0a, + 0x45, 0x67, 0x4b, 0x58, 0x54, 0x69, 0x43, 0x51, 0x38, 0x50, 0x38, 0x4e, + 0x48, 0x75, 0x4a, 0x42, 0x4f, 0x39, 0x4e, 0x41, 0x4f, 0x75, 0x65, 0x4e, + 0x58, 0x64, 0x70, 0x6d, 0x35, 0x41, 0x4b, 0x77, 0x42, 0x31, 0x4b, 0x59, + 0x58, 0x41, 0x36, 0x4f, 0x4d, 0x35, 0x7a, 0x43, 0x70, 0x70, 0x58, 0x37, + 0x56, 0x52, 0x6c, 0x75, 0x54, 0x49, 0x36, 0x75, 0x53, 0x77, 0x2b, 0x39, + 0x77, 0x54, 0x68, 0x4e, 0x0a, 0x58, 0x6f, 0x2b, 0x45, 0x48, 0x57, 0x62, + 0x4e, 0x78, 0x57, 0x43, 0x57, 0x74, 0x46, 0x4a, 0x61, 0x42, 0x59, 0x6d, + 0x4f, 0x6c, 0x58, 0x71, 0x59, 0x77, 0x5a, 0x45, 0x38, 0x6c, 0x53, 0x4f, + 0x79, 0x44, 0x76, 0x52, 0x35, 0x74, 0x4d, 0x6c, 0x38, 0x77, 0x55, 0x6f, + 0x68, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x61, 0x6a, 0x42, + 0x6f, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x0a, 0x44, 0x67, + 0x51, 0x57, 0x42, 0x42, 0x54, 0x4d, 0x7a, 0x4f, 0x2f, 0x4d, 0x4b, 0x57, + 0x43, 0x6b, 0x4f, 0x37, 0x47, 0x53, 0x74, 0x6a, 0x7a, 0x36, 0x4d, 0x6d, + 0x4b, 0x50, 0x72, 0x43, 0x55, 0x56, 0x4f, 0x7a, 0x41, 0x4d, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, + 0x48, 0x2f, 0x4d, 0x44, 0x6b, 0x47, 0x42, 0x47, 0x63, 0x71, 0x42, 0x77, + 0x41, 0x45, 0x0a, 0x4d, 0x54, 0x41, 0x76, 0x4d, 0x43, 0x30, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x43, 0x51, 0x59, 0x46, 0x4b, 0x77, 0x34, 0x44, 0x41, + 0x68, 0x6f, 0x46, 0x41, 0x44, 0x41, 0x48, 0x42, 0x67, 0x56, 0x6e, 0x4b, + 0x67, 0x4d, 0x41, 0x41, 0x41, 0x51, 0x55, 0x41, 0x35, 0x76, 0x77, 0x49, + 0x68, 0x50, 0x2f, 0x6c, 0x53, 0x67, 0x32, 0x30, 0x39, 0x79, 0x65, 0x77, + 0x44, 0x4c, 0x37, 0x4d, 0x54, 0x71, 0x4b, 0x0a, 0x55, 0x57, 0x55, 0x77, + 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, + 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x42, + 0x41, 0x45, 0x43, 0x41, 0x53, 0x76, 0x6f, 0x6d, 0x79, 0x63, 0x35, 0x65, + 0x4d, 0x4e, 0x31, 0x50, 0x68, 0x6e, 0x52, 0x32, 0x57, 0x50, 0x57, 0x75, + 0x73, 0x34, 0x4d, 0x7a, 0x65, 0x4b, 0x52, 0x36, 0x64, 0x42, 0x63, 0x5a, + 0x0a, 0x54, 0x75, 0x6c, 0x53, 0x74, 0x62, 0x6e, 0x67, 0x43, 0x6e, 0x52, + 0x69, 0x71, 0x6d, 0x6a, 0x4b, 0x65, 0x4b, 0x42, 0x4d, 0x6d, 0x6f, 0x34, + 0x73, 0x49, 0x79, 0x37, 0x56, 0x61, 0x68, 0x49, 0x6b, 0x76, 0x39, 0x52, + 0x6f, 0x30, 0x34, 0x72, 0x51, 0x32, 0x4a, 0x79, 0x66, 0x74, 0x42, 0x38, + 0x4d, 0x33, 0x6a, 0x68, 0x2b, 0x56, 0x7a, 0x6a, 0x38, 0x6a, 0x65, 0x4a, + 0x50, 0x58, 0x67, 0x79, 0x66, 0x0a, 0x71, 0x7a, 0x76, 0x53, 0x2f, 0x33, + 0x57, 0x58, 0x79, 0x36, 0x54, 0x6a, 0x5a, 0x77, 0x6a, 0x2f, 0x35, 0x63, + 0x41, 0x57, 0x74, 0x55, 0x67, 0x42, 0x66, 0x65, 0x6e, 0x35, 0x43, 0x76, + 0x38, 0x62, 0x35, 0x57, 0x70, 0x70, 0x76, 0x33, 0x67, 0x68, 0x71, 0x4d, + 0x4b, 0x6e, 0x49, 0x36, 0x6d, 0x47, 0x71, 0x33, 0x5a, 0x57, 0x36, 0x41, + 0x34, 0x4d, 0x39, 0x68, 0x50, 0x64, 0x4b, 0x6d, 0x61, 0x4b, 0x0a, 0x5a, + 0x45, 0x6b, 0x39, 0x47, 0x68, 0x69, 0x48, 0x6b, 0x41, 0x53, 0x66, 0x51, + 0x6c, 0x4b, 0x33, 0x54, 0x38, 0x76, 0x2b, 0x52, 0x30, 0x46, 0x32, 0x4e, + 0x65, 0x2f, 0x2f, 0x41, 0x48, 0x59, 0x32, 0x52, 0x54, 0x4b, 0x62, 0x78, + 0x6b, 0x61, 0x46, 0x58, 0x65, 0x49, 0x6b, 0x73, 0x42, 0x37, 0x6a, 0x53, + 0x4a, 0x61, 0x59, 0x56, 0x30, 0x65, 0x55, 0x56, 0x58, 0x6f, 0x50, 0x51, + 0x62, 0x46, 0x45, 0x0a, 0x4a, 0x50, 0x50, 0x42, 0x2f, 0x68, 0x70, 0x72, + 0x76, 0x34, 0x6a, 0x39, 0x77, 0x61, 0x62, 0x61, 0x6b, 0x32, 0x42, 0x65, + 0x67, 0x55, 0x71, 0x5a, 0x49, 0x4a, 0x78, 0x49, 0x5a, 0x68, 0x6d, 0x31, + 0x41, 0x48, 0x6c, 0x55, 0x44, 0x37, 0x67, 0x73, 0x4c, 0x30, 0x75, 0x38, + 0x71, 0x56, 0x31, 0x62, 0x59, 0x48, 0x2b, 0x4d, 0x68, 0x36, 0x58, 0x67, + 0x55, 0x6d, 0x4d, 0x71, 0x76, 0x74, 0x67, 0x37, 0x0a, 0x68, 0x55, 0x41, + 0x56, 0x2f, 0x68, 0x36, 0x32, 0x5a, 0x54, 0x2f, 0x46, 0x53, 0x39, 0x70, + 0x2b, 0x74, 0x58, 0x6f, 0x31, 0x4b, 0x61, 0x4d, 0x75, 0x65, 0x70, 0x68, + 0x67, 0x49, 0x71, 0x50, 0x30, 0x66, 0x53, 0x64, 0x4f, 0x4c, 0x65, 0x71, + 0x30, 0x64, 0x44, 0x7a, 0x70, 0x44, 0x36, 0x51, 0x7a, 0x44, 0x78, 0x41, + 0x52, 0x76, 0x42, 0x4d, 0x42, 0x31, 0x75, 0x55, 0x4f, 0x30, 0x37, 0x2b, + 0x31, 0x0a, 0x45, 0x71, 0x4c, 0x68, 0x52, 0x53, 0x50, 0x41, 0x7a, 0x41, + 0x68, 0x75, 0x59, 0x62, 0x65, 0x4a, 0x71, 0x34, 0x50, 0x6a, 0x4a, 0x42, + 0x37, 0x6d, 0x58, 0x51, 0x66, 0x6e, 0x48, 0x79, 0x41, 0x2b, 0x7a, 0x32, + 0x66, 0x49, 0x35, 0x36, 0x77, 0x77, 0x62, 0x53, 0x64, 0x4c, 0x61, 0x47, + 0x35, 0x4c, 0x4b, 0x6c, 0x77, 0x43, 0x43, 0x44, 0x54, 0x62, 0x2b, 0x48, + 0x62, 0x6b, 0x5a, 0x36, 0x4d, 0x6d, 0x0a, 0x6e, 0x44, 0x2b, 0x69, 0x4d, + 0x73, 0x4a, 0x4b, 0x78, 0x59, 0x45, 0x59, 0x4d, 0x52, 0x42, 0x57, 0x71, + 0x6f, 0x54, 0x76, 0x4c, 0x51, 0x72, 0x2f, 0x75, 0x42, 0x39, 0x33, 0x30, + 0x72, 0x2b, 0x6c, 0x57, 0x4b, 0x42, 0x69, 0x35, 0x4e, 0x64, 0x4c, 0x6b, + 0x58, 0x57, 0x4e, 0x69, 0x59, 0x43, 0x59, 0x66, 0x6d, 0x33, 0x4c, 0x55, + 0x30, 0x35, 0x65, 0x72, 0x2f, 0x61, 0x79, 0x6c, 0x34, 0x57, 0x58, 0x0a, + 0x75, 0x64, 0x70, 0x56, 0x42, 0x72, 0x6b, 0x6b, 0x37, 0x74, 0x66, 0x47, + 0x4f, 0x42, 0x35, 0x6a, 0x47, 0x78, 0x49, 0x37, 0x6c, 0x65, 0x46, 0x59, + 0x72, 0x50, 0x4c, 0x66, 0x68, 0x4e, 0x56, 0x66, 0x6d, 0x53, 0x38, 0x4e, + 0x56, 0x56, 0x76, 0x6d, 0x4f, 0x4e, 0x73, 0x75, 0x50, 0x33, 0x4c, 0x70, + 0x53, 0x49, 0x58, 0x4c, 0x75, 0x79, 0x6b, 0x54, 0x6a, 0x78, 0x34, 0x34, + 0x56, 0x62, 0x6e, 0x7a, 0x0a, 0x73, 0x73, 0x51, 0x77, 0x6d, 0x53, 0x4e, + 0x4f, 0x58, 0x66, 0x4a, 0x49, 0x6f, 0x52, 0x49, 0x4d, 0x33, 0x42, 0x4b, + 0x51, 0x43, 0x5a, 0x42, 0x55, 0x6b, 0x51, 0x4d, 0x38, 0x52, 0x2b, 0x58, + 0x56, 0x79, 0x57, 0x58, 0x67, 0x74, 0x30, 0x74, 0x39, 0x37, 0x45, 0x66, + 0x54, 0x73, 0x77, 0x73, 0x2b, 0x72, 0x5a, 0x37, 0x51, 0x64, 0x41, 0x41, + 0x4f, 0x36, 0x37, 0x31, 0x52, 0x72, 0x63, 0x44, 0x65, 0x0a, 0x4c, 0x4d, + 0x44, 0x44, 0x61, 0x76, 0x37, 0x76, 0x33, 0x41, 0x75, 0x6e, 0x2b, 0x6b, + 0x62, 0x66, 0x59, 0x4e, 0x75, 0x63, 0x70, 0x6c, 0x6c, 0x51, 0x64, 0x53, + 0x4e, 0x70, 0x63, 0x35, 0x4f, 0x79, 0x2b, 0x66, 0x77, 0x43, 0x30, 0x30, + 0x66, 0x6d, 0x63, 0x63, 0x34, 0x51, 0x41, 0x75, 0x34, 0x6e, 0x6a, 0x49, + 0x54, 0x2f, 0x72, 0x45, 0x55, 0x4e, 0x45, 0x31, 0x79, 0x44, 0x4d, 0x75, + 0x41, 0x6c, 0x0a, 0x70, 0x59, 0x59, 0x73, 0x66, 0x50, 0x51, 0x53, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, + 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x65, 0x64, 0x20, 0x49, 0x44, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, + 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, + 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, + 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x65, + 0x64, 0x20, 0x49, 0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x20, 0x4f, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64, + 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, + 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, + 0x65, 0x64, 0x20, 0x49, 0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x31, 0x37, 0x31, 0x35, 0x34, 0x37, 0x31, 0x37, 0x39, 0x33, 0x34, + 0x31, 0x32, 0x30, 0x35, 0x38, 0x37, 0x38, 0x36, 0x32, 0x31, 0x36, 0x37, + 0x37, 0x39, 0x34, 0x39, 0x31, 0x34, 0x30, 0x37, 0x31, 0x34, 0x32, 0x35, + 0x30, 0x38, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, + 0x37, 0x3a, 0x63, 0x65, 0x3a, 0x30, 0x62, 0x3a, 0x37, 0x62, 0x3a, 0x32, + 0x61, 0x3a, 0x30, 0x65, 0x3a, 0x34, 0x39, 0x3a, 0x30, 0x30, 0x3a, 0x65, + 0x31, 0x3a, 0x35, 0x38, 0x3a, 0x37, 0x31, 0x3a, 0x39, 0x62, 0x3a, 0x33, + 0x37, 0x3a, 0x61, 0x38, 0x3a, 0x39, 0x33, 0x3a, 0x37, 0x32, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x35, 0x3a, 0x36, 0x33, + 0x3a, 0x62, 0x38, 0x3a, 0x36, 0x33, 0x3a, 0x30, 0x64, 0x3a, 0x36, 0x32, + 0x3a, 0x64, 0x37, 0x3a, 0x35, 0x61, 0x3a, 0x62, 0x62, 0x3a, 0x63, 0x38, + 0x3a, 0x61, 0x62, 0x3a, 0x31, 0x65, 0x3a, 0x34, 0x62, 0x3a, 0x64, 0x66, + 0x3a, 0x62, 0x35, 0x3a, 0x61, 0x38, 0x3a, 0x39, 0x39, 0x3a, 0x62, 0x32, + 0x3a, 0x34, 0x64, 0x3a, 0x34, 0x33, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x65, 0x3a, 0x39, 0x30, 0x3a, 0x39, + 0x39, 0x3a, 0x62, 0x35, 0x3a, 0x30, 0x31, 0x3a, 0x35, 0x65, 0x3a, 0x38, + 0x66, 0x3a, 0x34, 0x38, 0x3a, 0x36, 0x63, 0x3a, 0x30, 0x30, 0x3a, 0x62, + 0x63, 0x3a, 0x65, 0x61, 0x3a, 0x39, 0x64, 0x3a, 0x31, 0x31, 0x3a, 0x31, + 0x65, 0x3a, 0x65, 0x37, 0x3a, 0x32, 0x31, 0x3a, 0x66, 0x61, 0x3a, 0x62, + 0x61, 0x3a, 0x33, 0x35, 0x3a, 0x35, 0x61, 0x3a, 0x38, 0x39, 0x3a, 0x62, + 0x63, 0x3a, 0x66, 0x31, 0x3a, 0x64, 0x66, 0x3a, 0x36, 0x39, 0x3a, 0x35, + 0x36, 0x3a, 0x31, 0x65, 0x3a, 0x33, 0x64, 0x3a, 0x63, 0x36, 0x3a, 0x33, + 0x32, 0x3a, 0x35, 0x63, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x44, 0x74, 0x7a, 0x43, 0x43, 0x41, 0x70, 0x2b, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x51, 0x44, 0x4f, 0x66, 0x67, 0x35, 0x52, 0x66, + 0x59, 0x52, 0x76, 0x36, 0x50, 0x35, 0x57, 0x44, 0x38, 0x47, 0x2f, 0x41, + 0x77, 0x4f, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, + 0x6c, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x56, 0x4d, 0x42, + 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4d, 0x52, 0x47, + 0x6c, 0x6e, 0x61, 0x55, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x67, 0x53, 0x57, + 0x35, 0x6a, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4c, 0x45, 0x78, 0x42, 0x33, 0x0a, 0x64, 0x33, 0x63, 0x75, 0x5a, + 0x47, 0x6c, 0x6e, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x75, 0x59, + 0x32, 0x39, 0x74, 0x4d, 0x53, 0x51, 0x77, 0x49, 0x67, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x44, 0x45, 0x78, 0x74, 0x45, 0x61, 0x57, 0x64, 0x70, 0x51, + 0x32, 0x56, 0x79, 0x64, 0x43, 0x42, 0x42, 0x63, 0x33, 0x4e, 0x31, 0x63, + 0x6d, 0x56, 0x6b, 0x49, 0x45, 0x6c, 0x45, 0x49, 0x46, 0x4a, 0x76, 0x0a, + 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x77, 0x48, 0x68, 0x63, 0x4e, + 0x4d, 0x44, 0x59, 0x78, 0x4d, 0x54, 0x45, 0x77, 0x4d, 0x44, 0x41, 0x77, + 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x45, 0x78, + 0x4d, 0x54, 0x45, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, + 0x57, 0x6a, 0x42, 0x6c, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x47, 0x0a, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, + 0x56, 0x4d, 0x42, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, + 0x4d, 0x52, 0x47, 0x6c, 0x6e, 0x61, 0x55, 0x4e, 0x6c, 0x63, 0x6e, 0x51, + 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x42, 0x33, 0x64, 0x33, 0x63, + 0x75, 0x5a, 0x47, 0x6c, 0x6e, 0x61, 0x57, 0x4e, 0x6c, 0x0a, 0x63, 0x6e, + 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4d, 0x53, 0x51, 0x77, 0x49, 0x67, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x74, 0x45, 0x61, 0x57, + 0x64, 0x70, 0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x42, 0x42, 0x63, 0x33, + 0x4e, 0x31, 0x63, 0x6d, 0x56, 0x6b, 0x49, 0x45, 0x6c, 0x45, 0x49, 0x46, + 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x77, 0x67, 0x67, + 0x45, 0x69, 0x0a, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, + 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, + 0x34, 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, + 0x6f, 0x49, 0x42, 0x41, 0x51, 0x43, 0x74, 0x44, 0x68, 0x58, 0x4f, 0x35, + 0x45, 0x4f, 0x41, 0x58, 0x4c, 0x47, 0x48, 0x38, 0x37, 0x64, 0x67, 0x2b, + 0x58, 0x45, 0x53, 0x70, 0x61, 0x37, 0x63, 0x0a, 0x4a, 0x70, 0x53, 0x49, + 0x71, 0x76, 0x54, 0x4f, 0x39, 0x53, 0x41, 0x35, 0x4b, 0x46, 0x68, 0x67, + 0x44, 0x50, 0x69, 0x41, 0x32, 0x71, 0x6b, 0x56, 0x6c, 0x54, 0x4a, 0x68, + 0x50, 0x4c, 0x57, 0x78, 0x4b, 0x49, 0x53, 0x4b, 0x69, 0x74, 0x79, 0x66, + 0x43, 0x67, 0x79, 0x44, 0x46, 0x33, 0x71, 0x50, 0x6b, 0x4b, 0x79, 0x4b, + 0x35, 0x33, 0x6c, 0x54, 0x58, 0x44, 0x47, 0x45, 0x4b, 0x76, 0x59, 0x50, + 0x0a, 0x6d, 0x44, 0x49, 0x32, 0x64, 0x73, 0x7a, 0x65, 0x33, 0x54, 0x79, + 0x6f, 0x6f, 0x75, 0x39, 0x71, 0x2b, 0x79, 0x48, 0x79, 0x55, 0x6d, 0x48, + 0x66, 0x6e, 0x79, 0x44, 0x58, 0x48, 0x2b, 0x4b, 0x78, 0x32, 0x66, 0x34, + 0x59, 0x5a, 0x4e, 0x49, 0x53, 0x57, 0x31, 0x2f, 0x35, 0x57, 0x42, 0x67, + 0x31, 0x76, 0x45, 0x66, 0x4e, 0x6f, 0x54, 0x62, 0x35, 0x61, 0x33, 0x2f, + 0x55, 0x73, 0x44, 0x67, 0x2b, 0x0a, 0x77, 0x52, 0x76, 0x44, 0x6a, 0x44, + 0x50, 0x5a, 0x32, 0x43, 0x38, 0x59, 0x2f, 0x69, 0x67, 0x50, 0x73, 0x36, + 0x65, 0x44, 0x31, 0x73, 0x4e, 0x75, 0x52, 0x4d, 0x42, 0x68, 0x4e, 0x5a, + 0x59, 0x57, 0x2f, 0x6c, 0x6d, 0x63, 0x69, 0x33, 0x5a, 0x74, 0x31, 0x2f, + 0x47, 0x69, 0x53, 0x77, 0x30, 0x72, 0x2f, 0x77, 0x74, 0x79, 0x32, 0x70, + 0x35, 0x67, 0x30, 0x49, 0x36, 0x51, 0x4e, 0x63, 0x5a, 0x34, 0x0a, 0x56, + 0x59, 0x63, 0x67, 0x6f, 0x63, 0x2f, 0x6c, 0x62, 0x51, 0x72, 0x49, 0x53, + 0x58, 0x77, 0x78, 0x6d, 0x44, 0x4e, 0x73, 0x49, 0x75, 0x6d, 0x48, 0x30, + 0x44, 0x4a, 0x61, 0x6f, 0x72, 0x6f, 0x54, 0x67, 0x68, 0x48, 0x74, 0x4f, + 0x52, 0x65, 0x64, 0x6d, 0x54, 0x70, 0x79, 0x6f, 0x65, 0x62, 0x36, 0x70, + 0x4e, 0x6e, 0x56, 0x46, 0x7a, 0x46, 0x31, 0x72, 0x6f, 0x56, 0x39, 0x49, + 0x71, 0x34, 0x2f, 0x0a, 0x41, 0x55, 0x61, 0x47, 0x39, 0x69, 0x68, 0x35, + 0x79, 0x4c, 0x48, 0x61, 0x35, 0x46, 0x63, 0x58, 0x78, 0x48, 0x34, 0x63, + 0x44, 0x72, 0x43, 0x30, 0x6b, 0x71, 0x5a, 0x57, 0x73, 0x37, 0x32, 0x79, + 0x6c, 0x2b, 0x32, 0x71, 0x70, 0x2f, 0x43, 0x33, 0x78, 0x61, 0x67, 0x2f, + 0x6c, 0x52, 0x62, 0x51, 0x2f, 0x36, 0x47, 0x57, 0x36, 0x77, 0x68, 0x66, + 0x47, 0x48, 0x64, 0x50, 0x41, 0x67, 0x4d, 0x42, 0x0a, 0x41, 0x41, 0x47, + 0x6a, 0x59, 0x7a, 0x42, 0x68, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, + 0x42, 0x68, 0x6a, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, + 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, + 0x2f, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, + 0x57, 0x0a, 0x42, 0x42, 0x52, 0x46, 0x36, 0x36, 0x4b, 0x76, 0x39, 0x4a, + 0x4c, 0x4c, 0x67, 0x6a, 0x45, 0x74, 0x55, 0x59, 0x75, 0x6e, 0x70, 0x79, + 0x47, 0x64, 0x38, 0x32, 0x33, 0x49, 0x44, 0x7a, 0x41, 0x66, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, + 0x52, 0x46, 0x36, 0x36, 0x4b, 0x76, 0x39, 0x4a, 0x4c, 0x4c, 0x67, 0x6a, + 0x45, 0x74, 0x55, 0x59, 0x75, 0x6e, 0x0a, 0x70, 0x79, 0x47, 0x64, 0x38, + 0x32, 0x33, 0x49, 0x44, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, + 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x6f, 0x67, 0x36, 0x38, 0x33, + 0x2b, 0x4c, 0x74, 0x38, 0x4f, 0x4e, 0x79, 0x63, 0x33, 0x70, 0x6b, 0x6c, + 0x4c, 0x2f, 0x33, 0x63, 0x6d, 0x62, 0x59, 0x4d, 0x75, 0x52, 0x43, 0x0a, + 0x64, 0x57, 0x4b, 0x75, 0x68, 0x2b, 0x76, 0x79, 0x31, 0x64, 0x6e, 0x65, + 0x56, 0x72, 0x4f, 0x66, 0x7a, 0x4d, 0x34, 0x55, 0x4b, 0x4c, 0x6b, 0x4e, + 0x6c, 0x32, 0x42, 0x63, 0x45, 0x6b, 0x78, 0x59, 0x35, 0x4e, 0x4d, 0x39, + 0x67, 0x30, 0x6c, 0x46, 0x57, 0x4a, 0x63, 0x31, 0x61, 0x52, 0x71, 0x6f, + 0x52, 0x2b, 0x70, 0x57, 0x78, 0x6e, 0x6d, 0x72, 0x45, 0x74, 0x68, 0x6e, + 0x67, 0x59, 0x54, 0x66, 0x0a, 0x66, 0x77, 0x6b, 0x38, 0x6c, 0x4f, 0x61, + 0x34, 0x4a, 0x69, 0x77, 0x67, 0x76, 0x54, 0x32, 0x7a, 0x4b, 0x49, 0x6e, + 0x33, 0x58, 0x2f, 0x38, 0x69, 0x34, 0x70, 0x65, 0x45, 0x48, 0x2b, 0x6c, + 0x6c, 0x37, 0x34, 0x66, 0x67, 0x33, 0x38, 0x46, 0x6e, 0x53, 0x62, 0x4e, + 0x64, 0x36, 0x37, 0x49, 0x4a, 0x4b, 0x75, 0x73, 0x6d, 0x37, 0x58, 0x69, + 0x2b, 0x66, 0x54, 0x38, 0x72, 0x38, 0x37, 0x63, 0x6d, 0x0a, 0x4e, 0x57, + 0x31, 0x66, 0x69, 0x51, 0x47, 0x32, 0x53, 0x56, 0x75, 0x66, 0x41, 0x51, + 0x57, 0x62, 0x71, 0x7a, 0x30, 0x6c, 0x77, 0x63, 0x79, 0x32, 0x66, 0x38, + 0x4c, 0x78, 0x62, 0x34, 0x62, 0x47, 0x2b, 0x6d, 0x52, 0x6f, 0x36, 0x34, + 0x45, 0x74, 0x6c, 0x4f, 0x74, 0x43, 0x74, 0x2f, 0x71, 0x4d, 0x48, 0x74, + 0x31, 0x69, 0x38, 0x62, 0x35, 0x51, 0x5a, 0x37, 0x64, 0x73, 0x76, 0x66, + 0x50, 0x78, 0x0a, 0x48, 0x32, 0x73, 0x4d, 0x4e, 0x67, 0x63, 0x57, 0x66, + 0x7a, 0x64, 0x38, 0x71, 0x56, 0x74, 0x74, 0x65, 0x76, 0x45, 0x53, 0x52, + 0x6d, 0x43, 0x44, 0x31, 0x79, 0x63, 0x45, 0x76, 0x6b, 0x76, 0x4f, 0x6c, + 0x37, 0x37, 0x44, 0x5a, 0x79, 0x70, 0x6f, 0x45, 0x64, 0x2b, 0x41, 0x35, + 0x77, 0x77, 0x7a, 0x5a, 0x72, 0x38, 0x54, 0x44, 0x52, 0x52, 0x75, 0x38, + 0x33, 0x38, 0x66, 0x59, 0x78, 0x41, 0x65, 0x0a, 0x2b, 0x6f, 0x30, 0x62, + 0x4a, 0x57, 0x31, 0x73, 0x6a, 0x36, 0x57, 0x33, 0x59, 0x51, 0x47, 0x78, + 0x30, 0x71, 0x4d, 0x6d, 0x6f, 0x52, 0x42, 0x78, 0x6e, 0x61, 0x33, 0x69, + 0x77, 0x2f, 0x6e, 0x44, 0x6d, 0x56, 0x47, 0x33, 0x4b, 0x77, 0x63, 0x49, + 0x7a, 0x69, 0x37, 0x6d, 0x55, 0x4c, 0x4b, 0x6e, 0x2b, 0x67, 0x70, 0x46, + 0x4c, 0x36, 0x4c, 0x77, 0x38, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, + 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x20, 0x4f, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64, + 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, + 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x20, 0x4f, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, + 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, + 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x44, + 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x30, + 0x39, 0x34, 0x34, 0x37, 0x31, 0x39, 0x35, 0x39, 0x38, 0x39, 0x35, 0x32, + 0x30, 0x34, 0x30, 0x33, 0x37, 0x34, 0x39, 0x35, 0x31, 0x38, 0x33, 0x32, + 0x39, 0x36, 0x33, 0x37, 0x39, 0x34, 0x34, 0x35, 0x34, 0x33, 0x34, 0x36, + 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x39, 0x3a, 0x65, + 0x34, 0x3a, 0x61, 0x39, 0x3a, 0x38, 0x34, 0x3a, 0x30, 0x64, 0x3a, 0x37, + 0x64, 0x3a, 0x33, 0x61, 0x3a, 0x39, 0x36, 0x3a, 0x64, 0x37, 0x3a, 0x63, + 0x30, 0x3a, 0x34, 0x66, 0x3a, 0x65, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x34, + 0x63, 0x3a, 0x38, 0x39, 0x3a, 0x32, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x38, 0x3a, 0x39, 0x38, 0x3a, 0x35, 0x64, + 0x3a, 0x33, 0x61, 0x3a, 0x36, 0x35, 0x3a, 0x65, 0x35, 0x3a, 0x65, 0x35, + 0x3a, 0x63, 0x34, 0x3a, 0x62, 0x32, 0x3a, 0x64, 0x37, 0x3a, 0x64, 0x36, + 0x3a, 0x36, 0x64, 0x3a, 0x34, 0x30, 0x3a, 0x63, 0x36, 0x3a, 0x64, 0x64, + 0x3a, 0x32, 0x66, 0x3a, 0x62, 0x31, 0x3a, 0x39, 0x63, 0x3a, 0x35, 0x34, + 0x3a, 0x33, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x34, 0x33, 0x3a, 0x34, 0x38, 0x3a, 0x61, 0x30, 0x3a, 0x65, + 0x39, 0x3a, 0x34, 0x34, 0x3a, 0x34, 0x63, 0x3a, 0x37, 0x38, 0x3a, 0x63, + 0x62, 0x3a, 0x32, 0x36, 0x3a, 0x35, 0x65, 0x3a, 0x30, 0x35, 0x3a, 0x38, + 0x64, 0x3a, 0x35, 0x65, 0x3a, 0x38, 0x39, 0x3a, 0x34, 0x34, 0x3a, 0x62, + 0x34, 0x3a, 0x64, 0x38, 0x3a, 0x34, 0x66, 0x3a, 0x39, 0x36, 0x3a, 0x36, + 0x32, 0x3a, 0x62, 0x64, 0x3a, 0x32, 0x36, 0x3a, 0x64, 0x62, 0x3a, 0x32, + 0x35, 0x3a, 0x37, 0x66, 0x3a, 0x38, 0x39, 0x3a, 0x33, 0x34, 0x3a, 0x61, + 0x34, 0x3a, 0x34, 0x33, 0x3a, 0x63, 0x37, 0x3a, 0x30, 0x31, 0x3a, 0x36, + 0x31, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x72, 0x7a, + 0x43, 0x43, 0x41, 0x70, 0x65, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, + 0x49, 0x51, 0x43, 0x44, 0x76, 0x67, 0x56, 0x70, 0x42, 0x43, 0x52, 0x72, + 0x47, 0x68, 0x64, 0x57, 0x72, 0x4a, 0x57, 0x5a, 0x48, 0x48, 0x53, 0x6a, + 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, + 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x68, 0x0a, 0x4d, + 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, + 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x56, 0x4d, 0x42, 0x4d, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4d, 0x52, 0x47, 0x6c, 0x6e, 0x61, + 0x55, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d, + 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, + 0x78, 0x42, 0x33, 0x0a, 0x64, 0x33, 0x63, 0x75, 0x5a, 0x47, 0x6c, 0x6e, + 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, + 0x4d, 0x53, 0x41, 0x77, 0x48, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, + 0x45, 0x78, 0x64, 0x45, 0x61, 0x57, 0x64, 0x70, 0x51, 0x32, 0x56, 0x79, + 0x64, 0x43, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x77, 0x67, + 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x0a, 0x51, 0x54, 0x41, + 0x65, 0x46, 0x77, 0x30, 0x77, 0x4e, 0x6a, 0x45, 0x78, 0x4d, 0x54, 0x41, + 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, + 0x7a, 0x4d, 0x54, 0x45, 0x78, 0x4d, 0x54, 0x41, 0x77, 0x4d, 0x44, 0x41, + 0x77, 0x4d, 0x44, 0x42, 0x61, 0x4d, 0x47, 0x45, 0x78, 0x43, 0x7a, 0x41, + 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, + 0x54, 0x0a, 0x4d, 0x52, 0x55, 0x77, 0x45, 0x77, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4b, 0x45, 0x77, 0x78, 0x45, 0x61, 0x57, 0x64, 0x70, 0x51, 0x32, + 0x56, 0x79, 0x64, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x78, 0x47, 0x54, + 0x41, 0x58, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x45, 0x48, + 0x64, 0x33, 0x64, 0x79, 0x35, 0x6b, 0x61, 0x57, 0x64, 0x70, 0x59, 0x32, + 0x56, 0x79, 0x64, 0x43, 0x35, 0x6a, 0x0a, 0x62, 0x32, 0x30, 0x78, 0x49, + 0x44, 0x41, 0x65, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x46, + 0x30, 0x52, 0x70, 0x5a, 0x32, 0x6c, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x49, + 0x45, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62, 0x43, 0x42, 0x53, 0x62, + 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x49, 0x49, 0x42, 0x49, + 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x0a, + 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, + 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, + 0x41, 0x51, 0x45, 0x41, 0x34, 0x6a, 0x76, 0x68, 0x45, 0x58, 0x4c, 0x65, + 0x71, 0x4b, 0x54, 0x54, 0x6f, 0x31, 0x65, 0x71, 0x55, 0x4b, 0x4b, 0x50, + 0x43, 0x33, 0x65, 0x51, 0x79, 0x61, 0x4b, 0x6c, 0x37, 0x68, 0x4c, 0x4f, + 0x6c, 0x6c, 0x73, 0x42, 0x0a, 0x43, 0x53, 0x44, 0x4d, 0x41, 0x5a, 0x4f, + 0x6e, 0x54, 0x6a, 0x43, 0x33, 0x55, 0x2f, 0x64, 0x44, 0x78, 0x47, 0x6b, + 0x41, 0x56, 0x35, 0x33, 0x69, 0x6a, 0x53, 0x4c, 0x64, 0x68, 0x77, 0x5a, + 0x41, 0x41, 0x49, 0x45, 0x4a, 0x7a, 0x73, 0x34, 0x62, 0x67, 0x37, 0x2f, + 0x66, 0x7a, 0x54, 0x74, 0x78, 0x52, 0x75, 0x4c, 0x57, 0x5a, 0x73, 0x63, + 0x46, 0x73, 0x33, 0x59, 0x6e, 0x46, 0x6f, 0x39, 0x37, 0x0a, 0x6e, 0x68, + 0x36, 0x56, 0x66, 0x65, 0x36, 0x33, 0x53, 0x4b, 0x4d, 0x49, 0x32, 0x74, + 0x61, 0x76, 0x65, 0x67, 0x77, 0x35, 0x42, 0x6d, 0x56, 0x2f, 0x53, 0x6c, + 0x30, 0x66, 0x76, 0x42, 0x66, 0x34, 0x71, 0x37, 0x37, 0x75, 0x4b, 0x4e, + 0x64, 0x30, 0x66, 0x33, 0x70, 0x34, 0x6d, 0x56, 0x6d, 0x46, 0x61, 0x47, + 0x35, 0x63, 0x49, 0x7a, 0x4a, 0x4c, 0x76, 0x30, 0x37, 0x41, 0x36, 0x46, + 0x70, 0x74, 0x0a, 0x34, 0x33, 0x43, 0x2f, 0x64, 0x78, 0x43, 0x2f, 0x2f, + 0x41, 0x48, 0x32, 0x68, 0x64, 0x6d, 0x6f, 0x52, 0x42, 0x42, 0x59, 0x4d, + 0x71, 0x6c, 0x31, 0x47, 0x4e, 0x58, 0x52, 0x6f, 0x72, 0x35, 0x48, 0x34, + 0x69, 0x64, 0x71, 0x39, 0x4a, 0x6f, 0x7a, 0x2b, 0x45, 0x6b, 0x49, 0x59, + 0x49, 0x76, 0x55, 0x58, 0x37, 0x51, 0x36, 0x68, 0x4c, 0x2b, 0x68, 0x71, + 0x6b, 0x70, 0x4d, 0x66, 0x54, 0x37, 0x50, 0x0a, 0x54, 0x31, 0x39, 0x73, + 0x64, 0x6c, 0x36, 0x67, 0x53, 0x7a, 0x65, 0x52, 0x6e, 0x74, 0x77, 0x69, + 0x35, 0x6d, 0x33, 0x4f, 0x46, 0x42, 0x71, 0x4f, 0x61, 0x73, 0x76, 0x2b, + 0x7a, 0x62, 0x4d, 0x55, 0x5a, 0x42, 0x66, 0x48, 0x57, 0x79, 0x6d, 0x65, + 0x4d, 0x72, 0x2f, 0x79, 0x37, 0x76, 0x72, 0x54, 0x43, 0x30, 0x4c, 0x55, + 0x71, 0x37, 0x64, 0x42, 0x4d, 0x74, 0x6f, 0x4d, 0x31, 0x4f, 0x2f, 0x34, + 0x0a, 0x67, 0x64, 0x57, 0x37, 0x6a, 0x56, 0x67, 0x2f, 0x74, 0x52, 0x76, + 0x6f, 0x53, 0x53, 0x69, 0x69, 0x63, 0x4e, 0x6f, 0x78, 0x42, 0x4e, 0x33, + 0x33, 0x73, 0x68, 0x62, 0x79, 0x54, 0x41, 0x70, 0x4f, 0x42, 0x36, 0x6a, + 0x74, 0x53, 0x6a, 0x31, 0x65, 0x74, 0x58, 0x2b, 0x6a, 0x6b, 0x4d, 0x4f, + 0x76, 0x4a, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x32, 0x4d, + 0x77, 0x59, 0x54, 0x41, 0x4f, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, + 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x59, + 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, + 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, + 0x51, 0x55, 0x41, 0x39, 0x35, 0x51, 0x4e, 0x56, 0x62, 0x52, 0x0a, 0x54, + 0x4c, 0x74, 0x6d, 0x38, 0x4b, 0x50, 0x69, 0x47, 0x78, 0x76, 0x44, 0x6c, + 0x37, 0x49, 0x39, 0x30, 0x56, 0x55, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x41, + 0x39, 0x35, 0x51, 0x4e, 0x56, 0x62, 0x52, 0x54, 0x4c, 0x74, 0x6d, 0x38, + 0x4b, 0x50, 0x69, 0x47, 0x78, 0x76, 0x44, 0x6c, 0x37, 0x49, 0x39, 0x30, + 0x56, 0x55, 0x77, 0x0a, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, + 0x67, 0x67, 0x45, 0x42, 0x41, 0x4d, 0x75, 0x63, 0x4e, 0x36, 0x70, 0x49, + 0x45, 0x78, 0x49, 0x4b, 0x2b, 0x74, 0x31, 0x45, 0x6e, 0x45, 0x39, 0x53, + 0x73, 0x50, 0x54, 0x66, 0x72, 0x67, 0x54, 0x31, 0x65, 0x58, 0x6b, 0x49, + 0x6f, 0x79, 0x51, 0x59, 0x2f, 0x45, 0x73, 0x72, 0x0a, 0x68, 0x4d, 0x41, + 0x74, 0x75, 0x64, 0x58, 0x48, 0x2f, 0x76, 0x54, 0x42, 0x48, 0x31, 0x6a, + 0x4c, 0x75, 0x47, 0x32, 0x63, 0x65, 0x6e, 0x54, 0x6e, 0x6d, 0x43, 0x6d, + 0x72, 0x45, 0x62, 0x58, 0x6a, 0x63, 0x4b, 0x43, 0x68, 0x7a, 0x55, 0x79, + 0x49, 0x6d, 0x5a, 0x4f, 0x4d, 0x6b, 0x58, 0x44, 0x69, 0x71, 0x77, 0x38, + 0x63, 0x76, 0x70, 0x4f, 0x70, 0x2f, 0x32, 0x50, 0x56, 0x35, 0x41, 0x64, + 0x67, 0x0a, 0x30, 0x36, 0x4f, 0x2f, 0x6e, 0x56, 0x73, 0x4a, 0x38, 0x64, + 0x57, 0x4f, 0x34, 0x31, 0x50, 0x30, 0x6a, 0x6d, 0x50, 0x36, 0x50, 0x36, + 0x66, 0x62, 0x74, 0x47, 0x62, 0x66, 0x59, 0x6d, 0x62, 0x57, 0x30, 0x57, + 0x35, 0x42, 0x6a, 0x66, 0x49, 0x74, 0x74, 0x65, 0x70, 0x33, 0x53, 0x70, + 0x2b, 0x64, 0x57, 0x4f, 0x49, 0x72, 0x57, 0x63, 0x42, 0x41, 0x49, 0x2b, + 0x30, 0x74, 0x4b, 0x49, 0x4a, 0x46, 0x0a, 0x50, 0x6e, 0x6c, 0x55, 0x6b, + 0x69, 0x61, 0x59, 0x34, 0x49, 0x42, 0x49, 0x71, 0x44, 0x66, 0x76, 0x38, + 0x4e, 0x5a, 0x35, 0x59, 0x42, 0x62, 0x65, 0x72, 0x4f, 0x67, 0x4f, 0x7a, + 0x57, 0x36, 0x73, 0x52, 0x42, 0x63, 0x34, 0x4c, 0x30, 0x6e, 0x61, 0x34, + 0x55, 0x55, 0x2b, 0x4b, 0x72, 0x6b, 0x32, 0x55, 0x38, 0x38, 0x36, 0x55, + 0x41, 0x62, 0x33, 0x4c, 0x75, 0x6a, 0x45, 0x56, 0x30, 0x6c, 0x73, 0x0a, + 0x59, 0x53, 0x45, 0x59, 0x31, 0x51, 0x53, 0x74, 0x65, 0x44, 0x77, 0x73, + 0x4f, 0x6f, 0x42, 0x72, 0x70, 0x2b, 0x75, 0x76, 0x46, 0x52, 0x54, 0x70, + 0x32, 0x49, 0x6e, 0x42, 0x75, 0x54, 0x68, 0x73, 0x34, 0x70, 0x46, 0x73, + 0x69, 0x76, 0x39, 0x6b, 0x75, 0x58, 0x63, 0x6c, 0x56, 0x7a, 0x44, 0x41, + 0x47, 0x79, 0x53, 0x6a, 0x34, 0x64, 0x7a, 0x70, 0x33, 0x30, 0x64, 0x38, + 0x74, 0x62, 0x51, 0x6b, 0x0a, 0x43, 0x41, 0x55, 0x77, 0x37, 0x43, 0x32, + 0x39, 0x43, 0x37, 0x39, 0x46, 0x76, 0x31, 0x43, 0x35, 0x71, 0x66, 0x50, + 0x72, 0x6d, 0x41, 0x45, 0x53, 0x72, 0x63, 0x69, 0x49, 0x78, 0x70, 0x67, + 0x30, 0x58, 0x34, 0x30, 0x4b, 0x50, 0x4d, 0x62, 0x70, 0x31, 0x5a, 0x57, + 0x56, 0x62, 0x64, 0x34, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48, 0x69, 0x67, 0x68, 0x20, + 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x45, 0x56, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x44, + 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x20, + 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, + 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48, 0x69, 0x67, 0x68, 0x20, + 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x45, 0x56, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x44, + 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x20, + 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, + 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, + 0x72, 0x74, 0x20, 0x48, 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, + 0x72, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x33, 0x35, 0x35, 0x33, 0x34, 0x30, 0x30, 0x30, + 0x37, 0x36, 0x34, 0x31, 0x30, 0x35, 0x34, 0x37, 0x39, 0x31, 0x39, 0x37, + 0x32, 0x34, 0x37, 0x33, 0x30, 0x37, 0x33, 0x34, 0x33, 0x37, 0x38, 0x31, + 0x30, 0x30, 0x30, 0x38, 0x37, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x64, 0x34, 0x3a, 0x37, 0x34, 0x3a, 0x64, 0x65, 0x3a, 0x35, 0x37, + 0x3a, 0x35, 0x63, 0x3a, 0x33, 0x39, 0x3a, 0x62, 0x32, 0x3a, 0x64, 0x33, + 0x3a, 0x39, 0x63, 0x3a, 0x38, 0x35, 0x3a, 0x38, 0x33, 0x3a, 0x63, 0x35, + 0x3a, 0x63, 0x30, 0x3a, 0x36, 0x35, 0x3a, 0x34, 0x39, 0x3a, 0x38, 0x61, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x66, 0x3a, + 0x62, 0x37, 0x3a, 0x65, 0x65, 0x3a, 0x30, 0x36, 0x3a, 0x33, 0x33, 0x3a, + 0x65, 0x32, 0x3a, 0x35, 0x39, 0x3a, 0x64, 0x62, 0x3a, 0x61, 0x64, 0x3a, + 0x30, 0x63, 0x3a, 0x34, 0x63, 0x3a, 0x39, 0x61, 0x3a, 0x65, 0x36, 0x3a, + 0x64, 0x33, 0x3a, 0x38, 0x66, 0x3a, 0x31, 0x61, 0x3a, 0x36, 0x31, 0x3a, + 0x63, 0x37, 0x3a, 0x64, 0x63, 0x3a, 0x32, 0x35, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x34, 0x3a, 0x33, 0x31, + 0x3a, 0x65, 0x35, 0x3a, 0x66, 0x34, 0x3a, 0x63, 0x33, 0x3a, 0x63, 0x31, + 0x3a, 0x63, 0x65, 0x3a, 0x34, 0x36, 0x3a, 0x39, 0x30, 0x3a, 0x37, 0x37, + 0x3a, 0x34, 0x66, 0x3a, 0x30, 0x62, 0x3a, 0x36, 0x31, 0x3a, 0x65, 0x30, + 0x3a, 0x35, 0x34, 0x3a, 0x34, 0x30, 0x3a, 0x38, 0x38, 0x3a, 0x33, 0x62, + 0x3a, 0x61, 0x39, 0x3a, 0x61, 0x30, 0x3a, 0x31, 0x65, 0x3a, 0x64, 0x30, + 0x3a, 0x30, 0x62, 0x3a, 0x61, 0x36, 0x3a, 0x61, 0x62, 0x3a, 0x64, 0x37, + 0x3a, 0x38, 0x30, 0x3a, 0x36, 0x65, 0x3a, 0x64, 0x33, 0x3a, 0x62, 0x31, + 0x3a, 0x31, 0x38, 0x3a, 0x63, 0x66, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x44, 0x78, 0x54, 0x43, 0x43, 0x41, 0x71, 0x32, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x41, 0x71, 0x78, 0x63, 0x4a, + 0x6d, 0x6f, 0x4c, 0x51, 0x4a, 0x75, 0x50, 0x43, 0x33, 0x6e, 0x79, 0x72, + 0x6b, 0x59, 0x6c, 0x64, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, + 0x44, 0x42, 0x73, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x56, + 0x4d, 0x42, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4d, + 0x52, 0x47, 0x6c, 0x6e, 0x61, 0x55, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x67, + 0x53, 0x57, 0x35, 0x6a, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x42, 0x33, 0x0a, 0x64, 0x33, 0x63, + 0x75, 0x5a, 0x47, 0x6c, 0x6e, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x6e, 0x51, + 0x75, 0x59, 0x32, 0x39, 0x74, 0x4d, 0x53, 0x73, 0x77, 0x4b, 0x51, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x79, 0x4a, 0x45, 0x61, 0x57, 0x64, + 0x70, 0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x42, 0x49, 0x61, 0x57, 0x64, + 0x6f, 0x49, 0x45, 0x46, 0x7a, 0x63, 0x33, 0x56, 0x79, 0x59, 0x57, 0x35, + 0x6a, 0x0a, 0x5a, 0x53, 0x42, 0x46, 0x56, 0x69, 0x42, 0x53, 0x62, 0x32, + 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, + 0x41, 0x32, 0x4d, 0x54, 0x45, 0x78, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, + 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x4d, 0x78, 0x4d, 0x54, + 0x45, 0x78, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, + 0x6f, 0x77, 0x62, 0x44, 0x45, 0x4c, 0x0a, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, + 0x54, 0x41, 0x54, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, + 0x45, 0x52, 0x70, 0x5a, 0x32, 0x6c, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x49, + 0x45, 0x6c, 0x75, 0x59, 0x7a, 0x45, 0x5a, 0x4d, 0x42, 0x63, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x51, 0x64, 0x33, 0x64, 0x33, 0x0a, + 0x4c, 0x6d, 0x52, 0x70, 0x5a, 0x32, 0x6c, 0x6a, 0x5a, 0x58, 0x4a, 0x30, + 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x54, 0x45, 0x72, 0x4d, 0x43, 0x6b, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x69, 0x52, 0x47, 0x6c, 0x6e, + 0x61, 0x55, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x67, 0x53, 0x47, 0x6c, 0x6e, + 0x61, 0x43, 0x42, 0x42, 0x63, 0x33, 0x4e, 0x31, 0x63, 0x6d, 0x46, 0x75, + 0x59, 0x32, 0x55, 0x67, 0x0a, 0x52, 0x56, 0x59, 0x67, 0x55, 0x6d, 0x39, + 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x54, 0x43, 0x43, 0x41, 0x53, 0x49, + 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, + 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, + 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, + 0x42, 0x41, 0x4d, 0x62, 0x4d, 0x35, 0x58, 0x50, 0x6d, 0x0a, 0x2b, 0x39, + 0x53, 0x37, 0x35, 0x53, 0x30, 0x74, 0x4d, 0x71, 0x62, 0x66, 0x35, 0x59, + 0x45, 0x2f, 0x79, 0x63, 0x30, 0x6c, 0x53, 0x62, 0x5a, 0x78, 0x4b, 0x73, + 0x50, 0x56, 0x6c, 0x44, 0x52, 0x6e, 0x6f, 0x67, 0x6f, 0x63, 0x73, 0x46, + 0x39, 0x70, 0x70, 0x6b, 0x43, 0x78, 0x78, 0x4c, 0x65, 0x79, 0x6a, 0x39, + 0x43, 0x59, 0x70, 0x4b, 0x6c, 0x42, 0x57, 0x54, 0x72, 0x54, 0x33, 0x4a, + 0x54, 0x57, 0x0a, 0x50, 0x4e, 0x74, 0x30, 0x4f, 0x4b, 0x52, 0x4b, 0x7a, + 0x45, 0x30, 0x6c, 0x67, 0x76, 0x64, 0x4b, 0x70, 0x56, 0x4d, 0x53, 0x4f, + 0x4f, 0x37, 0x7a, 0x53, 0x57, 0x31, 0x78, 0x6b, 0x58, 0x35, 0x6a, 0x74, + 0x71, 0x75, 0x6d, 0x58, 0x38, 0x4f, 0x6b, 0x68, 0x50, 0x68, 0x50, 0x59, + 0x6c, 0x47, 0x2b, 0x2b, 0x4d, 0x58, 0x73, 0x32, 0x7a, 0x69, 0x53, 0x34, + 0x77, 0x62, 0x6c, 0x43, 0x4a, 0x45, 0x4d, 0x0a, 0x78, 0x43, 0x68, 0x42, + 0x56, 0x66, 0x76, 0x4c, 0x57, 0x6f, 0x6b, 0x56, 0x66, 0x6e, 0x48, 0x6f, + 0x4e, 0x62, 0x39, 0x4e, 0x63, 0x67, 0x6b, 0x39, 0x76, 0x6a, 0x6f, 0x34, + 0x55, 0x46, 0x74, 0x33, 0x4d, 0x52, 0x75, 0x4e, 0x73, 0x38, 0x63, 0x6b, + 0x52, 0x5a, 0x71, 0x6e, 0x72, 0x47, 0x30, 0x41, 0x46, 0x46, 0x6f, 0x45, + 0x74, 0x37, 0x6f, 0x54, 0x36, 0x31, 0x45, 0x4b, 0x6d, 0x45, 0x46, 0x42, + 0x0a, 0x49, 0x6b, 0x35, 0x6c, 0x59, 0x59, 0x65, 0x42, 0x51, 0x56, 0x43, + 0x6d, 0x65, 0x56, 0x79, 0x4a, 0x33, 0x68, 0x6c, 0x4b, 0x56, 0x39, 0x55, + 0x75, 0x35, 0x6c, 0x30, 0x63, 0x55, 0x79, 0x78, 0x2b, 0x6d, 0x4d, 0x30, + 0x61, 0x42, 0x68, 0x61, 0x6b, 0x61, 0x48, 0x50, 0x51, 0x4e, 0x41, 0x51, + 0x54, 0x58, 0x4b, 0x46, 0x78, 0x30, 0x31, 0x70, 0x38, 0x56, 0x64, 0x74, + 0x65, 0x5a, 0x4f, 0x45, 0x33, 0x0a, 0x68, 0x7a, 0x42, 0x57, 0x42, 0x4f, + 0x55, 0x52, 0x74, 0x43, 0x6d, 0x41, 0x45, 0x76, 0x46, 0x35, 0x4f, 0x59, + 0x69, 0x69, 0x41, 0x68, 0x46, 0x38, 0x4a, 0x32, 0x61, 0x33, 0x69, 0x4c, + 0x64, 0x34, 0x38, 0x73, 0x6f, 0x4b, 0x71, 0x44, 0x69, 0x72, 0x43, 0x6d, + 0x54, 0x43, 0x76, 0x32, 0x5a, 0x64, 0x6c, 0x59, 0x54, 0x42, 0x6f, 0x53, + 0x55, 0x65, 0x68, 0x31, 0x30, 0x61, 0x55, 0x41, 0x73, 0x67, 0x0a, 0x45, + 0x73, 0x78, 0x42, 0x75, 0x32, 0x34, 0x4c, 0x55, 0x54, 0x69, 0x34, 0x53, + 0x38, 0x73, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, 0x6a, 0x4d, + 0x47, 0x45, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, + 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x47, 0x47, 0x4d, + 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, + 0x77, 0x51, 0x46, 0x0a, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, + 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, + 0x46, 0x4c, 0x45, 0x2b, 0x77, 0x32, 0x6b, 0x44, 0x2b, 0x4c, 0x39, 0x48, + 0x41, 0x64, 0x53, 0x59, 0x4a, 0x68, 0x6f, 0x49, 0x41, 0x75, 0x39, 0x6a, + 0x5a, 0x43, 0x76, 0x44, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, 0x61, 0x41, 0x0a, 0x46, 0x4c, 0x45, + 0x2b, 0x77, 0x32, 0x6b, 0x44, 0x2b, 0x4c, 0x39, 0x48, 0x41, 0x64, 0x53, + 0x59, 0x4a, 0x68, 0x6f, 0x49, 0x41, 0x75, 0x39, 0x6a, 0x5a, 0x43, 0x76, + 0x44, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, + 0x42, 0x41, 0x51, 0x41, 0x63, 0x47, 0x67, 0x61, 0x58, 0x33, 0x4e, 0x65, + 0x63, 0x0a, 0x6e, 0x7a, 0x79, 0x49, 0x5a, 0x67, 0x59, 0x49, 0x56, 0x79, + 0x48, 0x62, 0x49, 0x55, 0x66, 0x34, 0x4b, 0x6d, 0x65, 0x71, 0x76, 0x78, + 0x67, 0x79, 0x64, 0x6b, 0x41, 0x51, 0x56, 0x38, 0x47, 0x4b, 0x38, 0x33, + 0x72, 0x5a, 0x45, 0x57, 0x57, 0x4f, 0x4e, 0x66, 0x71, 0x65, 0x2f, 0x45, + 0x57, 0x31, 0x6e, 0x74, 0x6c, 0x4d, 0x4d, 0x55, 0x75, 0x34, 0x6b, 0x65, + 0x68, 0x44, 0x4c, 0x49, 0x36, 0x7a, 0x0a, 0x65, 0x4d, 0x37, 0x62, 0x34, + 0x31, 0x4e, 0x35, 0x63, 0x64, 0x62, 0x6c, 0x49, 0x5a, 0x51, 0x42, 0x32, + 0x6c, 0x57, 0x48, 0x6d, 0x69, 0x52, 0x6b, 0x39, 0x6f, 0x70, 0x6d, 0x7a, + 0x4e, 0x36, 0x63, 0x4e, 0x38, 0x32, 0x6f, 0x4e, 0x4c, 0x46, 0x70, 0x6d, + 0x79, 0x50, 0x49, 0x6e, 0x6e, 0x67, 0x69, 0x4b, 0x33, 0x42, 0x44, 0x34, + 0x31, 0x56, 0x48, 0x4d, 0x57, 0x45, 0x5a, 0x37, 0x31, 0x6a, 0x46, 0x0a, + 0x68, 0x53, 0x39, 0x4f, 0x4d, 0x50, 0x61, 0x67, 0x4d, 0x52, 0x59, 0x6a, + 0x79, 0x4f, 0x66, 0x69, 0x5a, 0x52, 0x59, 0x7a, 0x79, 0x37, 0x38, 0x61, + 0x47, 0x36, 0x41, 0x39, 0x2b, 0x4d, 0x70, 0x65, 0x69, 0x7a, 0x47, 0x4c, + 0x59, 0x41, 0x69, 0x4a, 0x4c, 0x51, 0x77, 0x47, 0x58, 0x46, 0x4b, 0x33, + 0x78, 0x50, 0x6b, 0x4b, 0x6d, 0x4e, 0x45, 0x56, 0x58, 0x35, 0x38, 0x53, + 0x76, 0x6e, 0x77, 0x32, 0x0a, 0x59, 0x7a, 0x69, 0x39, 0x52, 0x4b, 0x52, + 0x2f, 0x35, 0x43, 0x59, 0x72, 0x43, 0x73, 0x53, 0x58, 0x61, 0x51, 0x33, + 0x70, 0x6a, 0x4f, 0x4c, 0x41, 0x45, 0x46, 0x65, 0x34, 0x79, 0x48, 0x59, + 0x53, 0x6b, 0x56, 0x58, 0x79, 0x53, 0x47, 0x6e, 0x59, 0x76, 0x43, 0x6f, + 0x43, 0x57, 0x77, 0x39, 0x45, 0x31, 0x43, 0x41, 0x78, 0x32, 0x2f, 0x53, + 0x36, 0x63, 0x43, 0x5a, 0x64, 0x6b, 0x47, 0x43, 0x65, 0x0a, 0x76, 0x45, + 0x73, 0x58, 0x43, 0x53, 0x2b, 0x30, 0x79, 0x78, 0x35, 0x44, 0x61, 0x4d, + 0x6b, 0x48, 0x4a, 0x38, 0x48, 0x53, 0x58, 0x50, 0x66, 0x71, 0x49, 0x62, + 0x6c, 0x6f, 0x45, 0x70, 0x77, 0x38, 0x6e, 0x4c, 0x2b, 0x65, 0x2f, 0x49, + 0x42, 0x63, 0x6d, 0x32, 0x50, 0x4e, 0x37, 0x45, 0x65, 0x71, 0x4a, 0x53, + 0x64, 0x6e, 0x6f, 0x44, 0x66, 0x7a, 0x41, 0x49, 0x4a, 0x39, 0x56, 0x4e, + 0x65, 0x70, 0x0a, 0x2b, 0x4f, 0x6b, 0x75, 0x45, 0x36, 0x4e, 0x33, 0x36, + 0x42, 0x39, 0x4b, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x32, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, + 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x70, 0x6c, 0x75, + 0x73, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, + 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x41, 0x20, 0x4f, + 0x3d, 0x43, 0x65, 0x72, 0x74, 0x70, 0x6c, 0x75, 0x73, 0x0a, 0x23, 0x20, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x65, 0x72, 0x74, + 0x70, 0x6c, 0x75, 0x73, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, + 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x41, 0x22, + 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, + 0x37, 0x37, 0x37, 0x37, 0x30, 0x32, 0x30, 0x38, 0x30, 0x34, 0x35, 0x39, + 0x33, 0x34, 0x30, 0x34, 0x30, 0x32, 0x34, 0x31, 0x34, 0x36, 0x38, 0x37, + 0x36, 0x30, 0x34, 0x38, 0x38, 0x33, 0x32, 0x37, 0x35, 0x39, 0x35, 0x30, + 0x34, 0x33, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x38, + 0x3a, 0x32, 0x63, 0x3a, 0x38, 0x63, 0x3a, 0x35, 0x32, 0x3a, 0x62, 0x38, + 0x3a, 0x61, 0x32, 0x3a, 0x33, 0x63, 0x3a, 0x66, 0x33, 0x3a, 0x66, 0x37, + 0x3a, 0x62, 0x62, 0x3a, 0x30, 0x33, 0x3a, 0x65, 0x61, 0x3a, 0x61, 0x65, + 0x3a, 0x61, 0x63, 0x3a, 0x34, 0x32, 0x3a, 0x30, 0x62, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x34, 0x3a, 0x32, 0x30, 0x3a, + 0x37, 0x34, 0x3a, 0x34, 0x31, 0x3a, 0x37, 0x32, 0x3a, 0x39, 0x63, 0x3a, + 0x64, 0x64, 0x3a, 0x39, 0x32, 0x3a, 0x65, 0x63, 0x3a, 0x37, 0x39, 0x3a, + 0x33, 0x31, 0x3a, 0x64, 0x38, 0x3a, 0x32, 0x33, 0x3a, 0x31, 0x30, 0x3a, + 0x38, 0x64, 0x3a, 0x63, 0x32, 0x3a, 0x38, 0x31, 0x3a, 0x39, 0x32, 0x3a, + 0x65, 0x32, 0x3a, 0x62, 0x62, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x66, 0x3a, 0x39, 0x39, 0x3a, 0x33, 0x63, + 0x3a, 0x38, 0x61, 0x3a, 0x65, 0x66, 0x3a, 0x39, 0x37, 0x3a, 0x62, 0x61, + 0x3a, 0x61, 0x66, 0x3a, 0x35, 0x36, 0x3a, 0x38, 0x37, 0x3a, 0x31, 0x34, + 0x3a, 0x30, 0x65, 0x3a, 0x64, 0x35, 0x3a, 0x39, 0x61, 0x3a, 0x64, 0x31, + 0x3a, 0x38, 0x32, 0x3a, 0x31, 0x62, 0x3a, 0x62, 0x34, 0x3a, 0x61, 0x66, + 0x3a, 0x61, 0x63, 0x3a, 0x66, 0x30, 0x3a, 0x61, 0x61, 0x3a, 0x39, 0x61, + 0x3a, 0x35, 0x38, 0x3a, 0x62, 0x35, 0x3a, 0x64, 0x35, 0x3a, 0x37, 0x61, + 0x3a, 0x33, 0x33, 0x3a, 0x38, 0x61, 0x3a, 0x33, 0x61, 0x3a, 0x66, 0x62, + 0x3a, 0x63, 0x62, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, + 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, + 0x6b, 0x6a, 0x43, 0x43, 0x41, 0x6e, 0x71, 0x67, 0x41, 0x77, 0x49, 0x42, + 0x41, 0x67, 0x49, 0x52, 0x41, 0x49, 0x57, 0x39, 0x53, 0x2f, 0x50, 0x59, + 0x32, 0x75, 0x4e, 0x70, 0x39, 0x70, 0x54, 0x58, 0x58, 0x38, 0x4f, 0x6c, + 0x52, 0x43, 0x4d, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x77, + 0x0a, 0x50, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x6c, 0x49, 0x78, 0x45, 0x54, 0x41, + 0x50, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x43, 0x45, 0x4e, + 0x6c, 0x63, 0x6e, 0x52, 0x77, 0x62, 0x48, 0x56, 0x7a, 0x4d, 0x52, 0x73, + 0x77, 0x47, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x4a, + 0x44, 0x62, 0x47, 0x46, 0x7a, 0x0a, 0x63, 0x79, 0x41, 0x79, 0x49, 0x46, + 0x42, 0x79, 0x61, 0x57, 0x31, 0x68, 0x63, 0x6e, 0x6b, 0x67, 0x51, 0x30, + 0x45, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4f, 0x54, 0x6b, 0x77, 0x4e, 0x7a, + 0x41, 0x33, 0x4d, 0x54, 0x63, 0x77, 0x4e, 0x54, 0x41, 0x77, 0x57, 0x68, + 0x63, 0x4e, 0x4d, 0x54, 0x6b, 0x77, 0x4e, 0x7a, 0x41, 0x32, 0x4d, 0x6a, + 0x4d, 0x31, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, 0x41, 0x39, 0x0a, 0x4d, + 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, + 0x77, 0x4a, 0x47, 0x55, 0x6a, 0x45, 0x52, 0x4d, 0x41, 0x38, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x49, 0x51, 0x32, 0x56, 0x79, 0x64, + 0x48, 0x42, 0x73, 0x64, 0x58, 0x4d, 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x45, 0x6b, 0x4e, 0x73, 0x59, + 0x58, 0x4e, 0x7a, 0x0a, 0x49, 0x44, 0x49, 0x67, 0x55, 0x48, 0x4a, 0x70, + 0x62, 0x57, 0x46, 0x79, 0x65, 0x53, 0x42, 0x44, 0x51, 0x54, 0x43, 0x43, + 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, + 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, + 0x67, 0x67, 0x45, 0x42, 0x41, 0x4e, 0x78, 0x51, 0x0a, 0x6c, 0x74, 0x41, + 0x53, 0x2b, 0x44, 0x58, 0x53, 0x43, 0x48, 0x68, 0x36, 0x74, 0x6c, 0x4a, + 0x77, 0x2f, 0x57, 0x2f, 0x75, 0x7a, 0x37, 0x6b, 0x52, 0x79, 0x31, 0x31, + 0x33, 0x34, 0x65, 0x7a, 0x70, 0x66, 0x67, 0x53, 0x4e, 0x31, 0x73, 0x78, + 0x76, 0x63, 0x30, 0x4e, 0x58, 0x59, 0x4b, 0x77, 0x7a, 0x43, 0x6b, 0x54, + 0x73, 0x41, 0x31, 0x38, 0x63, 0x67, 0x43, 0x53, 0x52, 0x35, 0x61, 0x69, + 0x52, 0x0a, 0x56, 0x68, 0x4b, 0x43, 0x39, 0x2b, 0x41, 0x72, 0x39, 0x4e, + 0x75, 0x75, 0x59, 0x53, 0x36, 0x4a, 0x45, 0x49, 0x31, 0x72, 0x62, 0x4c, + 0x71, 0x7a, 0x41, 0x72, 0x33, 0x56, 0x4e, 0x73, 0x56, 0x49, 0x4e, 0x79, + 0x50, 0x69, 0x38, 0x46, 0x6f, 0x33, 0x55, 0x6a, 0x4d, 0x58, 0x45, 0x75, + 0x4c, 0x52, 0x59, 0x45, 0x32, 0x2b, 0x4c, 0x30, 0x45, 0x52, 0x34, 0x2f, + 0x59, 0x58, 0x4a, 0x51, 0x79, 0x4c, 0x0a, 0x6b, 0x63, 0x41, 0x62, 0x6d, + 0x58, 0x75, 0x5a, 0x56, 0x67, 0x32, 0x76, 0x37, 0x74, 0x4b, 0x38, 0x52, + 0x31, 0x66, 0x6a, 0x65, 0x55, 0x6c, 0x37, 0x4e, 0x49, 0x6b, 0x6e, 0x4a, + 0x49, 0x54, 0x65, 0x73, 0x65, 0x7a, 0x70, 0x57, 0x45, 0x37, 0x2b, 0x54, + 0x74, 0x39, 0x61, 0x76, 0x6b, 0x47, 0x74, 0x72, 0x41, 0x6a, 0x46, 0x47, + 0x41, 0x37, 0x76, 0x30, 0x6c, 0x50, 0x75, 0x62, 0x4e, 0x43, 0x64, 0x0a, + 0x45, 0x67, 0x45, 0x54, 0x6a, 0x64, 0x79, 0x41, 0x59, 0x76, 0x65, 0x56, + 0x71, 0x55, 0x53, 0x49, 0x53, 0x6e, 0x46, 0x4f, 0x59, 0x46, 0x57, 0x65, + 0x32, 0x79, 0x4d, 0x5a, 0x65, 0x56, 0x59, 0x48, 0x44, 0x44, 0x39, 0x6a, + 0x43, 0x31, 0x79, 0x77, 0x34, 0x72, 0x35, 0x2b, 0x46, 0x66, 0x79, 0x55, + 0x4d, 0x31, 0x68, 0x42, 0x4f, 0x48, 0x54, 0x45, 0x34, 0x59, 0x2b, 0x4c, + 0x33, 0x79, 0x61, 0x73, 0x0a, 0x48, 0x37, 0x57, 0x4c, 0x4f, 0x37, 0x64, + 0x44, 0x57, 0x57, 0x75, 0x77, 0x4a, 0x4b, 0x5a, 0x74, 0x6b, 0x49, 0x76, + 0x45, 0x63, 0x75, 0x70, 0x64, 0x4d, 0x35, 0x69, 0x33, 0x79, 0x39, 0x35, + 0x65, 0x65, 0x2b, 0x2b, 0x55, 0x38, 0x52, 0x73, 0x2b, 0x79, 0x73, 0x6b, + 0x68, 0x77, 0x63, 0x57, 0x59, 0x41, 0x71, 0x71, 0x69, 0x39, 0x6c, 0x74, + 0x33, 0x6d, 0x2f, 0x56, 0x2b, 0x6c, 0x6c, 0x55, 0x30, 0x0a, 0x48, 0x47, + 0x64, 0x70, 0x77, 0x50, 0x46, 0x43, 0x34, 0x30, 0x65, 0x73, 0x2f, 0x43, + 0x67, 0x63, 0x5a, 0x6c, 0x55, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, + 0x4f, 0x42, 0x6a, 0x44, 0x43, 0x42, 0x69, 0x54, 0x41, 0x50, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x45, 0x43, 0x44, 0x41, 0x47, 0x41, 0x51, + 0x48, 0x2f, 0x41, 0x67, 0x45, 0x4b, 0x4d, 0x41, 0x73, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x0a, 0x44, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, + 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, + 0x67, 0x51, 0x55, 0x34, 0x33, 0x4d, 0x74, 0x33, 0x38, 0x73, 0x4f, 0x4b, + 0x41, 0x7a, 0x65, 0x33, 0x62, 0x4f, 0x6b, 0x79, 0x6e, 0x6d, 0x34, 0x6a, + 0x72, 0x76, 0x6f, 0x4d, 0x49, 0x6b, 0x77, 0x45, 0x51, 0x59, 0x4a, 0x59, + 0x49, 0x5a, 0x49, 0x41, 0x59, 0x62, 0x34, 0x0a, 0x51, 0x67, 0x45, 0x42, + 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x44, 0x63, 0x47, + 0x41, 0x31, 0x55, 0x64, 0x48, 0x77, 0x51, 0x77, 0x4d, 0x43, 0x34, 0x77, + 0x4c, 0x4b, 0x41, 0x71, 0x6f, 0x43, 0x69, 0x47, 0x4a, 0x6d, 0x68, 0x30, + 0x64, 0x48, 0x41, 0x36, 0x4c, 0x79, 0x39, 0x33, 0x64, 0x33, 0x63, 0x75, + 0x59, 0x32, 0x56, 0x79, 0x64, 0x48, 0x42, 0x73, 0x64, 0x58, 0x4d, 0x75, + 0x0a, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x30, 0x4e, 0x53, 0x54, 0x43, 0x39, + 0x6a, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x7a, 0x49, 0x75, 0x59, 0x33, 0x4a, + 0x73, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, + 0x42, 0x41, 0x51, 0x43, 0x6e, 0x56, 0x4d, 0x2b, 0x49, 0x52, 0x42, 0x6e, + 0x4c, 0x33, 0x39, 0x52, 0x2f, 0x0a, 0x41, 0x4e, 0x39, 0x57, 0x4d, 0x32, + 0x4b, 0x31, 0x39, 0x31, 0x45, 0x42, 0x6b, 0x4f, 0x76, 0x44, 0x50, 0x39, + 0x47, 0x49, 0x52, 0x4f, 0x6b, 0x6b, 0x58, 0x65, 0x2f, 0x6e, 0x46, 0x4c, + 0x30, 0x67, 0x74, 0x35, 0x6f, 0x38, 0x41, 0x50, 0x35, 0x74, 0x6e, 0x39, + 0x75, 0x51, 0x33, 0x4e, 0x66, 0x30, 0x59, 0x74, 0x61, 0x4c, 0x63, 0x46, + 0x33, 0x6e, 0x35, 0x51, 0x52, 0x49, 0x71, 0x57, 0x68, 0x38, 0x0a, 0x79, + 0x66, 0x46, 0x43, 0x38, 0x32, 0x78, 0x2f, 0x78, 0x58, 0x70, 0x38, 0x48, + 0x56, 0x47, 0x49, 0x75, 0x74, 0x49, 0x4b, 0x50, 0x69, 0x64, 0x64, 0x33, + 0x69, 0x31, 0x52, 0x54, 0x74, 0x4d, 0x54, 0x5a, 0x47, 0x6e, 0x6b, 0x4c, + 0x75, 0x50, 0x54, 0x35, 0x35, 0x73, 0x4a, 0x6d, 0x61, 0x62, 0x67, 0x6c, + 0x5a, 0x76, 0x4f, 0x47, 0x74, 0x64, 0x2f, 0x76, 0x6a, 0x7a, 0x4f, 0x55, + 0x72, 0x4d, 0x52, 0x0a, 0x46, 0x63, 0x45, 0x50, 0x46, 0x38, 0x30, 0x44, + 0x75, 0x35, 0x77, 0x6c, 0x46, 0x62, 0x71, 0x69, 0x64, 0x6f, 0x6e, 0x38, + 0x42, 0x76, 0x45, 0x59, 0x30, 0x4a, 0x4e, 0x4c, 0x44, 0x6e, 0x79, 0x43, + 0x74, 0x36, 0x58, 0x30, 0x39, 0x6c, 0x2f, 0x2b, 0x37, 0x55, 0x43, 0x6d, + 0x6e, 0x59, 0x52, 0x30, 0x4f, 0x62, 0x6e, 0x63, 0x48, 0x6f, 0x55, 0x57, + 0x32, 0x69, 0x6b, 0x62, 0x68, 0x69, 0x4d, 0x41, 0x0a, 0x79, 0x62, 0x75, + 0x4a, 0x66, 0x6d, 0x36, 0x41, 0x69, 0x42, 0x34, 0x76, 0x46, 0x4c, 0x51, + 0x44, 0x4a, 0x4b, 0x67, 0x79, 0x62, 0x77, 0x4f, 0x61, 0x52, 0x79, 0x77, + 0x77, 0x76, 0x6c, 0x62, 0x47, 0x70, 0x30, 0x49, 0x43, 0x63, 0x42, 0x76, + 0x71, 0x51, 0x4e, 0x69, 0x36, 0x42, 0x51, 0x4e, 0x77, 0x42, 0x36, 0x53, + 0x57, 0x2f, 0x2f, 0x31, 0x49, 0x4d, 0x77, 0x72, 0x68, 0x33, 0x4b, 0x57, + 0x42, 0x0a, 0x6b, 0x4a, 0x74, 0x4e, 0x33, 0x58, 0x33, 0x6e, 0x35, 0x37, + 0x4c, 0x4e, 0x58, 0x4d, 0x68, 0x71, 0x6c, 0x66, 0x69, 0x6c, 0x39, 0x6f, + 0x33, 0x45, 0x58, 0x58, 0x67, 0x49, 0x76, 0x6e, 0x73, 0x47, 0x31, 0x6b, + 0x6e, 0x50, 0x47, 0x54, 0x5a, 0x51, 0x49, 0x79, 0x34, 0x49, 0x35, 0x70, + 0x34, 0x46, 0x54, 0x55, 0x63, 0x59, 0x31, 0x52, 0x62, 0x70, 0x73, 0x64, + 0x61, 0x32, 0x45, 0x4e, 0x57, 0x37, 0x0a, 0x6c, 0x37, 0x2b, 0x69, 0x6a, + 0x72, 0x52, 0x55, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x53, 0x54, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x58, 0x33, 0x20, 0x4f, + 0x3d, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x53, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x43, 0x6f, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x53, 0x54, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x58, 0x33, 0x20, 0x4f, 0x3d, + 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x53, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x43, 0x6f, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x44, 0x53, 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x20, 0x58, 0x33, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x39, 0x31, 0x32, 0x39, 0x39, 0x37, 0x33, 0x35, + 0x35, 0x37, 0x35, 0x33, 0x33, 0x39, 0x39, 0x35, 0x33, 0x33, 0x33, 0x35, + 0x39, 0x31, 0x39, 0x32, 0x36, 0x36, 0x39, 0x36, 0x35, 0x38, 0x30, 0x33, + 0x37, 0x37, 0x38, 0x31, 0x35, 0x35, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x34, 0x31, 0x3a, 0x30, 0x33, 0x3a, 0x35, 0x32, 0x3a, 0x64, + 0x63, 0x3a, 0x30, 0x66, 0x3a, 0x66, 0x37, 0x3a, 0x35, 0x30, 0x3a, 0x31, + 0x62, 0x3a, 0x31, 0x36, 0x3a, 0x66, 0x30, 0x3a, 0x30, 0x32, 0x3a, 0x38, + 0x65, 0x3a, 0x62, 0x61, 0x3a, 0x36, 0x66, 0x3a, 0x34, 0x35, 0x3a, 0x63, + 0x35, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x61, + 0x3a, 0x63, 0x39, 0x3a, 0x30, 0x32, 0x3a, 0x34, 0x66, 0x3a, 0x35, 0x34, + 0x3a, 0x64, 0x38, 0x3a, 0x66, 0x36, 0x3a, 0x64, 0x66, 0x3a, 0x39, 0x34, + 0x3a, 0x39, 0x33, 0x3a, 0x35, 0x66, 0x3a, 0x62, 0x31, 0x3a, 0x37, 0x33, + 0x3a, 0x32, 0x36, 0x3a, 0x33, 0x38, 0x3a, 0x63, 0x61, 0x3a, 0x36, 0x61, + 0x3a, 0x64, 0x37, 0x3a, 0x37, 0x63, 0x3a, 0x31, 0x33, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x36, 0x3a, 0x38, + 0x37, 0x3a, 0x32, 0x36, 0x3a, 0x30, 0x33, 0x3a, 0x33, 0x31, 0x3a, 0x61, + 0x37, 0x3a, 0x32, 0x34, 0x3a, 0x30, 0x33, 0x3a, 0x64, 0x39, 0x3a, 0x30, + 0x39, 0x3a, 0x66, 0x31, 0x3a, 0x30, 0x35, 0x3a, 0x65, 0x36, 0x3a, 0x39, + 0x62, 0x3a, 0x63, 0x66, 0x3a, 0x30, 0x64, 0x3a, 0x33, 0x32, 0x3a, 0x65, + 0x31, 0x3a, 0x62, 0x64, 0x3a, 0x32, 0x34, 0x3a, 0x39, 0x33, 0x3a, 0x66, + 0x66, 0x3a, 0x63, 0x36, 0x3a, 0x64, 0x39, 0x3a, 0x32, 0x30, 0x3a, 0x36, + 0x64, 0x3a, 0x31, 0x31, 0x3a, 0x62, 0x63, 0x3a, 0x64, 0x36, 0x3a, 0x37, + 0x37, 0x3a, 0x30, 0x37, 0x3a, 0x33, 0x39, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x44, 0x53, 0x6a, 0x43, 0x43, 0x41, 0x6a, 0x4b, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x52, 0x4b, 0x2b, 0x77, + 0x67, 0x4e, 0x61, 0x6a, 0x4a, 0x37, 0x71, 0x4a, 0x4d, 0x44, 0x6d, 0x47, + 0x4c, 0x76, 0x68, 0x41, 0x61, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, + 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, + 0x41, 0x44, 0x41, 0x2f, 0x0a, 0x4d, 0x53, 0x51, 0x77, 0x49, 0x67, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x74, 0x45, 0x61, 0x57, 0x64, + 0x70, 0x64, 0x47, 0x46, 0x73, 0x49, 0x46, 0x4e, 0x70, 0x5a, 0x32, 0x35, + 0x68, 0x64, 0x48, 0x56, 0x79, 0x5a, 0x53, 0x42, 0x55, 0x63, 0x6e, 0x56, + 0x7a, 0x64, 0x43, 0x42, 0x44, 0x62, 0x79, 0x34, 0x78, 0x46, 0x7a, 0x41, + 0x56, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x0a, 0x44, 0x6b, + 0x52, 0x54, 0x56, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, + 0x4e, 0x42, 0x49, 0x46, 0x67, 0x7a, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, + 0x41, 0x77, 0x4d, 0x44, 0x6b, 0x7a, 0x4d, 0x44, 0x49, 0x78, 0x4d, 0x54, + 0x49, 0x78, 0x4f, 0x56, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x78, 0x4d, 0x44, + 0x6b, 0x7a, 0x4d, 0x44, 0x45, 0x30, 0x4d, 0x44, 0x45, 0x78, 0x4e, 0x56, + 0x6f, 0x77, 0x0a, 0x50, 0x7a, 0x45, 0x6b, 0x4d, 0x43, 0x49, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x62, 0x52, 0x47, 0x6c, 0x6e, 0x61, + 0x58, 0x52, 0x68, 0x62, 0x43, 0x42, 0x54, 0x61, 0x57, 0x64, 0x75, 0x59, + 0x58, 0x52, 0x31, 0x63, 0x6d, 0x55, 0x67, 0x56, 0x48, 0x4a, 0x31, 0x63, + 0x33, 0x51, 0x67, 0x51, 0x32, 0x38, 0x75, 0x4d, 0x52, 0x63, 0x77, 0x46, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x0a, 0x45, 0x77, 0x35, 0x45, + 0x55, 0x31, 0x51, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, + 0x51, 0x53, 0x42, 0x59, 0x4d, 0x7a, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, + 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, + 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, + 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, + 0x0a, 0x41, 0x4e, 0x2b, 0x76, 0x36, 0x5a, 0x64, 0x51, 0x43, 0x49, 0x4e, + 0x58, 0x74, 0x4d, 0x78, 0x69, 0x5a, 0x66, 0x61, 0x51, 0x67, 0x75, 0x7a, + 0x48, 0x30, 0x79, 0x78, 0x72, 0x4d, 0x4d, 0x70, 0x62, 0x37, 0x4e, 0x6e, + 0x44, 0x66, 0x63, 0x64, 0x41, 0x77, 0x52, 0x67, 0x55, 0x69, 0x2b, 0x44, + 0x6f, 0x4d, 0x33, 0x5a, 0x4a, 0x4b, 0x75, 0x4d, 0x2f, 0x49, 0x55, 0x6d, + 0x54, 0x72, 0x45, 0x34, 0x4f, 0x0a, 0x72, 0x7a, 0x35, 0x49, 0x79, 0x32, + 0x58, 0x75, 0x2f, 0x4e, 0x4d, 0x68, 0x44, 0x32, 0x58, 0x53, 0x4b, 0x74, + 0x6b, 0x79, 0x6a, 0x34, 0x7a, 0x6c, 0x39, 0x33, 0x65, 0x77, 0x45, 0x6e, + 0x75, 0x31, 0x6c, 0x63, 0x43, 0x4a, 0x6f, 0x36, 0x6d, 0x36, 0x37, 0x58, + 0x4d, 0x75, 0x65, 0x67, 0x77, 0x47, 0x4d, 0x6f, 0x4f, 0x69, 0x66, 0x6f, + 0x6f, 0x55, 0x4d, 0x4d, 0x30, 0x52, 0x6f, 0x4f, 0x45, 0x71, 0x0a, 0x4f, + 0x4c, 0x6c, 0x35, 0x43, 0x6a, 0x48, 0x39, 0x55, 0x4c, 0x32, 0x41, 0x5a, + 0x64, 0x2b, 0x33, 0x55, 0x57, 0x4f, 0x44, 0x79, 0x4f, 0x4b, 0x49, 0x59, + 0x65, 0x70, 0x4c, 0x59, 0x59, 0x48, 0x73, 0x55, 0x6d, 0x75, 0x35, 0x6f, + 0x75, 0x4a, 0x4c, 0x47, 0x69, 0x69, 0x66, 0x53, 0x4b, 0x4f, 0x65, 0x44, + 0x4e, 0x6f, 0x4a, 0x6a, 0x6a, 0x34, 0x58, 0x4c, 0x68, 0x37, 0x64, 0x49, + 0x4e, 0x39, 0x62, 0x0a, 0x78, 0x69, 0x71, 0x4b, 0x71, 0x79, 0x36, 0x39, + 0x63, 0x4b, 0x33, 0x46, 0x43, 0x78, 0x6f, 0x6c, 0x6b, 0x48, 0x52, 0x79, + 0x78, 0x58, 0x74, 0x71, 0x71, 0x7a, 0x54, 0x57, 0x4d, 0x49, 0x6e, 0x2f, + 0x35, 0x57, 0x67, 0x54, 0x65, 0x31, 0x51, 0x4c, 0x79, 0x4e, 0x61, 0x75, + 0x37, 0x46, 0x71, 0x63, 0x6b, 0x68, 0x34, 0x39, 0x5a, 0x4c, 0x4f, 0x4d, + 0x78, 0x74, 0x2b, 0x2f, 0x79, 0x55, 0x46, 0x77, 0x0a, 0x37, 0x42, 0x5a, + 0x79, 0x31, 0x53, 0x62, 0x73, 0x4f, 0x46, 0x55, 0x35, 0x51, 0x39, 0x44, + 0x38, 0x2f, 0x52, 0x68, 0x63, 0x51, 0x50, 0x47, 0x58, 0x36, 0x39, 0x57, + 0x61, 0x6d, 0x34, 0x30, 0x64, 0x75, 0x74, 0x6f, 0x6c, 0x75, 0x63, 0x62, + 0x59, 0x33, 0x38, 0x45, 0x56, 0x41, 0x6a, 0x71, 0x72, 0x32, 0x6d, 0x37, + 0x78, 0x50, 0x69, 0x37, 0x31, 0x58, 0x41, 0x69, 0x63, 0x50, 0x4e, 0x61, + 0x44, 0x0a, 0x61, 0x65, 0x51, 0x51, 0x6d, 0x78, 0x6b, 0x71, 0x74, 0x69, + 0x6c, 0x58, 0x34, 0x2b, 0x55, 0x39, 0x6d, 0x35, 0x2f, 0x77, 0x41, 0x6c, + 0x30, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, 0x43, 0x4d, 0x45, + 0x41, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, + 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x51, 0x38, 0x42, 0x41, + 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x48, + 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, + 0x4d, 0x53, 0x6e, 0x73, 0x61, 0x52, 0x37, 0x4c, 0x48, 0x48, 0x36, 0x32, + 0x2b, 0x46, 0x4c, 0x6b, 0x48, 0x58, 0x2f, 0x78, 0x42, 0x56, 0x67, 0x68, + 0x59, 0x6b, 0x51, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x0a, + 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, + 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x43, 0x6a, 0x47, 0x69, 0x79, 0x62, + 0x46, 0x77, 0x42, 0x63, 0x71, 0x52, 0x37, 0x75, 0x4b, 0x47, 0x59, 0x33, + 0x4f, 0x72, 0x2b, 0x44, 0x78, 0x7a, 0x39, 0x4c, 0x77, 0x77, 0x6d, 0x67, + 0x6c, 0x53, 0x42, 0x64, 0x34, 0x39, 0x6c, 0x5a, 0x52, 0x4e, 0x49, 0x2b, + 0x44, 0x54, 0x36, 0x39, 0x0a, 0x69, 0x6b, 0x75, 0x67, 0x64, 0x42, 0x2f, + 0x4f, 0x45, 0x49, 0x4b, 0x63, 0x64, 0x42, 0x6f, 0x64, 0x66, 0x70, 0x67, + 0x61, 0x33, 0x63, 0x73, 0x54, 0x53, 0x37, 0x4d, 0x67, 0x52, 0x4f, 0x53, + 0x52, 0x36, 0x63, 0x7a, 0x38, 0x66, 0x61, 0x58, 0x62, 0x61, 0x75, 0x58, + 0x2b, 0x35, 0x76, 0x33, 0x67, 0x54, 0x74, 0x32, 0x33, 0x41, 0x44, 0x71, + 0x31, 0x63, 0x45, 0x6d, 0x76, 0x38, 0x75, 0x58, 0x72, 0x0a, 0x41, 0x76, + 0x48, 0x52, 0x41, 0x6f, 0x73, 0x5a, 0x79, 0x35, 0x51, 0x36, 0x58, 0x6b, + 0x6a, 0x45, 0x47, 0x42, 0x35, 0x59, 0x47, 0x56, 0x38, 0x65, 0x41, 0x6c, + 0x72, 0x77, 0x44, 0x50, 0x47, 0x78, 0x72, 0x61, 0x6e, 0x63, 0x57, 0x59, + 0x61, 0x4c, 0x62, 0x75, 0x6d, 0x52, 0x39, 0x59, 0x62, 0x4b, 0x2b, 0x72, + 0x6c, 0x6d, 0x4d, 0x36, 0x70, 0x5a, 0x57, 0x38, 0x37, 0x69, 0x70, 0x78, + 0x5a, 0x7a, 0x0a, 0x52, 0x38, 0x73, 0x72, 0x7a, 0x4a, 0x6d, 0x77, 0x4e, + 0x30, 0x6a, 0x50, 0x34, 0x31, 0x5a, 0x4c, 0x39, 0x63, 0x38, 0x50, 0x44, + 0x48, 0x49, 0x79, 0x68, 0x38, 0x62, 0x77, 0x52, 0x4c, 0x74, 0x54, 0x63, + 0x6d, 0x31, 0x44, 0x39, 0x53, 0x5a, 0x49, 0x6d, 0x6c, 0x4a, 0x6e, 0x74, + 0x31, 0x69, 0x72, 0x2f, 0x6d, 0x64, 0x32, 0x63, 0x58, 0x6a, 0x62, 0x44, + 0x61, 0x4a, 0x57, 0x46, 0x42, 0x4d, 0x35, 0x0a, 0x4a, 0x44, 0x47, 0x46, + 0x6f, 0x71, 0x67, 0x43, 0x57, 0x6a, 0x42, 0x48, 0x34, 0x64, 0x31, 0x51, + 0x42, 0x37, 0x77, 0x43, 0x43, 0x5a, 0x41, 0x41, 0x36, 0x32, 0x52, 0x6a, + 0x59, 0x4a, 0x73, 0x57, 0x76, 0x49, 0x6a, 0x4a, 0x45, 0x75, 0x62, 0x53, + 0x66, 0x5a, 0x47, 0x4c, 0x2b, 0x54, 0x30, 0x79, 0x6a, 0x57, 0x57, 0x30, + 0x36, 0x58, 0x79, 0x78, 0x56, 0x33, 0x62, 0x71, 0x78, 0x62, 0x59, 0x6f, + 0x0a, 0x4f, 0x62, 0x38, 0x56, 0x5a, 0x52, 0x7a, 0x49, 0x39, 0x6e, 0x65, + 0x57, 0x61, 0x67, 0x71, 0x4e, 0x64, 0x77, 0x76, 0x59, 0x6b, 0x51, 0x73, + 0x45, 0x6a, 0x67, 0x66, 0x62, 0x4b, 0x62, 0x59, 0x4b, 0x37, 0x70, 0x32, + 0x43, 0x4e, 0x54, 0x55, 0x51, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x77, + 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x47, 0x6f, 0x6c, 0x64, + 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x53, + 0x77, 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x41, 0x47, 0x0a, + 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x53, 0x77, 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20, + 0x47, 0x6f, 0x6c, 0x64, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, + 0x20, 0x4f, 0x3d, 0x53, 0x77, 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x41, 0x47, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x53, 0x77, 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20, + 0x47, 0x6f, 0x6c, 0x64, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, + 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, + 0x31, 0x33, 0x34, 0x39, 0x32, 0x38, 0x31, 0x35, 0x35, 0x36, 0x31, 0x38, + 0x30, 0x36, 0x39, 0x39, 0x31, 0x32, 0x38, 0x30, 0x0a, 0x23, 0x20, 0x4d, + 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x34, 0x3a, 0x37, 0x37, 0x3a, 0x64, 0x39, + 0x3a, 0x61, 0x38, 0x3a, 0x39, 0x31, 0x3a, 0x64, 0x31, 0x3a, 0x33, 0x62, + 0x3a, 0x66, 0x61, 0x3a, 0x38, 0x38, 0x3a, 0x32, 0x64, 0x3a, 0x63, 0x32, + 0x3a, 0x66, 0x66, 0x3a, 0x66, 0x38, 0x3a, 0x63, 0x64, 0x3a, 0x33, 0x33, + 0x3a, 0x39, 0x33, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x64, 0x38, 0x3a, 0x63, 0x35, 0x3a, 0x33, 0x38, 0x3a, 0x38, 0x61, 0x3a, + 0x62, 0x37, 0x3a, 0x33, 0x30, 0x3a, 0x31, 0x62, 0x3a, 0x31, 0x62, 0x3a, + 0x36, 0x65, 0x3a, 0x64, 0x34, 0x3a, 0x37, 0x61, 0x3a, 0x65, 0x36, 0x3a, + 0x34, 0x35, 0x3a, 0x32, 0x35, 0x3a, 0x33, 0x61, 0x3a, 0x36, 0x66, 0x3a, + 0x39, 0x66, 0x3a, 0x31, 0x61, 0x3a, 0x32, 0x37, 0x3a, 0x36, 0x31, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x32, + 0x3a, 0x64, 0x64, 0x3a, 0x30, 0x62, 0x3a, 0x65, 0x39, 0x3a, 0x62, 0x39, + 0x3a, 0x66, 0x35, 0x3a, 0x30, 0x61, 0x3a, 0x31, 0x36, 0x3a, 0x33, 0x65, + 0x3a, 0x61, 0x30, 0x3a, 0x66, 0x38, 0x3a, 0x65, 0x37, 0x3a, 0x35, 0x63, + 0x3a, 0x30, 0x35, 0x3a, 0x33, 0x62, 0x3a, 0x31, 0x65, 0x3a, 0x63, 0x61, + 0x3a, 0x35, 0x37, 0x3a, 0x65, 0x61, 0x3a, 0x35, 0x35, 0x3a, 0x63, 0x38, + 0x3a, 0x36, 0x38, 0x3a, 0x38, 0x66, 0x3a, 0x36, 0x34, 0x3a, 0x37, 0x63, + 0x3a, 0x36, 0x38, 0x3a, 0x38, 0x31, 0x3a, 0x66, 0x32, 0x3a, 0x63, 0x38, + 0x3a, 0x33, 0x35, 0x3a, 0x37, 0x62, 0x3a, 0x39, 0x35, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x75, 0x6a, 0x43, 0x43, 0x41, 0x36, + 0x4b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x4a, 0x41, 0x4c, + 0x74, 0x41, 0x48, 0x45, 0x50, 0x31, 0x58, 0x6b, 0x2b, 0x77, 0x4d, 0x41, + 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, + 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x4d, 0x45, 0x55, 0x78, 0x43, 0x7a, + 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x59, 0x54, 0x41, + 0x6b, 0x4e, 0x49, 0x4d, 0x52, 0x55, 0x77, 0x45, 0x77, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x4b, 0x45, 0x77, 0x78, 0x54, 0x64, 0x32, 0x6c, 0x7a, 0x63, + 0x31, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x67, 0x51, 0x55, 0x63, 0x78, 0x48, + 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x46, + 0x6c, 0x4e, 0x33, 0x61, 0x58, 0x4e, 0x7a, 0x55, 0x32, 0x6c, 0x6e, 0x0a, + 0x62, 0x69, 0x42, 0x48, 0x62, 0x32, 0x78, 0x6b, 0x49, 0x45, 0x4e, 0x42, + 0x49, 0x43, 0x30, 0x67, 0x52, 0x7a, 0x49, 0x77, 0x48, 0x68, 0x63, 0x4e, + 0x4d, 0x44, 0x59, 0x78, 0x4d, 0x44, 0x49, 0x31, 0x4d, 0x44, 0x67, 0x7a, + 0x4d, 0x44, 0x4d, 0x31, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x59, 0x78, + 0x4d, 0x44, 0x49, 0x31, 0x4d, 0x44, 0x67, 0x7a, 0x4d, 0x44, 0x4d, 0x31, + 0x57, 0x6a, 0x42, 0x46, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x44, 0x53, 0x44, 0x45, + 0x56, 0x4d, 0x42, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, + 0x4d, 0x55, 0x33, 0x64, 0x70, 0x63, 0x33, 0x4e, 0x54, 0x61, 0x57, 0x64, + 0x75, 0x49, 0x45, 0x46, 0x48, 0x4d, 0x52, 0x38, 0x77, 0x48, 0x51, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x5a, 0x54, 0x0a, 0x64, 0x32, + 0x6c, 0x7a, 0x63, 0x31, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x67, 0x52, 0x32, + 0x39, 0x73, 0x5a, 0x43, 0x42, 0x44, 0x51, 0x53, 0x41, 0x74, 0x49, 0x45, + 0x63, 0x79, 0x4d, 0x49, 0x49, 0x43, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x38, 0x41, 0x4d, 0x49, + 0x49, 0x43, 0x0a, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x67, 0x45, 0x41, 0x72, + 0x2b, 0x54, 0x75, 0x66, 0x6f, 0x73, 0x6b, 0x44, 0x68, 0x4a, 0x75, 0x71, + 0x56, 0x41, 0x74, 0x46, 0x6b, 0x51, 0x37, 0x6b, 0x70, 0x4a, 0x63, 0x79, + 0x72, 0x68, 0x64, 0x68, 0x4a, 0x4a, 0x43, 0x45, 0x79, 0x71, 0x38, 0x5a, + 0x56, 0x65, 0x43, 0x51, 0x44, 0x35, 0x58, 0x4a, 0x4d, 0x31, 0x51, 0x69, + 0x79, 0x55, 0x71, 0x74, 0x32, 0x2f, 0x38, 0x0a, 0x37, 0x36, 0x4c, 0x51, + 0x77, 0x42, 0x38, 0x43, 0x4a, 0x45, 0x6f, 0x54, 0x6c, 0x6f, 0x38, 0x6a, + 0x45, 0x2b, 0x59, 0x6f, 0x57, 0x41, 0x43, 0x6a, 0x52, 0x38, 0x63, 0x47, + 0x70, 0x34, 0x51, 0x6a, 0x4b, 0x37, 0x75, 0x39, 0x6c, 0x69, 0x74, 0x2f, + 0x56, 0x63, 0x79, 0x4c, 0x77, 0x56, 0x63, 0x66, 0x44, 0x6d, 0x4a, 0x6c, + 0x44, 0x39, 0x30, 0x39, 0x56, 0x6f, 0x70, 0x7a, 0x32, 0x71, 0x35, 0x2b, + 0x0a, 0x62, 0x62, 0x71, 0x42, 0x48, 0x48, 0x35, 0x43, 0x6a, 0x43, 0x41, + 0x31, 0x32, 0x55, 0x4e, 0x4e, 0x68, 0x50, 0x71, 0x45, 0x32, 0x31, 0x49, + 0x73, 0x38, 0x77, 0x34, 0x6e, 0x64, 0x77, 0x74, 0x72, 0x76, 0x78, 0x45, + 0x76, 0x63, 0x6e, 0x69, 0x66, 0x4c, 0x74, 0x67, 0x2b, 0x35, 0x68, 0x67, + 0x33, 0x57, 0x69, 0x70, 0x79, 0x2b, 0x64, 0x70, 0x69, 0x6b, 0x4a, 0x4b, + 0x56, 0x79, 0x68, 0x2b, 0x63, 0x0a, 0x36, 0x62, 0x4d, 0x38, 0x4b, 0x38, + 0x76, 0x7a, 0x41, 0x52, 0x4f, 0x2f, 0x57, 0x73, 0x2f, 0x42, 0x74, 0x51, + 0x70, 0x67, 0x76, 0x64, 0x32, 0x31, 0x6d, 0x57, 0x52, 0x54, 0x75, 0x4b, + 0x43, 0x57, 0x73, 0x32, 0x2f, 0x69, 0x4a, 0x6e, 0x65, 0x52, 0x6a, 0x4f, + 0x42, 0x69, 0x45, 0x41, 0x4b, 0x66, 0x4e, 0x41, 0x2b, 0x6b, 0x31, 0x5a, + 0x49, 0x7a, 0x55, 0x64, 0x36, 0x2b, 0x6a, 0x62, 0x71, 0x45, 0x0a, 0x65, + 0x6d, 0x41, 0x38, 0x61, 0x74, 0x75, 0x66, 0x4b, 0x2b, 0x7a, 0x65, 0x33, + 0x67, 0x45, 0x2f, 0x62, 0x6b, 0x33, 0x6c, 0x55, 0x49, 0x62, 0x4c, 0x74, + 0x4b, 0x2f, 0x74, 0x52, 0x45, 0x44, 0x46, 0x79, 0x6c, 0x71, 0x4d, 0x32, + 0x74, 0x49, 0x72, 0x66, 0x4b, 0x6a, 0x75, 0x76, 0x71, 0x62, 0x6c, 0x43, + 0x71, 0x6f, 0x4f, 0x70, 0x64, 0x38, 0x46, 0x55, 0x72, 0x64, 0x56, 0x78, + 0x79, 0x4a, 0x64, 0x0a, 0x4d, 0x6d, 0x71, 0x58, 0x6c, 0x32, 0x4d, 0x54, + 0x32, 0x38, 0x6e, 0x62, 0x65, 0x54, 0x5a, 0x37, 0x68, 0x54, 0x70, 0x4b, + 0x78, 0x56, 0x4b, 0x4a, 0x2b, 0x53, 0x54, 0x6e, 0x6e, 0x58, 0x65, 0x70, + 0x67, 0x76, 0x39, 0x56, 0x48, 0x4b, 0x56, 0x78, 0x61, 0x53, 0x76, 0x52, + 0x41, 0x69, 0x54, 0x79, 0x73, 0x79, 0x62, 0x55, 0x61, 0x39, 0x6f, 0x45, + 0x56, 0x65, 0x58, 0x42, 0x43, 0x73, 0x64, 0x74, 0x0a, 0x4d, 0x44, 0x65, + 0x51, 0x4b, 0x75, 0x53, 0x65, 0x46, 0x44, 0x4e, 0x65, 0x46, 0x68, 0x64, + 0x56, 0x78, 0x56, 0x75, 0x31, 0x79, 0x7a, 0x53, 0x4a, 0x6b, 0x76, 0x47, + 0x64, 0x4a, 0x6f, 0x2b, 0x68, 0x42, 0x39, 0x54, 0x47, 0x73, 0x6e, 0x68, + 0x51, 0x32, 0x77, 0x77, 0x4d, 0x43, 0x33, 0x77, 0x4c, 0x6a, 0x45, 0x48, + 0x58, 0x75, 0x65, 0x6e, 0x64, 0x6a, 0x49, 0x6a, 0x33, 0x6f, 0x30, 0x32, + 0x79, 0x0a, 0x4d, 0x73, 0x7a, 0x59, 0x46, 0x39, 0x72, 0x4e, 0x74, 0x38, + 0x35, 0x6d, 0x6e, 0x64, 0x54, 0x39, 0x58, 0x76, 0x2b, 0x39, 0x6c, 0x7a, + 0x34, 0x70, 0x64, 0x65, 0x64, 0x2b, 0x70, 0x32, 0x4a, 0x59, 0x72, 0x79, + 0x55, 0x30, 0x70, 0x55, 0x48, 0x48, 0x50, 0x62, 0x77, 0x4e, 0x55, 0x4d, + 0x6f, 0x44, 0x41, 0x77, 0x38, 0x49, 0x57, 0x68, 0x2b, 0x56, 0x63, 0x33, + 0x68, 0x69, 0x76, 0x36, 0x39, 0x79, 0x0a, 0x46, 0x47, 0x6b, 0x4f, 0x70, + 0x65, 0x55, 0x44, 0x44, 0x6e, 0x69, 0x4f, 0x4a, 0x69, 0x68, 0x43, 0x38, + 0x41, 0x63, 0x4c, 0x59, 0x69, 0x41, 0x51, 0x5a, 0x7a, 0x6c, 0x47, 0x2b, + 0x71, 0x6b, 0x44, 0x7a, 0x41, 0x51, 0x34, 0x65, 0x6d, 0x62, 0x76, 0x49, + 0x49, 0x4f, 0x31, 0x6a, 0x45, 0x70, 0x57, 0x6a, 0x70, 0x45, 0x41, 0x2f, + 0x49, 0x35, 0x63, 0x67, 0x74, 0x36, 0x49, 0x6f, 0x4d, 0x50, 0x69, 0x0a, + 0x61, 0x47, 0x35, 0x39, 0x6a, 0x65, 0x38, 0x38, 0x33, 0x57, 0x58, 0x30, + 0x58, 0x61, 0x78, 0x52, 0x37, 0x79, 0x53, 0x41, 0x72, 0x71, 0x70, 0x57, + 0x6c, 0x32, 0x2f, 0x35, 0x72, 0x58, 0x33, 0x61, 0x59, 0x54, 0x2b, 0x59, + 0x64, 0x7a, 0x79, 0x6c, 0x6b, 0x62, 0x59, 0x63, 0x6a, 0x43, 0x62, 0x61, + 0x5a, 0x61, 0x49, 0x4a, 0x62, 0x63, 0x48, 0x69, 0x56, 0x4f, 0x4f, 0x35, + 0x79, 0x6b, 0x78, 0x4d, 0x0a, 0x67, 0x49, 0x39, 0x33, 0x65, 0x32, 0x43, + 0x61, 0x48, 0x74, 0x2b, 0x32, 0x38, 0x6b, 0x67, 0x65, 0x44, 0x72, 0x70, + 0x4f, 0x56, 0x47, 0x32, 0x59, 0x34, 0x4f, 0x47, 0x69, 0x47, 0x71, 0x4a, + 0x33, 0x55, 0x4d, 0x2f, 0x45, 0x59, 0x35, 0x4c, 0x73, 0x52, 0x78, 0x6d, + 0x64, 0x36, 0x2b, 0x5a, 0x72, 0x7a, 0x73, 0x45, 0x43, 0x41, 0x77, 0x45, + 0x41, 0x41, 0x61, 0x4f, 0x42, 0x72, 0x44, 0x43, 0x42, 0x0a, 0x71, 0x54, + 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, + 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x44, 0x77, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, + 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x64, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x57, 0x79, + 0x56, 0x37, 0x0a, 0x6c, 0x71, 0x52, 0x6c, 0x55, 0x58, 0x36, 0x34, 0x4f, + 0x66, 0x50, 0x41, 0x65, 0x47, 0x5a, 0x65, 0x36, 0x44, 0x72, 0x6e, 0x38, + 0x4f, 0x34, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6a, 0x42, + 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x57, 0x79, 0x56, 0x37, 0x6c, + 0x71, 0x52, 0x6c, 0x55, 0x58, 0x36, 0x34, 0x4f, 0x66, 0x50, 0x41, 0x65, + 0x47, 0x5a, 0x65, 0x36, 0x44, 0x72, 0x6e, 0x0a, 0x38, 0x4f, 0x34, 0x77, + 0x52, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x67, 0x42, 0x44, 0x38, 0x77, + 0x50, 0x54, 0x41, 0x37, 0x42, 0x67, 0x6c, 0x67, 0x68, 0x58, 0x51, 0x42, + 0x57, 0x51, 0x45, 0x43, 0x41, 0x51, 0x45, 0x77, 0x4c, 0x6a, 0x41, 0x73, + 0x42, 0x67, 0x67, 0x72, 0x42, 0x67, 0x45, 0x46, 0x42, 0x51, 0x63, 0x43, + 0x41, 0x52, 0x59, 0x67, 0x61, 0x48, 0x52, 0x30, 0x63, 0x44, 0x6f, 0x76, + 0x0a, 0x4c, 0x33, 0x4a, 0x6c, 0x63, 0x47, 0x39, 0x7a, 0x61, 0x58, 0x52, + 0x76, 0x63, 0x6e, 0x6b, 0x75, 0x63, 0x33, 0x64, 0x70, 0x63, 0x33, 0x4e, + 0x7a, 0x61, 0x57, 0x64, 0x75, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x53, 0x38, + 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, + 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, + 0x42, 0x41, 0x43, 0x65, 0x36, 0x0a, 0x34, 0x35, 0x52, 0x38, 0x38, 0x61, + 0x37, 0x41, 0x33, 0x68, 0x66, 0x6d, 0x35, 0x64, 0x6a, 0x56, 0x39, 0x56, + 0x53, 0x77, 0x67, 0x2f, 0x53, 0x37, 0x7a, 0x56, 0x34, 0x46, 0x65, 0x30, + 0x2b, 0x66, 0x64, 0x57, 0x61, 0x76, 0x50, 0x4f, 0x68, 0x57, 0x66, 0x76, + 0x78, 0x79, 0x65, 0x44, 0x67, 0x44, 0x32, 0x53, 0x74, 0x69, 0x47, 0x77, + 0x43, 0x35, 0x2b, 0x4f, 0x6c, 0x67, 0x7a, 0x63, 0x7a, 0x4f, 0x0a, 0x55, + 0x59, 0x72, 0x48, 0x55, 0x44, 0x46, 0x75, 0x34, 0x55, 0x70, 0x2b, 0x47, + 0x43, 0x39, 0x70, 0x57, 0x62, 0x59, 0x39, 0x5a, 0x49, 0x45, 0x72, 0x34, + 0x34, 0x4f, 0x45, 0x35, 0x69, 0x4b, 0x48, 0x6a, 0x6e, 0x33, 0x67, 0x37, + 0x67, 0x4b, 0x5a, 0x59, 0x62, 0x67, 0x65, 0x39, 0x4c, 0x67, 0x72, 0x69, + 0x42, 0x49, 0x57, 0x68, 0x4d, 0x49, 0x78, 0x6b, 0x7a, 0x69, 0x57, 0x4d, + 0x61, 0x61, 0x35, 0x0a, 0x4f, 0x31, 0x4d, 0x2f, 0x77, 0x79, 0x53, 0x54, + 0x56, 0x6c, 0x74, 0x70, 0x6b, 0x75, 0x7a, 0x46, 0x77, 0x62, 0x73, 0x34, + 0x41, 0x4f, 0x50, 0x73, 0x46, 0x36, 0x6d, 0x34, 0x33, 0x4d, 0x64, 0x38, + 0x41, 0x59, 0x4f, 0x66, 0x4d, 0x6b, 0x65, 0x36, 0x55, 0x69, 0x49, 0x30, + 0x48, 0x54, 0x4a, 0x36, 0x43, 0x56, 0x61, 0x6e, 0x66, 0x43, 0x55, 0x32, + 0x71, 0x54, 0x31, 0x4c, 0x32, 0x73, 0x43, 0x43, 0x0a, 0x62, 0x77, 0x71, + 0x37, 0x45, 0x73, 0x69, 0x48, 0x53, 0x79, 0x63, 0x52, 0x2b, 0x52, 0x34, + 0x74, 0x78, 0x35, 0x4d, 0x2f, 0x6e, 0x74, 0x74, 0x66, 0x4a, 0x6d, 0x74, + 0x53, 0x32, 0x53, 0x36, 0x4b, 0x38, 0x52, 0x54, 0x47, 0x52, 0x49, 0x30, + 0x56, 0x71, 0x62, 0x65, 0x2f, 0x76, 0x64, 0x36, 0x6d, 0x47, 0x75, 0x36, + 0x75, 0x4c, 0x66, 0x74, 0x49, 0x64, 0x78, 0x66, 0x2b, 0x75, 0x2b, 0x79, + 0x76, 0x0a, 0x47, 0x50, 0x55, 0x71, 0x55, 0x66, 0x41, 0x35, 0x68, 0x4a, + 0x65, 0x56, 0x62, 0x47, 0x34, 0x62, 0x77, 0x79, 0x76, 0x45, 0x64, 0x47, + 0x42, 0x35, 0x4a, 0x62, 0x41, 0x4b, 0x4a, 0x39, 0x2f, 0x66, 0x58, 0x74, + 0x49, 0x35, 0x7a, 0x30, 0x56, 0x39, 0x51, 0x6b, 0x76, 0x66, 0x73, 0x79, + 0x77, 0x65, 0x78, 0x63, 0x5a, 0x64, 0x79, 0x6c, 0x55, 0x36, 0x6f, 0x4a, + 0x78, 0x70, 0x6d, 0x6f, 0x2f, 0x61, 0x0a, 0x37, 0x37, 0x4b, 0x77, 0x50, + 0x4a, 0x2b, 0x48, 0x62, 0x42, 0x49, 0x72, 0x5a, 0x58, 0x41, 0x56, 0x55, + 0x6a, 0x45, 0x61, 0x4a, 0x4d, 0x39, 0x76, 0x4d, 0x53, 0x4e, 0x51, 0x48, + 0x34, 0x78, 0x50, 0x6a, 0x79, 0x50, 0x44, 0x64, 0x45, 0x46, 0x6a, 0x48, + 0x46, 0x57, 0x6f, 0x46, 0x4e, 0x30, 0x2b, 0x34, 0x46, 0x46, 0x51, 0x7a, + 0x2f, 0x45, 0x62, 0x4d, 0x46, 0x59, 0x4f, 0x6b, 0x72, 0x43, 0x43, 0x0a, + 0x68, 0x64, 0x69, 0x44, 0x79, 0x79, 0x4a, 0x6b, 0x76, 0x43, 0x32, 0x34, + 0x4a, 0x64, 0x56, 0x55, 0x6f, 0x72, 0x67, 0x47, 0x36, 0x71, 0x32, 0x53, + 0x70, 0x43, 0x53, 0x67, 0x77, 0x59, 0x61, 0x31, 0x53, 0x68, 0x4e, 0x71, + 0x52, 0x38, 0x38, 0x75, 0x43, 0x31, 0x61, 0x56, 0x56, 0x4d, 0x76, 0x4f, + 0x6d, 0x74, 0x74, 0x71, 0x74, 0x4b, 0x61, 0x79, 0x32, 0x30, 0x45, 0x49, + 0x68, 0x69, 0x64, 0x33, 0x0a, 0x39, 0x32, 0x71, 0x67, 0x51, 0x6d, 0x77, + 0x4c, 0x4f, 0x4d, 0x37, 0x58, 0x64, 0x56, 0x41, 0x79, 0x6b, 0x73, 0x4c, + 0x66, 0x4b, 0x7a, 0x41, 0x69, 0x53, 0x4e, 0x44, 0x56, 0x51, 0x54, 0x67, + 0x6c, 0x58, 0x61, 0x54, 0x70, 0x58, 0x5a, 0x2f, 0x47, 0x6c, 0x48, 0x58, + 0x51, 0x52, 0x66, 0x30, 0x77, 0x6c, 0x30, 0x4f, 0x50, 0x6b, 0x4b, 0x73, + 0x4b, 0x78, 0x34, 0x5a, 0x7a, 0x59, 0x45, 0x70, 0x70, 0x0a, 0x4c, 0x64, + 0x36, 0x6c, 0x65, 0x4e, 0x63, 0x47, 0x32, 0x6d, 0x71, 0x65, 0x53, 0x7a, + 0x35, 0x33, 0x4f, 0x69, 0x41, 0x54, 0x49, 0x67, 0x48, 0x51, 0x76, 0x32, + 0x69, 0x65, 0x59, 0x32, 0x42, 0x72, 0x4e, 0x55, 0x30, 0x4c, 0x62, 0x62, + 0x71, 0x68, 0x50, 0x63, 0x43, 0x54, 0x34, 0x48, 0x38, 0x6a, 0x73, 0x31, + 0x57, 0x74, 0x63, 0x69, 0x56, 0x4f, 0x52, 0x76, 0x6e, 0x53, 0x46, 0x75, + 0x2b, 0x77, 0x0a, 0x5a, 0x4d, 0x45, 0x42, 0x6e, 0x75, 0x6e, 0x4b, 0x6f, + 0x47, 0x71, 0x59, 0x44, 0x73, 0x2f, 0x59, 0x59, 0x50, 0x49, 0x76, 0x53, + 0x62, 0x6a, 0x6b, 0x51, 0x75, 0x45, 0x34, 0x4e, 0x52, 0x62, 0x30, 0x79, + 0x47, 0x35, 0x50, 0x39, 0x34, 0x46, 0x57, 0x36, 0x4c, 0x71, 0x6a, 0x76, + 0x69, 0x4f, 0x76, 0x72, 0x76, 0x31, 0x76, 0x41, 0x2b, 0x41, 0x43, 0x4f, + 0x7a, 0x42, 0x32, 0x2b, 0x68, 0x74, 0x74, 0x0a, 0x51, 0x63, 0x38, 0x42, + 0x73, 0x65, 0x6d, 0x34, 0x79, 0x57, 0x62, 0x30, 0x32, 0x79, 0x62, 0x7a, + 0x4f, 0x71, 0x52, 0x30, 0x38, 0x6b, 0x6b, 0x6b, 0x57, 0x38, 0x6d, 0x77, + 0x30, 0x46, 0x66, 0x42, 0x2b, 0x6a, 0x35, 0x36, 0x34, 0x5a, 0x66, 0x4a, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x77, 0x69, 0x73, 0x73, 0x53, 0x69, + 0x67, 0x6e, 0x20, 0x53, 0x69, 0x6c, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, + 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x53, 0x77, 0x69, 0x73, + 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x41, 0x47, 0x0a, 0x23, 0x20, 0x53, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, + 0x77, 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x53, 0x69, 0x6c, + 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, + 0x4f, 0x3d, 0x53, 0x77, 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20, + 0x41, 0x47, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x53, 0x77, 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x53, + 0x69, 0x6c, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, + 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x35, 0x37, 0x30, 0x30, 0x33, 0x38, 0x33, 0x30, 0x35, 0x33, 0x31, + 0x31, 0x37, 0x35, 0x39, 0x39, 0x35, 0x36, 0x33, 0x0a, 0x23, 0x20, 0x4d, + 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x30, 0x3a, 0x30, 0x36, 0x3a, 0x61, 0x31, + 0x3a, 0x63, 0x39, 0x3a, 0x37, 0x64, 0x3a, 0x63, 0x66, 0x3a, 0x63, 0x39, + 0x3a, 0x66, 0x63, 0x3a, 0x30, 0x64, 0x3a, 0x63, 0x30, 0x3a, 0x35, 0x36, + 0x3a, 0x37, 0x35, 0x3a, 0x39, 0x36, 0x3a, 0x64, 0x38, 0x3a, 0x36, 0x32, + 0x3a, 0x31, 0x33, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x39, 0x62, 0x3a, 0x61, 0x61, 0x3a, 0x65, 0x35, 0x3a, 0x39, 0x66, 0x3a, + 0x35, 0x36, 0x3a, 0x65, 0x65, 0x3a, 0x32, 0x31, 0x3a, 0x63, 0x62, 0x3a, + 0x34, 0x33, 0x3a, 0x35, 0x61, 0x3a, 0x62, 0x65, 0x3a, 0x32, 0x35, 0x3a, + 0x39, 0x33, 0x3a, 0x64, 0x66, 0x3a, 0x61, 0x37, 0x3a, 0x66, 0x30, 0x3a, + 0x34, 0x30, 0x3a, 0x64, 0x31, 0x3a, 0x31, 0x64, 0x3a, 0x63, 0x62, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x65, + 0x3a, 0x36, 0x63, 0x3a, 0x34, 0x64, 0x3a, 0x61, 0x32, 0x3a, 0x62, 0x62, + 0x3a, 0x62, 0x39, 0x3a, 0x62, 0x61, 0x3a, 0x35, 0x39, 0x3a, 0x62, 0x36, + 0x3a, 0x66, 0x33, 0x3a, 0x39, 0x33, 0x3a, 0x39, 0x37, 0x3a, 0x36, 0x38, + 0x3a, 0x33, 0x37, 0x3a, 0x34, 0x32, 0x3a, 0x34, 0x36, 0x3a, 0x63, 0x33, + 0x3a, 0x63, 0x30, 0x3a, 0x30, 0x35, 0x3a, 0x39, 0x39, 0x3a, 0x33, 0x66, + 0x3a, 0x61, 0x39, 0x3a, 0x38, 0x66, 0x3a, 0x30, 0x32, 0x3a, 0x30, 0x64, + 0x3a, 0x31, 0x64, 0x3a, 0x65, 0x64, 0x3a, 0x62, 0x65, 0x3a, 0x64, 0x34, + 0x3a, 0x38, 0x61, 0x3a, 0x38, 0x31, 0x3a, 0x64, 0x35, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x76, 0x54, 0x43, 0x43, 0x41, 0x36, + 0x57, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x49, 0x54, 0x78, + 0x76, 0x55, 0x4c, 0x31, 0x53, 0x37, 0x4c, 0x30, 0x73, 0x77, 0x44, 0x51, + 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, + 0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x52, 0x7a, 0x45, 0x4c, 0x4d, 0x41, + 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x42, 0x68, 0x4d, 0x43, 0x51, + 0x30, 0x67, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x6f, 0x54, 0x44, 0x46, 0x4e, 0x33, 0x61, 0x58, 0x4e, 0x7a, 0x55, + 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x42, 0x52, 0x7a, 0x45, 0x68, 0x4d, + 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x59, 0x55, + 0x33, 0x64, 0x70, 0x63, 0x33, 0x4e, 0x54, 0x61, 0x57, 0x64, 0x75, 0x0a, + 0x49, 0x46, 0x4e, 0x70, 0x62, 0x48, 0x5a, 0x6c, 0x63, 0x69, 0x42, 0x44, + 0x51, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x79, 0x4d, 0x42, 0x34, 0x58, + 0x44, 0x54, 0x41, 0x32, 0x4d, 0x54, 0x41, 0x79, 0x4e, 0x54, 0x41, 0x34, + 0x4d, 0x7a, 0x49, 0x30, 0x4e, 0x6c, 0x6f, 0x58, 0x44, 0x54, 0x4d, 0x32, + 0x4d, 0x54, 0x41, 0x79, 0x4e, 0x54, 0x41, 0x34, 0x4d, 0x7a, 0x49, 0x30, + 0x4e, 0x6c, 0x6f, 0x77, 0x0a, 0x52, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x51, 0x30, 0x67, + 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, + 0x54, 0x44, 0x46, 0x4e, 0x33, 0x61, 0x58, 0x4e, 0x7a, 0x55, 0x32, 0x6c, + 0x6e, 0x62, 0x69, 0x42, 0x42, 0x52, 0x7a, 0x45, 0x68, 0x4d, 0x42, 0x38, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x59, 0x0a, 0x55, 0x33, + 0x64, 0x70, 0x63, 0x33, 0x4e, 0x54, 0x61, 0x57, 0x64, 0x75, 0x49, 0x46, + 0x4e, 0x70, 0x62, 0x48, 0x5a, 0x6c, 0x63, 0x69, 0x42, 0x44, 0x51, 0x53, + 0x41, 0x74, 0x49, 0x45, 0x63, 0x79, 0x4d, 0x49, 0x49, 0x43, 0x49, 0x6a, + 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, + 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, + 0x38, 0x41, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x43, 0x67, 0x4b, 0x43, 0x41, + 0x67, 0x45, 0x41, 0x78, 0x50, 0x47, 0x48, 0x66, 0x39, 0x4e, 0x34, 0x4d, + 0x66, 0x63, 0x34, 0x79, 0x66, 0x6a, 0x44, 0x6d, 0x55, 0x4f, 0x38, 0x78, + 0x2f, 0x65, 0x38, 0x4e, 0x2b, 0x64, 0x4f, 0x63, 0x62, 0x70, 0x4c, 0x6a, + 0x36, 0x56, 0x7a, 0x48, 0x56, 0x78, 0x75, 0x6d, 0x4b, 0x34, 0x44, 0x56, + 0x36, 0x34, 0x34, 0x4e, 0x30, 0x4d, 0x76, 0x0a, 0x46, 0x7a, 0x30, 0x66, + 0x79, 0x4d, 0x35, 0x6f, 0x45, 0x4d, 0x46, 0x34, 0x72, 0x68, 0x6b, 0x44, + 0x4b, 0x78, 0x44, 0x36, 0x4c, 0x48, 0x6d, 0x44, 0x39, 0x75, 0x69, 0x35, + 0x61, 0x4c, 0x6c, 0x56, 0x38, 0x67, 0x52, 0x45, 0x70, 0x7a, 0x6e, 0x35, + 0x2f, 0x41, 0x53, 0x4c, 0x48, 0x76, 0x47, 0x69, 0x54, 0x53, 0x66, 0x35, + 0x59, 0x58, 0x75, 0x36, 0x74, 0x2b, 0x57, 0x69, 0x45, 0x37, 0x62, 0x72, + 0x0a, 0x59, 0x54, 0x37, 0x51, 0x62, 0x4e, 0x48, 0x6d, 0x2b, 0x2f, 0x70, + 0x65, 0x37, 0x52, 0x32, 0x30, 0x6e, 0x71, 0x41, 0x31, 0x57, 0x36, 0x47, + 0x53, 0x79, 0x2f, 0x42, 0x4a, 0x6b, 0x76, 0x36, 0x46, 0x43, 0x67, 0x55, + 0x2b, 0x35, 0x74, 0x6b, 0x4c, 0x34, 0x6b, 0x2b, 0x37, 0x33, 0x4a, 0x55, + 0x33, 0x2f, 0x4a, 0x48, 0x70, 0x4d, 0x6a, 0x55, 0x69, 0x30, 0x52, 0x38, + 0x36, 0x54, 0x69, 0x65, 0x46, 0x0a, 0x6e, 0x62, 0x41, 0x56, 0x6c, 0x44, + 0x4c, 0x61, 0x59, 0x51, 0x31, 0x48, 0x54, 0x57, 0x42, 0x43, 0x72, 0x70, + 0x4a, 0x48, 0x36, 0x49, 0x4e, 0x61, 0x55, 0x46, 0x6a, 0x70, 0x69, 0x6f, + 0x75, 0x35, 0x58, 0x61, 0x48, 0x63, 0x33, 0x5a, 0x6c, 0x4b, 0x48, 0x7a, + 0x5a, 0x6e, 0x75, 0x30, 0x6a, 0x6b, 0x67, 0x37, 0x59, 0x33, 0x36, 0x30, + 0x67, 0x36, 0x72, 0x77, 0x39, 0x6e, 0x6a, 0x78, 0x63, 0x48, 0x0a, 0x36, + 0x41, 0x54, 0x4b, 0x37, 0x32, 0x6f, 0x78, 0x68, 0x39, 0x54, 0x41, 0x74, + 0x76, 0x6d, 0x55, 0x63, 0x58, 0x74, 0x6e, 0x5a, 0x4c, 0x69, 0x32, 0x6b, + 0x55, 0x70, 0x43, 0x65, 0x32, 0x55, 0x75, 0x4d, 0x47, 0x6f, 0x4d, 0x39, + 0x5a, 0x44, 0x75, 0x6c, 0x65, 0x62, 0x79, 0x7a, 0x59, 0x4c, 0x73, 0x32, + 0x61, 0x46, 0x4b, 0x37, 0x50, 0x61, 0x79, 0x53, 0x2b, 0x56, 0x46, 0x68, + 0x65, 0x5a, 0x74, 0x0a, 0x65, 0x4a, 0x4d, 0x45, 0x4c, 0x70, 0x79, 0x43, + 0x62, 0x54, 0x61, 0x70, 0x78, 0x44, 0x46, 0x6b, 0x48, 0x34, 0x61, 0x44, + 0x43, 0x79, 0x72, 0x30, 0x4e, 0x51, 0x70, 0x34, 0x79, 0x56, 0x58, 0x50, + 0x51, 0x62, 0x42, 0x48, 0x36, 0x54, 0x43, 0x66, 0x6d, 0x62, 0x35, 0x68, + 0x71, 0x41, 0x61, 0x45, 0x75, 0x53, 0x68, 0x36, 0x58, 0x7a, 0x6a, 0x5a, + 0x47, 0x36, 0x6b, 0x34, 0x73, 0x49, 0x4e, 0x2f, 0x0a, 0x63, 0x38, 0x48, + 0x44, 0x4f, 0x30, 0x67, 0x71, 0x67, 0x67, 0x38, 0x68, 0x6d, 0x37, 0x6a, + 0x4d, 0x71, 0x44, 0x58, 0x44, 0x68, 0x42, 0x75, 0x44, 0x73, 0x7a, 0x36, + 0x2b, 0x70, 0x4a, 0x56, 0x70, 0x41, 0x54, 0x71, 0x4a, 0x41, 0x48, 0x67, + 0x45, 0x32, 0x63, 0x6e, 0x30, 0x6d, 0x52, 0x6d, 0x72, 0x56, 0x6e, 0x35, + 0x62, 0x69, 0x34, 0x59, 0x35, 0x46, 0x5a, 0x47, 0x6b, 0x45, 0x43, 0x77, + 0x4a, 0x0a, 0x4d, 0x6f, 0x42, 0x67, 0x73, 0x35, 0x50, 0x41, 0x4b, 0x72, + 0x59, 0x59, 0x43, 0x35, 0x31, 0x2b, 0x6a, 0x55, 0x6e, 0x79, 0x45, 0x45, + 0x70, 0x2f, 0x2b, 0x64, 0x56, 0x47, 0x4c, 0x78, 0x6d, 0x53, 0x6f, 0x35, + 0x6d, 0x6e, 0x4a, 0x71, 0x79, 0x37, 0x6a, 0x44, 0x7a, 0x6d, 0x44, 0x72, + 0x78, 0x48, 0x42, 0x39, 0x78, 0x7a, 0x55, 0x66, 0x46, 0x77, 0x5a, 0x43, + 0x38, 0x49, 0x2b, 0x62, 0x52, 0x48, 0x0a, 0x48, 0x54, 0x42, 0x73, 0x52, + 0x4f, 0x6f, 0x70, 0x4e, 0x34, 0x57, 0x53, 0x61, 0x47, 0x61, 0x38, 0x67, + 0x7a, 0x6a, 0x2b, 0x65, 0x7a, 0x6b, 0x75, 0x30, 0x31, 0x44, 0x77, 0x48, + 0x2f, 0x74, 0x65, 0x59, 0x4c, 0x61, 0x70, 0x70, 0x76, 0x6f, 0x6e, 0x51, + 0x66, 0x47, 0x62, 0x47, 0x48, 0x4c, 0x79, 0x39, 0x59, 0x52, 0x30, 0x53, + 0x73, 0x6c, 0x6e, 0x78, 0x46, 0x53, 0x75, 0x53, 0x47, 0x54, 0x66, 0x0a, + 0x6a, 0x4e, 0x46, 0x75, 0x73, 0x42, 0x33, 0x68, 0x42, 0x34, 0x38, 0x49, + 0x48, 0x70, 0x6d, 0x63, 0x63, 0x65, 0x6c, 0x4d, 0x32, 0x4b, 0x58, 0x33, + 0x52, 0x78, 0x49, 0x66, 0x64, 0x4e, 0x46, 0x52, 0x6e, 0x6f, 0x62, 0x7a, + 0x77, 0x71, 0x49, 0x6a, 0x51, 0x41, 0x74, 0x7a, 0x32, 0x30, 0x75, 0x6d, + 0x35, 0x33, 0x4d, 0x47, 0x6a, 0x4d, 0x47, 0x67, 0x36, 0x63, 0x46, 0x5a, + 0x72, 0x45, 0x62, 0x36, 0x0a, 0x35, 0x69, 0x2f, 0x34, 0x7a, 0x33, 0x47, + 0x63, 0x52, 0x6d, 0x32, 0x35, 0x78, 0x42, 0x57, 0x4e, 0x4f, 0x48, 0x6b, + 0x44, 0x52, 0x55, 0x6a, 0x76, 0x78, 0x46, 0x33, 0x58, 0x43, 0x4f, 0x36, + 0x48, 0x4f, 0x53, 0x4b, 0x47, 0x73, 0x67, 0x30, 0x50, 0x57, 0x45, 0x50, + 0x33, 0x63, 0x61, 0x6c, 0x49, 0x4c, 0x76, 0x33, 0x71, 0x31, 0x68, 0x38, + 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4f, 0x42, 0x0a, 0x72, 0x44, + 0x43, 0x42, 0x71, 0x54, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, + 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, + 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, + 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, + 0x51, 0x55, 0x0a, 0x46, 0x36, 0x44, 0x4e, 0x77, 0x65, 0x52, 0x42, 0x74, + 0x6a, 0x70, 0x62, 0x4f, 0x38, 0x74, 0x46, 0x6e, 0x62, 0x30, 0x63, 0x77, + 0x70, 0x6a, 0x36, 0x68, 0x6c, 0x67, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x46, + 0x36, 0x44, 0x4e, 0x77, 0x65, 0x52, 0x42, 0x74, 0x6a, 0x70, 0x62, 0x4f, + 0x38, 0x74, 0x46, 0x6e, 0x62, 0x30, 0x63, 0x0a, 0x77, 0x70, 0x6a, 0x36, + 0x68, 0x6c, 0x67, 0x77, 0x52, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x67, + 0x42, 0x44, 0x38, 0x77, 0x50, 0x54, 0x41, 0x37, 0x42, 0x67, 0x6c, 0x67, + 0x68, 0x58, 0x51, 0x42, 0x57, 0x51, 0x45, 0x44, 0x41, 0x51, 0x45, 0x77, + 0x4c, 0x6a, 0x41, 0x73, 0x42, 0x67, 0x67, 0x72, 0x42, 0x67, 0x45, 0x46, + 0x42, 0x51, 0x63, 0x43, 0x41, 0x52, 0x59, 0x67, 0x61, 0x48, 0x52, 0x30, + 0x0a, 0x63, 0x44, 0x6f, 0x76, 0x4c, 0x33, 0x4a, 0x6c, 0x63, 0x47, 0x39, + 0x7a, 0x61, 0x58, 0x52, 0x76, 0x63, 0x6e, 0x6b, 0x75, 0x63, 0x33, 0x64, + 0x70, 0x63, 0x33, 0x4e, 0x7a, 0x61, 0x57, 0x64, 0x75, 0x4c, 0x6d, 0x4e, + 0x76, 0x62, 0x53, 0x38, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, + 0x44, 0x67, 0x67, 0x49, 0x42, 0x0a, 0x41, 0x48, 0x50, 0x47, 0x67, 0x65, + 0x41, 0x6e, 0x30, 0x69, 0x30, 0x50, 0x34, 0x4a, 0x55, 0x77, 0x34, 0x70, + 0x70, 0x42, 0x66, 0x31, 0x41, 0x73, 0x58, 0x31, 0x39, 0x69, 0x59, 0x61, + 0x6d, 0x47, 0x61, 0x6d, 0x6b, 0x59, 0x44, 0x48, 0x52, 0x4a, 0x31, 0x6c, + 0x32, 0x45, 0x36, 0x6b, 0x46, 0x53, 0x47, 0x47, 0x39, 0x59, 0x72, 0x56, + 0x42, 0x57, 0x49, 0x47, 0x72, 0x47, 0x76, 0x53, 0x68, 0x70, 0x0a, 0x57, + 0x4a, 0x48, 0x63, 0x6b, 0x52, 0x45, 0x31, 0x71, 0x54, 0x6f, 0x64, 0x76, + 0x42, 0x71, 0x6c, 0x59, 0x4a, 0x37, 0x59, 0x48, 0x33, 0x39, 0x46, 0x6b, + 0x57, 0x6e, 0x5a, 0x66, 0x72, 0x74, 0x34, 0x63, 0x73, 0x45, 0x47, 0x44, + 0x79, 0x72, 0x4f, 0x6a, 0x34, 0x56, 0x77, 0x59, 0x61, 0x79, 0x67, 0x7a, + 0x51, 0x75, 0x34, 0x4f, 0x53, 0x6c, 0x57, 0x68, 0x44, 0x4a, 0x4f, 0x68, + 0x72, 0x73, 0x39, 0x0a, 0x78, 0x43, 0x72, 0x5a, 0x31, 0x78, 0x39, 0x79, + 0x37, 0x76, 0x35, 0x52, 0x6f, 0x53, 0x4a, 0x42, 0x73, 0x58, 0x45, 0x43, + 0x59, 0x78, 0x71, 0x43, 0x73, 0x47, 0x4b, 0x72, 0x58, 0x6c, 0x63, 0x53, + 0x48, 0x39, 0x2f, 0x4c, 0x33, 0x58, 0x57, 0x67, 0x77, 0x46, 0x31, 0x35, + 0x6b, 0x49, 0x77, 0x62, 0x34, 0x46, 0x44, 0x6d, 0x33, 0x6a, 0x48, 0x2b, + 0x6d, 0x48, 0x74, 0x77, 0x58, 0x36, 0x57, 0x51, 0x0a, 0x32, 0x4b, 0x33, + 0x34, 0x41, 0x72, 0x5a, 0x76, 0x30, 0x32, 0x44, 0x64, 0x51, 0x45, 0x73, + 0x69, 0x78, 0x54, 0x32, 0x74, 0x4f, 0x6e, 0x71, 0x66, 0x47, 0x68, 0x70, + 0x48, 0x6b, 0x58, 0x6b, 0x7a, 0x75, 0x6f, 0x4c, 0x63, 0x4d, 0x6d, 0x6b, + 0x44, 0x6c, 0x6d, 0x34, 0x66, 0x53, 0x2f, 0x42, 0x78, 0x2f, 0x75, 0x4e, + 0x6e, 0x63, 0x71, 0x43, 0x78, 0x76, 0x31, 0x79, 0x4c, 0x35, 0x50, 0x71, + 0x5a, 0x0a, 0x49, 0x73, 0x65, 0x45, 0x75, 0x52, 0x75, 0x4e, 0x49, 0x35, + 0x63, 0x2f, 0x37, 0x53, 0x58, 0x67, 0x7a, 0x32, 0x57, 0x37, 0x39, 0x57, + 0x45, 0x45, 0x37, 0x39, 0x30, 0x65, 0x73, 0x6c, 0x70, 0x42, 0x49, 0x6c, + 0x71, 0x68, 0x6e, 0x31, 0x30, 0x73, 0x36, 0x46, 0x76, 0x4a, 0x62, 0x61, + 0x6b, 0x4d, 0x44, 0x48, 0x69, 0x71, 0x59, 0x4d, 0x5a, 0x57, 0x6a, 0x77, + 0x46, 0x61, 0x44, 0x47, 0x69, 0x38, 0x0a, 0x61, 0x52, 0x6c, 0x35, 0x78, + 0x42, 0x39, 0x2b, 0x6c, 0x77, 0x57, 0x2f, 0x78, 0x65, 0x6b, 0x6b, 0x55, + 0x56, 0x37, 0x55, 0x31, 0x55, 0x74, 0x54, 0x37, 0x64, 0x6b, 0x6a, 0x57, + 0x6a, 0x59, 0x44, 0x5a, 0x61, 0x50, 0x42, 0x41, 0x36, 0x31, 0x42, 0x4d, + 0x50, 0x4e, 0x47, 0x47, 0x34, 0x57, 0x51, 0x72, 0x32, 0x57, 0x31, 0x31, + 0x62, 0x48, 0x6b, 0x46, 0x6c, 0x74, 0x34, 0x64, 0x52, 0x32, 0x58, 0x0a, + 0x65, 0x6d, 0x31, 0x5a, 0x71, 0x53, 0x71, 0x50, 0x65, 0x39, 0x37, 0x44, + 0x68, 0x34, 0x6b, 0x51, 0x6d, 0x55, 0x6c, 0x7a, 0x65, 0x4d, 0x67, 0x39, + 0x76, 0x56, 0x45, 0x31, 0x64, 0x43, 0x72, 0x56, 0x38, 0x58, 0x35, 0x70, + 0x47, 0x79, 0x71, 0x37, 0x4f, 0x37, 0x30, 0x6c, 0x75, 0x4a, 0x70, 0x61, + 0x50, 0x58, 0x4a, 0x68, 0x6b, 0x47, 0x61, 0x48, 0x37, 0x67, 0x7a, 0x57, + 0x54, 0x64, 0x51, 0x52, 0x0a, 0x64, 0x41, 0x74, 0x71, 0x2f, 0x67, 0x73, + 0x44, 0x2f, 0x4b, 0x4e, 0x56, 0x56, 0x34, 0x6e, 0x2b, 0x53, 0x73, 0x75, + 0x75, 0x57, 0x78, 0x63, 0x46, 0x79, 0x50, 0x4b, 0x4e, 0x49, 0x7a, 0x46, + 0x54, 0x4f, 0x4e, 0x49, 0x74, 0x61, 0x6a, 0x2b, 0x43, 0x75, 0x59, 0x30, + 0x49, 0x61, 0x76, 0x64, 0x65, 0x51, 0x58, 0x52, 0x75, 0x77, 0x78, 0x46, + 0x2b, 0x42, 0x36, 0x77, 0x70, 0x59, 0x4a, 0x45, 0x2f, 0x0a, 0x4f, 0x4d, + 0x70, 0x58, 0x45, 0x41, 0x32, 0x39, 0x4d, 0x43, 0x2f, 0x48, 0x70, 0x65, + 0x5a, 0x42, 0x6f, 0x4e, 0x71, 0x75, 0x42, 0x59, 0x65, 0x61, 0x6f, 0x4b, + 0x52, 0x6c, 0x62, 0x45, 0x77, 0x4a, 0x44, 0x49, 0x6d, 0x36, 0x75, 0x4e, + 0x4f, 0x35, 0x77, 0x4a, 0x4f, 0x4b, 0x4d, 0x50, 0x71, 0x4e, 0x35, 0x5a, + 0x70, 0x72, 0x46, 0x51, 0x46, 0x4f, 0x5a, 0x36, 0x72, 0x61, 0x59, 0x6c, + 0x59, 0x2b, 0x0a, 0x68, 0x41, 0x68, 0x6d, 0x30, 0x73, 0x51, 0x32, 0x66, + 0x61, 0x63, 0x2b, 0x45, 0x50, 0x79, 0x49, 0x34, 0x4e, 0x53, 0x41, 0x35, + 0x51, 0x43, 0x39, 0x71, 0x76, 0x4e, 0x4f, 0x42, 0x71, 0x4e, 0x36, 0x61, + 0x76, 0x6c, 0x69, 0x63, 0x75, 0x4d, 0x4a, 0x54, 0x2b, 0x75, 0x62, 0x44, + 0x67, 0x45, 0x6a, 0x38, 0x5a, 0x2b, 0x37, 0x66, 0x4e, 0x7a, 0x63, 0x62, + 0x42, 0x47, 0x58, 0x4a, 0x62, 0x4c, 0x79, 0x0a, 0x74, 0x47, 0x4d, 0x55, + 0x30, 0x67, 0x59, 0x71, 0x5a, 0x34, 0x79, 0x44, 0x39, 0x63, 0x37, 0x71, + 0x42, 0x39, 0x69, 0x61, 0x61, 0x68, 0x37, 0x73, 0x35, 0x41, 0x71, 0x37, + 0x4b, 0x6b, 0x7a, 0x72, 0x43, 0x57, 0x41, 0x35, 0x7a, 0x73, 0x70, 0x69, + 0x32, 0x43, 0x35, 0x75, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, + 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, + 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x33, 0x32, 0x37, 0x39, 0x38, + 0x32, 0x32, 0x36, 0x35, 0x35, 0x31, 0x32, 0x35, 0x36, 0x39, 0x36, 0x33, + 0x33, 0x32, 0x34, 0x33, 0x31, 0x33, 0x38, 0x30, 0x36, 0x34, 0x33, 0x36, + 0x39, 0x38, 0x31, 0x39, 0x38, 0x32, 0x33, 0x36, 0x39, 0x0a, 0x23, 0x20, + 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x32, 0x3a, 0x32, 0x36, 0x3a, 0x63, + 0x33, 0x3a, 0x30, 0x31, 0x3a, 0x35, 0x65, 0x3a, 0x30, 0x38, 0x3a, 0x33, + 0x30, 0x3a, 0x33, 0x37, 0x3a, 0x34, 0x33, 0x3a, 0x61, 0x39, 0x3a, 0x64, + 0x30, 0x3a, 0x37, 0x64, 0x3a, 0x63, 0x66, 0x3a, 0x33, 0x37, 0x3a, 0x65, + 0x36, 0x3a, 0x62, 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x33, 0x32, 0x3a, 0x33, 0x63, 0x3a, 0x31, 0x31, 0x3a, 0x38, 0x65, + 0x3a, 0x31, 0x62, 0x3a, 0x66, 0x37, 0x3a, 0x62, 0x38, 0x3a, 0x62, 0x36, + 0x3a, 0x35, 0x32, 0x3a, 0x35, 0x34, 0x3a, 0x65, 0x32, 0x3a, 0x65, 0x32, + 0x3a, 0x31, 0x30, 0x3a, 0x30, 0x64, 0x3a, 0x64, 0x36, 0x3a, 0x30, 0x32, + 0x3a, 0x39, 0x30, 0x3a, 0x33, 0x37, 0x3a, 0x66, 0x30, 0x3a, 0x39, 0x36, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, + 0x37, 0x3a, 0x64, 0x35, 0x3a, 0x31, 0x30, 0x3a, 0x30, 0x36, 0x3a, 0x63, + 0x35, 0x3a, 0x31, 0x32, 0x3a, 0x65, 0x61, 0x3a, 0x61, 0x62, 0x3a, 0x36, + 0x32, 0x3a, 0x36, 0x34, 0x3a, 0x32, 0x31, 0x3a, 0x66, 0x31, 0x3a, 0x65, + 0x63, 0x3a, 0x38, 0x63, 0x3a, 0x39, 0x32, 0x3a, 0x30, 0x31, 0x3a, 0x33, + 0x66, 0x3a, 0x63, 0x35, 0x3a, 0x66, 0x38, 0x3a, 0x32, 0x61, 0x3a, 0x65, + 0x39, 0x3a, 0x38, 0x65, 0x3a, 0x65, 0x35, 0x3a, 0x33, 0x33, 0x3a, 0x65, + 0x62, 0x3a, 0x34, 0x36, 0x3a, 0x31, 0x39, 0x3a, 0x62, 0x38, 0x3a, 0x64, + 0x65, 0x3a, 0x62, 0x34, 0x3a, 0x64, 0x30, 0x3a, 0x36, 0x63, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x66, 0x44, 0x43, 0x43, 0x41, + 0x6d, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x47, + 0x4b, 0x79, 0x31, 0x61, 0x76, 0x31, 0x70, 0x74, 0x68, 0x55, 0x36, 0x59, + 0x32, 0x79, 0x76, 0x32, 0x76, 0x72, 0x45, 0x6f, 0x54, 0x41, 0x4e, 0x42, + 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, + 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x59, 0x0a, 0x4d, 0x51, 0x73, 0x77, + 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, + 0x55, 0x7a, 0x45, 0x57, 0x4d, 0x42, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x68, 0x4d, 0x4e, 0x52, 0x32, 0x56, 0x76, 0x56, 0x48, 0x4a, 0x31, + 0x63, 0x33, 0x51, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x78, + 0x4d, 0x43, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x6f, + 0x0a, 0x52, 0x32, 0x56, 0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, + 0x67, 0x55, 0x48, 0x4a, 0x70, 0x62, 0x57, 0x46, 0x79, 0x65, 0x53, 0x42, + 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, + 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, + 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, + 0x77, 0x4e, 0x6a, 0x45, 0x78, 0x0a, 0x4d, 0x6a, 0x63, 0x77, 0x4d, 0x44, + 0x41, 0x77, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4e, 0x6a, + 0x41, 0x33, 0x4d, 0x54, 0x59, 0x79, 0x4d, 0x7a, 0x55, 0x35, 0x4e, 0x54, + 0x6c, 0x61, 0x4d, 0x46, 0x67, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x52, + 0x59, 0x77, 0x46, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x0a, 0x45, + 0x77, 0x31, 0x48, 0x5a, 0x57, 0x39, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, + 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x54, 0x45, 0x77, 0x4c, + 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x79, 0x68, 0x48, 0x5a, + 0x57, 0x39, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x51, 0x63, + 0x6d, 0x6c, 0x74, 0x59, 0x58, 0x4a, 0x35, 0x49, 0x45, 0x4e, 0x6c, 0x63, + 0x6e, 0x52, 0x70, 0x0a, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, + 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, + 0x61, 0x58, 0x52, 0x35, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, + 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x0a, 0x41, 0x51, 0x45, + 0x41, 0x76, 0x72, 0x67, 0x56, 0x65, 0x2f, 0x2f, 0x55, 0x66, 0x48, 0x31, + 0x6e, 0x72, 0x59, 0x4e, 0x6b, 0x65, 0x38, 0x68, 0x43, 0x55, 0x79, 0x33, + 0x66, 0x39, 0x6f, 0x51, 0x49, 0x49, 0x47, 0x48, 0x57, 0x41, 0x56, 0x6c, + 0x71, 0x6e, 0x45, 0x51, 0x52, 0x72, 0x2b, 0x39, 0x32, 0x2f, 0x5a, 0x56, + 0x2b, 0x7a, 0x6d, 0x45, 0x77, 0x75, 0x33, 0x71, 0x44, 0x58, 0x77, 0x4b, + 0x39, 0x0a, 0x41, 0x57, 0x62, 0x4b, 0x37, 0x68, 0x57, 0x4e, 0x62, 0x36, + 0x45, 0x77, 0x6e, 0x4c, 0x32, 0x68, 0x68, 0x5a, 0x36, 0x55, 0x4f, 0x76, + 0x4e, 0x57, 0x69, 0x41, 0x41, 0x78, 0x7a, 0x39, 0x6a, 0x75, 0x61, 0x70, + 0x59, 0x43, 0x32, 0x65, 0x30, 0x44, 0x6a, 0x50, 0x74, 0x31, 0x62, 0x65, + 0x66, 0x71, 0x75, 0x46, 0x55, 0x57, 0x42, 0x52, 0x61, 0x61, 0x39, 0x4f, + 0x42, 0x65, 0x73, 0x59, 0x6a, 0x41, 0x0a, 0x5a, 0x49, 0x56, 0x63, 0x46, + 0x55, 0x32, 0x49, 0x78, 0x37, 0x65, 0x36, 0x34, 0x48, 0x58, 0x70, 0x72, + 0x51, 0x55, 0x39, 0x6e, 0x63, 0x65, 0x4a, 0x53, 0x4f, 0x43, 0x37, 0x4b, + 0x4d, 0x67, 0x44, 0x34, 0x54, 0x43, 0x54, 0x5a, 0x46, 0x35, 0x53, 0x77, + 0x46, 0x6c, 0x77, 0x49, 0x6a, 0x56, 0x58, 0x69, 0x49, 0x72, 0x78, 0x6c, + 0x51, 0x71, 0x44, 0x31, 0x37, 0x77, 0x78, 0x63, 0x77, 0x45, 0x30, 0x0a, + 0x37, 0x65, 0x39, 0x47, 0x63, 0x65, 0x42, 0x72, 0x41, 0x71, 0x67, 0x31, + 0x63, 0x6d, 0x75, 0x58, 0x6d, 0x32, 0x62, 0x67, 0x79, 0x78, 0x78, 0x35, + 0x58, 0x39, 0x67, 0x61, 0x42, 0x47, 0x67, 0x65, 0x52, 0x77, 0x4c, 0x6d, + 0x6e, 0x57, 0x44, 0x69, 0x4e, 0x70, 0x63, 0x42, 0x33, 0x38, 0x34, 0x31, + 0x6b, 0x74, 0x2b, 0x2b, 0x5a, 0x38, 0x64, 0x74, 0x64, 0x31, 0x6b, 0x37, + 0x6a, 0x35, 0x33, 0x57, 0x0a, 0x6b, 0x42, 0x57, 0x55, 0x76, 0x45, 0x49, + 0x30, 0x45, 0x4d, 0x45, 0x35, 0x2b, 0x62, 0x45, 0x6e, 0x50, 0x6e, 0x37, + 0x57, 0x69, 0x6e, 0x58, 0x46, 0x73, 0x71, 0x2b, 0x57, 0x30, 0x36, 0x4c, + 0x65, 0x6d, 0x2b, 0x53, 0x59, 0x76, 0x6e, 0x33, 0x68, 0x36, 0x59, 0x47, + 0x74, 0x74, 0x6d, 0x2f, 0x38, 0x31, 0x77, 0x37, 0x61, 0x34, 0x44, 0x53, + 0x77, 0x44, 0x52, 0x70, 0x33, 0x35, 0x2b, 0x4d, 0x49, 0x0a, 0x6d, 0x4f, + 0x39, 0x59, 0x2b, 0x70, 0x79, 0x45, 0x74, 0x7a, 0x61, 0x76, 0x77, 0x74, + 0x2b, 0x73, 0x30, 0x76, 0x51, 0x51, 0x42, 0x6e, 0x42, 0x78, 0x4e, 0x51, + 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, + 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, + 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, + 0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, + 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x64, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x4c, + 0x4e, 0x56, 0x51, 0x51, 0x5a, 0x63, 0x56, 0x69, 0x2f, 0x43, 0x50, 0x4e, + 0x6d, 0x46, 0x62, 0x53, 0x76, 0x74, 0x72, 0x32, 0x5a, 0x6e, 0x4a, 0x4d, + 0x35, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, + 0x67, 0x67, 0x45, 0x42, 0x41, 0x46, 0x70, 0x77, 0x66, 0x79, 0x7a, 0x64, + 0x74, 0x7a, 0x52, 0x50, 0x39, 0x59, 0x5a, 0x52, 0x71, 0x53, 0x61, 0x2b, + 0x53, 0x37, 0x69, 0x71, 0x38, 0x58, 0x45, 0x4e, 0x33, 0x47, 0x48, 0x48, + 0x6f, 0x4f, 0x6f, 0x30, 0x48, 0x6e, 0x70, 0x33, 0x44, 0x77, 0x51, 0x31, + 0x0a, 0x36, 0x43, 0x65, 0x50, 0x62, 0x4a, 0x43, 0x2f, 0x6b, 0x52, 0x59, + 0x6b, 0x52, 0x6a, 0x35, 0x4b, 0x54, 0x73, 0x34, 0x72, 0x46, 0x74, 0x55, + 0x4c, 0x55, 0x68, 0x33, 0x38, 0x48, 0x32, 0x65, 0x69, 0x41, 0x6b, 0x55, + 0x78, 0x54, 0x38, 0x37, 0x7a, 0x2b, 0x67, 0x4f, 0x6e, 0x65, 0x5a, 0x31, + 0x54, 0x61, 0x74, 0x6e, 0x61, 0x59, 0x7a, 0x72, 0x34, 0x67, 0x4e, 0x66, + 0x54, 0x6d, 0x65, 0x47, 0x6c, 0x0a, 0x34, 0x62, 0x37, 0x55, 0x56, 0x58, + 0x47, 0x59, 0x4e, 0x54, 0x71, 0x2b, 0x6b, 0x2b, 0x71, 0x75, 0x72, 0x55, + 0x4b, 0x79, 0x6b, 0x47, 0x2f, 0x67, 0x2f, 0x43, 0x46, 0x4e, 0x4e, 0x57, + 0x4d, 0x7a, 0x69, 0x55, 0x6e, 0x57, 0x6d, 0x30, 0x37, 0x4b, 0x78, 0x2b, + 0x64, 0x4f, 0x43, 0x51, 0x44, 0x33, 0x32, 0x73, 0x66, 0x76, 0x6d, 0x57, + 0x4b, 0x5a, 0x64, 0x37, 0x61, 0x56, 0x49, 0x6c, 0x36, 0x4b, 0x0a, 0x6f, + 0x4b, 0x76, 0x30, 0x75, 0x48, 0x69, 0x59, 0x79, 0x6a, 0x67, 0x5a, 0x6d, + 0x63, 0x6c, 0x79, 0x6e, 0x6e, 0x6a, 0x4e, 0x53, 0x36, 0x79, 0x76, 0x47, + 0x61, 0x42, 0x7a, 0x45, 0x69, 0x33, 0x38, 0x77, 0x6b, 0x47, 0x36, 0x67, + 0x5a, 0x48, 0x61, 0x46, 0x6c, 0x6f, 0x78, 0x74, 0x2f, 0x6d, 0x30, 0x63, + 0x59, 0x41, 0x53, 0x53, 0x4a, 0x6c, 0x79, 0x63, 0x31, 0x70, 0x5a, 0x55, + 0x38, 0x46, 0x6a, 0x0a, 0x55, 0x6a, 0x50, 0x74, 0x70, 0x38, 0x6e, 0x53, + 0x4f, 0x51, 0x4a, 0x77, 0x2b, 0x75, 0x43, 0x78, 0x51, 0x6d, 0x59, 0x70, + 0x71, 0x70, 0x74, 0x52, 0x37, 0x54, 0x42, 0x55, 0x49, 0x68, 0x52, 0x66, + 0x32, 0x61, 0x73, 0x64, 0x77, 0x65, 0x53, 0x55, 0x38, 0x50, 0x6a, 0x31, + 0x4b, 0x2f, 0x66, 0x71, 0x79, 0x6e, 0x68, 0x47, 0x31, 0x72, 0x69, 0x52, + 0x2f, 0x61, 0x59, 0x4e, 0x4b, 0x78, 0x6f, 0x55, 0x0a, 0x41, 0x54, 0x36, + 0x41, 0x38, 0x45, 0x4b, 0x67, 0x6c, 0x51, 0x64, 0x65, 0x62, 0x63, 0x33, + 0x4d, 0x53, 0x36, 0x52, 0x46, 0x6a, 0x61, 0x73, 0x53, 0x36, 0x4c, 0x50, + 0x65, 0x57, 0x75, 0x57, 0x67, 0x66, 0x4f, 0x67, 0x50, 0x49, 0x68, 0x31, + 0x61, 0x36, 0x56, 0x6b, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x74, 0x68, + 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x74, + 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, + 0x4f, 0x55, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x20, 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2f, 0x28, + 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x74, 0x68, 0x61, 0x77, + 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, + 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, + 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, + 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x69, 0x6d, + 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, + 0x4f, 0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x74, + 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, + 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, + 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, + 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x36, 0x39, + 0x35, 0x32, 0x39, 0x31, 0x38, 0x31, 0x39, 0x39, 0x32, 0x30, 0x33, 0x39, + 0x32, 0x30, 0x33, 0x35, 0x36, 0x36, 0x32, 0x39, 0x38, 0x39, 0x35, 0x33, + 0x37, 0x38, 0x37, 0x37, 0x31, 0x32, 0x39, 0x34, 0x30, 0x39, 0x30, 0x39, + 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x63, 0x3a, 0x63, + 0x61, 0x3a, 0x64, 0x63, 0x3a, 0x30, 0x62, 0x3a, 0x32, 0x32, 0x3a, 0x63, + 0x65, 0x3a, 0x66, 0x35, 0x3a, 0x62, 0x65, 0x3a, 0x37, 0x32, 0x3a, 0x61, + 0x63, 0x3a, 0x34, 0x31, 0x3a, 0x31, 0x61, 0x3a, 0x31, 0x31, 0x3a, 0x61, + 0x38, 0x3a, 0x64, 0x38, 0x3a, 0x31, 0x32, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x31, 0x3a, 0x63, 0x36, 0x3a, 0x64, 0x36, + 0x3a, 0x65, 0x65, 0x3a, 0x33, 0x65, 0x3a, 0x38, 0x61, 0x3a, 0x63, 0x38, + 0x3a, 0x36, 0x33, 0x3a, 0x38, 0x34, 0x3a, 0x65, 0x35, 0x3a, 0x34, 0x38, + 0x3a, 0x63, 0x32, 0x3a, 0x39, 0x39, 0x3a, 0x32, 0x39, 0x3a, 0x35, 0x63, + 0x3a, 0x37, 0x35, 0x3a, 0x36, 0x63, 0x3a, 0x38, 0x31, 0x3a, 0x37, 0x62, + 0x3a, 0x38, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x38, 0x64, 0x3a, 0x37, 0x32, 0x3a, 0x32, 0x66, 0x3a, 0x38, + 0x31, 0x3a, 0x61, 0x39, 0x3a, 0x63, 0x31, 0x3a, 0x31, 0x33, 0x3a, 0x63, + 0x30, 0x3a, 0x37, 0x39, 0x3a, 0x31, 0x64, 0x3a, 0x66, 0x31, 0x3a, 0x33, + 0x36, 0x3a, 0x61, 0x32, 0x3a, 0x39, 0x36, 0x3a, 0x36, 0x64, 0x3a, 0x62, + 0x32, 0x3a, 0x36, 0x63, 0x3a, 0x39, 0x35, 0x3a, 0x30, 0x61, 0x3a, 0x39, + 0x37, 0x3a, 0x31, 0x64, 0x3a, 0x62, 0x34, 0x3a, 0x36, 0x62, 0x3a, 0x34, + 0x31, 0x3a, 0x39, 0x39, 0x3a, 0x66, 0x34, 0x3a, 0x65, 0x61, 0x3a, 0x35, + 0x34, 0x3a, 0x62, 0x37, 0x3a, 0x38, 0x62, 0x3a, 0x66, 0x62, 0x3a, 0x39, + 0x66, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x49, 0x44, + 0x43, 0x43, 0x41, 0x77, 0x69, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, + 0x49, 0x51, 0x4e, 0x45, 0x37, 0x56, 0x56, 0x79, 0x44, 0x56, 0x37, 0x65, + 0x78, 0x4a, 0x39, 0x43, 0x2f, 0x4f, 0x4e, 0x39, 0x73, 0x72, 0x62, 0x54, + 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, + 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x71, + 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x48, 0x52, 0x6f, 0x59, + 0x58, 0x64, 0x30, 0x5a, 0x53, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, + 0x6a, 0x45, 0x6f, 0x4d, 0x43, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x78, 0x4d, 0x66, 0x0a, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, + 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x54, + 0x5a, 0x58, 0x4a, 0x32, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x79, 0x42, 0x45, + 0x61, 0x58, 0x5a, 0x70, 0x63, 0x32, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x34, + 0x4d, 0x44, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x76, + 0x4b, 0x47, 0x4d, 0x70, 0x49, 0x44, 0x49, 0x77, 0x0a, 0x4d, 0x44, 0x59, + 0x67, 0x64, 0x47, 0x68, 0x68, 0x64, 0x33, 0x52, 0x6c, 0x4c, 0x43, 0x42, + 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30, 0x67, 0x52, 0x6d, 0x39, + 0x79, 0x49, 0x47, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, + 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, 0x58, 0x4e, 0x6c, 0x49, 0x47, 0x39, + 0x75, 0x62, 0x48, 0x6b, 0x78, 0x48, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, + 0x56, 0x0a, 0x42, 0x41, 0x4d, 0x54, 0x46, 0x6e, 0x52, 0x6f, 0x59, 0x58, + 0x64, 0x30, 0x5a, 0x53, 0x42, 0x51, 0x63, 0x6d, 0x6c, 0x74, 0x59, 0x58, + 0x4a, 0x35, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, + 0x45, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x59, 0x78, 0x4d, 0x54, + 0x45, 0x33, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, + 0x63, 0x4e, 0x4d, 0x7a, 0x59, 0x77, 0x0a, 0x4e, 0x7a, 0x45, 0x32, 0x4d, + 0x6a, 0x4d, 0x31, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, 0x43, 0x42, 0x71, + 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x48, 0x52, 0x6f, 0x59, + 0x58, 0x64, 0x30, 0x5a, 0x53, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x0a, + 0x4c, 0x6a, 0x45, 0x6f, 0x4d, 0x43, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x78, 0x4d, 0x66, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, + 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x54, + 0x5a, 0x58, 0x4a, 0x32, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x79, 0x42, 0x45, + 0x61, 0x58, 0x5a, 0x70, 0x63, 0x32, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x34, + 0x4d, 0x44, 0x59, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, + 0x76, 0x4b, 0x47, 0x4d, 0x70, 0x49, 0x44, 0x49, 0x77, 0x4d, 0x44, 0x59, + 0x67, 0x64, 0x47, 0x68, 0x68, 0x64, 0x33, 0x52, 0x6c, 0x4c, 0x43, 0x42, + 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30, 0x67, 0x52, 0x6d, 0x39, + 0x79, 0x49, 0x47, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, + 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, 0x58, 0x4e, 0x6c, 0x0a, 0x49, 0x47, + 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x48, 0x7a, 0x41, 0x64, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x46, 0x6e, 0x52, 0x6f, 0x59, 0x58, + 0x64, 0x30, 0x5a, 0x53, 0x42, 0x51, 0x63, 0x6d, 0x6c, 0x74, 0x59, 0x58, + 0x4a, 0x35, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, + 0x45, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, + 0x71, 0x47, 0x0a, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, + 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, + 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x43, 0x73, 0x6f, + 0x50, 0x44, 0x37, 0x67, 0x46, 0x6e, 0x55, 0x6e, 0x4d, 0x65, 0x6b, 0x7a, + 0x35, 0x32, 0x68, 0x57, 0x58, 0x4d, 0x4a, 0x45, 0x45, 0x55, 0x4d, 0x44, + 0x53, 0x78, 0x75, 0x61, 0x50, 0x46, 0x73, 0x0a, 0x57, 0x30, 0x68, 0x6f, + 0x53, 0x56, 0x6b, 0x33, 0x2f, 0x41, 0x73, 0x7a, 0x47, 0x63, 0x4a, 0x33, + 0x66, 0x38, 0x77, 0x51, 0x4c, 0x5a, 0x55, 0x30, 0x48, 0x4f, 0x62, 0x72, + 0x54, 0x51, 0x6d, 0x6e, 0x48, 0x4e, 0x4b, 0x34, 0x79, 0x5a, 0x63, 0x32, + 0x41, 0x72, 0x65, 0x4a, 0x31, 0x43, 0x52, 0x66, 0x42, 0x73, 0x44, 0x4d, + 0x52, 0x4a, 0x53, 0x55, 0x6a, 0x51, 0x4a, 0x69, 0x62, 0x2b, 0x74, 0x61, + 0x0a, 0x33, 0x52, 0x47, 0x4e, 0x4b, 0x4a, 0x70, 0x63, 0x68, 0x4a, 0x41, + 0x51, 0x65, 0x67, 0x32, 0x39, 0x64, 0x47, 0x59, 0x76, 0x61, 0x6a, 0x69, + 0x67, 0x34, 0x74, 0x56, 0x55, 0x52, 0x4f, 0x73, 0x64, 0x42, 0x35, 0x38, + 0x48, 0x75, 0x6d, 0x2f, 0x75, 0x36, 0x66, 0x31, 0x4f, 0x43, 0x79, 0x6e, + 0x31, 0x50, 0x6f, 0x53, 0x67, 0x41, 0x66, 0x47, 0x63, 0x71, 0x2f, 0x67, + 0x63, 0x66, 0x6f, 0x6d, 0x6b, 0x0a, 0x36, 0x4b, 0x48, 0x59, 0x63, 0x57, + 0x55, 0x4e, 0x6f, 0x31, 0x46, 0x37, 0x37, 0x72, 0x7a, 0x53, 0x49, 0x6d, + 0x41, 0x4e, 0x75, 0x56, 0x75, 0x64, 0x33, 0x37, 0x72, 0x38, 0x55, 0x56, + 0x73, 0x4c, 0x72, 0x35, 0x69, 0x79, 0x36, 0x53, 0x37, 0x70, 0x42, 0x4f, + 0x68, 0x69, 0x68, 0x39, 0x34, 0x72, 0x79, 0x4e, 0x64, 0x4f, 0x77, 0x55, + 0x78, 0x6b, 0x48, 0x74, 0x33, 0x50, 0x68, 0x31, 0x69, 0x36, 0x0a, 0x53, + 0x6b, 0x2f, 0x4b, 0x61, 0x41, 0x63, 0x64, 0x48, 0x4a, 0x31, 0x4b, 0x78, + 0x74, 0x55, 0x76, 0x6b, 0x63, 0x78, 0x38, 0x63, 0x58, 0x49, 0x63, 0x78, + 0x63, 0x42, 0x6e, 0x36, 0x7a, 0x4c, 0x39, 0x79, 0x5a, 0x4a, 0x63, 0x6c, + 0x4e, 0x71, 0x46, 0x77, 0x4a, 0x75, 0x2f, 0x55, 0x33, 0x30, 0x72, 0x43, + 0x66, 0x53, 0x4d, 0x6e, 0x5a, 0x45, 0x66, 0x6c, 0x32, 0x70, 0x53, 0x79, + 0x39, 0x34, 0x4a, 0x0a, 0x4e, 0x71, 0x52, 0x33, 0x32, 0x48, 0x75, 0x48, + 0x55, 0x45, 0x54, 0x56, 0x50, 0x6d, 0x34, 0x70, 0x61, 0x66, 0x73, 0x35, + 0x53, 0x53, 0x59, 0x65, 0x43, 0x61, 0x57, 0x41, 0x65, 0x30, 0x41, 0x74, + 0x36, 0x2b, 0x67, 0x6e, 0x68, 0x63, 0x6e, 0x2b, 0x59, 0x66, 0x31, 0x2b, + 0x35, 0x6e, 0x79, 0x58, 0x48, 0x64, 0x57, 0x64, 0x41, 0x67, 0x4d, 0x42, + 0x41, 0x41, 0x47, 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x0a, 0x4d, 0x41, 0x38, + 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, + 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x44, 0x67, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, + 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x52, 0x37, 0x57, 0x30, 0x58, + 0x50, 0x0a, 0x72, 0x38, 0x37, 0x4c, 0x65, 0x76, 0x30, 0x78, 0x6b, 0x68, + 0x70, 0x71, 0x74, 0x76, 0x4e, 0x47, 0x36, 0x31, 0x64, 0x49, 0x55, 0x44, + 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, + 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, + 0x45, 0x41, 0x65, 0x52, 0x48, 0x41, 0x53, 0x37, 0x4f, 0x52, 0x74, 0x76, + 0x7a, 0x77, 0x36, 0x57, 0x66, 0x55, 0x0a, 0x44, 0x57, 0x35, 0x46, 0x76, + 0x6c, 0x58, 0x6f, 0x6b, 0x39, 0x4c, 0x4f, 0x41, 0x7a, 0x2f, 0x74, 0x32, + 0x69, 0x57, 0x77, 0x48, 0x56, 0x66, 0x4c, 0x48, 0x6a, 0x70, 0x32, 0x6f, + 0x45, 0x7a, 0x73, 0x55, 0x48, 0x62, 0x6f, 0x5a, 0x48, 0x49, 0x4d, 0x70, + 0x4b, 0x6e, 0x78, 0x75, 0x49, 0x76, 0x57, 0x31, 0x6f, 0x65, 0x45, 0x75, + 0x7a, 0x4c, 0x6c, 0x51, 0x52, 0x48, 0x41, 0x64, 0x39, 0x6d, 0x7a, 0x0a, + 0x59, 0x4a, 0x33, 0x72, 0x47, 0x39, 0x58, 0x52, 0x62, 0x6b, 0x52, 0x45, + 0x71, 0x61, 0x59, 0x42, 0x37, 0x46, 0x56, 0x69, 0x48, 0x58, 0x65, 0x34, + 0x58, 0x49, 0x35, 0x49, 0x53, 0x58, 0x79, 0x63, 0x4f, 0x31, 0x63, 0x52, + 0x72, 0x4b, 0x31, 0x7a, 0x4e, 0x34, 0x34, 0x76, 0x65, 0x46, 0x79, 0x51, + 0x61, 0x45, 0x66, 0x5a, 0x59, 0x47, 0x44, 0x6d, 0x2f, 0x41, 0x63, 0x39, + 0x49, 0x69, 0x41, 0x58, 0x0a, 0x78, 0x50, 0x63, 0x57, 0x36, 0x63, 0x54, + 0x59, 0x63, 0x76, 0x6e, 0x49, 0x63, 0x33, 0x7a, 0x66, 0x46, 0x69, 0x38, + 0x56, 0x71, 0x54, 0x37, 0x39, 0x61, 0x69, 0x65, 0x32, 0x6f, 0x65, 0x74, + 0x61, 0x75, 0x70, 0x67, 0x66, 0x31, 0x65, 0x4e, 0x4e, 0x5a, 0x41, 0x71, + 0x64, 0x45, 0x38, 0x68, 0x68, 0x75, 0x76, 0x55, 0x35, 0x48, 0x49, 0x65, + 0x36, 0x75, 0x4c, 0x31, 0x37, 0x49, 0x6e, 0x2f, 0x32, 0x0a, 0x2f, 0x71, + 0x78, 0x41, 0x65, 0x65, 0x57, 0x73, 0x45, 0x47, 0x38, 0x39, 0x6a, 0x78, + 0x74, 0x35, 0x64, 0x6f, 0x76, 0x45, 0x4e, 0x37, 0x4d, 0x68, 0x47, 0x49, + 0x54, 0x6c, 0x4e, 0x67, 0x44, 0x72, 0x59, 0x79, 0x43, 0x5a, 0x75, 0x65, + 0x6e, 0x2b, 0x4d, 0x77, 0x53, 0x37, 0x51, 0x63, 0x6a, 0x42, 0x41, 0x76, + 0x6c, 0x45, 0x59, 0x79, 0x43, 0x65, 0x67, 0x63, 0x35, 0x43, 0x30, 0x39, + 0x59, 0x2f, 0x0a, 0x4c, 0x48, 0x62, 0x54, 0x59, 0x35, 0x78, 0x5a, 0x33, + 0x59, 0x2b, 0x6d, 0x34, 0x51, 0x36, 0x67, 0x4c, 0x6b, 0x48, 0x33, 0x4c, + 0x70, 0x56, 0x48, 0x7a, 0x37, 0x7a, 0x39, 0x4d, 0x2f, 0x50, 0x32, 0x43, + 0x32, 0x46, 0x2b, 0x66, 0x70, 0x45, 0x72, 0x67, 0x55, 0x66, 0x43, 0x4a, + 0x7a, 0x44, 0x75, 0x70, 0x78, 0x42, 0x64, 0x4e, 0x34, 0x39, 0x63, 0x4f, + 0x53, 0x76, 0x6b, 0x42, 0x50, 0x42, 0x37, 0x0a, 0x6a, 0x56, 0x61, 0x4d, + 0x61, 0x41, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x56, 0x65, 0x72, + 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, + 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, + 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x20, 0x4f, 0x3d, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, + 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, + 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, + 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x56, 0x65, 0x72, + 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, + 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, + 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x35, 0x20, 0x4f, 0x3d, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, + 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, + 0x36, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, + 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, + 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, + 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x20, 0x2d, 0x20, 0x47, 0x35, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x33, 0x33, 0x30, 0x33, 0x37, 0x36, 0x34, + 0x34, 0x31, 0x36, 0x37, 0x35, 0x36, 0x38, 0x30, 0x35, 0x38, 0x39, 0x37, + 0x30, 0x31, 0x36, 0x34, 0x37, 0x31, 0x39, 0x34, 0x37, 0x35, 0x36, 0x37, + 0x36, 0x31, 0x30, 0x31, 0x34, 0x35, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, + 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x63, 0x62, 0x3a, 0x31, 0x37, 0x3a, 0x65, 0x34, 0x3a, + 0x33, 0x31, 0x3a, 0x36, 0x37, 0x3a, 0x33, 0x65, 0x3a, 0x65, 0x32, 0x3a, + 0x30, 0x39, 0x3a, 0x66, 0x65, 0x3a, 0x34, 0x35, 0x3a, 0x35, 0x37, 0x3a, + 0x39, 0x33, 0x3a, 0x66, 0x33, 0x3a, 0x30, 0x61, 0x3a, 0x66, 0x61, 0x3a, + 0x31, 0x63, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, + 0x65, 0x3a, 0x62, 0x36, 0x3a, 0x64, 0x35, 0x3a, 0x37, 0x38, 0x3a, 0x34, + 0x39, 0x3a, 0x39, 0x62, 0x3a, 0x31, 0x63, 0x3a, 0x63, 0x66, 0x3a, 0x35, + 0x66, 0x3a, 0x35, 0x38, 0x3a, 0x31, 0x65, 0x3a, 0x61, 0x64, 0x3a, 0x35, + 0x36, 0x3a, 0x62, 0x65, 0x3a, 0x33, 0x64, 0x3a, 0x39, 0x62, 0x3a, 0x36, + 0x37, 0x3a, 0x34, 0x34, 0x3a, 0x61, 0x35, 0x3a, 0x65, 0x35, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x61, 0x3a, + 0x63, 0x66, 0x3a, 0x61, 0x62, 0x3a, 0x37, 0x65, 0x3a, 0x34, 0x33, 0x3a, + 0x63, 0x38, 0x3a, 0x64, 0x38, 0x3a, 0x38, 0x30, 0x3a, 0x64, 0x30, 0x3a, + 0x36, 0x62, 0x3a, 0x32, 0x36, 0x3a, 0x32, 0x61, 0x3a, 0x39, 0x34, 0x3a, + 0x64, 0x65, 0x3a, 0x65, 0x65, 0x3a, 0x65, 0x34, 0x3a, 0x62, 0x34, 0x3a, + 0x36, 0x35, 0x3a, 0x39, 0x39, 0x3a, 0x38, 0x39, 0x3a, 0x63, 0x33, 0x3a, + 0x64, 0x30, 0x3a, 0x63, 0x61, 0x3a, 0x66, 0x31, 0x3a, 0x39, 0x62, 0x3a, + 0x61, 0x66, 0x3a, 0x36, 0x34, 0x3a, 0x30, 0x35, 0x3a, 0x65, 0x34, 0x3a, + 0x31, 0x61, 0x3a, 0x62, 0x37, 0x3a, 0x64, 0x66, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x30, 0x7a, 0x43, 0x43, 0x41, 0x37, 0x75, + 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x47, 0x4e, 0x72, + 0x52, 0x6e, 0x69, 0x5a, 0x39, 0x36, 0x4c, 0x74, 0x4b, 0x49, 0x56, 0x6a, + 0x4e, 0x7a, 0x47, 0x73, 0x37, 0x53, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, + 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, + 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x79, 0x6a, 0x45, 0x4c, 0x4d, 0x41, + 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, + 0x4d, 0x78, 0x46, 0x7a, 0x41, 0x56, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x6f, 0x54, 0x44, 0x6c, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, + 0x64, 0x75, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x52, + 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x0a, 0x45, + 0x78, 0x5a, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62, + 0x69, 0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4f, 0x5a, + 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x4d, 0x54, 0x6f, 0x77, 0x4f, + 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x7a, 0x45, 0x6f, 0x59, + 0x79, 0x6b, 0x67, 0x4d, 0x6a, 0x41, 0x77, 0x4e, 0x69, 0x42, 0x57, 0x5a, + 0x58, 0x4a, 0x70, 0x0a, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x77, 0x67, + 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x69, 0x41, 0x74, 0x49, 0x45, 0x5a, 0x76, + 0x63, 0x69, 0x42, 0x68, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, + 0x65, 0x6d, 0x56, 0x6b, 0x49, 0x48, 0x56, 0x7a, 0x5a, 0x53, 0x42, 0x76, + 0x62, 0x6d, 0x78, 0x35, 0x4d, 0x55, 0x55, 0x77, 0x51, 0x77, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x44, 0x45, 0x7a, 0x78, 0x57, 0x0a, 0x5a, 0x58, 0x4a, + 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x44, 0x62, 0x47, 0x46, + 0x7a, 0x63, 0x79, 0x41, 0x7a, 0x49, 0x46, 0x42, 0x31, 0x59, 0x6d, 0x78, + 0x70, 0x59, 0x79, 0x42, 0x51, 0x63, 0x6d, 0x6c, 0x74, 0x59, 0x58, 0x4a, + 0x35, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, + 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, + 0x30, 0x0a, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x49, 0x43, + 0x30, 0x67, 0x52, 0x7a, 0x55, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, + 0x59, 0x78, 0x4d, 0x54, 0x41, 0x34, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, + 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x59, 0x77, 0x4e, 0x7a, + 0x45, 0x32, 0x4d, 0x6a, 0x4d, 0x31, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, + 0x43, 0x42, 0x79, 0x6a, 0x45, 0x4c, 0x0a, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, + 0x7a, 0x41, 0x56, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, + 0x6c, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x4c, + 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x52, 0x38, 0x77, 0x48, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x5a, 0x57, 0x0a, + 0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x55, + 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, + 0x62, 0x33, 0x4a, 0x72, 0x4d, 0x54, 0x6f, 0x77, 0x4f, 0x41, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4c, 0x45, 0x7a, 0x45, 0x6f, 0x59, 0x79, 0x6b, 0x67, + 0x4d, 0x6a, 0x41, 0x77, 0x4e, 0x69, 0x42, 0x57, 0x5a, 0x58, 0x4a, 0x70, + 0x55, 0x32, 0x6c, 0x6e, 0x0a, 0x62, 0x69, 0x77, 0x67, 0x53, 0x57, 0x35, + 0x6a, 0x4c, 0x69, 0x41, 0x74, 0x49, 0x45, 0x5a, 0x76, 0x63, 0x69, 0x42, + 0x68, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x65, 0x6d, 0x56, + 0x6b, 0x49, 0x48, 0x56, 0x7a, 0x5a, 0x53, 0x42, 0x76, 0x62, 0x6d, 0x78, + 0x35, 0x4d, 0x55, 0x55, 0x77, 0x51, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x44, 0x45, 0x7a, 0x78, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x0a, 0x55, 0x32, + 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x44, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, + 0x41, 0x7a, 0x49, 0x46, 0x42, 0x31, 0x59, 0x6d, 0x78, 0x70, 0x59, 0x79, + 0x42, 0x51, 0x63, 0x6d, 0x6c, 0x74, 0x59, 0x58, 0x4a, 0x35, 0x49, 0x45, + 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, + 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, + 0x39, 0x79, 0x0a, 0x61, 0x58, 0x52, 0x35, 0x49, 0x43, 0x30, 0x67, 0x52, + 0x7a, 0x55, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, + 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, + 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, + 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x43, 0x76, 0x4a, + 0x41, 0x67, 0x49, 0x4b, 0x58, 0x6f, 0x31, 0x0a, 0x6e, 0x6d, 0x41, 0x4d, + 0x71, 0x75, 0x64, 0x4c, 0x4f, 0x30, 0x37, 0x63, 0x66, 0x4c, 0x77, 0x38, + 0x52, 0x52, 0x79, 0x37, 0x4b, 0x2b, 0x44, 0x2b, 0x4b, 0x51, 0x4c, 0x35, + 0x56, 0x77, 0x69, 0x6a, 0x5a, 0x49, 0x55, 0x56, 0x4a, 0x2f, 0x58, 0x78, + 0x72, 0x63, 0x67, 0x78, 0x69, 0x56, 0x30, 0x69, 0x36, 0x43, 0x71, 0x71, + 0x70, 0x6b, 0x4b, 0x7a, 0x6a, 0x2f, 0x69, 0x35, 0x56, 0x62, 0x65, 0x78, + 0x0a, 0x74, 0x30, 0x75, 0x7a, 0x2f, 0x6f, 0x39, 0x2b, 0x42, 0x31, 0x66, + 0x73, 0x37, 0x30, 0x50, 0x62, 0x5a, 0x6d, 0x49, 0x56, 0x59, 0x63, 0x39, + 0x67, 0x44, 0x61, 0x54, 0x59, 0x33, 0x76, 0x6a, 0x67, 0x77, 0x32, 0x49, + 0x49, 0x50, 0x56, 0x51, 0x54, 0x36, 0x30, 0x6e, 0x4b, 0x57, 0x56, 0x53, + 0x46, 0x4a, 0x75, 0x55, 0x72, 0x6a, 0x78, 0x75, 0x66, 0x36, 0x2f, 0x57, + 0x68, 0x6b, 0x63, 0x49, 0x7a, 0x0a, 0x53, 0x64, 0x68, 0x44, 0x59, 0x32, + 0x70, 0x53, 0x53, 0x39, 0x4b, 0x50, 0x36, 0x48, 0x42, 0x52, 0x54, 0x64, + 0x47, 0x4a, 0x61, 0x58, 0x76, 0x48, 0x63, 0x50, 0x61, 0x7a, 0x33, 0x42, + 0x4a, 0x30, 0x32, 0x33, 0x74, 0x64, 0x53, 0x31, 0x62, 0x54, 0x6c, 0x72, + 0x38, 0x56, 0x64, 0x36, 0x47, 0x77, 0x39, 0x4b, 0x49, 0x6c, 0x38, 0x71, + 0x38, 0x63, 0x6b, 0x6d, 0x63, 0x59, 0x35, 0x66, 0x51, 0x47, 0x0a, 0x42, + 0x4f, 0x2b, 0x51, 0x75, 0x65, 0x51, 0x41, 0x35, 0x4e, 0x30, 0x36, 0x74, + 0x52, 0x6e, 0x2f, 0x41, 0x72, 0x72, 0x30, 0x50, 0x4f, 0x37, 0x67, 0x69, + 0x2b, 0x73, 0x33, 0x69, 0x2b, 0x7a, 0x30, 0x31, 0x36, 0x7a, 0x79, 0x39, + 0x76, 0x41, 0x39, 0x72, 0x39, 0x31, 0x31, 0x6b, 0x54, 0x4d, 0x5a, 0x48, + 0x52, 0x78, 0x41, 0x79, 0x33, 0x51, 0x6b, 0x47, 0x53, 0x47, 0x54, 0x32, + 0x52, 0x54, 0x2b, 0x0a, 0x72, 0x43, 0x70, 0x53, 0x78, 0x34, 0x2f, 0x56, + 0x42, 0x45, 0x6e, 0x6b, 0x6a, 0x57, 0x4e, 0x48, 0x69, 0x44, 0x78, 0x70, + 0x67, 0x38, 0x76, 0x2b, 0x52, 0x37, 0x30, 0x72, 0x66, 0x6b, 0x2f, 0x46, + 0x6c, 0x61, 0x34, 0x4f, 0x6e, 0x64, 0x54, 0x52, 0x51, 0x38, 0x42, 0x6e, + 0x63, 0x2b, 0x4d, 0x55, 0x43, 0x48, 0x37, 0x6c, 0x50, 0x35, 0x39, 0x7a, + 0x75, 0x44, 0x4d, 0x4b, 0x7a, 0x31, 0x30, 0x2f, 0x0a, 0x4e, 0x49, 0x65, + 0x57, 0x69, 0x75, 0x35, 0x54, 0x36, 0x43, 0x55, 0x56, 0x41, 0x67, 0x4d, + 0x42, 0x41, 0x41, 0x47, 0x6a, 0x67, 0x62, 0x49, 0x77, 0x67, 0x61, 0x38, + 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, + 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, + 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, + 0x45, 0x0a, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x62, 0x51, + 0x59, 0x49, 0x4b, 0x77, 0x59, 0x42, 0x42, 0x51, 0x55, 0x48, 0x41, 0x51, + 0x77, 0x45, 0x59, 0x54, 0x42, 0x66, 0x6f, 0x56, 0x32, 0x67, 0x57, 0x7a, + 0x42, 0x5a, 0x4d, 0x46, 0x63, 0x77, 0x56, 0x52, 0x59, 0x4a, 0x61, 0x57, + 0x31, 0x68, 0x5a, 0x32, 0x55, 0x76, 0x5a, 0x32, 0x6c, 0x6d, 0x4d, 0x43, + 0x45, 0x77, 0x48, 0x7a, 0x41, 0x48, 0x0a, 0x42, 0x67, 0x55, 0x72, 0x44, + 0x67, 0x4d, 0x43, 0x47, 0x67, 0x51, 0x55, 0x6a, 0x2b, 0x58, 0x54, 0x47, + 0x6f, 0x61, 0x73, 0x6a, 0x59, 0x35, 0x72, 0x77, 0x38, 0x2b, 0x41, 0x61, + 0x74, 0x52, 0x49, 0x47, 0x43, 0x78, 0x37, 0x47, 0x53, 0x34, 0x77, 0x4a, + 0x52, 0x59, 0x6a, 0x61, 0x48, 0x52, 0x30, 0x63, 0x44, 0x6f, 0x76, 0x4c, + 0x32, 0x78, 0x76, 0x5a, 0x32, 0x38, 0x75, 0x64, 0x6d, 0x56, 0x79, 0x0a, + 0x61, 0x58, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x75, 0x59, 0x32, 0x39, 0x74, + 0x4c, 0x33, 0x5a, 0x7a, 0x62, 0x47, 0x39, 0x6e, 0x62, 0x79, 0x35, 0x6e, + 0x61, 0x57, 0x59, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, + 0x42, 0x42, 0x59, 0x45, 0x46, 0x48, 0x2f, 0x54, 0x5a, 0x61, 0x66, 0x43, + 0x33, 0x65, 0x79, 0x37, 0x38, 0x44, 0x41, 0x4a, 0x38, 0x30, 0x4d, 0x35, + 0x2b, 0x67, 0x4b, 0x76, 0x0a, 0x4d, 0x7a, 0x45, 0x7a, 0x4d, 0x41, 0x30, + 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, + 0x42, 0x42, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x43, + 0x54, 0x4a, 0x45, 0x6f, 0x77, 0x58, 0x32, 0x4c, 0x50, 0x32, 0x42, 0x71, + 0x59, 0x4c, 0x7a, 0x33, 0x71, 0x33, 0x4a, 0x6b, 0x74, 0x76, 0x58, 0x66, + 0x32, 0x70, 0x58, 0x6b, 0x69, 0x4f, 0x4f, 0x7a, 0x45, 0x0a, 0x70, 0x36, + 0x42, 0x34, 0x45, 0x71, 0x31, 0x69, 0x44, 0x6b, 0x56, 0x77, 0x5a, 0x4d, + 0x58, 0x6e, 0x6c, 0x32, 0x59, 0x74, 0x6d, 0x41, 0x6c, 0x2b, 0x58, 0x36, + 0x2f, 0x57, 0x7a, 0x43, 0x68, 0x6c, 0x38, 0x67, 0x47, 0x71, 0x43, 0x42, + 0x70, 0x48, 0x33, 0x76, 0x6e, 0x35, 0x66, 0x4a, 0x4a, 0x61, 0x43, 0x47, + 0x6b, 0x67, 0x44, 0x64, 0x6b, 0x2b, 0x62, 0x57, 0x34, 0x38, 0x44, 0x57, + 0x37, 0x59, 0x0a, 0x35, 0x67, 0x61, 0x52, 0x51, 0x42, 0x69, 0x35, 0x2b, + 0x4d, 0x48, 0x74, 0x33, 0x39, 0x74, 0x42, 0x71, 0x75, 0x43, 0x57, 0x49, + 0x4d, 0x6e, 0x4e, 0x5a, 0x42, 0x55, 0x34, 0x67, 0x63, 0x6d, 0x55, 0x37, + 0x71, 0x4b, 0x45, 0x4b, 0x51, 0x73, 0x54, 0x62, 0x34, 0x37, 0x62, 0x44, + 0x4e, 0x30, 0x6c, 0x41, 0x74, 0x75, 0x6b, 0x69, 0x78, 0x6c, 0x45, 0x30, + 0x6b, 0x46, 0x36, 0x42, 0x57, 0x6c, 0x4b, 0x0a, 0x57, 0x45, 0x39, 0x67, + 0x79, 0x6e, 0x36, 0x43, 0x61, 0x67, 0x73, 0x43, 0x71, 0x69, 0x55, 0x58, + 0x4f, 0x62, 0x58, 0x62, 0x66, 0x2b, 0x65, 0x45, 0x5a, 0x53, 0x71, 0x56, + 0x69, 0x72, 0x32, 0x47, 0x33, 0x6c, 0x36, 0x42, 0x46, 0x6f, 0x4d, 0x74, + 0x45, 0x4d, 0x7a, 0x65, 0x2f, 0x61, 0x69, 0x43, 0x4b, 0x6d, 0x30, 0x6f, + 0x48, 0x77, 0x30, 0x4c, 0x78, 0x4f, 0x58, 0x6e, 0x47, 0x69, 0x59, 0x5a, + 0x0a, 0x34, 0x66, 0x51, 0x52, 0x62, 0x78, 0x43, 0x31, 0x6c, 0x66, 0x7a, + 0x6e, 0x51, 0x67, 0x55, 0x79, 0x32, 0x38, 0x36, 0x64, 0x55, 0x56, 0x34, + 0x6f, 0x74, 0x70, 0x36, 0x46, 0x30, 0x31, 0x76, 0x76, 0x70, 0x58, 0x31, + 0x46, 0x51, 0x48, 0x4b, 0x4f, 0x74, 0x77, 0x35, 0x72, 0x44, 0x67, 0x62, + 0x37, 0x4d, 0x7a, 0x56, 0x49, 0x63, 0x62, 0x69, 0x64, 0x4a, 0x34, 0x76, + 0x45, 0x5a, 0x56, 0x38, 0x4e, 0x0a, 0x68, 0x6e, 0x61, 0x63, 0x52, 0x48, + 0x72, 0x32, 0x6c, 0x56, 0x7a, 0x32, 0x58, 0x54, 0x49, 0x49, 0x4d, 0x36, + 0x52, 0x55, 0x74, 0x68, 0x67, 0x2f, 0x61, 0x46, 0x7a, 0x79, 0x51, 0x6b, + 0x71, 0x46, 0x4f, 0x46, 0x53, 0x44, 0x58, 0x39, 0x48, 0x6f, 0x4c, 0x50, + 0x4b, 0x73, 0x45, 0x64, 0x61, 0x6f, 0x37, 0x57, 0x4e, 0x71, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x53, 0x65, 0x63, 0x75, + 0x72, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, + 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x65, + 0x63, 0x75, 0x72, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x41, + 0x20, 0x4f, 0x3d, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x31, 0x37, 0x31, 0x39, 0x39, 0x37, 0x37, 0x34, 0x35, + 0x38, 0x39, 0x31, 0x32, 0x35, 0x32, 0x37, 0x37, 0x37, 0x38, 0x38, 0x33, + 0x36, 0x32, 0x37, 0x35, 0x37, 0x30, 0x31, 0x34, 0x32, 0x36, 0x36, 0x38, + 0x36, 0x32, 0x30, 0x33, 0x32, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x64, 0x63, 0x3a, 0x33, 0x32, 0x3a, 0x63, 0x33, 0x3a, 0x61, 0x37, + 0x3a, 0x36, 0x64, 0x3a, 0x32, 0x35, 0x3a, 0x35, 0x37, 0x3a, 0x63, 0x37, + 0x3a, 0x36, 0x38, 0x3a, 0x30, 0x39, 0x3a, 0x39, 0x64, 0x3a, 0x65, 0x61, + 0x3a, 0x32, 0x64, 0x3a, 0x61, 0x39, 0x3a, 0x61, 0x32, 0x3a, 0x64, 0x31, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x37, 0x3a, + 0x38, 0x32, 0x3a, 0x63, 0x36, 0x3a, 0x63, 0x33, 0x3a, 0x30, 0x34, 0x3a, + 0x33, 0x35, 0x3a, 0x33, 0x62, 0x3a, 0x63, 0x66, 0x3a, 0x64, 0x32, 0x3a, + 0x39, 0x36, 0x3a, 0x39, 0x32, 0x3a, 0x64, 0x32, 0x3a, 0x35, 0x39, 0x3a, + 0x33, 0x65, 0x3a, 0x37, 0x64, 0x3a, 0x34, 0x34, 0x3a, 0x64, 0x39, 0x3a, + 0x33, 0x34, 0x3a, 0x66, 0x66, 0x3a, 0x31, 0x31, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x66, 0x31, 0x3a, 0x63, 0x31, + 0x3a, 0x62, 0x35, 0x3a, 0x30, 0x61, 0x3a, 0x65, 0x35, 0x3a, 0x61, 0x32, + 0x3a, 0x30, 0x64, 0x3a, 0x64, 0x38, 0x3a, 0x30, 0x33, 0x3a, 0x30, 0x65, + 0x3a, 0x63, 0x39, 0x3a, 0x66, 0x36, 0x3a, 0x62, 0x63, 0x3a, 0x32, 0x34, + 0x3a, 0x38, 0x32, 0x3a, 0x33, 0x64, 0x3a, 0x64, 0x33, 0x3a, 0x36, 0x37, + 0x3a, 0x62, 0x35, 0x3a, 0x32, 0x35, 0x3a, 0x35, 0x37, 0x3a, 0x35, 0x39, + 0x3a, 0x62, 0x34, 0x3a, 0x65, 0x37, 0x3a, 0x31, 0x62, 0x3a, 0x36, 0x31, + 0x3a, 0x66, 0x63, 0x3a, 0x65, 0x39, 0x3a, 0x66, 0x37, 0x3a, 0x33, 0x37, + 0x3a, 0x35, 0x64, 0x3a, 0x37, 0x33, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x44, 0x75, 0x44, 0x43, 0x43, 0x41, 0x71, 0x43, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x44, 0x50, 0x43, 0x4f, 0x58, + 0x41, 0x67, 0x57, 0x70, 0x61, 0x31, 0x43, 0x66, 0x2f, 0x44, 0x72, 0x4a, + 0x78, 0x68, 0x5a, 0x30, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, + 0x44, 0x42, 0x49, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x67, + 0x4d, 0x42, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x58, + 0x55, 0x32, 0x56, 0x6a, 0x64, 0x58, 0x4a, 0x6c, 0x56, 0x48, 0x4a, 0x31, + 0x63, 0x33, 0x51, 0x67, 0x51, 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, 0x79, + 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x78, 0x0a, 0x46, 0x7a, 0x41, + 0x56, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x44, 0x6c, 0x4e, + 0x6c, 0x59, 0x33, 0x56, 0x79, 0x5a, 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, + 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, + 0x32, 0x4d, 0x54, 0x45, 0x77, 0x4e, 0x7a, 0x45, 0x35, 0x4d, 0x7a, 0x45, + 0x78, 0x4f, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x35, 0x4d, 0x54, 0x49, + 0x7a, 0x0a, 0x4d, 0x54, 0x45, 0x35, 0x4e, 0x44, 0x41, 0x31, 0x4e, 0x56, + 0x6f, 0x77, 0x53, 0x44, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x49, 0x44, + 0x41, 0x65, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x46, 0x31, + 0x4e, 0x6c, 0x59, 0x33, 0x56, 0x79, 0x5a, 0x56, 0x52, 0x79, 0x64, 0x58, + 0x4e, 0x30, 0x49, 0x45, 0x4e, 0x76, 0x0a, 0x63, 0x6e, 0x42, 0x76, 0x63, + 0x6d, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x63, 0x77, 0x46, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x77, 0x35, 0x54, 0x5a, + 0x57, 0x4e, 0x31, 0x63, 0x6d, 0x56, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, + 0x43, 0x42, 0x44, 0x51, 0x54, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, + 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x0a, + 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, + 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, + 0x41, 0x4b, 0x75, 0x6b, 0x67, 0x65, 0x57, 0x56, 0x7a, 0x66, 0x58, 0x32, + 0x46, 0x49, 0x37, 0x43, 0x54, 0x38, 0x72, 0x55, 0x34, 0x6e, 0x69, 0x56, + 0x57, 0x4a, 0x78, 0x42, 0x34, 0x51, 0x32, 0x5a, 0x51, 0x43, 0x51, 0x58, + 0x4f, 0x5a, 0x45, 0x7a, 0x0a, 0x5a, 0x75, 0x6d, 0x2b, 0x34, 0x59, 0x4f, + 0x76, 0x59, 0x6c, 0x79, 0x4a, 0x30, 0x66, 0x77, 0x6b, 0x57, 0x32, 0x47, + 0x7a, 0x34, 0x42, 0x45, 0x52, 0x51, 0x52, 0x77, 0x64, 0x62, 0x76, 0x43, + 0x34, 0x75, 0x2f, 0x6a, 0x65, 0x70, 0x34, 0x47, 0x36, 0x70, 0x6b, 0x6a, + 0x47, 0x6e, 0x78, 0x32, 0x39, 0x76, 0x6f, 0x36, 0x70, 0x51, 0x54, 0x36, + 0x34, 0x6c, 0x4f, 0x30, 0x70, 0x47, 0x74, 0x53, 0x4f, 0x0a, 0x30, 0x67, + 0x4d, 0x64, 0x41, 0x2b, 0x39, 0x74, 0x44, 0x57, 0x63, 0x63, 0x56, 0x39, + 0x63, 0x47, 0x72, 0x63, 0x72, 0x49, 0x39, 0x66, 0x34, 0x4f, 0x72, 0x32, + 0x59, 0x6c, 0x53, 0x41, 0x53, 0x57, 0x43, 0x31, 0x32, 0x6a, 0x75, 0x68, + 0x62, 0x44, 0x43, 0x45, 0x2f, 0x52, 0x52, 0x76, 0x67, 0x55, 0x58, 0x50, + 0x4c, 0x49, 0x58, 0x67, 0x47, 0x5a, 0x62, 0x66, 0x32, 0x49, 0x7a, 0x49, + 0x61, 0x6f, 0x0a, 0x77, 0x57, 0x38, 0x78, 0x51, 0x6d, 0x78, 0x53, 0x50, + 0x6d, 0x6a, 0x4c, 0x38, 0x78, 0x6b, 0x30, 0x33, 0x37, 0x75, 0x48, 0x47, + 0x46, 0x61, 0x41, 0x4a, 0x73, 0x54, 0x51, 0x33, 0x4d, 0x42, 0x76, 0x33, + 0x39, 0x36, 0x67, 0x77, 0x70, 0x45, 0x57, 0x6f, 0x47, 0x51, 0x52, 0x53, + 0x30, 0x53, 0x38, 0x48, 0x76, 0x62, 0x6e, 0x2b, 0x6d, 0x50, 0x65, 0x5a, + 0x71, 0x78, 0x32, 0x70, 0x48, 0x47, 0x6a, 0x0a, 0x37, 0x44, 0x61, 0x55, + 0x61, 0x48, 0x70, 0x33, 0x70, 0x4c, 0x48, 0x6e, 0x44, 0x69, 0x2b, 0x42, + 0x65, 0x75, 0x4b, 0x31, 0x63, 0x6f, 0x62, 0x76, 0x6f, 0x6d, 0x75, 0x4c, + 0x38, 0x41, 0x2f, 0x62, 0x30, 0x31, 0x6b, 0x2f, 0x75, 0x6e, 0x4b, 0x38, + 0x52, 0x43, 0x53, 0x63, 0x34, 0x33, 0x4f, 0x7a, 0x39, 0x36, 0x39, 0x58, + 0x4c, 0x30, 0x49, 0x6d, 0x6e, 0x61, 0x6c, 0x30, 0x75, 0x67, 0x42, 0x53, + 0x0a, 0x38, 0x6b, 0x76, 0x4e, 0x55, 0x33, 0x78, 0x48, 0x43, 0x7a, 0x61, + 0x46, 0x44, 0x6d, 0x61, 0x70, 0x43, 0x4a, 0x63, 0x57, 0x4e, 0x46, 0x66, + 0x42, 0x5a, 0x76, 0x65, 0x41, 0x34, 0x2b, 0x31, 0x77, 0x56, 0x4d, 0x65, + 0x54, 0x34, 0x43, 0x34, 0x6f, 0x46, 0x56, 0x6d, 0x48, 0x75, 0x72, 0x73, + 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4f, 0x42, 0x6e, 0x54, 0x43, + 0x42, 0x6d, 0x6a, 0x41, 0x54, 0x0a, 0x42, 0x67, 0x6b, 0x72, 0x42, 0x67, + 0x45, 0x45, 0x41, 0x59, 0x49, 0x33, 0x46, 0x41, 0x49, 0x45, 0x42, 0x68, + 0x34, 0x45, 0x41, 0x45, 0x4d, 0x41, 0x51, 0x54, 0x41, 0x4c, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x51, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x59, + 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x0a, 0x2f, + 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, + 0x67, 0x51, 0x55, 0x51, 0x6a, 0x4b, 0x32, 0x46, 0x76, 0x6f, 0x45, 0x2f, + 0x66, 0x35, 0x64, 0x53, 0x33, 0x72, 0x44, 0x2f, 0x66, 0x64, 0x4d, 0x51, + 0x42, 0x31, 0x61, 0x51, 0x36, 0x38, 0x77, 0x4e, 0x41, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x66, 0x42, 0x43, 0x30, 0x77, 0x4b, 0x7a, 0x41, 0x70, 0x6f, + 0x43, 0x65, 0x67, 0x0a, 0x4a, 0x59, 0x59, 0x6a, 0x61, 0x48, 0x52, 0x30, + 0x63, 0x44, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x79, 0x62, 0x43, 0x35, 0x7a, + 0x5a, 0x57, 0x4e, 0x31, 0x63, 0x6d, 0x56, 0x30, 0x63, 0x6e, 0x56, 0x7a, + 0x64, 0x43, 0x35, 0x6a, 0x62, 0x32, 0x30, 0x76, 0x55, 0x31, 0x52, 0x44, + 0x51, 0x53, 0x35, 0x6a, 0x63, 0x6d, 0x77, 0x77, 0x45, 0x41, 0x59, 0x4a, + 0x4b, 0x77, 0x59, 0x42, 0x42, 0x41, 0x47, 0x43, 0x0a, 0x4e, 0x78, 0x55, + 0x42, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x41, 0x77, 0x44, 0x51, 0x59, + 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, + 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x44, 0x44, + 0x74, 0x54, 0x30, 0x72, 0x68, 0x57, 0x44, 0x70, 0x53, 0x63, 0x6c, 0x75, + 0x31, 0x70, 0x71, 0x4e, 0x6c, 0x47, 0x4b, 0x61, 0x37, 0x55, 0x54, 0x74, + 0x33, 0x0a, 0x36, 0x5a, 0x33, 0x71, 0x30, 0x35, 0x39, 0x63, 0x34, 0x45, + 0x56, 0x6c, 0x65, 0x77, 0x33, 0x4b, 0x57, 0x2b, 0x4a, 0x77, 0x55, 0x4c, + 0x4b, 0x55, 0x42, 0x52, 0x53, 0x75, 0x53, 0x63, 0x65, 0x4e, 0x51, 0x51, + 0x63, 0x53, 0x63, 0x35, 0x52, 0x2b, 0x44, 0x43, 0x4d, 0x68, 0x2f, 0x62, + 0x77, 0x51, 0x66, 0x32, 0x41, 0x51, 0x57, 0x6e, 0x4c, 0x31, 0x6d, 0x41, + 0x36, 0x73, 0x37, 0x4c, 0x6c, 0x2f, 0x0a, 0x33, 0x58, 0x70, 0x76, 0x58, + 0x64, 0x4d, 0x63, 0x39, 0x50, 0x2b, 0x49, 0x42, 0x57, 0x6c, 0x43, 0x71, + 0x51, 0x56, 0x78, 0x79, 0x4c, 0x65, 0x73, 0x4a, 0x75, 0x67, 0x75, 0x74, + 0x49, 0x78, 0x71, 0x2f, 0x33, 0x48, 0x63, 0x75, 0x4c, 0x48, 0x66, 0x6d, + 0x62, 0x78, 0x38, 0x49, 0x56, 0x51, 0x72, 0x35, 0x46, 0x69, 0x69, 0x75, + 0x31, 0x63, 0x70, 0x72, 0x70, 0x36, 0x70, 0x6f, 0x78, 0x6b, 0x6d, 0x0a, + 0x44, 0x35, 0x6b, 0x75, 0x43, 0x4c, 0x44, 0x76, 0x2f, 0x57, 0x6e, 0x50, + 0x6d, 0x52, 0x6f, 0x4a, 0x6a, 0x65, 0x4f, 0x6e, 0x6e, 0x79, 0x76, 0x4a, + 0x4e, 0x6a, 0x52, 0x37, 0x4a, 0x4c, 0x4e, 0x34, 0x54, 0x4a, 0x55, 0x58, + 0x70, 0x41, 0x59, 0x6d, 0x48, 0x72, 0x5a, 0x6b, 0x55, 0x6a, 0x5a, 0x66, + 0x59, 0x47, 0x66, 0x5a, 0x6e, 0x4d, 0x55, 0x46, 0x64, 0x41, 0x76, 0x6e, + 0x5a, 0x79, 0x50, 0x53, 0x0a, 0x43, 0x50, 0x79, 0x49, 0x36, 0x61, 0x36, + 0x4c, 0x66, 0x2b, 0x45, 0x77, 0x39, 0x44, 0x64, 0x2b, 0x2f, 0x63, 0x59, + 0x79, 0x32, 0x69, 0x32, 0x65, 0x52, 0x44, 0x41, 0x77, 0x62, 0x4f, 0x34, + 0x48, 0x33, 0x74, 0x49, 0x30, 0x2f, 0x4e, 0x4c, 0x2f, 0x51, 0x50, 0x5a, + 0x4c, 0x39, 0x47, 0x5a, 0x47, 0x42, 0x6c, 0x53, 0x6d, 0x38, 0x6a, 0x49, + 0x4b, 0x59, 0x79, 0x59, 0x77, 0x61, 0x35, 0x76, 0x52, 0x0a, 0x33, 0x49, + 0x74, 0x48, 0x75, 0x75, 0x47, 0x35, 0x31, 0x57, 0x4c, 0x51, 0x6f, 0x71, + 0x44, 0x30, 0x5a, 0x77, 0x56, 0x34, 0x4b, 0x57, 0x4d, 0x61, 0x62, 0x77, + 0x54, 0x57, 0x2b, 0x4d, 0x5a, 0x4d, 0x6f, 0x35, 0x71, 0x78, 0x4e, 0x37, + 0x53, 0x4e, 0x35, 0x53, 0x68, 0x4c, 0x48, 0x5a, 0x34, 0x73, 0x77, 0x72, + 0x68, 0x6f, 0x76, 0x4f, 0x30, 0x43, 0x37, 0x6a, 0x45, 0x3d, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x47, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x53, 0x65, + 0x63, 0x75, 0x72, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f, + 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x65, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, + 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x39, 0x37, 0x35, + 0x31, 0x38, 0x33, 0x36, 0x31, 0x36, 0x37, 0x37, 0x33, 0x31, 0x30, 0x35, + 0x31, 0x35, 0x35, 0x34, 0x32, 0x33, 0x32, 0x31, 0x31, 0x39, 0x34, 0x38, + 0x31, 0x34, 0x35, 0x36, 0x39, 0x37, 0x38, 0x35, 0x39, 0x37, 0x0a, 0x23, + 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x66, 0x3a, 0x66, 0x34, 0x3a, + 0x32, 0x37, 0x3a, 0x30, 0x64, 0x3a, 0x64, 0x34, 0x3a, 0x65, 0x64, 0x3a, + 0x64, 0x63, 0x3a, 0x36, 0x35, 0x3a, 0x31, 0x36, 0x3a, 0x34, 0x39, 0x3a, + 0x36, 0x64, 0x3a, 0x33, 0x64, 0x3a, 0x64, 0x61, 0x3a, 0x62, 0x66, 0x3a, + 0x36, 0x65, 0x3a, 0x64, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x33, 0x61, 0x3a, 0x34, 0x34, 0x3a, 0x37, 0x33, 0x3a, 0x35, + 0x61, 0x3a, 0x65, 0x35, 0x3a, 0x38, 0x31, 0x3a, 0x39, 0x30, 0x3a, 0x31, + 0x66, 0x3a, 0x32, 0x34, 0x3a, 0x38, 0x36, 0x3a, 0x36, 0x31, 0x3a, 0x34, + 0x36, 0x3a, 0x31, 0x65, 0x3a, 0x33, 0x62, 0x3a, 0x39, 0x63, 0x3a, 0x63, + 0x34, 0x3a, 0x35, 0x66, 0x3a, 0x66, 0x35, 0x3a, 0x33, 0x61, 0x3a, 0x31, + 0x62, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x34, 0x32, 0x3a, 0x30, 0x30, 0x3a, 0x66, 0x35, 0x3a, 0x30, 0x34, 0x3a, + 0x33, 0x61, 0x3a, 0x63, 0x38, 0x3a, 0x35, 0x39, 0x3a, 0x30, 0x65, 0x3a, + 0x62, 0x62, 0x3a, 0x35, 0x32, 0x3a, 0x37, 0x64, 0x3a, 0x32, 0x30, 0x3a, + 0x39, 0x65, 0x3a, 0x64, 0x31, 0x3a, 0x35, 0x30, 0x3a, 0x33, 0x30, 0x3a, + 0x32, 0x39, 0x3a, 0x66, 0x62, 0x3a, 0x63, 0x62, 0x3a, 0x64, 0x34, 0x3a, + 0x31, 0x63, 0x3a, 0x61, 0x31, 0x3a, 0x62, 0x35, 0x3a, 0x30, 0x36, 0x3a, + 0x65, 0x63, 0x3a, 0x32, 0x37, 0x3a, 0x66, 0x31, 0x3a, 0x35, 0x61, 0x3a, + 0x64, 0x65, 0x3a, 0x37, 0x64, 0x3a, 0x61, 0x63, 0x3a, 0x36, 0x39, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x76, 0x44, 0x43, 0x43, + 0x41, 0x71, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, + 0x42, 0x31, 0x59, 0x69, 0x70, 0x4f, 0x6a, 0x55, 0x69, 0x6f, 0x6c, 0x4e, + 0x39, 0x42, 0x50, 0x49, 0x38, 0x50, 0x6a, 0x71, 0x70, 0x54, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x4b, 0x0a, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, + 0x56, 0x55, 0x7a, 0x45, 0x67, 0x4d, 0x42, 0x34, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x68, 0x4d, 0x58, 0x55, 0x32, 0x56, 0x6a, 0x64, 0x58, 0x4a, + 0x6c, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x51, 0x32, 0x39, + 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, + 0x78, 0x0a, 0x47, 0x54, 0x41, 0x58, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x4d, 0x54, 0x45, 0x46, 0x4e, 0x6c, 0x59, 0x33, 0x56, 0x79, 0x5a, 0x53, + 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x77, 0x67, 0x51, 0x30, + 0x45, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x59, 0x78, 0x4d, 0x54, + 0x41, 0x33, 0x4d, 0x54, 0x6b, 0x30, 0x4d, 0x6a, 0x49, 0x34, 0x57, 0x68, + 0x63, 0x4e, 0x4d, 0x6a, 0x6b, 0x78, 0x0a, 0x4d, 0x6a, 0x4d, 0x78, 0x4d, + 0x54, 0x6b, 0x31, 0x4d, 0x6a, 0x41, 0x32, 0x57, 0x6a, 0x42, 0x4b, 0x4d, + 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, + 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x67, 0x4d, 0x42, 0x34, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x58, 0x55, 0x32, 0x56, 0x6a, 0x64, + 0x58, 0x4a, 0x6c, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x0a, + 0x51, 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, 0x58, 0x52, 0x70, + 0x62, 0x32, 0x34, 0x78, 0x47, 0x54, 0x41, 0x58, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x4d, 0x54, 0x45, 0x46, 0x4e, 0x6c, 0x59, 0x33, 0x56, 0x79, + 0x5a, 0x53, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x77, 0x67, + 0x51, 0x30, 0x45, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4d, 0x41, 0x30, 0x47, + 0x43, 0x53, 0x71, 0x47, 0x0a, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, + 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77, 0x41, + 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x43, + 0x76, 0x4e, 0x53, 0x37, 0x59, 0x72, 0x47, 0x78, 0x56, 0x61, 0x51, 0x5a, + 0x78, 0x35, 0x52, 0x4e, 0x6f, 0x4a, 0x4c, 0x4e, 0x50, 0x32, 0x4d, 0x77, + 0x68, 0x52, 0x2f, 0x6a, 0x78, 0x59, 0x44, 0x69, 0x4a, 0x0a, 0x69, 0x51, + 0x50, 0x70, 0x76, 0x65, 0x70, 0x65, 0x52, 0x6c, 0x4d, 0x4a, 0x33, 0x46, + 0x7a, 0x31, 0x57, 0x75, 0x6a, 0x33, 0x52, 0x53, 0x6f, 0x43, 0x36, 0x7a, + 0x46, 0x68, 0x31, 0x79, 0x6b, 0x7a, 0x54, 0x4d, 0x37, 0x48, 0x66, 0x41, + 0x6f, 0x33, 0x66, 0x67, 0x2b, 0x36, 0x4d, 0x70, 0x6a, 0x68, 0x48, 0x5a, + 0x65, 0x76, 0x6a, 0x38, 0x66, 0x63, 0x79, 0x54, 0x69, 0x57, 0x38, 0x39, + 0x73, 0x61, 0x0a, 0x2f, 0x46, 0x48, 0x74, 0x61, 0x4d, 0x62, 0x51, 0x62, + 0x71, 0x52, 0x38, 0x4a, 0x4e, 0x47, 0x75, 0x51, 0x73, 0x69, 0x57, 0x55, + 0x47, 0x4d, 0x75, 0x34, 0x50, 0x35, 0x31, 0x2f, 0x70, 0x69, 0x6e, 0x58, + 0x30, 0x6b, 0x75, 0x6c, 0x65, 0x4d, 0x35, 0x4d, 0x32, 0x53, 0x4f, 0x48, + 0x71, 0x52, 0x66, 0x6b, 0x4e, 0x4a, 0x6e, 0x50, 0x4c, 0x4c, 0x5a, 0x2f, + 0x6b, 0x47, 0x35, 0x56, 0x61, 0x63, 0x4a, 0x0a, 0x6a, 0x6e, 0x49, 0x46, + 0x48, 0x6f, 0x76, 0x64, 0x52, 0x49, 0x57, 0x43, 0x51, 0x74, 0x42, 0x4a, + 0x77, 0x42, 0x31, 0x67, 0x38, 0x4e, 0x45, 0x58, 0x4c, 0x4a, 0x58, 0x72, + 0x39, 0x71, 0x58, 0x42, 0x6b, 0x71, 0x50, 0x46, 0x77, 0x71, 0x63, 0x49, + 0x59, 0x41, 0x31, 0x67, 0x42, 0x42, 0x43, 0x57, 0x65, 0x5a, 0x34, 0x57, + 0x4e, 0x4f, 0x61, 0x70, 0x74, 0x76, 0x6f, 0x6c, 0x52, 0x54, 0x6e, 0x49, + 0x0a, 0x48, 0x6d, 0x58, 0x35, 0x6b, 0x2f, 0x57, 0x71, 0x38, 0x56, 0x4c, + 0x63, 0x6d, 0x5a, 0x67, 0x39, 0x70, 0x59, 0x59, 0x61, 0x44, 0x44, 0x55, + 0x7a, 0x2b, 0x6b, 0x75, 0x6c, 0x42, 0x41, 0x59, 0x56, 0x48, 0x44, 0x47, + 0x41, 0x37, 0x36, 0x6f, 0x59, 0x61, 0x38, 0x4a, 0x37, 0x31, 0x39, 0x72, + 0x4f, 0x2b, 0x54, 0x4d, 0x67, 0x31, 0x66, 0x57, 0x39, 0x61, 0x6a, 0x4d, + 0x74, 0x67, 0x51, 0x54, 0x37, 0x0a, 0x73, 0x46, 0x7a, 0x55, 0x6e, 0x4b, + 0x50, 0x69, 0x58, 0x42, 0x33, 0x6a, 0x71, 0x55, 0x4a, 0x31, 0x58, 0x6e, + 0x76, 0x55, 0x64, 0x2b, 0x38, 0x35, 0x56, 0x4c, 0x72, 0x4a, 0x43, 0x68, + 0x67, 0x62, 0x45, 0x70, 0x6c, 0x4a, 0x4c, 0x34, 0x68, 0x4c, 0x2f, 0x56, + 0x42, 0x69, 0x30, 0x58, 0x50, 0x6e, 0x6a, 0x33, 0x70, 0x44, 0x41, 0x67, + 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x67, 0x5a, 0x30, 0x77, 0x0a, 0x67, + 0x5a, 0x6f, 0x77, 0x45, 0x77, 0x59, 0x4a, 0x4b, 0x77, 0x59, 0x42, 0x42, + 0x41, 0x47, 0x43, 0x4e, 0x78, 0x51, 0x43, 0x42, 0x41, 0x59, 0x65, 0x42, + 0x41, 0x42, 0x44, 0x41, 0x45, 0x45, 0x77, 0x43, 0x77, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x50, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x47, 0x47, 0x4d, + 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, + 0x77, 0x51, 0x46, 0x0a, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, + 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, + 0x46, 0x4b, 0x39, 0x45, 0x42, 0x4d, 0x4a, 0x42, 0x66, 0x6b, 0x69, 0x44, + 0x32, 0x30, 0x34, 0x35, 0x41, 0x75, 0x7a, 0x73, 0x68, 0x48, 0x72, 0x6d, + 0x7a, 0x73, 0x6d, 0x6b, 0x4d, 0x44, 0x51, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x48, 0x77, 0x51, 0x74, 0x4d, 0x43, 0x73, 0x77, 0x0a, 0x4b, 0x61, 0x41, + 0x6e, 0x6f, 0x43, 0x57, 0x47, 0x49, 0x32, 0x68, 0x30, 0x64, 0x48, 0x41, + 0x36, 0x4c, 0x79, 0x39, 0x6a, 0x63, 0x6d, 0x77, 0x75, 0x63, 0x32, 0x56, + 0x6a, 0x64, 0x58, 0x4a, 0x6c, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, + 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x31, 0x4e, 0x48, 0x51, 0x30, 0x45, + 0x75, 0x59, 0x33, 0x4a, 0x73, 0x4d, 0x42, 0x41, 0x47, 0x43, 0x53, 0x73, + 0x47, 0x0a, 0x41, 0x51, 0x51, 0x42, 0x67, 0x6a, 0x63, 0x56, 0x41, 0x51, + 0x51, 0x44, 0x41, 0x67, 0x45, 0x41, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, + 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, + 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x42, 0x6a, 0x47, 0x67, + 0x68, 0x41, 0x66, 0x61, 0x52, 0x65, 0x55, 0x77, 0x31, 0x33, 0x32, 0x48, + 0x71, 0x75, 0x48, 0x77, 0x30, 0x4c, 0x0a, 0x55, 0x52, 0x59, 0x44, 0x37, + 0x78, 0x68, 0x38, 0x79, 0x4f, 0x4f, 0x76, 0x61, 0x6c, 0x69, 0x54, 0x46, + 0x47, 0x43, 0x52, 0x73, 0x6f, 0x54, 0x63, 0x69, 0x45, 0x36, 0x2b, 0x4f, + 0x59, 0x6f, 0x36, 0x38, 0x2b, 0x61, 0x43, 0x69, 0x56, 0x30, 0x42, 0x4e, + 0x37, 0x4f, 0x72, 0x4a, 0x4b, 0x51, 0x56, 0x44, 0x70, 0x49, 0x31, 0x57, + 0x6b, 0x70, 0x45, 0x58, 0x6b, 0x35, 0x58, 0x2b, 0x6e, 0x58, 0x4f, 0x0a, + 0x48, 0x30, 0x6a, 0x4f, 0x5a, 0x76, 0x51, 0x38, 0x51, 0x43, 0x61, 0x53, + 0x6d, 0x47, 0x77, 0x62, 0x37, 0x69, 0x52, 0x47, 0x44, 0x42, 0x65, 0x7a, + 0x55, 0x71, 0x58, 0x62, 0x70, 0x5a, 0x47, 0x52, 0x7a, 0x7a, 0x66, 0x54, + 0x62, 0x2b, 0x63, 0x6e, 0x43, 0x44, 0x70, 0x4f, 0x47, 0x52, 0x38, 0x36, + 0x70, 0x31, 0x68, 0x63, 0x46, 0x38, 0x39, 0x35, 0x50, 0x34, 0x76, 0x6b, + 0x70, 0x39, 0x4d, 0x6d, 0x0a, 0x49, 0x35, 0x30, 0x6d, 0x44, 0x31, 0x68, + 0x70, 0x2f, 0x45, 0x64, 0x2b, 0x73, 0x74, 0x43, 0x4e, 0x69, 0x35, 0x4f, + 0x2f, 0x4b, 0x55, 0x39, 0x44, 0x61, 0x58, 0x52, 0x32, 0x5a, 0x30, 0x76, + 0x50, 0x42, 0x34, 0x7a, 0x6d, 0x41, 0x76, 0x65, 0x31, 0x34, 0x62, 0x52, + 0x44, 0x74, 0x55, 0x73, 0x74, 0x46, 0x4a, 0x2f, 0x35, 0x33, 0x43, 0x59, + 0x4e, 0x76, 0x36, 0x5a, 0x48, 0x64, 0x41, 0x62, 0x59, 0x0a, 0x69, 0x4e, + 0x45, 0x36, 0x4b, 0x54, 0x43, 0x45, 0x7a, 0x74, 0x49, 0x35, 0x67, 0x47, + 0x49, 0x62, 0x71, 0x4d, 0x64, 0x58, 0x53, 0x62, 0x78, 0x71, 0x56, 0x56, + 0x46, 0x6e, 0x46, 0x55, 0x71, 0x2b, 0x4e, 0x51, 0x66, 0x6b, 0x31, 0x58, + 0x57, 0x59, 0x4e, 0x33, 0x6b, 0x77, 0x46, 0x4e, 0x73, 0x70, 0x6e, 0x57, + 0x7a, 0x46, 0x61, 0x63, 0x78, 0x48, 0x56, 0x61, 0x49, 0x77, 0x39, 0x38, + 0x78, 0x63, 0x0a, 0x66, 0x38, 0x4c, 0x44, 0x6d, 0x42, 0x78, 0x72, 0x54, + 0x68, 0x61, 0x41, 0x36, 0x33, 0x70, 0x34, 0x5a, 0x55, 0x57, 0x69, 0x41, + 0x42, 0x71, 0x76, 0x44, 0x41, 0x31, 0x56, 0x5a, 0x44, 0x52, 0x49, 0x75, + 0x4a, 0x4b, 0x35, 0x38, 0x62, 0x52, 0x51, 0x4b, 0x66, 0x4a, 0x50, 0x49, + 0x78, 0x2f, 0x61, 0x62, 0x4b, 0x77, 0x66, 0x52, 0x4f, 0x48, 0x64, 0x49, + 0x33, 0x68, 0x52, 0x57, 0x38, 0x63, 0x57, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, + 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x43, 0x4f, 0x4d, + 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, + 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, + 0x4f, 0x3d, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x41, 0x20, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, + 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, + 0x31, 0x30, 0x34, 0x33, 0x35, 0x30, 0x35, 0x31, 0x33, 0x36, 0x34, 0x38, + 0x32, 0x34, 0x39, 0x32, 0x33, 0x32, 0x39, 0x34, 0x31, 0x39, 0x39, 0x38, + 0x35, 0x30, 0x38, 0x39, 0x38, 0x35, 0x38, 0x33, 0x34, 0x34, 0x36, 0x34, + 0x35, 0x37, 0x33, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, + 0x63, 0x3a, 0x34, 0x38, 0x3a, 0x64, 0x63, 0x3a, 0x66, 0x37, 0x3a, 0x34, + 0x32, 0x3a, 0x37, 0x32, 0x3a, 0x65, 0x63, 0x3a, 0x35, 0x36, 0x3a, 0x39, + 0x34, 0x3a, 0x36, 0x64, 0x3a, 0x31, 0x63, 0x3a, 0x63, 0x63, 0x3a, 0x37, + 0x31, 0x3a, 0x33, 0x35, 0x3a, 0x38, 0x30, 0x3a, 0x37, 0x35, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x36, 0x3a, 0x33, 0x31, + 0x3a, 0x62, 0x66, 0x3a, 0x39, 0x65, 0x3a, 0x66, 0x37, 0x3a, 0x34, 0x66, + 0x3a, 0x39, 0x65, 0x3a, 0x62, 0x36, 0x3a, 0x63, 0x39, 0x3a, 0x64, 0x35, + 0x3a, 0x61, 0x36, 0x3a, 0x30, 0x63, 0x3a, 0x62, 0x61, 0x3a, 0x36, 0x61, + 0x3a, 0x62, 0x65, 0x3a, 0x64, 0x31, 0x3a, 0x66, 0x37, 0x3a, 0x62, 0x64, + 0x3a, 0x65, 0x66, 0x3a, 0x37, 0x62, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x63, 0x3a, 0x32, 0x63, 0x3a, 0x64, + 0x36, 0x3a, 0x33, 0x64, 0x3a, 0x66, 0x37, 0x3a, 0x38, 0x30, 0x3a, 0x36, + 0x66, 0x3a, 0x61, 0x33, 0x3a, 0x39, 0x39, 0x3a, 0x65, 0x64, 0x3a, 0x65, + 0x38, 0x3a, 0x30, 0x39, 0x3a, 0x31, 0x31, 0x3a, 0x36, 0x62, 0x3a, 0x35, + 0x37, 0x3a, 0x35, 0x62, 0x3a, 0x66, 0x38, 0x3a, 0x37, 0x39, 0x3a, 0x38, + 0x39, 0x3a, 0x66, 0x30, 0x3a, 0x36, 0x35, 0x3a, 0x31, 0x38, 0x3a, 0x66, + 0x39, 0x3a, 0x38, 0x30, 0x3a, 0x38, 0x63, 0x3a, 0x38, 0x36, 0x3a, 0x30, + 0x35, 0x3a, 0x30, 0x33, 0x3a, 0x31, 0x37, 0x3a, 0x38, 0x62, 0x3a, 0x61, + 0x66, 0x3a, 0x36, 0x36, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x45, 0x48, 0x54, 0x43, 0x43, 0x41, 0x77, 0x57, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x51, 0x54, 0x6f, 0x45, 0x74, 0x69, 0x6f, 0x4a, + 0x6c, 0x34, 0x41, 0x73, 0x43, 0x37, 0x6a, 0x34, 0x31, 0x41, 0x6b, 0x62, + 0x6c, 0x50, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x43, + 0x42, 0x0a, 0x67, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x30, 0x49, 0x78, 0x47, 0x7a, + 0x41, 0x5a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x54, 0x45, 0x6b, + 0x64, 0x79, 0x5a, 0x57, 0x46, 0x30, 0x5a, 0x58, 0x49, 0x67, 0x54, 0x57, + 0x46, 0x75, 0x59, 0x32, 0x68, 0x6c, 0x63, 0x33, 0x52, 0x6c, 0x63, 0x6a, + 0x45, 0x51, 0x4d, 0x41, 0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x78, 0x4d, 0x48, 0x55, 0x32, 0x46, 0x73, 0x5a, 0x6d, 0x39, 0x79, 0x5a, + 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x68, 0x4d, 0x52, 0x51, 0x30, 0x39, 0x4e, 0x54, 0x30, 0x52, 0x50, 0x49, + 0x45, 0x4e, 0x42, 0x49, 0x45, 0x78, 0x70, 0x62, 0x57, 0x6c, 0x30, 0x5a, + 0x57, 0x51, 0x78, 0x4a, 0x7a, 0x41, 0x6c, 0x42, 0x67, 0x4e, 0x56, 0x0a, + 0x42, 0x41, 0x4d, 0x54, 0x48, 0x6b, 0x4e, 0x50, 0x54, 0x55, 0x39, 0x45, + 0x54, 0x79, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, + 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, 0x31, + 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, 0x41, 0x65, + 0x46, 0x77, 0x30, 0x77, 0x4e, 0x6a, 0x45, 0x79, 0x4d, 0x44, 0x45, 0x77, + 0x4d, 0x44, 0x41, 0x77, 0x0a, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, + 0x79, 0x4f, 0x54, 0x45, 0x79, 0x4d, 0x7a, 0x45, 0x79, 0x4d, 0x7a, 0x55, + 0x35, 0x4e, 0x54, 0x6c, 0x61, 0x4d, 0x49, 0x47, 0x42, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, + 0x48, 0x51, 0x6a, 0x45, 0x62, 0x4d, 0x42, 0x6b, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x42, 0x4d, 0x53, 0x52, 0x33, 0x4a, 0x6c, 0x0a, 0x59, 0x58, + 0x52, 0x6c, 0x63, 0x69, 0x42, 0x4e, 0x59, 0x57, 0x35, 0x6a, 0x61, 0x47, + 0x56, 0x7a, 0x64, 0x47, 0x56, 0x79, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x45, 0x77, 0x64, 0x54, 0x59, 0x57, + 0x78, 0x6d, 0x62, 0x33, 0x4a, 0x6b, 0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x46, 0x44, 0x54, 0x30, + 0x31, 0x50, 0x0a, 0x52, 0x45, 0x38, 0x67, 0x51, 0x30, 0x45, 0x67, 0x54, + 0x47, 0x6c, 0x74, 0x61, 0x58, 0x52, 0x6c, 0x5a, 0x44, 0x45, 0x6e, 0x4d, + 0x43, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x65, 0x51, + 0x30, 0x39, 0x4e, 0x54, 0x30, 0x52, 0x50, 0x49, 0x45, 0x4e, 0x6c, 0x63, + 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, + 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x0a, 0x61, 0x47, 0x39, 0x79, + 0x61, 0x58, 0x52, 0x35, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, + 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, + 0x30, 0x45, 0x43, 0x4c, 0x69, 0x33, 0x4c, 0x6a, 0x6b, 0x52, 0x76, 0x33, + 0x0a, 0x55, 0x63, 0x45, 0x62, 0x56, 0x41, 0x53, 0x59, 0x30, 0x36, 0x6d, + 0x2f, 0x77, 0x65, 0x61, 0x4b, 0x58, 0x54, 0x75, 0x48, 0x2b, 0x37, 0x75, + 0x49, 0x7a, 0x67, 0x33, 0x6a, 0x4c, 0x7a, 0x38, 0x47, 0x6c, 0x76, 0x43, + 0x69, 0x4b, 0x56, 0x43, 0x5a, 0x72, 0x74, 0x73, 0x37, 0x6f, 0x56, 0x65, + 0x77, 0x64, 0x46, 0x46, 0x78, 0x7a, 0x65, 0x31, 0x43, 0x6b, 0x55, 0x31, + 0x42, 0x2f, 0x71, 0x6e, 0x49, 0x0a, 0x32, 0x47, 0x71, 0x47, 0x64, 0x30, + 0x53, 0x37, 0x57, 0x57, 0x61, 0x58, 0x55, 0x46, 0x36, 0x30, 0x31, 0x43, + 0x78, 0x77, 0x52, 0x4d, 0x2f, 0x61, 0x4e, 0x35, 0x56, 0x43, 0x61, 0x54, + 0x77, 0x77, 0x78, 0x48, 0x47, 0x7a, 0x55, 0x76, 0x41, 0x68, 0x54, 0x61, + 0x48, 0x59, 0x75, 0x6a, 0x6c, 0x38, 0x48, 0x4a, 0x36, 0x6a, 0x4a, 0x4a, + 0x33, 0x79, 0x67, 0x78, 0x61, 0x59, 0x71, 0x68, 0x5a, 0x38, 0x0a, 0x51, + 0x35, 0x73, 0x56, 0x57, 0x37, 0x65, 0x75, 0x4e, 0x4a, 0x48, 0x2b, 0x31, + 0x47, 0x49, 0x6d, 0x47, 0x45, 0x61, 0x61, 0x50, 0x2b, 0x76, 0x42, 0x2b, + 0x66, 0x47, 0x51, 0x56, 0x2b, 0x75, 0x73, 0x65, 0x67, 0x32, 0x4c, 0x32, + 0x33, 0x49, 0x77, 0x61, 0x6d, 0x62, 0x56, 0x34, 0x45, 0x61, 0x6a, 0x63, + 0x4e, 0x78, 0x6f, 0x32, 0x66, 0x38, 0x45, 0x53, 0x49, 0x6c, 0x33, 0x33, + 0x72, 0x58, 0x70, 0x0a, 0x2b, 0x32, 0x64, 0x74, 0x51, 0x65, 0x6d, 0x38, + 0x4f, 0x62, 0x30, 0x79, 0x32, 0x57, 0x49, 0x43, 0x38, 0x62, 0x47, 0x6f, + 0x50, 0x57, 0x34, 0x33, 0x6e, 0x4f, 0x49, 0x76, 0x34, 0x74, 0x4f, 0x69, + 0x4a, 0x6f, 0x76, 0x47, 0x75, 0x46, 0x56, 0x44, 0x69, 0x4f, 0x45, 0x6a, + 0x50, 0x71, 0x58, 0x53, 0x4a, 0x44, 0x6c, 0x71, 0x52, 0x36, 0x73, 0x41, + 0x31, 0x4b, 0x47, 0x7a, 0x71, 0x53, 0x58, 0x2b, 0x0a, 0x44, 0x54, 0x2b, + 0x6e, 0x48, 0x62, 0x72, 0x54, 0x55, 0x63, 0x45, 0x4c, 0x70, 0x4e, 0x71, + 0x73, 0x4f, 0x4f, 0x39, 0x56, 0x55, 0x43, 0x51, 0x46, 0x5a, 0x55, 0x61, + 0x54, 0x4e, 0x45, 0x38, 0x74, 0x6a, 0x61, 0x33, 0x47, 0x31, 0x43, 0x45, + 0x5a, 0x30, 0x6f, 0x37, 0x4b, 0x42, 0x57, 0x46, 0x78, 0x42, 0x33, 0x4e, + 0x48, 0x35, 0x59, 0x6f, 0x5a, 0x45, 0x72, 0x30, 0x45, 0x54, 0x63, 0x35, + 0x4f, 0x0a, 0x6e, 0x4b, 0x56, 0x49, 0x72, 0x4c, 0x73, 0x6d, 0x39, 0x77, + 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x34, 0x47, 0x4f, 0x4d, 0x49, + 0x47, 0x4c, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, + 0x51, 0x57, 0x42, 0x42, 0x51, 0x4c, 0x57, 0x4f, 0x57, 0x4c, 0x78, 0x6b, + 0x77, 0x56, 0x4e, 0x36, 0x52, 0x41, 0x71, 0x54, 0x43, 0x70, 0x49, 0x62, + 0x35, 0x48, 0x4e, 0x6c, 0x70, 0x57, 0x0a, 0x2f, 0x7a, 0x41, 0x4f, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, + 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, + 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x42, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x52, 0x38, 0x45, 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x44, 0x36, 0x67, 0x0a, + 0x50, 0x4b, 0x41, 0x36, 0x68, 0x6a, 0x68, 0x6f, 0x64, 0x48, 0x52, 0x77, + 0x4f, 0x69, 0x38, 0x76, 0x59, 0x33, 0x4a, 0x73, 0x4c, 0x6d, 0x4e, 0x76, + 0x62, 0x57, 0x39, 0x6b, 0x62, 0x32, 0x4e, 0x68, 0x4c, 0x6d, 0x4e, 0x76, + 0x62, 0x53, 0x39, 0x44, 0x54, 0x30, 0x31, 0x50, 0x52, 0x45, 0x39, 0x44, + 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, + 0x61, 0x57, 0x39, 0x75, 0x0a, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, + 0x79, 0x61, 0x58, 0x52, 0x35, 0x4c, 0x6d, 0x4e, 0x79, 0x62, 0x44, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, + 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, + 0x41, 0x50, 0x70, 0x69, 0x65, 0x6d, 0x2f, 0x59, 0x62, 0x36, 0x64, 0x63, + 0x35, 0x74, 0x33, 0x69, 0x75, 0x48, 0x58, 0x49, 0x59, 0x0a, 0x53, 0x64, + 0x4f, 0x48, 0x35, 0x45, 0x4f, 0x43, 0x36, 0x7a, 0x2f, 0x4a, 0x71, 0x76, + 0x57, 0x6f, 0x74, 0x65, 0x39, 0x56, 0x66, 0x43, 0x46, 0x53, 0x5a, 0x66, + 0x6e, 0x56, 0x44, 0x65, 0x46, 0x73, 0x39, 0x44, 0x36, 0x4d, 0x6b, 0x33, + 0x4f, 0x52, 0x4c, 0x67, 0x4c, 0x45, 0x54, 0x67, 0x64, 0x78, 0x62, 0x38, + 0x43, 0x50, 0x4f, 0x47, 0x45, 0x49, 0x71, 0x42, 0x36, 0x42, 0x43, 0x73, + 0x41, 0x76, 0x0a, 0x49, 0x43, 0x39, 0x42, 0x69, 0x35, 0x48, 0x63, 0x53, + 0x45, 0x57, 0x38, 0x38, 0x63, 0x62, 0x65, 0x75, 0x6e, 0x5a, 0x72, 0x4d, + 0x38, 0x67, 0x41, 0x4c, 0x54, 0x46, 0x47, 0x54, 0x4f, 0x33, 0x6e, 0x6e, + 0x63, 0x2b, 0x49, 0x6c, 0x50, 0x38, 0x7a, 0x77, 0x46, 0x62, 0x6f, 0x4a, + 0x49, 0x59, 0x6d, 0x75, 0x4e, 0x67, 0x34, 0x4f, 0x4e, 0x38, 0x71, 0x61, + 0x39, 0x30, 0x53, 0x7a, 0x4d, 0x63, 0x2f, 0x0a, 0x52, 0x78, 0x64, 0x4d, + 0x6f, 0x73, 0x49, 0x47, 0x6c, 0x67, 0x6e, 0x57, 0x32, 0x2f, 0x34, 0x2f, + 0x50, 0x45, 0x5a, 0x42, 0x33, 0x31, 0x6a, 0x69, 0x56, 0x67, 0x38, 0x38, + 0x4f, 0x38, 0x45, 0x63, 0x6b, 0x7a, 0x58, 0x5a, 0x4f, 0x46, 0x4b, 0x73, + 0x37, 0x73, 0x6a, 0x73, 0x4c, 0x6a, 0x42, 0x4f, 0x6c, 0x44, 0x57, 0x30, + 0x4a, 0x42, 0x39, 0x4c, 0x65, 0x47, 0x6e, 0x61, 0x38, 0x67, 0x49, 0x34, + 0x0a, 0x7a, 0x4a, 0x56, 0x53, 0x6b, 0x2f, 0x42, 0x77, 0x4a, 0x56, 0x6d, + 0x63, 0x49, 0x47, 0x66, 0x45, 0x37, 0x76, 0x6d, 0x4c, 0x56, 0x32, 0x48, + 0x30, 0x6b, 0x6e, 0x5a, 0x39, 0x50, 0x34, 0x53, 0x4e, 0x56, 0x62, 0x66, + 0x6f, 0x35, 0x61, 0x7a, 0x56, 0x38, 0x66, 0x55, 0x5a, 0x56, 0x71, 0x5a, + 0x61, 0x2b, 0x35, 0x41, 0x63, 0x72, 0x35, 0x50, 0x72, 0x35, 0x52, 0x7a, + 0x55, 0x5a, 0x35, 0x64, 0x64, 0x0a, 0x42, 0x41, 0x36, 0x2b, 0x43, 0x34, + 0x4f, 0x6d, 0x46, 0x34, 0x4f, 0x35, 0x4d, 0x42, 0x4b, 0x67, 0x78, 0x54, + 0x4d, 0x56, 0x42, 0x62, 0x6b, 0x4e, 0x2b, 0x38, 0x63, 0x46, 0x64, 0x75, + 0x50, 0x59, 0x53, 0x6f, 0x33, 0x38, 0x4e, 0x42, 0x65, 0x6a, 0x78, 0x69, + 0x45, 0x6f, 0x76, 0x6a, 0x42, 0x46, 0x4d, 0x52, 0x37, 0x48, 0x65, 0x4c, + 0x35, 0x59, 0x59, 0x54, 0x69, 0x73, 0x4f, 0x2b, 0x49, 0x42, 0x0a, 0x5a, + 0x51, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, + 0x4f, 0x3d, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, + 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x4c, 0x2e, 0x4c, 0x2e, + 0x43, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x4c, 0x2e, 0x4c, 0x2e, 0x43, 0x2e, 0x0a, + 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x31, 0x31, 0x36, 0x36, 0x39, 0x37, 0x39, 0x31, 0x35, 0x31, 0x35, + 0x32, 0x39, 0x33, 0x37, 0x34, 0x39, 0x37, 0x34, 0x39, 0x30, 0x34, 0x33, + 0x37, 0x35, 0x35, 0x36, 0x33, 0x38, 0x36, 0x38, 0x31, 0x32, 0x34, 0x38, + 0x37, 0x39, 0x30, 0x34, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x64, 0x33, 0x3a, 0x66, 0x33, 0x3a, 0x61, 0x36, 0x3a, 0x31, 0x36, 0x3a, + 0x63, 0x30, 0x3a, 0x66, 0x61, 0x3a, 0x36, 0x62, 0x3a, 0x31, 0x64, 0x3a, + 0x35, 0x39, 0x3a, 0x62, 0x31, 0x3a, 0x32, 0x64, 0x3a, 0x39, 0x36, 0x3a, + 0x34, 0x64, 0x3a, 0x30, 0x65, 0x3a, 0x31, 0x31, 0x3a, 0x32, 0x65, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x34, 0x3a, 0x66, + 0x38, 0x3a, 0x61, 0x33, 0x3a, 0x63, 0x33, 0x3a, 0x65, 0x66, 0x3a, 0x65, + 0x37, 0x3a, 0x62, 0x33, 0x3a, 0x39, 0x30, 0x3a, 0x30, 0x36, 0x3a, 0x34, + 0x62, 0x3a, 0x38, 0x33, 0x3a, 0x39, 0x30, 0x3a, 0x33, 0x63, 0x3a, 0x32, + 0x31, 0x3a, 0x36, 0x34, 0x3a, 0x36, 0x30, 0x3a, 0x32, 0x30, 0x3a, 0x65, + 0x35, 0x3a, 0x64, 0x66, 0x3a, 0x63, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x35, 0x3a, 0x66, 0x30, 0x3a, + 0x62, 0x61, 0x3a, 0x30, 0x30, 0x3a, 0x61, 0x33, 0x3a, 0x61, 0x63, 0x3a, + 0x37, 0x61, 0x3a, 0x66, 0x33, 0x3a, 0x61, 0x63, 0x3a, 0x38, 0x38, 0x3a, + 0x34, 0x63, 0x3a, 0x30, 0x37, 0x3a, 0x32, 0x62, 0x3a, 0x31, 0x30, 0x3a, + 0x31, 0x31, 0x3a, 0x61, 0x30, 0x3a, 0x37, 0x37, 0x3a, 0x62, 0x64, 0x3a, + 0x37, 0x37, 0x3a, 0x63, 0x30, 0x3a, 0x39, 0x37, 0x3a, 0x66, 0x34, 0x3a, + 0x30, 0x31, 0x3a, 0x36, 0x34, 0x3a, 0x62, 0x32, 0x3a, 0x66, 0x38, 0x3a, + 0x35, 0x39, 0x3a, 0x38, 0x61, 0x3a, 0x62, 0x64, 0x3a, 0x38, 0x33, 0x3a, + 0x38, 0x36, 0x3a, 0x30, 0x63, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, + 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, + 0x49, 0x44, 0x35, 0x6a, 0x43, 0x43, 0x41, 0x73, 0x36, 0x67, 0x41, 0x77, + 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x56, 0x38, 0x73, 0x7a, 0x62, 0x38, + 0x4a, 0x63, 0x46, 0x75, 0x5a, 0x48, 0x46, 0x68, 0x66, 0x6a, 0x6b, 0x44, + 0x46, 0x6f, 0x34, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, + 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, + 0x42, 0x69, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x68, 0x4d, + 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x59, 0x54, + 0x6d, 0x56, 0x30, 0x64, 0x32, 0x39, 0x79, 0x61, 0x79, 0x42, 0x54, 0x62, + 0x32, 0x78, 0x31, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6e, 0x4d, 0x67, 0x54, + 0x43, 0x35, 0x4d, 0x4c, 0x6b, 0x4d, 0x75, 0x0a, 0x4d, 0x54, 0x41, 0x77, + 0x4c, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x79, 0x64, 0x4f, + 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x49, 0x46, 0x4e, 0x76, + 0x62, 0x48, 0x56, 0x30, 0x61, 0x57, 0x39, 0x75, 0x63, 0x79, 0x42, 0x44, + 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, + 0x5a, 0x53, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, + 0x0a, 0x64, 0x48, 0x6b, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x59, + 0x78, 0x4d, 0x6a, 0x41, 0x78, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, + 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x6b, 0x78, 0x4d, 0x6a, 0x4d, + 0x78, 0x4d, 0x6a, 0x4d, 0x31, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, 0x42, + 0x69, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x47, 0x45, 0x77, 0x4a, 0x56, 0x0a, 0x55, 0x7a, 0x45, 0x68, 0x4d, 0x42, + 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x59, 0x54, 0x6d, + 0x56, 0x30, 0x64, 0x32, 0x39, 0x79, 0x61, 0x79, 0x42, 0x54, 0x62, 0x32, + 0x78, 0x31, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6e, 0x4d, 0x67, 0x54, 0x43, + 0x35, 0x4d, 0x4c, 0x6b, 0x4d, 0x75, 0x4d, 0x54, 0x41, 0x77, 0x4c, 0x67, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x79, 0x64, 0x4f, 0x0a, 0x5a, + 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x49, 0x46, 0x4e, 0x76, 0x62, + 0x48, 0x56, 0x30, 0x61, 0x57, 0x39, 0x75, 0x63, 0x79, 0x42, 0x44, 0x5a, + 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, + 0x53, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, + 0x48, 0x6b, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, + 0x53, 0x71, 0x47, 0x0a, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, + 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, + 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x44, 0x6b, + 0x76, 0x48, 0x36, 0x53, 0x4d, 0x47, 0x33, 0x47, 0x32, 0x49, 0x34, 0x72, + 0x43, 0x37, 0x78, 0x47, 0x7a, 0x75, 0x41, 0x6e, 0x6c, 0x74, 0x37, 0x65, + 0x2b, 0x66, 0x6f, 0x53, 0x30, 0x7a, 0x77, 0x7a, 0x0a, 0x63, 0x37, 0x4d, + 0x45, 0x4c, 0x37, 0x78, 0x78, 0x6a, 0x4f, 0x57, 0x66, 0x74, 0x69, 0x4a, + 0x67, 0x50, 0x6c, 0x39, 0x64, 0x7a, 0x67, 0x6e, 0x2f, 0x67, 0x67, 0x77, + 0x62, 0x6d, 0x6c, 0x46, 0x51, 0x47, 0x69, 0x61, 0x4a, 0x33, 0x64, 0x56, + 0x68, 0x58, 0x52, 0x6e, 0x63, 0x45, 0x67, 0x38, 0x74, 0x43, 0x71, 0x4a, + 0x44, 0x58, 0x52, 0x66, 0x51, 0x4e, 0x4a, 0x49, 0x67, 0x36, 0x6e, 0x50, + 0x50, 0x0a, 0x4f, 0x43, 0x77, 0x47, 0x4a, 0x67, 0x6c, 0x36, 0x63, 0x76, + 0x66, 0x36, 0x55, 0x44, 0x4c, 0x34, 0x77, 0x70, 0x50, 0x54, 0x61, 0x61, + 0x49, 0x6a, 0x7a, 0x6b, 0x47, 0x78, 0x7a, 0x4f, 0x54, 0x56, 0x48, 0x7a, + 0x62, 0x52, 0x69, 0x6a, 0x72, 0x34, 0x6a, 0x47, 0x50, 0x69, 0x46, 0x46, + 0x6c, 0x70, 0x37, 0x51, 0x33, 0x54, 0x66, 0x32, 0x76, 0x6f, 0x75, 0x41, + 0x50, 0x6c, 0x54, 0x32, 0x72, 0x6c, 0x0a, 0x6d, 0x47, 0x4e, 0x70, 0x53, + 0x41, 0x57, 0x2b, 0x4c, 0x76, 0x38, 0x7a, 0x74, 0x75, 0x6d, 0x58, 0x57, + 0x57, 0x6e, 0x34, 0x5a, 0x78, 0x6d, 0x75, 0x6b, 0x32, 0x47, 0x57, 0x52, + 0x42, 0x58, 0x54, 0x63, 0x72, 0x41, 0x2f, 0x76, 0x47, 0x70, 0x39, 0x37, + 0x45, 0x68, 0x2f, 0x6a, 0x63, 0x4f, 0x72, 0x71, 0x6e, 0x45, 0x72, 0x55, + 0x32, 0x6c, 0x42, 0x55, 0x7a, 0x53, 0x31, 0x73, 0x4c, 0x6e, 0x46, 0x0a, + 0x42, 0x67, 0x72, 0x45, 0x73, 0x45, 0x58, 0x31, 0x51, 0x56, 0x31, 0x75, + 0x69, 0x55, 0x56, 0x37, 0x50, 0x54, 0x73, 0x6d, 0x6a, 0x48, 0x54, 0x43, + 0x35, 0x64, 0x4c, 0x52, 0x66, 0x62, 0x49, 0x52, 0x31, 0x50, 0x74, 0x59, + 0x4d, 0x69, 0x4b, 0x61, 0x67, 0x4d, 0x6e, 0x63, 0x2f, 0x51, 0x7a, 0x70, + 0x66, 0x31, 0x34, 0x44, 0x6c, 0x38, 0x34, 0x37, 0x41, 0x42, 0x53, 0x48, + 0x4a, 0x33, 0x41, 0x34, 0x0a, 0x71, 0x59, 0x35, 0x75, 0x73, 0x79, 0x64, + 0x32, 0x6d, 0x46, 0x48, 0x67, 0x42, 0x65, 0x4d, 0x68, 0x71, 0x78, 0x72, + 0x56, 0x68, 0x53, 0x49, 0x38, 0x4b, 0x62, 0x57, 0x61, 0x46, 0x73, 0x57, + 0x41, 0x71, 0x50, 0x53, 0x37, 0x61, 0x7a, 0x43, 0x50, 0x4c, 0x30, 0x59, + 0x43, 0x6f, 0x72, 0x45, 0x4d, 0x49, 0x75, 0x44, 0x54, 0x41, 0x67, 0x4d, + 0x42, 0x41, 0x41, 0x47, 0x6a, 0x67, 0x5a, 0x63, 0x77, 0x0a, 0x67, 0x5a, + 0x51, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, + 0x59, 0x45, 0x46, 0x43, 0x45, 0x77, 0x79, 0x66, 0x73, 0x41, 0x31, 0x30, + 0x36, 0x59, 0x32, 0x6f, 0x65, 0x71, 0x4b, 0x74, 0x43, 0x6e, 0x4c, 0x72, + 0x46, 0x41, 0x4d, 0x61, 0x64, 0x4d, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, + 0x49, 0x42, 0x0a, 0x42, 0x6a, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, + 0x51, 0x48, 0x2f, 0x4d, 0x46, 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, 0x48, + 0x77, 0x52, 0x4c, 0x4d, 0x45, 0x6b, 0x77, 0x52, 0x36, 0x42, 0x46, 0x6f, + 0x45, 0x4f, 0x47, 0x51, 0x57, 0x68, 0x30, 0x64, 0x48, 0x41, 0x36, 0x4c, + 0x79, 0x39, 0x6a, 0x63, 0x6d, 0x77, 0x75, 0x0a, 0x62, 0x6d, 0x56, 0x30, + 0x63, 0x32, 0x39, 0x73, 0x63, 0x33, 0x4e, 0x73, 0x4c, 0x6d, 0x4e, 0x76, + 0x62, 0x53, 0x39, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, + 0x55, 0x32, 0x39, 0x73, 0x64, 0x58, 0x52, 0x70, 0x62, 0x32, 0x35, 0x7a, + 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, + 0x64, 0x47, 0x56, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, + 0x0a, 0x64, 0x48, 0x6b, 0x75, 0x59, 0x33, 0x4a, 0x73, 0x4d, 0x41, 0x30, + 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, + 0x42, 0x42, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x43, + 0x37, 0x72, 0x6b, 0x76, 0x6e, 0x74, 0x31, 0x66, 0x72, 0x66, 0x36, 0x6f, + 0x74, 0x74, 0x33, 0x4e, 0x48, 0x68, 0x57, 0x72, 0x42, 0x35, 0x4b, 0x55, + 0x64, 0x35, 0x4f, 0x63, 0x38, 0x0a, 0x36, 0x66, 0x52, 0x5a, 0x5a, 0x58, + 0x65, 0x31, 0x65, 0x6c, 0x74, 0x61, 0x6a, 0x53, 0x55, 0x32, 0x34, 0x48, + 0x71, 0x58, 0x4c, 0x6a, 0x6a, 0x41, 0x56, 0x32, 0x43, 0x44, 0x6d, 0x41, + 0x61, 0x44, 0x6e, 0x37, 0x6c, 0x32, 0x65, 0x6d, 0x35, 0x51, 0x34, 0x4c, + 0x71, 0x49, 0x4c, 0x50, 0x78, 0x46, 0x7a, 0x42, 0x69, 0x77, 0x6d, 0x5a, + 0x56, 0x52, 0x44, 0x75, 0x77, 0x64, 0x75, 0x49, 0x6a, 0x2f, 0x0a, 0x68, + 0x31, 0x41, 0x63, 0x67, 0x73, 0x4c, 0x6a, 0x34, 0x44, 0x4b, 0x41, 0x76, + 0x36, 0x41, 0x4c, 0x52, 0x38, 0x6a, 0x44, 0x4d, 0x65, 0x2b, 0x5a, 0x5a, + 0x7a, 0x4b, 0x41, 0x54, 0x78, 0x63, 0x68, 0x65, 0x51, 0x78, 0x70, 0x58, + 0x4e, 0x35, 0x65, 0x4e, 0x4b, 0x34, 0x43, 0x74, 0x53, 0x62, 0x71, 0x55, + 0x4e, 0x39, 0x2f, 0x47, 0x47, 0x55, 0x73, 0x79, 0x66, 0x4a, 0x6a, 0x34, + 0x61, 0x6b, 0x48, 0x0a, 0x2f, 0x6e, 0x78, 0x78, 0x48, 0x32, 0x73, 0x7a, + 0x4a, 0x47, 0x6f, 0x65, 0x42, 0x66, 0x63, 0x46, 0x61, 0x4d, 0x42, 0x71, + 0x45, 0x73, 0x73, 0x75, 0x58, 0x6d, 0x48, 0x4c, 0x72, 0x69, 0x6a, 0x54, + 0x66, 0x73, 0x4b, 0x30, 0x5a, 0x70, 0x45, 0x6d, 0x58, 0x7a, 0x77, 0x75, + 0x4a, 0x46, 0x2f, 0x4c, 0x57, 0x41, 0x2f, 0x72, 0x4b, 0x4f, 0x79, 0x76, + 0x45, 0x5a, 0x62, 0x7a, 0x33, 0x48, 0x74, 0x76, 0x0a, 0x77, 0x4b, 0x65, + 0x49, 0x38, 0x6c, 0x4e, 0x33, 0x73, 0x32, 0x42, 0x65, 0x72, 0x71, 0x34, + 0x6f, 0x32, 0x6a, 0x55, 0x73, 0x62, 0x7a, 0x52, 0x46, 0x30, 0x79, 0x62, + 0x68, 0x33, 0x75, 0x78, 0x62, 0x54, 0x79, 0x64, 0x72, 0x46, 0x6e, 0x79, + 0x39, 0x52, 0x41, 0x51, 0x59, 0x67, 0x72, 0x4f, 0x4a, 0x65, 0x52, 0x63, + 0x51, 0x63, 0x54, 0x31, 0x36, 0x6f, 0x68, 0x5a, 0x4f, 0x39, 0x51, 0x48, + 0x4e, 0x0a, 0x70, 0x47, 0x78, 0x6c, 0x61, 0x4b, 0x46, 0x4a, 0x64, 0x6c, + 0x78, 0x44, 0x79, 0x64, 0x69, 0x38, 0x4e, 0x6d, 0x64, 0x73, 0x70, 0x5a, + 0x53, 0x31, 0x31, 0x4d, 0x79, 0x35, 0x76, 0x57, 0x6f, 0x31, 0x56, 0x69, + 0x48, 0x65, 0x32, 0x4d, 0x50, 0x72, 0x2b, 0x38, 0x75, 0x6b, 0x59, 0x45, + 0x79, 0x77, 0x56, 0x61, 0x43, 0x67, 0x65, 0x31, 0x65, 0x79, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x45, 0x43, + 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x20, 0x4f, 0x3d, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, + 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x45, 0x43, 0x43, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, + 0x3d, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x41, 0x20, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, + 0x45, 0x43, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x34, 0x31, 0x35, 0x37, 0x38, 0x32, 0x38, 0x33, 0x38, + 0x36, 0x37, 0x30, 0x38, 0x36, 0x36, 0x39, 0x32, 0x36, 0x33, 0x38, 0x32, + 0x35, 0x36, 0x39, 0x32, 0x31, 0x35, 0x38, 0x39, 0x37, 0x30, 0x37, 0x39, + 0x33, 0x38, 0x30, 0x39, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x37, 0x63, 0x3a, 0x36, 0x32, 0x3a, 0x66, 0x66, 0x3a, 0x37, 0x34, + 0x3a, 0x39, 0x64, 0x3a, 0x33, 0x31, 0x3a, 0x35, 0x33, 0x3a, 0x35, 0x65, + 0x3a, 0x36, 0x38, 0x3a, 0x34, 0x61, 0x3a, 0x64, 0x35, 0x3a, 0x37, 0x38, + 0x3a, 0x61, 0x61, 0x3a, 0x31, 0x65, 0x3a, 0x62, 0x66, 0x3a, 0x32, 0x33, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x66, 0x3a, + 0x37, 0x34, 0x3a, 0x34, 0x65, 0x3a, 0x39, 0x66, 0x3a, 0x32, 0x62, 0x3a, + 0x34, 0x64, 0x3a, 0x62, 0x61, 0x3a, 0x65, 0x63, 0x3a, 0x30, 0x66, 0x3a, + 0x33, 0x31, 0x3a, 0x32, 0x63, 0x3a, 0x35, 0x30, 0x3a, 0x62, 0x36, 0x3a, + 0x35, 0x36, 0x3a, 0x33, 0x62, 0x3a, 0x38, 0x65, 0x3a, 0x32, 0x64, 0x3a, + 0x39, 0x33, 0x3a, 0x63, 0x33, 0x3a, 0x31, 0x31, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x37, 0x3a, 0x39, 0x33, + 0x3a, 0x39, 0x32, 0x3a, 0x37, 0x61, 0x3a, 0x30, 0x36, 0x3a, 0x31, 0x34, + 0x3a, 0x35, 0x34, 0x3a, 0x39, 0x37, 0x3a, 0x38, 0x39, 0x3a, 0x61, 0x64, + 0x3a, 0x63, 0x65, 0x3a, 0x32, 0x66, 0x3a, 0x38, 0x66, 0x3a, 0x33, 0x34, + 0x3a, 0x66, 0x37, 0x3a, 0x66, 0x30, 0x3a, 0x62, 0x36, 0x3a, 0x36, 0x64, + 0x3a, 0x30, 0x66, 0x3a, 0x33, 0x61, 0x3a, 0x65, 0x33, 0x3a, 0x61, 0x33, + 0x3a, 0x62, 0x38, 0x3a, 0x34, 0x64, 0x3a, 0x32, 0x31, 0x3a, 0x65, 0x63, + 0x3a, 0x31, 0x35, 0x3a, 0x64, 0x62, 0x3a, 0x62, 0x61, 0x3a, 0x34, 0x66, + 0x3a, 0x61, 0x64, 0x3a, 0x63, 0x37, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x43, 0x69, 0x54, 0x43, 0x43, 0x41, 0x67, 0x2b, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x48, 0x30, 0x65, 0x76, 0x71, + 0x6d, 0x49, 0x41, 0x63, 0x46, 0x42, 0x55, 0x54, 0x41, 0x47, 0x65, 0x6d, + 0x32, 0x4f, 0x5a, 0x4b, 0x6a, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, + 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x7a, 0x43, 0x42, 0x68, + 0x54, 0x45, 0x4c, 0x0a, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x42, 0x68, 0x4d, 0x43, 0x52, 0x30, 0x49, 0x78, 0x47, 0x7a, 0x41, 0x5a, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x54, 0x45, 0x6b, 0x64, 0x79, + 0x5a, 0x57, 0x46, 0x30, 0x5a, 0x58, 0x49, 0x67, 0x54, 0x57, 0x46, 0x75, + 0x59, 0x32, 0x68, 0x6c, 0x63, 0x33, 0x52, 0x6c, 0x63, 0x6a, 0x45, 0x51, + 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x42, 0x78, 0x4d, + 0x48, 0x55, 0x32, 0x46, 0x73, 0x5a, 0x6d, 0x39, 0x79, 0x5a, 0x44, 0x45, + 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, + 0x52, 0x51, 0x30, 0x39, 0x4e, 0x54, 0x30, 0x52, 0x50, 0x49, 0x45, 0x4e, + 0x42, 0x49, 0x45, 0x78, 0x70, 0x62, 0x57, 0x6c, 0x30, 0x5a, 0x57, 0x51, + 0x78, 0x4b, 0x7a, 0x41, 0x70, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, + 0x54, 0x0a, 0x49, 0x6b, 0x4e, 0x50, 0x54, 0x55, 0x39, 0x45, 0x54, 0x79, + 0x42, 0x46, 0x51, 0x30, 0x4d, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, + 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, + 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, + 0x6b, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x67, 0x77, 0x4d, 0x7a, + 0x41, 0x32, 0x4d, 0x44, 0x41, 0x77, 0x0a, 0x4d, 0x44, 0x41, 0x77, 0x57, + 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x67, 0x77, 0x4d, 0x54, 0x45, 0x34, 0x4d, + 0x6a, 0x4d, 0x31, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, 0x43, 0x42, 0x68, + 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x68, 0x4d, 0x43, 0x52, 0x30, 0x49, 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x54, 0x45, 0x6b, 0x64, 0x79, 0x0a, + 0x5a, 0x57, 0x46, 0x30, 0x5a, 0x58, 0x49, 0x67, 0x54, 0x57, 0x46, 0x75, + 0x59, 0x32, 0x68, 0x6c, 0x63, 0x33, 0x52, 0x6c, 0x63, 0x6a, 0x45, 0x51, + 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x78, 0x4d, 0x48, + 0x55, 0x32, 0x46, 0x73, 0x5a, 0x6d, 0x39, 0x79, 0x5a, 0x44, 0x45, 0x61, + 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x52, + 0x51, 0x30, 0x39, 0x4e, 0x0a, 0x54, 0x30, 0x52, 0x50, 0x49, 0x45, 0x4e, + 0x42, 0x49, 0x45, 0x78, 0x70, 0x62, 0x57, 0x6c, 0x30, 0x5a, 0x57, 0x51, + 0x78, 0x4b, 0x7a, 0x41, 0x70, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, + 0x54, 0x49, 0x6b, 0x4e, 0x50, 0x54, 0x55, 0x39, 0x45, 0x54, 0x79, 0x42, + 0x46, 0x51, 0x30, 0x4d, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, + 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x0a, 0x62, 0x69, + 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, + 0x6b, 0x77, 0x64, 0x6a, 0x41, 0x51, 0x42, 0x67, 0x63, 0x71, 0x68, 0x6b, + 0x6a, 0x4f, 0x50, 0x51, 0x49, 0x42, 0x42, 0x67, 0x55, 0x72, 0x67, 0x51, + 0x51, 0x41, 0x49, 0x67, 0x4e, 0x69, 0x41, 0x41, 0x51, 0x44, 0x52, 0x33, + 0x73, 0x76, 0x64, 0x63, 0x6d, 0x43, 0x46, 0x59, 0x58, 0x37, 0x64, 0x65, + 0x53, 0x52, 0x0a, 0x46, 0x74, 0x53, 0x72, 0x59, 0x70, 0x6e, 0x31, 0x50, + 0x6c, 0x49, 0x4c, 0x42, 0x73, 0x35, 0x42, 0x41, 0x48, 0x2b, 0x58, 0x34, + 0x51, 0x6f, 0x6b, 0x50, 0x42, 0x30, 0x42, 0x42, 0x4f, 0x34, 0x39, 0x30, + 0x6f, 0x30, 0x4a, 0x6c, 0x77, 0x7a, 0x67, 0x64, 0x65, 0x54, 0x36, 0x2b, + 0x33, 0x65, 0x4b, 0x4b, 0x76, 0x55, 0x44, 0x59, 0x45, 0x73, 0x32, 0x69, + 0x78, 0x59, 0x6a, 0x46, 0x71, 0x30, 0x4a, 0x0a, 0x63, 0x66, 0x52, 0x4b, + 0x39, 0x43, 0x68, 0x51, 0x74, 0x50, 0x36, 0x49, 0x48, 0x47, 0x34, 0x2f, + 0x62, 0x43, 0x38, 0x76, 0x43, 0x56, 0x6c, 0x62, 0x70, 0x56, 0x73, 0x4c, + 0x4d, 0x35, 0x6e, 0x69, 0x77, 0x7a, 0x32, 0x4a, 0x2b, 0x57, 0x6f, 0x73, + 0x37, 0x37, 0x4c, 0x54, 0x42, 0x75, 0x6d, 0x6a, 0x51, 0x6a, 0x42, 0x41, + 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, + 0x0a, 0x42, 0x42, 0x52, 0x31, 0x63, 0x61, 0x63, 0x5a, 0x53, 0x42, 0x6d, + 0x38, 0x6e, 0x5a, 0x33, 0x71, 0x51, 0x55, 0x66, 0x66, 0x6c, 0x4d, 0x52, + 0x49, 0x64, 0x35, 0x6e, 0x54, 0x65, 0x54, 0x41, 0x4f, 0x42, 0x67, 0x4e, + 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, + 0x43, 0x41, 0x51, 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, + 0x54, 0x41, 0x51, 0x48, 0x2f, 0x0a, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, + 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, + 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x77, 0x4e, 0x6f, 0x41, 0x44, + 0x42, 0x6c, 0x41, 0x6a, 0x45, 0x41, 0x37, 0x77, 0x4e, 0x62, 0x65, 0x71, + 0x79, 0x33, 0x65, 0x41, 0x70, 0x79, 0x74, 0x34, 0x6a, 0x66, 0x2f, 0x37, + 0x56, 0x47, 0x46, 0x41, 0x6b, 0x4b, 0x2b, 0x71, 0x44, 0x6d, 0x0a, 0x66, + 0x51, 0x6a, 0x47, 0x47, 0x6f, 0x65, 0x39, 0x47, 0x4b, 0x68, 0x7a, 0x76, + 0x53, 0x62, 0x4b, 0x59, 0x41, 0x79, 0x64, 0x7a, 0x70, 0x6d, 0x66, 0x7a, + 0x31, 0x77, 0x50, 0x4d, 0x4f, 0x47, 0x2b, 0x46, 0x44, 0x48, 0x71, 0x41, + 0x6a, 0x41, 0x55, 0x39, 0x4a, 0x4d, 0x38, 0x53, 0x61, 0x63, 0x7a, 0x65, + 0x70, 0x42, 0x47, 0x52, 0x37, 0x4e, 0x6a, 0x66, 0x52, 0x4f, 0x62, 0x54, + 0x72, 0x64, 0x76, 0x0a, 0x47, 0x44, 0x65, 0x41, 0x55, 0x2f, 0x37, 0x64, + 0x49, 0x4f, 0x41, 0x31, 0x6d, 0x6a, 0x62, 0x52, 0x78, 0x77, 0x47, 0x35, + 0x35, 0x74, 0x7a, 0x64, 0x38, 0x2f, 0x38, 0x64, 0x4c, 0x44, 0x6f, 0x57, + 0x56, 0x39, 0x6d, 0x53, 0x4f, 0x64, 0x59, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, + 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x4f, 0x49, 0x53, 0x54, 0x45, 0x20, 0x57, 0x49, 0x53, 0x65, 0x4b, + 0x65, 0x79, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x47, 0x41, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x57, + 0x49, 0x53, 0x65, 0x4b, 0x65, 0x79, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x6f, + 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, + 0x32, 0x30, 0x30, 0x35, 0x2f, 0x4f, 0x49, 0x53, 0x54, 0x45, 0x20, 0x46, + 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x45, 0x6e, + 0x64, 0x6f, 0x72, 0x73, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x4f, 0x49, 0x53, + 0x54, 0x45, 0x20, 0x57, 0x49, 0x53, 0x65, 0x4b, 0x65, 0x79, 0x20, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, + 0x41, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x57, 0x49, 0x53, 0x65, 0x4b, + 0x65, 0x79, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x35, + 0x2f, 0x4f, 0x49, 0x53, 0x54, 0x45, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x73, + 0x65, 0x64, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x4f, 0x49, 0x53, 0x54, 0x45, 0x20, 0x57, 0x49, 0x53, 0x65, 0x4b, + 0x65, 0x79, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x47, 0x41, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, + 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x38, 0x36, 0x37, 0x31, + 0x38, 0x38, 0x37, 0x37, 0x38, 0x37, 0x31, 0x31, 0x33, 0x33, 0x31, 0x35, + 0x39, 0x30, 0x39, 0x30, 0x30, 0x38, 0x30, 0x35, 0x35, 0x35, 0x39, 0x31, + 0x31, 0x38, 0x32, 0x33, 0x35, 0x34, 0x38, 0x33, 0x31, 0x34, 0x0a, 0x23, + 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x63, 0x3a, 0x36, 0x63, 0x3a, + 0x35, 0x31, 0x3a, 0x33, 0x33, 0x3a, 0x61, 0x37, 0x3a, 0x65, 0x39, 0x3a, + 0x64, 0x33, 0x3a, 0x36, 0x36, 0x3a, 0x36, 0x33, 0x3a, 0x35, 0x34, 0x3a, + 0x31, 0x35, 0x3a, 0x37, 0x32, 0x3a, 0x31, 0x62, 0x3a, 0x32, 0x31, 0x3a, + 0x39, 0x32, 0x3a, 0x39, 0x33, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x35, 0x39, 0x3a, 0x32, 0x32, 0x3a, 0x61, 0x31, 0x3a, 0x65, + 0x31, 0x3a, 0x35, 0x61, 0x3a, 0x65, 0x61, 0x3a, 0x31, 0x36, 0x3a, 0x33, + 0x35, 0x3a, 0x32, 0x31, 0x3a, 0x66, 0x38, 0x3a, 0x39, 0x38, 0x3a, 0x33, + 0x39, 0x3a, 0x36, 0x61, 0x3a, 0x34, 0x36, 0x3a, 0x34, 0x36, 0x3a, 0x62, + 0x30, 0x3a, 0x34, 0x34, 0x3a, 0x31, 0x62, 0x3a, 0x30, 0x66, 0x3a, 0x61, + 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x34, 0x31, 0x3a, 0x63, 0x39, 0x3a, 0x32, 0x33, 0x3a, 0x38, 0x36, 0x3a, + 0x36, 0x61, 0x3a, 0x62, 0x34, 0x3a, 0x63, 0x61, 0x3a, 0x64, 0x36, 0x3a, + 0x62, 0x37, 0x3a, 0x61, 0x64, 0x3a, 0x35, 0x37, 0x3a, 0x38, 0x30, 0x3a, + 0x38, 0x31, 0x3a, 0x35, 0x38, 0x3a, 0x32, 0x65, 0x3a, 0x30, 0x32, 0x3a, + 0x30, 0x37, 0x3a, 0x39, 0x37, 0x3a, 0x61, 0x36, 0x3a, 0x63, 0x62, 0x3a, + 0x64, 0x66, 0x3a, 0x34, 0x66, 0x3a, 0x66, 0x66, 0x3a, 0x37, 0x38, 0x3a, + 0x63, 0x65, 0x3a, 0x38, 0x33, 0x3a, 0x39, 0x36, 0x3a, 0x62, 0x33, 0x3a, + 0x38, 0x39, 0x3a, 0x33, 0x37, 0x3a, 0x64, 0x37, 0x3a, 0x66, 0x35, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x38, 0x54, 0x43, 0x43, + 0x41, 0x74, 0x6d, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, + 0x51, 0x54, 0x31, 0x79, 0x78, 0x2f, 0x52, 0x72, 0x48, 0x34, 0x46, 0x44, + 0x66, 0x66, 0x48, 0x53, 0x4b, 0x46, 0x54, 0x66, 0x6d, 0x6a, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x69, 0x6a, 0x45, + 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x51, 0x30, 0x67, 0x78, 0x45, 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x54, 0x42, 0x31, 0x64, 0x4a, 0x55, 0x32, 0x56, + 0x4c, 0x5a, 0x58, 0x6b, 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x73, 0x54, 0x45, 0x6b, 0x4e, 0x76, 0x63, 0x48, 0x6c, + 0x79, 0x0a, 0x61, 0x57, 0x64, 0x6f, 0x64, 0x43, 0x41, 0x6f, 0x59, 0x79, + 0x6b, 0x67, 0x4d, 0x6a, 0x41, 0x77, 0x4e, 0x54, 0x45, 0x69, 0x4d, 0x43, + 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x5a, 0x54, 0x30, + 0x6c, 0x54, 0x56, 0x45, 0x55, 0x67, 0x52, 0x6d, 0x39, 0x31, 0x62, 0x6d, + 0x52, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x46, 0x62, 0x6d, + 0x52, 0x76, 0x63, 0x6e, 0x4e, 0x6c, 0x0a, 0x5a, 0x44, 0x45, 0x6f, 0x4d, + 0x43, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x66, 0x54, + 0x30, 0x6c, 0x54, 0x56, 0x45, 0x55, 0x67, 0x56, 0x30, 0x6c, 0x54, 0x5a, + 0x55, 0x74, 0x6c, 0x65, 0x53, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, + 0x57, 0x77, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x48, 0x51, + 0x53, 0x42, 0x44, 0x51, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, 0x77, 0x0a, + 0x4e, 0x54, 0x45, 0x79, 0x4d, 0x54, 0x45, 0x78, 0x4e, 0x6a, 0x41, 0x7a, + 0x4e, 0x44, 0x52, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4e, 0x7a, 0x45, 0x79, + 0x4d, 0x54, 0x45, 0x78, 0x4e, 0x6a, 0x41, 0x35, 0x4e, 0x54, 0x46, 0x61, + 0x4d, 0x49, 0x47, 0x4b, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x44, 0x53, 0x44, 0x45, 0x51, + 0x4d, 0x41, 0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, + 0x48, 0x56, 0x30, 0x6c, 0x54, 0x5a, 0x55, 0x74, 0x6c, 0x65, 0x54, 0x45, + 0x62, 0x4d, 0x42, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, + 0x53, 0x51, 0x32, 0x39, 0x77, 0x65, 0x58, 0x4a, 0x70, 0x5a, 0x32, 0x68, + 0x30, 0x49, 0x43, 0x68, 0x6a, 0x4b, 0x53, 0x41, 0x79, 0x4d, 0x44, 0x41, + 0x31, 0x4d, 0x53, 0x49, 0x77, 0x49, 0x41, 0x59, 0x44, 0x0a, 0x56, 0x51, + 0x51, 0x4c, 0x45, 0x78, 0x6c, 0x50, 0x53, 0x56, 0x4e, 0x55, 0x52, 0x53, + 0x42, 0x47, 0x62, 0x33, 0x56, 0x75, 0x5a, 0x47, 0x46, 0x30, 0x61, 0x57, + 0x39, 0x75, 0x49, 0x45, 0x56, 0x75, 0x5a, 0x47, 0x39, 0x79, 0x63, 0x32, + 0x56, 0x6b, 0x4d, 0x53, 0x67, 0x77, 0x4a, 0x67, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x44, 0x45, 0x78, 0x39, 0x50, 0x53, 0x56, 0x4e, 0x55, 0x52, 0x53, + 0x42, 0x58, 0x0a, 0x53, 0x56, 0x4e, 0x6c, 0x53, 0x32, 0x56, 0x35, 0x49, + 0x45, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62, 0x43, 0x42, 0x53, 0x62, + 0x32, 0x39, 0x30, 0x49, 0x45, 0x64, 0x42, 0x49, 0x45, 0x4e, 0x42, 0x4d, + 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, + 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x0a, 0x4d, 0x49, 0x49, 0x42, + 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x79, 0x30, 0x2b, 0x7a, + 0x41, 0x4a, 0x73, 0x39, 0x4e, 0x74, 0x33, 0x35, 0x30, 0x55, 0x6c, 0x71, + 0x61, 0x78, 0x42, 0x4a, 0x48, 0x2b, 0x7a, 0x59, 0x4b, 0x37, 0x4c, 0x47, + 0x2b, 0x44, 0x4b, 0x42, 0x4b, 0x55, 0x4f, 0x56, 0x54, 0x4a, 0x6f, 0x5a, + 0x49, 0x79, 0x45, 0x56, 0x52, 0x64, 0x37, 0x6a, 0x79, 0x42, 0x78, 0x52, + 0x0a, 0x56, 0x56, 0x75, 0x75, 0x6b, 0x2b, 0x67, 0x33, 0x2f, 0x79, 0x74, + 0x72, 0x36, 0x64, 0x54, 0x71, 0x76, 0x69, 0x72, 0x64, 0x71, 0x46, 0x45, + 0x72, 0x31, 0x32, 0x62, 0x44, 0x59, 0x56, 0x78, 0x67, 0x41, 0x73, 0x6a, + 0x31, 0x7a, 0x6e, 0x4a, 0x37, 0x4f, 0x37, 0x6a, 0x79, 0x54, 0x6d, 0x55, + 0x49, 0x6d, 0x73, 0x32, 0x6b, 0x61, 0x68, 0x6e, 0x42, 0x41, 0x62, 0x74, + 0x7a, 0x70, 0x74, 0x66, 0x32, 0x0a, 0x77, 0x39, 0x33, 0x4e, 0x76, 0x4b, + 0x53, 0x4c, 0x74, 0x5a, 0x6c, 0x68, 0x75, 0x41, 0x47, 0x69, 0x6f, 0x39, + 0x52, 0x4e, 0x31, 0x41, 0x55, 0x39, 0x6b, 0x61, 0x33, 0x34, 0x74, 0x41, + 0x68, 0x78, 0x5a, 0x4b, 0x39, 0x77, 0x38, 0x52, 0x78, 0x72, 0x66, 0x76, + 0x62, 0x44, 0x64, 0x35, 0x30, 0x6b, 0x63, 0x33, 0x76, 0x6b, 0x44, 0x49, + 0x7a, 0x68, 0x32, 0x54, 0x62, 0x68, 0x6d, 0x59, 0x73, 0x46, 0x0a, 0x6d, + 0x51, 0x76, 0x74, 0x52, 0x54, 0x45, 0x4a, 0x79, 0x73, 0x49, 0x41, 0x32, + 0x2f, 0x64, 0x79, 0x6f, 0x4a, 0x61, 0x71, 0x6c, 0x59, 0x66, 0x51, 0x6a, + 0x73, 0x65, 0x32, 0x59, 0x58, 0x4d, 0x4e, 0x64, 0x6d, 0x61, 0x4d, 0x33, + 0x42, 0x75, 0x30, 0x59, 0x36, 0x4b, 0x66, 0x66, 0x35, 0x4d, 0x54, 0x4d, + 0x50, 0x47, 0x68, 0x4a, 0x39, 0x76, 0x5a, 0x2f, 0x79, 0x78, 0x56, 0x69, + 0x4a, 0x47, 0x67, 0x0a, 0x34, 0x45, 0x38, 0x48, 0x73, 0x43, 0x68, 0x57, + 0x6a, 0x42, 0x67, 0x62, 0x6c, 0x30, 0x53, 0x4f, 0x69, 0x64, 0x33, 0x67, + 0x46, 0x32, 0x37, 0x6e, 0x4b, 0x75, 0x2b, 0x50, 0x4f, 0x51, 0x6f, 0x78, + 0x68, 0x49, 0x4c, 0x59, 0x51, 0x42, 0x52, 0x4a, 0x4c, 0x6e, 0x70, 0x42, + 0x35, 0x4b, 0x66, 0x2b, 0x34, 0x32, 0x54, 0x4d, 0x77, 0x56, 0x6c, 0x78, + 0x53, 0x79, 0x77, 0x68, 0x70, 0x31, 0x74, 0x39, 0x0a, 0x34, 0x42, 0x33, + 0x52, 0x4c, 0x6f, 0x47, 0x62, 0x77, 0x39, 0x68, 0x6f, 0x39, 0x37, 0x32, + 0x57, 0x47, 0x36, 0x78, 0x77, 0x73, 0x52, 0x59, 0x55, 0x43, 0x39, 0x74, + 0x67, 0x75, 0x53, 0x59, 0x42, 0x42, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, + 0x42, 0x6f, 0x31, 0x45, 0x77, 0x54, 0x7a, 0x41, 0x4c, 0x42, 0x67, 0x4e, + 0x56, 0x48, 0x51, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x59, 0x59, + 0x77, 0x0a, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, + 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, + 0x51, 0x55, 0x73, 0x77, 0x4e, 0x2b, 0x72, 0x6a, 0x61, 0x38, 0x73, 0x48, + 0x6e, 0x52, 0x33, 0x4a, 0x51, 0x6d, 0x74, 0x68, 0x47, 0x2b, 0x49, 0x62, + 0x4a, 0x70, 0x68, 0x70, 0x51, 0x77, 0x0a, 0x45, 0x41, 0x59, 0x4a, 0x4b, + 0x77, 0x59, 0x42, 0x42, 0x41, 0x47, 0x43, 0x4e, 0x78, 0x55, 0x42, 0x42, + 0x41, 0x4d, 0x43, 0x41, 0x51, 0x41, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, + 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x45, 0x75, 0x68, 0x2f, + 0x77, 0x75, 0x48, 0x62, 0x72, 0x50, 0x35, 0x77, 0x55, 0x4f, 0x78, 0x0a, + 0x53, 0x50, 0x4d, 0x6f, 0x77, 0x42, 0x30, 0x75, 0x79, 0x51, 0x6c, 0x42, + 0x2b, 0x70, 0x51, 0x41, 0x48, 0x4b, 0x53, 0x6b, 0x71, 0x30, 0x6c, 0x50, + 0x6a, 0x7a, 0x30, 0x65, 0x37, 0x30, 0x31, 0x76, 0x76, 0x62, 0x79, 0x6b, + 0x39, 0x76, 0x49, 0x6d, 0x4d, 0x4d, 0x6b, 0x51, 0x79, 0x68, 0x32, 0x49, + 0x2b, 0x33, 0x51, 0x5a, 0x48, 0x34, 0x56, 0x46, 0x76, 0x62, 0x42, 0x73, + 0x55, 0x66, 0x6b, 0x32, 0x0a, 0x66, 0x74, 0x76, 0x31, 0x54, 0x44, 0x49, + 0x36, 0x51, 0x55, 0x39, 0x62, 0x52, 0x38, 0x2f, 0x6f, 0x43, 0x79, 0x32, + 0x32, 0x78, 0x42, 0x6d, 0x64, 0x64, 0x4d, 0x56, 0x48, 0x78, 0x6a, 0x74, + 0x71, 0x44, 0x36, 0x77, 0x55, 0x32, 0x7a, 0x7a, 0x30, 0x63, 0x35, 0x79, + 0x70, 0x42, 0x64, 0x38, 0x41, 0x33, 0x48, 0x52, 0x34, 0x2b, 0x76, 0x67, + 0x31, 0x59, 0x46, 0x6b, 0x43, 0x45, 0x78, 0x68, 0x38, 0x0a, 0x76, 0x50, + 0x74, 0x4e, 0x73, 0x43, 0x42, 0x74, 0x51, 0x37, 0x74, 0x67, 0x4d, 0x48, + 0x70, 0x6e, 0x4d, 0x31, 0x7a, 0x46, 0x6d, 0x64, 0x48, 0x34, 0x4c, 0x54, + 0x6c, 0x53, 0x63, 0x2f, 0x75, 0x4d, 0x71, 0x70, 0x63, 0x6c, 0x58, 0x48, + 0x4c, 0x5a, 0x43, 0x42, 0x36, 0x72, 0x54, 0x6a, 0x7a, 0x6a, 0x67, 0x54, + 0x47, 0x66, 0x41, 0x36, 0x62, 0x37, 0x77, 0x50, 0x34, 0x70, 0x69, 0x46, + 0x58, 0x61, 0x0a, 0x68, 0x4e, 0x56, 0x51, 0x41, 0x37, 0x62, 0x69, 0x68, + 0x4b, 0x4f, 0x6d, 0x4e, 0x71, 0x6f, 0x52, 0x4f, 0x67, 0x48, 0x68, 0x47, + 0x45, 0x76, 0x57, 0x52, 0x47, 0x69, 0x7a, 0x50, 0x66, 0x6c, 0x54, 0x64, + 0x49, 0x53, 0x7a, 0x52, 0x70, 0x46, 0x47, 0x6c, 0x67, 0x43, 0x33, 0x67, + 0x43, 0x79, 0x32, 0x34, 0x65, 0x4d, 0x51, 0x34, 0x74, 0x75, 0x69, 0x35, + 0x79, 0x69, 0x50, 0x41, 0x5a, 0x5a, 0x69, 0x0a, 0x46, 0x6a, 0x34, 0x41, + 0x34, 0x78, 0x79, 0x6c, 0x4e, 0x6f, 0x45, 0x59, 0x6f, 0x6b, 0x78, 0x53, + 0x64, 0x73, 0x41, 0x52, 0x6f, 0x32, 0x37, 0x6d, 0x48, 0x62, 0x72, 0x6a, + 0x57, 0x72, 0x34, 0x32, 0x55, 0x38, 0x55, 0x2b, 0x64, 0x59, 0x2b, 0x47, + 0x61, 0x53, 0x6c, 0x59, 0x55, 0x37, 0x57, 0x63, 0x75, 0x32, 0x2b, 0x66, + 0x58, 0x4d, 0x55, 0x59, 0x37, 0x4e, 0x30, 0x76, 0x34, 0x5a, 0x6a, 0x4a, + 0x0a, 0x2f, 0x4c, 0x37, 0x66, 0x43, 0x67, 0x30, 0x3d, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x67, 0x6e, 0x61, 0x20, 0x4f, + 0x3d, 0x44, 0x68, 0x69, 0x6d, 0x79, 0x6f, 0x74, 0x69, 0x73, 0x0a, 0x23, + 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x67, 0x6e, 0x61, 0x20, 0x4f, 0x3d, + 0x44, 0x68, 0x69, 0x6d, 0x79, 0x6f, 0x74, 0x69, 0x73, 0x0a, 0x23, 0x20, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x67, 0x6e, 0x61, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x38, 0x33, 0x36, 0x34, 0x38, 0x30, 0x32, + 0x39, 0x37, 0x34, 0x32, 0x30, 0x39, 0x33, 0x36, 0x32, 0x31, 0x37, 0x35, + 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x62, 0x3a, 0x35, + 0x37, 0x3a, 0x61, 0x36, 0x3a, 0x35, 0x62, 0x3a, 0x37, 0x64, 0x3a, 0x34, + 0x32, 0x3a, 0x38, 0x32, 0x3a, 0x31, 0x39, 0x3a, 0x62, 0x35, 0x3a, 0x64, + 0x38, 0x3a, 0x35, 0x38, 0x3a, 0x32, 0x36, 0x3a, 0x32, 0x38, 0x3a, 0x35, + 0x65, 0x3a, 0x66, 0x64, 0x3a, 0x66, 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x31, 0x3a, 0x32, 0x65, 0x3a, 0x31, 0x33, + 0x3a, 0x36, 0x33, 0x3a, 0x34, 0x35, 0x3a, 0x38, 0x36, 0x3a, 0x61, 0x34, + 0x3a, 0x36, 0x66, 0x3a, 0x31, 0x61, 0x3a, 0x62, 0x32, 0x3a, 0x36, 0x30, + 0x3a, 0x36, 0x38, 0x3a, 0x33, 0x37, 0x3a, 0x35, 0x38, 0x3a, 0x32, 0x64, + 0x3a, 0x63, 0x34, 0x3a, 0x61, 0x63, 0x3a, 0x66, 0x64, 0x3a, 0x39, 0x34, + 0x3a, 0x39, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x65, 0x33, 0x3a, 0x62, 0x36, 0x3a, 0x61, 0x32, 0x3a, 0x64, + 0x62, 0x3a, 0x32, 0x65, 0x3a, 0x64, 0x37, 0x3a, 0x63, 0x65, 0x3a, 0x34, + 0x38, 0x3a, 0x38, 0x34, 0x3a, 0x32, 0x66, 0x3a, 0x37, 0x61, 0x3a, 0x63, + 0x35, 0x3a, 0x33, 0x32, 0x3a, 0x34, 0x31, 0x3a, 0x63, 0x37, 0x3a, 0x62, + 0x37, 0x3a, 0x31, 0x64, 0x3a, 0x35, 0x34, 0x3a, 0x31, 0x34, 0x3a, 0x34, + 0x62, 0x3a, 0x66, 0x62, 0x3a, 0x34, 0x30, 0x3a, 0x63, 0x31, 0x3a, 0x31, + 0x66, 0x3a, 0x33, 0x66, 0x3a, 0x31, 0x64, 0x3a, 0x30, 0x62, 0x3a, 0x34, + 0x32, 0x3a, 0x66, 0x35, 0x3a, 0x65, 0x65, 0x3a, 0x61, 0x31, 0x3a, 0x32, + 0x64, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x71, 0x44, + 0x43, 0x43, 0x41, 0x70, 0x43, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, + 0x49, 0x4a, 0x41, 0x50, 0x37, 0x63, 0x34, 0x77, 0x45, 0x50, 0x79, 0x55, + 0x6a, 0x2f, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, + 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x4d, 0x44, + 0x51, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, + 0x41, 0x59, 0x54, 0x41, 0x6b, 0x5a, 0x53, 0x4d, 0x52, 0x49, 0x77, 0x45, + 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, 0x6c, 0x45, 0x61, + 0x47, 0x6c, 0x74, 0x65, 0x57, 0x39, 0x30, 0x61, 0x58, 0x4d, 0x78, 0x45, + 0x54, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x43, + 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x32, 0x35, 0x68, 0x4d, + 0x42, 0x34, 0x58, 0x0a, 0x44, 0x54, 0x41, 0x33, 0x4d, 0x44, 0x59, 0x79, + 0x4f, 0x54, 0x45, 0x31, 0x4d, 0x54, 0x4d, 0x77, 0x4e, 0x56, 0x6f, 0x58, + 0x44, 0x54, 0x49, 0x33, 0x4d, 0x44, 0x59, 0x79, 0x4f, 0x54, 0x45, 0x31, + 0x4d, 0x54, 0x4d, 0x77, 0x4e, 0x56, 0x6f, 0x77, 0x4e, 0x44, 0x45, 0x4c, + 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, + 0x52, 0x6c, 0x49, 0x78, 0x45, 0x6a, 0x41, 0x51, 0x0a, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x43, 0x55, 0x52, 0x6f, 0x61, 0x57, 0x31, + 0x35, 0x62, 0x33, 0x52, 0x70, 0x63, 0x7a, 0x45, 0x52, 0x4d, 0x41, 0x38, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x49, 0x51, 0x32, 0x56, + 0x79, 0x64, 0x47, 0x6c, 0x6e, 0x62, 0x6d, 0x45, 0x77, 0x67, 0x67, 0x45, + 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x33, 0x0a, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, + 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, + 0x49, 0x42, 0x41, 0x51, 0x44, 0x49, 0x61, 0x50, 0x48, 0x4a, 0x31, 0x74, + 0x61, 0x7a, 0x4e, 0x48, 0x55, 0x6d, 0x67, 0x68, 0x37, 0x73, 0x74, 0x4c, + 0x37, 0x71, 0x58, 0x4f, 0x45, 0x6d, 0x37, 0x52, 0x46, 0x48, 0x59, 0x65, + 0x47, 0x69, 0x66, 0x42, 0x5a, 0x34, 0x0a, 0x51, 0x43, 0x48, 0x6b, 0x59, + 0x4a, 0x35, 0x61, 0x79, 0x47, 0x50, 0x68, 0x78, 0x4c, 0x47, 0x57, 0x6b, + 0x76, 0x38, 0x59, 0x62, 0x57, 0x6b, 0x6a, 0x34, 0x53, 0x74, 0x69, 0x39, + 0x39, 0x33, 0x69, 0x4e, 0x69, 0x2b, 0x52, 0x42, 0x37, 0x6c, 0x49, 0x7a, + 0x77, 0x37, 0x73, 0x65, 0x62, 0x59, 0x73, 0x35, 0x7a, 0x52, 0x4c, 0x63, + 0x41, 0x67, 0x6c, 0x6f, 0x7a, 0x79, 0x48, 0x47, 0x78, 0x6e, 0x79, 0x0a, + 0x67, 0x51, 0x63, 0x50, 0x4f, 0x4a, 0x41, 0x5a, 0x30, 0x78, 0x48, 0x2b, + 0x68, 0x72, 0x54, 0x79, 0x30, 0x56, 0x34, 0x65, 0x48, 0x70, 0x62, 0x4e, + 0x67, 0x47, 0x7a, 0x4f, 0x4f, 0x7a, 0x47, 0x54, 0x74, 0x76, 0x4b, 0x67, + 0x30, 0x4b, 0x6d, 0x56, 0x45, 0x6e, 0x32, 0x6c, 0x6d, 0x73, 0x78, 0x72, + 0x79, 0x49, 0x52, 0x57, 0x69, 0x6a, 0x4f, 0x70, 0x35, 0x79, 0x49, 0x56, + 0x55, 0x78, 0x62, 0x77, 0x0a, 0x7a, 0x42, 0x66, 0x73, 0x56, 0x31, 0x2f, + 0x70, 0x6f, 0x67, 0x71, 0x59, 0x43, 0x64, 0x37, 0x6a, 0x58, 0x35, 0x78, + 0x76, 0x33, 0x45, 0x6a, 0x6a, 0x68, 0x51, 0x73, 0x56, 0x57, 0x71, 0x61, + 0x36, 0x6e, 0x36, 0x78, 0x49, 0x34, 0x77, 0x6d, 0x79, 0x39, 0x2f, 0x51, + 0x79, 0x33, 0x6c, 0x34, 0x30, 0x76, 0x68, 0x78, 0x34, 0x58, 0x55, 0x4a, + 0x62, 0x7a, 0x67, 0x34, 0x69, 0x6a, 0x30, 0x32, 0x51, 0x0a, 0x31, 0x33, + 0x30, 0x79, 0x47, 0x4c, 0x4d, 0x4c, 0x4c, 0x47, 0x71, 0x2f, 0x6a, 0x6a, + 0x38, 0x55, 0x45, 0x59, 0x6b, 0x67, 0x44, 0x6e, 0x63, 0x55, 0x74, 0x54, + 0x32, 0x55, 0x43, 0x49, 0x66, 0x33, 0x4a, 0x52, 0x37, 0x56, 0x73, 0x6d, + 0x41, 0x41, 0x37, 0x47, 0x38, 0x71, 0x4b, 0x43, 0x56, 0x75, 0x4b, 0x6a, + 0x34, 0x59, 0x59, 0x78, 0x63, 0x6c, 0x50, 0x7a, 0x35, 0x45, 0x49, 0x42, + 0x62, 0x32, 0x0a, 0x4a, 0x73, 0x67, 0x6c, 0x72, 0x67, 0x56, 0x4b, 0x74, + 0x4f, 0x64, 0x6a, 0x4c, 0x50, 0x4f, 0x4d, 0x46, 0x6c, 0x4e, 0x2b, 0x58, + 0x50, 0x73, 0x52, 0x47, 0x67, 0x6a, 0x42, 0x52, 0x6d, 0x4b, 0x66, 0x49, + 0x72, 0x6a, 0x78, 0x77, 0x6f, 0x31, 0x70, 0x33, 0x50, 0x6f, 0x36, 0x57, + 0x41, 0x62, 0x66, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x67, + 0x62, 0x77, 0x77, 0x67, 0x62, 0x6b, 0x77, 0x0a, 0x44, 0x77, 0x59, 0x44, + 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, + 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x47, 0x75, 0x33, 0x2b, + 0x51, 0x54, 0x6d, 0x51, 0x74, 0x43, 0x52, 0x5a, 0x76, 0x67, 0x48, 0x79, + 0x55, 0x74, 0x56, 0x46, 0x39, 0x6c, 0x6f, 0x35, 0x33, 0x42, 0x45, 0x77, + 0x0a, 0x5a, 0x41, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6a, 0x42, 0x46, 0x30, + 0x77, 0x57, 0x34, 0x41, 0x55, 0x47, 0x75, 0x33, 0x2b, 0x51, 0x54, 0x6d, + 0x51, 0x74, 0x43, 0x52, 0x5a, 0x76, 0x67, 0x48, 0x79, 0x55, 0x74, 0x56, + 0x46, 0x39, 0x6c, 0x6f, 0x35, 0x33, 0x42, 0x47, 0x68, 0x4f, 0x4b, 0x51, + 0x32, 0x4d, 0x44, 0x51, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x59, 0x54, 0x0a, 0x41, 0x6b, 0x5a, 0x53, 0x4d, 0x52, + 0x49, 0x77, 0x45, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, + 0x6c, 0x45, 0x61, 0x47, 0x6c, 0x74, 0x65, 0x57, 0x39, 0x30, 0x61, 0x58, + 0x4d, 0x78, 0x45, 0x54, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x4d, 0x4d, 0x43, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x32, + 0x35, 0x68, 0x67, 0x67, 0x6b, 0x41, 0x2f, 0x74, 0x7a, 0x6a, 0x0a, 0x41, + 0x51, 0x2f, 0x4a, 0x53, 0x50, 0x38, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, + 0x67, 0x45, 0x47, 0x4d, 0x42, 0x45, 0x47, 0x43, 0x57, 0x43, 0x47, 0x53, + 0x41, 0x47, 0x47, 0x2b, 0x45, 0x49, 0x42, 0x41, 0x51, 0x51, 0x45, 0x41, + 0x77, 0x49, 0x41, 0x42, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x0a, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, + 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x68, 0x51, 0x4d, 0x65, + 0x6b, 0x6e, 0x48, 0x32, 0x51, 0x71, 0x2f, 0x68, 0x6f, 0x32, 0x47, 0x65, + 0x36, 0x2f, 0x50, 0x41, 0x44, 0x2f, 0x4b, 0x6c, 0x31, 0x4e, 0x71, 0x56, + 0x35, 0x74, 0x61, 0x2b, 0x61, 0x44, 0x59, 0x39, 0x66, 0x6d, 0x34, 0x66, + 0x54, 0x49, 0x72, 0x76, 0x30, 0x51, 0x38, 0x68, 0x0a, 0x62, 0x56, 0x36, + 0x6c, 0x55, 0x6d, 0x50, 0x4f, 0x45, 0x76, 0x6a, 0x76, 0x4b, 0x74, 0x70, + 0x76, 0x36, 0x7a, 0x66, 0x2b, 0x45, 0x77, 0x4c, 0x48, 0x79, 0x7a, 0x73, + 0x2b, 0x49, 0x6d, 0x76, 0x61, 0x59, 0x53, 0x35, 0x2f, 0x31, 0x48, 0x49, + 0x39, 0x33, 0x54, 0x44, 0x68, 0x48, 0x6b, 0x78, 0x41, 0x47, 0x59, 0x77, + 0x50, 0x31, 0x35, 0x7a, 0x52, 0x67, 0x7a, 0x42, 0x37, 0x6d, 0x46, 0x6e, + 0x63, 0x0a, 0x66, 0x63, 0x61, 0x35, 0x44, 0x43, 0x6c, 0x4d, 0x6f, 0x54, + 0x4f, 0x69, 0x36, 0x32, 0x63, 0x36, 0x5a, 0x59, 0x54, 0x54, 0x6c, 0x75, + 0x4c, 0x74, 0x64, 0x6b, 0x56, 0x77, 0x6a, 0x37, 0x55, 0x72, 0x33, 0x76, + 0x6b, 0x6a, 0x31, 0x6b, 0x6c, 0x75, 0x50, 0x42, 0x53, 0x31, 0x78, 0x70, + 0x38, 0x31, 0x48, 0x6c, 0x44, 0x51, 0x77, 0x59, 0x39, 0x71, 0x63, 0x45, + 0x51, 0x43, 0x59, 0x73, 0x75, 0x75, 0x0a, 0x48, 0x57, 0x68, 0x42, 0x70, + 0x36, 0x70, 0x58, 0x36, 0x46, 0x4f, 0x71, 0x42, 0x39, 0x49, 0x47, 0x39, + 0x74, 0x55, 0x55, 0x42, 0x67, 0x75, 0x52, 0x41, 0x33, 0x55, 0x73, 0x62, + 0x48, 0x4b, 0x31, 0x59, 0x5a, 0x57, 0x61, 0x44, 0x59, 0x75, 0x35, 0x44, + 0x65, 0x66, 0x31, 0x33, 0x31, 0x54, 0x4e, 0x33, 0x75, 0x62, 0x59, 0x31, + 0x67, 0x6b, 0x49, 0x6c, 0x32, 0x50, 0x6c, 0x77, 0x53, 0x36, 0x77, 0x0a, + 0x74, 0x30, 0x51, 0x6d, 0x77, 0x43, 0x62, 0x41, 0x72, 0x31, 0x55, 0x77, + 0x6e, 0x6a, 0x76, 0x56, 0x4e, 0x69, 0x6f, 0x5a, 0x42, 0x50, 0x52, 0x63, + 0x48, 0x76, 0x2f, 0x50, 0x4c, 0x4c, 0x66, 0x2f, 0x30, 0x50, 0x32, 0x48, + 0x51, 0x42, 0x48, 0x56, 0x45, 0x53, 0x4f, 0x37, 0x53, 0x4d, 0x41, 0x68, + 0x71, 0x61, 0x51, 0x6f, 0x4c, 0x66, 0x30, 0x56, 0x2b, 0x4c, 0x42, 0x4f, + 0x4b, 0x2f, 0x51, 0x77, 0x0a, 0x57, 0x79, 0x48, 0x38, 0x45, 0x5a, 0x45, + 0x30, 0x76, 0x6b, 0x48, 0x76, 0x65, 0x35, 0x32, 0x58, 0x64, 0x66, 0x2b, + 0x58, 0x6c, 0x63, 0x43, 0x57, 0x57, 0x43, 0x2f, 0x71, 0x75, 0x30, 0x62, + 0x58, 0x75, 0x2b, 0x54, 0x5a, 0x4c, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x44, 0x65, 0x75, 0x74, 0x73, 0x63, 0x68, 0x65, 0x20, 0x54, + 0x65, 0x6c, 0x65, 0x6b, 0x6f, 0x6d, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x20, 0x32, 0x20, 0x4f, 0x3d, 0x44, 0x65, 0x75, 0x74, 0x73, + 0x63, 0x68, 0x65, 0x20, 0x54, 0x65, 0x6c, 0x65, 0x6b, 0x6f, 0x6d, 0x20, + 0x41, 0x47, 0x20, 0x4f, 0x55, 0x3d, 0x54, 0x2d, 0x54, 0x65, 0x6c, 0x65, + 0x53, 0x65, 0x63, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x65, 0x75, 0x74, 0x73, + 0x63, 0x68, 0x65, 0x20, 0x54, 0x65, 0x6c, 0x65, 0x6b, 0x6f, 0x6d, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, 0x20, 0x4f, 0x3d, + 0x44, 0x65, 0x75, 0x74, 0x73, 0x63, 0x68, 0x65, 0x20, 0x54, 0x65, 0x6c, + 0x65, 0x6b, 0x6f, 0x6d, 0x20, 0x41, 0x47, 0x20, 0x4f, 0x55, 0x3d, 0x54, + 0x2d, 0x54, 0x65, 0x6c, 0x65, 0x53, 0x65, 0x63, 0x20, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x0a, 0x23, 0x20, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x44, 0x65, 0x75, 0x74, + 0x73, 0x63, 0x68, 0x65, 0x20, 0x54, 0x65, 0x6c, 0x65, 0x6b, 0x6f, 0x6d, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x33, 0x38, + 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x34, 0x3a, 0x30, + 0x31, 0x3a, 0x34, 0x61, 0x3a, 0x39, 0x31, 0x3a, 0x62, 0x31, 0x3a, 0x30, + 0x38, 0x3a, 0x63, 0x34, 0x3a, 0x35, 0x38, 0x3a, 0x63, 0x65, 0x3a, 0x34, + 0x37, 0x3a, 0x63, 0x64, 0x3a, 0x66, 0x30, 0x3a, 0x64, 0x64, 0x3a, 0x31, + 0x31, 0x3a, 0x35, 0x33, 0x3a, 0x30, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x35, 0x3a, 0x61, 0x34, 0x3a, 0x30, 0x38, + 0x3a, 0x63, 0x30, 0x3a, 0x39, 0x63, 0x3a, 0x31, 0x39, 0x3a, 0x33, 0x65, + 0x3a, 0x35, 0x64, 0x3a, 0x35, 0x31, 0x3a, 0x35, 0x38, 0x3a, 0x37, 0x64, + 0x3a, 0x63, 0x64, 0x3a, 0x64, 0x36, 0x3a, 0x31, 0x33, 0x3a, 0x33, 0x30, + 0x3a, 0x66, 0x64, 0x3a, 0x38, 0x63, 0x3a, 0x64, 0x65, 0x3a, 0x33, 0x37, + 0x3a, 0x62, 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x62, 0x36, 0x3a, 0x31, 0x39, 0x3a, 0x31, 0x61, 0x3a, 0x35, + 0x30, 0x3a, 0x64, 0x30, 0x3a, 0x63, 0x33, 0x3a, 0x39, 0x37, 0x3a, 0x37, + 0x66, 0x3a, 0x37, 0x64, 0x3a, 0x61, 0x39, 0x3a, 0x39, 0x62, 0x3a, 0x63, + 0x64, 0x3a, 0x61, 0x61, 0x3a, 0x63, 0x38, 0x3a, 0x36, 0x61, 0x3a, 0x32, + 0x32, 0x3a, 0x37, 0x64, 0x3a, 0x61, 0x65, 0x3a, 0x62, 0x39, 0x3a, 0x36, + 0x37, 0x3a, 0x39, 0x65, 0x3a, 0x63, 0x37, 0x3a, 0x30, 0x62, 0x3a, 0x61, + 0x33, 0x3a, 0x62, 0x30, 0x3a, 0x63, 0x39, 0x3a, 0x64, 0x39, 0x3a, 0x32, + 0x32, 0x3a, 0x37, 0x31, 0x3a, 0x63, 0x31, 0x3a, 0x37, 0x30, 0x3a, 0x64, + 0x33, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x6e, 0x7a, + 0x43, 0x43, 0x41, 0x6f, 0x65, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, + 0x49, 0x42, 0x4a, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, + 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, + 0x42, 0x78, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x47, 0x45, 0x77, 0x4a, 0x45, 0x52, 0x54, 0x45, 0x63, 0x0a, 0x4d, + 0x42, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x54, 0x52, + 0x47, 0x56, 0x31, 0x64, 0x48, 0x4e, 0x6a, 0x61, 0x47, 0x55, 0x67, 0x56, + 0x47, 0x56, 0x73, 0x5a, 0x57, 0x74, 0x76, 0x62, 0x53, 0x42, 0x42, 0x52, + 0x7a, 0x45, 0x66, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x78, 0x4d, 0x57, 0x56, 0x43, 0x31, 0x55, 0x5a, 0x57, 0x78, 0x6c, 0x55, + 0x32, 0x56, 0x6a, 0x0a, 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, + 0x49, 0x45, 0x4e, 0x6c, 0x62, 0x6e, 0x52, 0x6c, 0x63, 0x6a, 0x45, 0x6a, + 0x4d, 0x43, 0x45, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x61, + 0x52, 0x47, 0x56, 0x31, 0x64, 0x48, 0x4e, 0x6a, 0x61, 0x47, 0x55, 0x67, + 0x56, 0x47, 0x56, 0x73, 0x5a, 0x57, 0x74, 0x76, 0x62, 0x53, 0x42, 0x53, + 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x0a, 0x49, 0x44, 0x49, + 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4f, 0x54, 0x6b, 0x77, 0x4e, 0x7a, 0x41, + 0x35, 0x4d, 0x54, 0x49, 0x78, 0x4d, 0x54, 0x41, 0x77, 0x57, 0x68, 0x63, + 0x4e, 0x4d, 0x54, 0x6b, 0x77, 0x4e, 0x7a, 0x41, 0x35, 0x4d, 0x6a, 0x4d, + 0x31, 0x4f, 0x54, 0x41, 0x77, 0x57, 0x6a, 0x42, 0x78, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, + 0x45, 0x0a, 0x52, 0x54, 0x45, 0x63, 0x4d, 0x42, 0x6f, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x68, 0x4d, 0x54, 0x52, 0x47, 0x56, 0x31, 0x64, 0x48, + 0x4e, 0x6a, 0x61, 0x47, 0x55, 0x67, 0x56, 0x47, 0x56, 0x73, 0x5a, 0x57, + 0x74, 0x76, 0x62, 0x53, 0x42, 0x42, 0x52, 0x7a, 0x45, 0x66, 0x4d, 0x42, + 0x30, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x57, 0x56, 0x43, + 0x31, 0x55, 0x5a, 0x57, 0x78, 0x6c, 0x0a, 0x55, 0x32, 0x56, 0x6a, 0x49, + 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x4e, 0x6c, 0x62, + 0x6e, 0x52, 0x6c, 0x63, 0x6a, 0x45, 0x6a, 0x4d, 0x43, 0x45, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x61, 0x52, 0x47, 0x56, 0x31, 0x64, + 0x48, 0x4e, 0x6a, 0x61, 0x47, 0x55, 0x67, 0x56, 0x47, 0x56, 0x73, 0x5a, + 0x57, 0x74, 0x76, 0x62, 0x53, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x0a, + 0x49, 0x45, 0x4e, 0x42, 0x49, 0x44, 0x49, 0x77, 0x67, 0x67, 0x45, 0x69, + 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, + 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, + 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, + 0x41, 0x51, 0x43, 0x72, 0x43, 0x36, 0x4d, 0x31, 0x34, 0x49, 0x73, 0x70, + 0x46, 0x4c, 0x45, 0x55, 0x0a, 0x68, 0x61, 0x38, 0x38, 0x45, 0x4f, 0x51, + 0x35, 0x62, 0x7a, 0x56, 0x64, 0x53, 0x71, 0x37, 0x64, 0x36, 0x6d, 0x47, + 0x4e, 0x6c, 0x55, 0x6e, 0x30, 0x62, 0x32, 0x53, 0x6a, 0x47, 0x6d, 0x42, + 0x6d, 0x70, 0x4b, 0x6c, 0x41, 0x49, 0x6f, 0x54, 0x5a, 0x31, 0x4b, 0x58, + 0x6c, 0x65, 0x4a, 0x4d, 0x4f, 0x61, 0x41, 0x47, 0x74, 0x75, 0x55, 0x31, + 0x63, 0x4f, 0x73, 0x37, 0x54, 0x75, 0x4b, 0x68, 0x43, 0x0a, 0x51, 0x4e, + 0x2f, 0x50, 0x6f, 0x37, 0x71, 0x43, 0x57, 0x57, 0x71, 0x53, 0x47, 0x36, + 0x77, 0x63, 0x6d, 0x74, 0x6f, 0x49, 0x4b, 0x79, 0x55, 0x6e, 0x2b, 0x57, + 0x6b, 0x6a, 0x52, 0x2f, 0x48, 0x67, 0x36, 0x79, 0x78, 0x36, 0x6d, 0x2f, + 0x55, 0x54, 0x41, 0x74, 0x42, 0x2b, 0x4e, 0x48, 0x7a, 0x43, 0x6e, 0x6a, + 0x77, 0x41, 0x57, 0x61, 0x76, 0x31, 0x32, 0x67, 0x7a, 0x31, 0x4d, 0x6a, + 0x77, 0x72, 0x0a, 0x72, 0x46, 0x44, 0x61, 0x31, 0x73, 0x50, 0x65, 0x67, + 0x35, 0x54, 0x4b, 0x71, 0x41, 0x79, 0x5a, 0x4d, 0x67, 0x34, 0x49, 0x53, + 0x46, 0x5a, 0x62, 0x61, 0x76, 0x76, 0x61, 0x34, 0x56, 0x68, 0x59, 0x41, + 0x55, 0x6c, 0x66, 0x63, 0x6b, 0x45, 0x38, 0x46, 0x51, 0x59, 0x42, 0x6a, + 0x6c, 0x32, 0x74, 0x71, 0x72, 0x69, 0x54, 0x74, 0x4d, 0x32, 0x65, 0x36, + 0x36, 0x66, 0x6f, 0x61, 0x69, 0x31, 0x53, 0x0a, 0x4e, 0x4e, 0x73, 0x36, + 0x37, 0x31, 0x78, 0x31, 0x55, 0x64, 0x72, 0x62, 0x38, 0x7a, 0x48, 0x35, + 0x37, 0x6e, 0x47, 0x59, 0x4d, 0x73, 0x52, 0x55, 0x46, 0x55, 0x51, 0x4d, + 0x2b, 0x5a, 0x74, 0x56, 0x37, 0x61, 0x33, 0x66, 0x47, 0x41, 0x69, 0x67, + 0x6f, 0x34, 0x61, 0x4b, 0x53, 0x65, 0x35, 0x54, 0x42, 0x59, 0x38, 0x5a, + 0x54, 0x4e, 0x58, 0x65, 0x57, 0x48, 0x6d, 0x62, 0x30, 0x6d, 0x6f, 0x63, + 0x0a, 0x51, 0x71, 0x76, 0x46, 0x31, 0x61, 0x66, 0x50, 0x61, 0x41, 0x2b, + 0x57, 0x35, 0x4f, 0x46, 0x68, 0x6d, 0x48, 0x5a, 0x68, 0x79, 0x4a, 0x46, + 0x38, 0x31, 0x6a, 0x34, 0x41, 0x34, 0x70, 0x46, 0x51, 0x68, 0x2b, 0x47, + 0x64, 0x43, 0x75, 0x61, 0x74, 0x6c, 0x39, 0x49, 0x64, 0x78, 0x6a, 0x70, + 0x39, 0x79, 0x37, 0x7a, 0x61, 0x41, 0x7a, 0x54, 0x56, 0x6a, 0x6c, 0x73, + 0x42, 0x39, 0x57, 0x6f, 0x48, 0x0a, 0x74, 0x78, 0x61, 0x32, 0x62, 0x6b, + 0x70, 0x2f, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x51, 0x6a, + 0x42, 0x41, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, + 0x51, 0x57, 0x42, 0x42, 0x51, 0x78, 0x77, 0x33, 0x6b, 0x62, 0x75, 0x76, + 0x56, 0x54, 0x31, 0x78, 0x66, 0x67, 0x69, 0x58, 0x6f, 0x74, 0x46, 0x32, + 0x77, 0x4b, 0x73, 0x79, 0x75, 0x64, 0x4d, 0x7a, 0x41, 0x50, 0x0a, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x45, 0x43, 0x44, 0x41, 0x47, 0x41, + 0x51, 0x48, 0x2f, 0x41, 0x67, 0x45, 0x46, 0x4d, 0x41, 0x34, 0x47, 0x41, + 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, + 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, + 0x41, 0x4f, 0x43, 0x0a, 0x41, 0x51, 0x45, 0x41, 0x6c, 0x47, 0x52, 0x5a, + 0x72, 0x54, 0x6c, 0x6b, 0x35, 0x79, 0x6e, 0x72, 0x45, 0x2f, 0x35, 0x61, + 0x77, 0x34, 0x73, 0x54, 0x56, 0x38, 0x67, 0x45, 0x4a, 0x50, 0x42, 0x30, + 0x64, 0x38, 0x42, 0x67, 0x34, 0x32, 0x66, 0x37, 0x36, 0x59, 0x6d, 0x6d, + 0x67, 0x37, 0x2b, 0x57, 0x67, 0x6e, 0x78, 0x75, 0x31, 0x4d, 0x4d, 0x39, + 0x37, 0x35, 0x36, 0x41, 0x62, 0x72, 0x73, 0x70, 0x0a, 0x74, 0x4a, 0x68, + 0x36, 0x73, 0x54, 0x74, 0x55, 0x36, 0x7a, 0x6b, 0x58, 0x52, 0x33, 0x34, + 0x61, 0x6a, 0x67, 0x76, 0x38, 0x48, 0x7a, 0x46, 0x5a, 0x4d, 0x51, 0x53, + 0x79, 0x7a, 0x68, 0x66, 0x7a, 0x4c, 0x4d, 0x64, 0x69, 0x4e, 0x6c, 0x58, + 0x69, 0x49, 0x74, 0x69, 0x4a, 0x56, 0x62, 0x53, 0x59, 0x53, 0x4b, 0x70, + 0x6b, 0x2b, 0x74, 0x59, 0x63, 0x4e, 0x74, 0x68, 0x45, 0x65, 0x46, 0x70, + 0x61, 0x0a, 0x49, 0x7a, 0x70, 0x58, 0x6c, 0x2f, 0x56, 0x36, 0x4d, 0x45, + 0x2b, 0x75, 0x6e, 0x32, 0x70, 0x4d, 0x53, 0x79, 0x75, 0x4f, 0x6f, 0x41, + 0x50, 0x6a, 0x50, 0x75, 0x43, 0x70, 0x31, 0x4e, 0x4a, 0x37, 0x30, 0x72, + 0x4f, 0x6f, 0x34, 0x6e, 0x49, 0x38, 0x72, 0x5a, 0x37, 0x2f, 0x67, 0x46, + 0x6e, 0x6b, 0x6d, 0x30, 0x57, 0x30, 0x39, 0x6a, 0x75, 0x77, 0x7a, 0x54, + 0x6b, 0x5a, 0x6d, 0x44, 0x4c, 0x6c, 0x0a, 0x36, 0x69, 0x46, 0x68, 0x6b, + 0x4f, 0x51, 0x78, 0x49, 0x59, 0x34, 0x30, 0x73, 0x66, 0x63, 0x76, 0x4e, + 0x55, 0x71, 0x46, 0x45, 0x4e, 0x72, 0x6e, 0x69, 0x6a, 0x63, 0x68, 0x76, + 0x6c, 0x6c, 0x6a, 0x34, 0x50, 0x4b, 0x46, 0x69, 0x44, 0x46, 0x54, 0x31, + 0x46, 0x51, 0x55, 0x68, 0x58, 0x42, 0x35, 0x39, 0x43, 0x34, 0x47, 0x64, + 0x79, 0x64, 0x31, 0x4c, 0x78, 0x2b, 0x34, 0x69, 0x76, 0x6e, 0x2b, 0x0a, + 0x78, 0x62, 0x72, 0x59, 0x4e, 0x75, 0x53, 0x44, 0x37, 0x4f, 0x64, 0x6c, + 0x74, 0x37, 0x39, 0x6a, 0x57, 0x76, 0x4e, 0x47, 0x72, 0x34, 0x47, 0x55, + 0x4e, 0x39, 0x52, 0x42, 0x6a, 0x4e, 0x59, 0x6a, 0x31, 0x68, 0x37, 0x50, + 0x39, 0x57, 0x67, 0x62, 0x52, 0x47, 0x4f, 0x69, 0x57, 0x72, 0x71, 0x6e, + 0x4e, 0x56, 0x6d, 0x68, 0x35, 0x58, 0x41, 0x46, 0x6d, 0x77, 0x34, 0x6a, + 0x56, 0x35, 0x6d, 0x55, 0x0a, 0x43, 0x6d, 0x32, 0x36, 0x4f, 0x57, 0x4d, + 0x6f, 0x68, 0x70, 0x4c, 0x7a, 0x47, 0x49, 0x54, 0x59, 0x2b, 0x39, 0x48, + 0x50, 0x42, 0x56, 0x5a, 0x6b, 0x56, 0x77, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x43, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x4f, 0x3d, 0x43, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x79, 0x62, + 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x43, 0x79, + 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x43, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x34, 0x38, + 0x33, 0x35, 0x37, 0x30, 0x33, 0x32, 0x37, 0x38, 0x34, 0x35, 0x39, 0x36, + 0x38, 0x32, 0x38, 0x37, 0x37, 0x34, 0x38, 0x34, 0x33, 0x36, 0x30, 0x0a, + 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x32, 0x3a, 0x65, 0x34, + 0x3a, 0x34, 0x61, 0x3a, 0x38, 0x37, 0x3a, 0x65, 0x33, 0x3a, 0x36, 0x39, + 0x3a, 0x34, 0x30, 0x3a, 0x38, 0x30, 0x3a, 0x37, 0x37, 0x3a, 0x65, 0x61, + 0x3a, 0x62, 0x63, 0x3a, 0x65, 0x33, 0x3a, 0x66, 0x34, 0x3a, 0x66, 0x66, + 0x3a, 0x66, 0x30, 0x3a, 0x65, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x35, 0x66, 0x3a, 0x34, 0x33, 0x3a, 0x65, 0x35, 0x3a, + 0x62, 0x31, 0x3a, 0x62, 0x66, 0x3a, 0x66, 0x38, 0x3a, 0x37, 0x38, 0x3a, + 0x38, 0x63, 0x3a, 0x61, 0x63, 0x3a, 0x31, 0x63, 0x3a, 0x63, 0x37, 0x3a, + 0x63, 0x61, 0x3a, 0x34, 0x61, 0x3a, 0x39, 0x61, 0x3a, 0x63, 0x36, 0x3a, + 0x32, 0x32, 0x3a, 0x32, 0x62, 0x3a, 0x63, 0x63, 0x3a, 0x33, 0x34, 0x3a, + 0x63, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x39, 0x36, 0x3a, 0x30, 0x61, 0x3a, 0x64, 0x66, 0x3a, 0x30, 0x30, + 0x3a, 0x36, 0x33, 0x3a, 0x65, 0x39, 0x3a, 0x36, 0x33, 0x3a, 0x35, 0x36, + 0x3a, 0x37, 0x35, 0x3a, 0x30, 0x63, 0x3a, 0x32, 0x39, 0x3a, 0x36, 0x35, + 0x3a, 0x64, 0x64, 0x3a, 0x30, 0x61, 0x3a, 0x30, 0x38, 0x3a, 0x36, 0x37, + 0x3a, 0x64, 0x61, 0x3a, 0x30, 0x62, 0x3a, 0x39, 0x63, 0x3a, 0x62, 0x64, + 0x3a, 0x36, 0x65, 0x3a, 0x37, 0x37, 0x3a, 0x37, 0x31, 0x3a, 0x34, 0x61, + 0x3a, 0x65, 0x61, 0x3a, 0x66, 0x62, 0x3a, 0x32, 0x33, 0x3a, 0x34, 0x39, + 0x3a, 0x61, 0x62, 0x3a, 0x33, 0x39, 0x3a, 0x33, 0x64, 0x3a, 0x61, 0x33, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x6f, 0x54, 0x43, + 0x43, 0x41, 0x6f, 0x6d, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x4c, 0x42, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x44, 0x34, 0x57, + 0x71, 0x4c, 0x55, 0x67, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, + 0x77, 0x4f, 0x7a, 0x45, 0x59, 0x4d, 0x42, 0x59, 0x47, 0x0a, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x68, 0x4d, 0x50, 0x51, 0x33, 0x6c, 0x69, 0x5a, 0x58, + 0x4a, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x77, 0x67, 0x53, 0x57, + 0x35, 0x6a, 0x4d, 0x52, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x44, 0x45, 0x78, 0x5a, 0x44, 0x65, 0x57, 0x4a, 0x6c, 0x63, 0x6e, + 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x64, 0x73, 0x62, 0x32, + 0x4a, 0x68, 0x0a, 0x62, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x4d, + 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x32, 0x4d, 0x54, 0x49, 0x78, 0x4e, + 0x54, 0x41, 0x34, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, + 0x54, 0x49, 0x78, 0x4d, 0x54, 0x49, 0x78, 0x4e, 0x54, 0x41, 0x34, 0x4d, + 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x77, 0x4f, 0x7a, 0x45, 0x59, 0x4d, + 0x42, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x43, 0x68, 0x4d, 0x50, + 0x51, 0x33, 0x6c, 0x69, 0x5a, 0x58, 0x4a, 0x30, 0x63, 0x6e, 0x56, 0x7a, + 0x64, 0x43, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d, 0x52, 0x38, 0x77, + 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x5a, 0x44, + 0x65, 0x57, 0x4a, 0x6c, 0x63, 0x6e, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, + 0x49, 0x45, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62, 0x43, 0x42, 0x53, + 0x0a, 0x62, 0x32, 0x39, 0x30, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, + 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, + 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, + 0x41, 0x2b, 0x4d, 0x69, 0x38, 0x76, 0x52, 0x52, 0x51, 0x5a, 0x68, 0x50, + 0x2f, 0x38, 0x4e, 0x4e, 0x35, 0x0a, 0x37, 0x43, 0x50, 0x79, 0x74, 0x78, + 0x72, 0x48, 0x6a, 0x6f, 0x58, 0x78, 0x45, 0x6e, 0x4f, 0x6d, 0x47, 0x61, + 0x6f, 0x51, 0x32, 0x35, 0x79, 0x69, 0x5a, 0x58, 0x52, 0x61, 0x64, 0x7a, + 0x35, 0x52, 0x66, 0x56, 0x62, 0x32, 0x33, 0x43, 0x4f, 0x32, 0x31, 0x4f, + 0x31, 0x66, 0x57, 0x4c, 0x45, 0x33, 0x54, 0x64, 0x56, 0x4a, 0x44, 0x6d, + 0x37, 0x31, 0x61, 0x6f, 0x66, 0x57, 0x30, 0x6f, 0x7a, 0x53, 0x0a, 0x4a, + 0x38, 0x62, 0x69, 0x2f, 0x7a, 0x61, 0x66, 0x6d, 0x47, 0x57, 0x67, 0x45, + 0x30, 0x37, 0x47, 0x4b, 0x6d, 0x53, 0x62, 0x31, 0x5a, 0x41, 0x53, 0x7a, + 0x78, 0x51, 0x47, 0x39, 0x44, 0x76, 0x6a, 0x31, 0x43, 0x69, 0x2b, 0x36, + 0x41, 0x37, 0x34, 0x71, 0x30, 0x35, 0x49, 0x6c, 0x47, 0x32, 0x4f, 0x6c, + 0x54, 0x45, 0x51, 0x58, 0x4f, 0x32, 0x69, 0x4c, 0x62, 0x33, 0x56, 0x4f, + 0x6d, 0x32, 0x79, 0x0a, 0x48, 0x4c, 0x74, 0x67, 0x77, 0x45, 0x5a, 0x4c, + 0x41, 0x66, 0x56, 0x4a, 0x72, 0x6e, 0x35, 0x47, 0x69, 0x74, 0x42, 0x30, + 0x6a, 0x61, 0x45, 0x4d, 0x41, 0x73, 0x37, 0x75, 0x2f, 0x4f, 0x65, 0x50, + 0x75, 0x47, 0x74, 0x6d, 0x38, 0x33, 0x39, 0x45, 0x41, 0x4c, 0x39, 0x6d, + 0x4a, 0x52, 0x51, 0x72, 0x33, 0x52, 0x41, 0x77, 0x48, 0x51, 0x65, 0x57, + 0x50, 0x30, 0x33, 0x32, 0x61, 0x37, 0x69, 0x50, 0x0a, 0x74, 0x33, 0x73, + 0x4d, 0x70, 0x54, 0x6a, 0x72, 0x33, 0x6b, 0x66, 0x62, 0x31, 0x56, 0x30, + 0x35, 0x2f, 0x49, 0x69, 0x6e, 0x38, 0x39, 0x63, 0x71, 0x64, 0x50, 0x48, + 0x6f, 0x57, 0x71, 0x49, 0x37, 0x6e, 0x31, 0x43, 0x36, 0x70, 0x6f, 0x78, + 0x46, 0x4e, 0x63, 0x4a, 0x51, 0x5a, 0x5a, 0x58, 0x63, 0x59, 0x34, 0x4c, + 0x76, 0x33, 0x62, 0x39, 0x33, 0x54, 0x5a, 0x78, 0x69, 0x79, 0x57, 0x4e, + 0x7a, 0x0a, 0x46, 0x74, 0x41, 0x70, 0x44, 0x30, 0x6d, 0x70, 0x53, 0x50, + 0x43, 0x7a, 0x71, 0x72, 0x64, 0x73, 0x78, 0x61, 0x63, 0x77, 0x4f, 0x55, + 0x42, 0x64, 0x72, 0x73, 0x54, 0x69, 0x58, 0x53, 0x5a, 0x54, 0x38, 0x4d, + 0x34, 0x63, 0x49, 0x77, 0x68, 0x68, 0x71, 0x4a, 0x51, 0x5a, 0x75, 0x67, + 0x52, 0x69, 0x51, 0x4f, 0x77, 0x66, 0x4f, 0x48, 0x42, 0x33, 0x45, 0x67, + 0x5a, 0x78, 0x70, 0x7a, 0x41, 0x59, 0x0a, 0x58, 0x53, 0x55, 0x6e, 0x70, + 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x34, 0x47, 0x6c, 0x4d, + 0x49, 0x47, 0x69, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, + 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, + 0x6a, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, + 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x0a, + 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, + 0x42, 0x42, 0x53, 0x32, 0x43, 0x48, 0x73, 0x4e, 0x65, 0x73, 0x79, 0x73, + 0x49, 0x45, 0x79, 0x47, 0x56, 0x6a, 0x4a, 0x65, 0x7a, 0x36, 0x74, 0x75, + 0x68, 0x53, 0x31, 0x77, 0x56, 0x7a, 0x41, 0x2f, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x52, 0x38, 0x45, 0x4f, 0x44, 0x41, 0x32, 0x4d, 0x44, 0x53, 0x67, + 0x4d, 0x71, 0x41, 0x77, 0x0a, 0x68, 0x69, 0x35, 0x6f, 0x64, 0x48, 0x52, + 0x77, 0x4f, 0x69, 0x38, 0x76, 0x64, 0x33, 0x64, 0x33, 0x4d, 0x69, 0x35, + 0x77, 0x64, 0x57, 0x4a, 0x73, 0x61, 0x57, 0x4d, 0x74, 0x64, 0x48, 0x4a, + 0x31, 0x63, 0x33, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x32, 0x4e, + 0x79, 0x62, 0x43, 0x39, 0x6a, 0x64, 0x43, 0x39, 0x6a, 0x64, 0x48, 0x4a, + 0x76, 0x62, 0x33, 0x51, 0x75, 0x59, 0x33, 0x4a, 0x73, 0x0a, 0x4d, 0x42, + 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, + 0x61, 0x41, 0x46, 0x4c, 0x59, 0x49, 0x65, 0x77, 0x31, 0x36, 0x7a, 0x4b, + 0x77, 0x67, 0x54, 0x49, 0x5a, 0x57, 0x4d, 0x6c, 0x37, 0x50, 0x71, 0x32, + 0x36, 0x46, 0x4c, 0x58, 0x42, 0x58, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, + 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, + 0x55, 0x41, 0x0a, 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x42, 0x57, 0x37, + 0x77, 0x6f, 0x6a, 0x6f, 0x46, 0x52, 0x4f, 0x6c, 0x5a, 0x66, 0x4a, 0x2b, + 0x49, 0x6e, 0x61, 0x52, 0x63, 0x48, 0x55, 0x6f, 0x77, 0x41, 0x6c, 0x39, + 0x42, 0x38, 0x54, 0x71, 0x37, 0x65, 0x6a, 0x68, 0x56, 0x68, 0x70, 0x77, + 0x6a, 0x43, 0x74, 0x32, 0x42, 0x57, 0x4b, 0x4c, 0x65, 0x50, 0x4a, 0x7a, + 0x59, 0x46, 0x61, 0x2b, 0x48, 0x4d, 0x6a, 0x0a, 0x57, 0x71, 0x64, 0x38, + 0x42, 0x66, 0x50, 0x39, 0x49, 0x6a, 0x73, 0x4f, 0x30, 0x51, 0x62, 0x45, + 0x32, 0x7a, 0x5a, 0x4d, 0x63, 0x77, 0x53, 0x4f, 0x35, 0x62, 0x41, 0x69, + 0x35, 0x4d, 0x58, 0x7a, 0x4c, 0x71, 0x58, 0x5a, 0x49, 0x2b, 0x4f, 0x34, + 0x54, 0x6b, 0x6f, 0x67, 0x70, 0x32, 0x34, 0x43, 0x4a, 0x4a, 0x38, 0x69, + 0x59, 0x47, 0x64, 0x37, 0x69, 0x78, 0x31, 0x79, 0x43, 0x63, 0x55, 0x78, + 0x0a, 0x58, 0x4f, 0x6c, 0x35, 0x6e, 0x34, 0x42, 0x48, 0x50, 0x61, 0x32, + 0x68, 0x43, 0x77, 0x63, 0x55, 0x50, 0x55, 0x66, 0x2f, 0x41, 0x32, 0x6b, + 0x61, 0x44, 0x41, 0x74, 0x45, 0x35, 0x32, 0x4d, 0x6c, 0x70, 0x33, 0x2b, + 0x79, 0x79, 0x62, 0x68, 0x32, 0x68, 0x4f, 0x30, 0x6a, 0x39, 0x6e, 0x30, + 0x48, 0x71, 0x30, 0x56, 0x2b, 0x30, 0x39, 0x2b, 0x7a, 0x76, 0x2b, 0x6d, + 0x4b, 0x74, 0x73, 0x32, 0x6f, 0x0a, 0x6f, 0x6d, 0x63, 0x72, 0x55, 0x74, + 0x57, 0x33, 0x5a, 0x66, 0x41, 0x35, 0x54, 0x47, 0x4f, 0x67, 0x6b, 0x58, + 0x6d, 0x54, 0x55, 0x67, 0x39, 0x55, 0x33, 0x59, 0x4f, 0x37, 0x6e, 0x39, + 0x47, 0x50, 0x70, 0x31, 0x4e, 0x7a, 0x77, 0x38, 0x76, 0x2f, 0x4d, 0x4f, + 0x78, 0x38, 0x42, 0x4c, 0x6a, 0x59, 0x52, 0x42, 0x2b, 0x54, 0x58, 0x33, + 0x45, 0x4a, 0x49, 0x72, 0x64, 0x75, 0x50, 0x75, 0x6f, 0x63, 0x0a, 0x41, + 0x30, 0x36, 0x64, 0x47, 0x69, 0x42, 0x68, 0x2b, 0x34, 0x45, 0x33, 0x37, + 0x46, 0x37, 0x38, 0x43, 0x6b, 0x57, 0x72, 0x31, 0x2b, 0x63, 0x58, 0x56, + 0x64, 0x43, 0x67, 0x36, 0x6d, 0x43, 0x62, 0x70, 0x76, 0x62, 0x6a, 0x6a, + 0x46, 0x73, 0x70, 0x77, 0x67, 0x5a, 0x67, 0x46, 0x4a, 0x30, 0x74, 0x6c, + 0x30, 0x79, 0x70, 0x6b, 0x78, 0x57, 0x64, 0x59, 0x63, 0x51, 0x42, 0x58, + 0x30, 0x6a, 0x57, 0x0a, 0x57, 0x4c, 0x31, 0x57, 0x4d, 0x52, 0x4a, 0x4f, + 0x45, 0x63, 0x67, 0x68, 0x34, 0x4c, 0x4d, 0x52, 0x6b, 0x57, 0x58, 0x62, + 0x74, 0x4b, 0x61, 0x49, 0x4f, 0x4d, 0x35, 0x56, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, + 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x4f, 0x3d, + 0x43, 0x68, 0x75, 0x6e, 0x67, 0x68, 0x77, 0x61, 0x20, 0x54, 0x65, 0x6c, + 0x65, 0x63, 0x6f, 0x6d, 0x20, 0x43, 0x6f, 0x2e, 0x2c, 0x20, 0x4c, 0x74, + 0x64, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x65, 0x50, 0x4b, 0x49, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x3a, 0x20, 0x4f, 0x3d, 0x43, 0x68, 0x75, 0x6e, 0x67, 0x68, 0x77, + 0x61, 0x20, 0x54, 0x65, 0x6c, 0x65, 0x63, 0x6f, 0x6d, 0x20, 0x43, 0x6f, + 0x2e, 0x2c, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x65, + 0x50, 0x4b, 0x49, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x65, 0x50, 0x4b, 0x49, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x32, 0x38, 0x39, 0x35, 0x36, 0x30, 0x38, 0x38, + 0x36, 0x38, 0x32, 0x37, 0x33, 0x35, 0x31, 0x38, 0x39, 0x36, 0x35, 0x35, + 0x30, 0x33, 0x30, 0x35, 0x32, 0x39, 0x30, 0x35, 0x37, 0x33, 0x35, 0x32, + 0x37, 0x36, 0x30, 0x34, 0x37, 0x37, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x31, 0x62, 0x3a, 0x32, 0x65, 0x3a, 0x30, 0x30, 0x3a, 0x63, + 0x61, 0x3a, 0x32, 0x36, 0x3a, 0x30, 0x36, 0x3a, 0x39, 0x30, 0x3a, 0x33, + 0x64, 0x3a, 0x61, 0x64, 0x3a, 0x66, 0x65, 0x3a, 0x36, 0x66, 0x3a, 0x31, + 0x35, 0x3a, 0x36, 0x38, 0x3a, 0x64, 0x33, 0x3a, 0x36, 0x62, 0x3a, 0x62, + 0x33, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x37, + 0x3a, 0x36, 0x35, 0x3a, 0x30, 0x64, 0x3a, 0x66, 0x31, 0x3a, 0x37, 0x65, + 0x3a, 0x38, 0x65, 0x3a, 0x37, 0x65, 0x3a, 0x35, 0x62, 0x3a, 0x38, 0x32, + 0x3a, 0x34, 0x30, 0x3a, 0x61, 0x34, 0x3a, 0x66, 0x34, 0x3a, 0x35, 0x36, + 0x3a, 0x34, 0x62, 0x3a, 0x63, 0x66, 0x3a, 0x65, 0x32, 0x3a, 0x33, 0x64, + 0x3a, 0x36, 0x39, 0x3a, 0x63, 0x36, 0x3a, 0x66, 0x30, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x30, 0x3a, 0x61, + 0x36, 0x3a, 0x66, 0x34, 0x3a, 0x64, 0x63, 0x3a, 0x36, 0x33, 0x3a, 0x61, + 0x32, 0x3a, 0x34, 0x62, 0x3a, 0x66, 0x64, 0x3a, 0x63, 0x66, 0x3a, 0x35, + 0x34, 0x3a, 0x65, 0x66, 0x3a, 0x32, 0x61, 0x3a, 0x36, 0x61, 0x3a, 0x30, + 0x38, 0x3a, 0x32, 0x61, 0x3a, 0x30, 0x61, 0x3a, 0x37, 0x32, 0x3a, 0x64, + 0x65, 0x3a, 0x33, 0x35, 0x3a, 0x38, 0x30, 0x3a, 0x33, 0x65, 0x3a, 0x32, + 0x66, 0x3a, 0x66, 0x35, 0x3a, 0x66, 0x66, 0x3a, 0x35, 0x32, 0x3a, 0x37, + 0x61, 0x3a, 0x65, 0x35, 0x3a, 0x64, 0x38, 0x3a, 0x37, 0x32, 0x3a, 0x30, + 0x36, 0x3a, 0x64, 0x66, 0x3a, 0x64, 0x35, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x46, 0x73, 0x44, 0x43, 0x43, 0x41, 0x35, 0x69, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x46, 0x63, 0x69, 0x39, + 0x5a, 0x55, 0x64, 0x63, 0x72, 0x37, 0x69, 0x58, 0x41, 0x46, 0x37, 0x6b, + 0x42, 0x74, 0x4b, 0x38, 0x6e, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, + 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, + 0x41, 0x44, 0x42, 0x65, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x55, 0x56, 0x7a, 0x45, + 0x6a, 0x4d, 0x43, 0x45, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, + 0x61, 0x51, 0x32, 0x68, 0x31, 0x62, 0x6d, 0x64, 0x6f, 0x64, 0x32, 0x45, + 0x67, 0x56, 0x47, 0x56, 0x73, 0x5a, 0x57, 0x4e, 0x76, 0x62, 0x53, 0x42, + 0x44, 0x62, 0x79, 0x34, 0x73, 0x49, 0x45, 0x78, 0x30, 0x0a, 0x5a, 0x43, + 0x34, 0x78, 0x4b, 0x6a, 0x41, 0x6f, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x73, 0x4d, 0x49, 0x57, 0x56, 0x51, 0x53, 0x30, 0x6b, 0x67, 0x55, 0x6d, + 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, + 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, + 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, + 0x41, 0x65, 0x0a, 0x46, 0x77, 0x30, 0x77, 0x4e, 0x44, 0x45, 0x79, 0x4d, + 0x6a, 0x41, 0x77, 0x4d, 0x6a, 0x4d, 0x78, 0x4d, 0x6a, 0x64, 0x61, 0x46, + 0x77, 0x30, 0x7a, 0x4e, 0x44, 0x45, 0x79, 0x4d, 0x6a, 0x41, 0x77, 0x4d, + 0x6a, 0x4d, 0x78, 0x4d, 0x6a, 0x64, 0x61, 0x4d, 0x46, 0x34, 0x78, 0x43, + 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, + 0x6c, 0x52, 0x58, 0x4d, 0x53, 0x4d, 0x77, 0x0a, 0x49, 0x51, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x70, 0x44, 0x61, 0x48, 0x56, 0x75, + 0x5a, 0x32, 0x68, 0x33, 0x59, 0x53, 0x42, 0x55, 0x5a, 0x57, 0x78, 0x6c, + 0x59, 0x32, 0x39, 0x74, 0x49, 0x45, 0x4e, 0x76, 0x4c, 0x69, 0x77, 0x67, + 0x54, 0x48, 0x52, 0x6b, 0x4c, 0x6a, 0x45, 0x71, 0x4d, 0x43, 0x67, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x77, 0x77, 0x68, 0x5a, 0x56, 0x42, 0x4c, + 0x0a, 0x53, 0x53, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, + 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, + 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, + 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x49, 0x49, 0x43, 0x49, 0x6a, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, + 0x42, 0x41, 0x51, 0x45, 0x46, 0x0a, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, + 0x38, 0x41, 0x4d, 0x49, 0x49, 0x43, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x67, + 0x45, 0x41, 0x34, 0x53, 0x55, 0x50, 0x37, 0x6f, 0x33, 0x62, 0x69, 0x44, + 0x4e, 0x31, 0x5a, 0x38, 0x32, 0x74, 0x48, 0x33, 0x30, 0x36, 0x54, 0x6d, + 0x32, 0x64, 0x30, 0x79, 0x38, 0x55, 0x38, 0x32, 0x4e, 0x30, 0x79, 0x77, + 0x45, 0x68, 0x61, 0x6a, 0x66, 0x71, 0x68, 0x46, 0x41, 0x48, 0x0a, 0x53, + 0x79, 0x5a, 0x62, 0x43, 0x55, 0x4e, 0x73, 0x49, 0x5a, 0x35, 0x71, 0x79, + 0x4e, 0x55, 0x44, 0x39, 0x57, 0x42, 0x70, 0x6a, 0x38, 0x7a, 0x77, 0x49, + 0x75, 0x51, 0x66, 0x35, 0x2f, 0x64, 0x71, 0x49, 0x6a, 0x47, 0x33, 0x4c, + 0x42, 0x58, 0x79, 0x34, 0x50, 0x34, 0x41, 0x61, 0x6b, 0x50, 0x2f, 0x68, + 0x32, 0x58, 0x47, 0x74, 0x52, 0x72, 0x42, 0x70, 0x30, 0x78, 0x74, 0x49, + 0x6e, 0x41, 0x68, 0x0a, 0x69, 0x6a, 0x48, 0x79, 0x6c, 0x33, 0x53, 0x4a, + 0x43, 0x52, 0x49, 0x6d, 0x48, 0x4a, 0x37, 0x4b, 0x32, 0x52, 0x4b, 0x69, + 0x6c, 0x54, 0x7a, 0x61, 0x36, 0x57, 0x65, 0x2f, 0x43, 0x4b, 0x42, 0x6b, + 0x34, 0x39, 0x5a, 0x43, 0x74, 0x30, 0x58, 0x76, 0x6c, 0x2f, 0x54, 0x32, + 0x39, 0x64, 0x65, 0x31, 0x53, 0x68, 0x55, 0x43, 0x57, 0x48, 0x32, 0x59, + 0x57, 0x45, 0x74, 0x67, 0x76, 0x4d, 0x33, 0x58, 0x0a, 0x44, 0x5a, 0x6f, + 0x54, 0x4d, 0x31, 0x50, 0x52, 0x59, 0x66, 0x6c, 0x36, 0x31, 0x64, 0x64, + 0x34, 0x73, 0x35, 0x6f, 0x7a, 0x39, 0x77, 0x43, 0x47, 0x7a, 0x68, 0x31, + 0x4e, 0x6c, 0x44, 0x69, 0x76, 0x71, 0x4f, 0x78, 0x34, 0x55, 0x58, 0x43, + 0x4b, 0x58, 0x42, 0x43, 0x44, 0x55, 0x53, 0x48, 0x33, 0x45, 0x54, 0x30, + 0x30, 0x68, 0x6c, 0x37, 0x6c, 0x53, 0x4d, 0x32, 0x58, 0x67, 0x59, 0x49, + 0x31, 0x0a, 0x54, 0x42, 0x6e, 0x73, 0x5a, 0x66, 0x5a, 0x72, 0x78, 0x51, + 0x57, 0x68, 0x37, 0x6b, 0x63, 0x54, 0x31, 0x72, 0x4d, 0x68, 0x4a, 0x35, + 0x51, 0x51, 0x43, 0x74, 0x6b, 0x6b, 0x4f, 0x37, 0x71, 0x2b, 0x52, 0x42, + 0x4e, 0x47, 0x4d, 0x44, 0x2b, 0x58, 0x50, 0x4e, 0x6a, 0x58, 0x31, 0x32, + 0x72, 0x75, 0x4f, 0x7a, 0x6a, 0x6a, 0x4b, 0x39, 0x53, 0x58, 0x44, 0x72, + 0x6b, 0x62, 0x35, 0x77, 0x64, 0x4a, 0x0a, 0x66, 0x7a, 0x63, 0x71, 0x2b, + 0x58, 0x64, 0x34, 0x7a, 0x31, 0x54, 0x74, 0x57, 0x30, 0x61, 0x64, 0x6f, + 0x34, 0x41, 0x4f, 0x6b, 0x55, 0x50, 0x42, 0x31, 0x6c, 0x74, 0x66, 0x46, + 0x4c, 0x71, 0x66, 0x70, 0x6f, 0x30, 0x6b, 0x52, 0x30, 0x42, 0x5a, 0x76, + 0x33, 0x49, 0x34, 0x73, 0x6a, 0x5a, 0x73, 0x4e, 0x2f, 0x2b, 0x5a, 0x30, + 0x56, 0x30, 0x4f, 0x57, 0x51, 0x71, 0x72, 0x61, 0x66, 0x66, 0x41, 0x0a, + 0x73, 0x67, 0x52, 0x46, 0x65, 0x6c, 0x51, 0x41, 0x72, 0x72, 0x35, 0x54, + 0x39, 0x72, 0x58, 0x6e, 0x34, 0x66, 0x67, 0x38, 0x6f, 0x7a, 0x48, 0x53, + 0x71, 0x66, 0x34, 0x68, 0x55, 0x6d, 0x54, 0x46, 0x70, 0x6d, 0x66, 0x77, + 0x64, 0x51, 0x63, 0x47, 0x6c, 0x42, 0x53, 0x42, 0x56, 0x63, 0x59, 0x6e, + 0x35, 0x41, 0x47, 0x50, 0x46, 0x38, 0x46, 0x71, 0x63, 0x64, 0x65, 0x2b, + 0x53, 0x2f, 0x75, 0x55, 0x0a, 0x57, 0x48, 0x31, 0x2b, 0x45, 0x54, 0x4f, + 0x78, 0x51, 0x76, 0x64, 0x69, 0x62, 0x42, 0x6a, 0x57, 0x7a, 0x77, 0x6c, + 0x6f, 0x50, 0x6e, 0x39, 0x73, 0x39, 0x68, 0x36, 0x50, 0x59, 0x71, 0x32, + 0x6c, 0x59, 0x39, 0x73, 0x4a, 0x70, 0x78, 0x38, 0x69, 0x51, 0x6b, 0x45, + 0x65, 0x62, 0x35, 0x6d, 0x4b, 0x50, 0x74, 0x66, 0x35, 0x50, 0x30, 0x42, + 0x36, 0x65, 0x62, 0x43, 0x6c, 0x41, 0x5a, 0x4c, 0x53, 0x0a, 0x6e, 0x54, + 0x30, 0x49, 0x46, 0x61, 0x55, 0x51, 0x41, 0x53, 0x32, 0x7a, 0x4d, 0x6e, + 0x61, 0x6f, 0x6c, 0x51, 0x32, 0x7a, 0x65, 0x70, 0x72, 0x37, 0x42, 0x78, + 0x42, 0x34, 0x45, 0x57, 0x2f, 0x68, 0x6a, 0x38, 0x65, 0x36, 0x44, 0x79, + 0x55, 0x61, 0x64, 0x43, 0x72, 0x6c, 0x48, 0x4a, 0x68, 0x42, 0x6d, 0x64, + 0x38, 0x68, 0x68, 0x2b, 0x69, 0x56, 0x42, 0x6d, 0x6f, 0x4b, 0x73, 0x32, + 0x70, 0x48, 0x0a, 0x64, 0x6d, 0x58, 0x32, 0x4f, 0x73, 0x2b, 0x50, 0x59, + 0x68, 0x63, 0x5a, 0x65, 0x77, 0x6f, 0x6f, 0x7a, 0x52, 0x72, 0x53, 0x67, + 0x78, 0x34, 0x68, 0x78, 0x79, 0x79, 0x2f, 0x76, 0x76, 0x39, 0x68, 0x61, + 0x4c, 0x64, 0x6e, 0x47, 0x37, 0x74, 0x34, 0x54, 0x59, 0x33, 0x4f, 0x5a, + 0x2b, 0x58, 0x6b, 0x77, 0x59, 0x36, 0x33, 0x49, 0x32, 0x62, 0x69, 0x6e, + 0x5a, 0x42, 0x31, 0x4e, 0x4a, 0x69, 0x70, 0x0a, 0x4e, 0x69, 0x75, 0x4b, + 0x6d, 0x70, 0x53, 0x35, 0x6e, 0x65, 0x7a, 0x4d, 0x69, 0x72, 0x48, 0x34, + 0x4a, 0x59, 0x6c, 0x63, 0x57, 0x72, 0x59, 0x76, 0x6a, 0x42, 0x39, 0x74, + 0x65, 0x53, 0x53, 0x6e, 0x55, 0x6d, 0x6a, 0x44, 0x68, 0x44, 0x58, 0x69, + 0x5a, 0x6f, 0x31, 0x6a, 0x44, 0x69, 0x56, 0x4e, 0x31, 0x52, 0x6d, 0x79, + 0x35, 0x6e, 0x6b, 0x33, 0x70, 0x79, 0x4b, 0x64, 0x56, 0x44, 0x45, 0x43, + 0x0a, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, 0x71, 0x4d, 0x47, 0x67, + 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, + 0x45, 0x46, 0x42, 0x34, 0x4d, 0x39, 0x37, 0x5a, 0x6e, 0x38, 0x75, 0x47, + 0x53, 0x4a, 0x67, 0x6c, 0x46, 0x77, 0x46, 0x55, 0x35, 0x4c, 0x6e, 0x63, + 0x2f, 0x51, 0x6b, 0x71, 0x69, 0x4d, 0x41, 0x77, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x45, 0x77, 0x51, 0x46, 0x0a, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, + 0x38, 0x77, 0x4f, 0x51, 0x59, 0x45, 0x5a, 0x79, 0x6f, 0x48, 0x41, 0x41, + 0x51, 0x78, 0x4d, 0x43, 0x38, 0x77, 0x4c, 0x51, 0x49, 0x42, 0x41, 0x44, + 0x41, 0x4a, 0x42, 0x67, 0x55, 0x72, 0x44, 0x67, 0x4d, 0x43, 0x47, 0x67, + 0x55, 0x41, 0x4d, 0x41, 0x63, 0x47, 0x42, 0x57, 0x63, 0x71, 0x41, 0x77, + 0x41, 0x41, 0x42, 0x42, 0x52, 0x46, 0x73, 0x4d, 0x4c, 0x48, 0x0a, 0x43, + 0x6c, 0x5a, 0x38, 0x37, 0x6c, 0x74, 0x34, 0x44, 0x4a, 0x58, 0x35, 0x47, + 0x46, 0x50, 0x42, 0x70, 0x68, 0x7a, 0x59, 0x45, 0x44, 0x41, 0x4e, 0x42, + 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, + 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, 0x43, + 0x62, 0x4f, 0x44, 0x55, 0x31, 0x6b, 0x42, 0x50, 0x70, 0x56, 0x4a, 0x75, + 0x66, 0x47, 0x42, 0x0a, 0x75, 0x76, 0x6c, 0x32, 0x49, 0x43, 0x4f, 0x31, + 0x4a, 0x32, 0x42, 0x30, 0x31, 0x47, 0x71, 0x5a, 0x4e, 0x46, 0x35, 0x73, + 0x41, 0x46, 0x50, 0x5a, 0x6e, 0x2f, 0x4b, 0x6d, 0x73, 0x53, 0x51, 0x48, + 0x52, 0x47, 0x6f, 0x71, 0x78, 0x71, 0x57, 0x4f, 0x65, 0x42, 0x4c, 0x6f, + 0x52, 0x39, 0x6c, 0x59, 0x47, 0x78, 0x4d, 0x71, 0x58, 0x6e, 0x6d, 0x62, + 0x6e, 0x77, 0x6f, 0x71, 0x5a, 0x36, 0x59, 0x6c, 0x0a, 0x50, 0x77, 0x5a, + 0x70, 0x56, 0x6e, 0x50, 0x44, 0x69, 0x6d, 0x5a, 0x49, 0x2b, 0x79, 0x6d, + 0x42, 0x56, 0x33, 0x51, 0x47, 0x79, 0x70, 0x7a, 0x71, 0x4b, 0x4f, 0x67, + 0x34, 0x5a, 0x79, 0x59, 0x72, 0x38, 0x64, 0x57, 0x31, 0x50, 0x32, 0x57, + 0x54, 0x2b, 0x44, 0x5a, 0x64, 0x6a, 0x6f, 0x32, 0x4e, 0x51, 0x43, 0x43, + 0x48, 0x47, 0x65, 0x72, 0x76, 0x4a, 0x38, 0x41, 0x39, 0x74, 0x44, 0x6b, + 0x50, 0x0a, 0x4a, 0x58, 0x74, 0x6f, 0x55, 0x48, 0x52, 0x56, 0x6e, 0x41, + 0x78, 0x5a, 0x66, 0x56, 0x6f, 0x39, 0x51, 0x5a, 0x51, 0x6c, 0x55, 0x67, + 0x6a, 0x67, 0x52, 0x79, 0x77, 0x56, 0x4d, 0x52, 0x6e, 0x56, 0x76, 0x77, + 0x64, 0x56, 0x78, 0x72, 0x73, 0x53, 0x74, 0x5a, 0x66, 0x30, 0x58, 0x34, + 0x4f, 0x46, 0x75, 0x6e, 0x48, 0x42, 0x32, 0x57, 0x79, 0x42, 0x45, 0x58, + 0x59, 0x4b, 0x43, 0x72, 0x43, 0x2f, 0x0a, 0x67, 0x70, 0x66, 0x33, 0x36, + 0x6a, 0x33, 0x36, 0x2b, 0x75, 0x77, 0x74, 0x71, 0x53, 0x69, 0x55, 0x4f, + 0x31, 0x62, 0x64, 0x30, 0x6c, 0x45, 0x75, 0x72, 0x73, 0x43, 0x39, 0x43, + 0x42, 0x57, 0x4d, 0x64, 0x31, 0x49, 0x30, 0x6c, 0x74, 0x61, 0x62, 0x72, + 0x4e, 0x4d, 0x64, 0x6a, 0x6d, 0x45, 0x50, 0x4e, 0x58, 0x75, 0x62, 0x72, + 0x6a, 0x6c, 0x70, 0x43, 0x32, 0x4a, 0x67, 0x51, 0x43, 0x41, 0x32, 0x0a, + 0x6a, 0x36, 0x2f, 0x37, 0x4e, 0x75, 0x34, 0x74, 0x43, 0x45, 0x6f, 0x64, + 0x75, 0x4c, 0x2b, 0x62, 0x58, 0x50, 0x6a, 0x71, 0x70, 0x52, 0x75, 0x67, + 0x63, 0x36, 0x62, 0x59, 0x2b, 0x47, 0x37, 0x67, 0x4d, 0x77, 0x52, 0x66, + 0x61, 0x4b, 0x6f, 0x6e, 0x68, 0x2b, 0x33, 0x5a, 0x77, 0x5a, 0x43, 0x63, + 0x37, 0x62, 0x33, 0x6a, 0x61, 0x6a, 0x57, 0x76, 0x59, 0x39, 0x2b, 0x72, + 0x47, 0x4e, 0x6d, 0x36, 0x0a, 0x35, 0x75, 0x6c, 0x4b, 0x36, 0x6c, 0x43, + 0x4b, 0x44, 0x32, 0x47, 0x54, 0x48, 0x75, 0x49, 0x74, 0x47, 0x65, 0x49, + 0x77, 0x6c, 0x44, 0x57, 0x53, 0x58, 0x51, 0x36, 0x32, 0x42, 0x36, 0x38, + 0x5a, 0x67, 0x49, 0x39, 0x48, 0x6b, 0x46, 0x46, 0x4c, 0x4c, 0x6b, 0x33, + 0x64, 0x68, 0x65, 0x4c, 0x53, 0x43, 0x6c, 0x49, 0x4b, 0x46, 0x35, 0x72, + 0x38, 0x47, 0x72, 0x42, 0x51, 0x41, 0x75, 0x55, 0x42, 0x0a, 0x6f, 0x32, + 0x4d, 0x33, 0x49, 0x55, 0x78, 0x45, 0x78, 0x4a, 0x74, 0x52, 0x6d, 0x52, + 0x45, 0x4f, 0x63, 0x35, 0x77, 0x47, 0x6a, 0x31, 0x51, 0x75, 0x70, 0x79, + 0x68, 0x65, 0x52, 0x44, 0x6d, 0x48, 0x56, 0x69, 0x30, 0x33, 0x76, 0x59, + 0x56, 0x45, 0x6c, 0x4f, 0x45, 0x4d, 0x53, 0x79, 0x79, 0x63, 0x77, 0x35, + 0x4b, 0x46, 0x4e, 0x47, 0x48, 0x4c, 0x44, 0x37, 0x69, 0x62, 0x53, 0x6b, + 0x4e, 0x53, 0x0a, 0x2f, 0x6a, 0x51, 0x36, 0x66, 0x62, 0x6a, 0x70, 0x4b, + 0x64, 0x78, 0x32, 0x71, 0x63, 0x67, 0x77, 0x2b, 0x42, 0x52, 0x78, 0x67, + 0x4d, 0x59, 0x65, 0x4e, 0x6b, 0x68, 0x30, 0x49, 0x6b, 0x46, 0x63, 0x68, + 0x34, 0x4c, 0x6f, 0x47, 0x48, 0x47, 0x4c, 0x51, 0x59, 0x6c, 0x45, 0x35, + 0x33, 0x35, 0x59, 0x57, 0x36, 0x69, 0x34, 0x6a, 0x52, 0x50, 0x70, 0x70, + 0x32, 0x7a, 0x44, 0x52, 0x2b, 0x32, 0x7a, 0x0a, 0x47, 0x70, 0x31, 0x69, + 0x72, 0x6f, 0x32, 0x43, 0x36, 0x70, 0x53, 0x65, 0x33, 0x56, 0x6b, 0x51, + 0x77, 0x36, 0x33, 0x64, 0x34, 0x6b, 0x33, 0x6a, 0x4d, 0x64, 0x58, 0x48, + 0x37, 0x4f, 0x6a, 0x79, 0x73, 0x50, 0x36, 0x53, 0x48, 0x68, 0x59, 0x4b, + 0x47, 0x76, 0x7a, 0x5a, 0x38, 0x2f, 0x67, 0x6e, 0x74, 0x73, 0x6d, 0x2b, + 0x48, 0x62, 0x52, 0x73, 0x5a, 0x4a, 0x42, 0x2f, 0x39, 0x4f, 0x54, 0x45, + 0x0a, 0x57, 0x39, 0x63, 0x33, 0x72, 0x6b, 0x49, 0x4f, 0x33, 0x61, 0x51, + 0x61, 0x62, 0x33, 0x79, 0x49, 0x56, 0x4d, 0x55, 0x57, 0x62, 0x75, 0x46, + 0x36, 0x61, 0x43, 0x37, 0x34, 0x4f, 0x72, 0x38, 0x4e, 0x70, 0x44, 0x79, + 0x4a, 0x4f, 0x33, 0x69, 0x6e, 0x54, 0x6d, 0x4f, 0x44, 0x42, 0x43, 0x45, + 0x49, 0x5a, 0x34, 0x33, 0x79, 0x67, 0x6b, 0x6e, 0x51, 0x57, 0x2f, 0x32, + 0x78, 0x7a, 0x51, 0x2b, 0x44, 0x0a, 0x68, 0x4e, 0x51, 0x2b, 0x49, 0x49, + 0x58, 0x33, 0x53, 0x6a, 0x30, 0x72, 0x6e, 0x50, 0x30, 0x71, 0x43, 0x67, + 0x6c, 0x4e, 0x36, 0x6f, 0x48, 0x34, 0x45, 0x5a, 0x77, 0x3d, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, + 0x4f, 0x3d, 0x63, 0x65, 0x72, 0x74, 0x53, 0x49, 0x47, 0x4e, 0x20, 0x4f, + 0x55, 0x3d, 0x63, 0x65, 0x72, 0x74, 0x53, 0x49, 0x47, 0x4e, 0x20, 0x52, + 0x4f, 0x4f, 0x54, 0x20, 0x43, 0x41, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x4f, 0x3d, 0x63, 0x65, 0x72, 0x74, + 0x53, 0x49, 0x47, 0x4e, 0x20, 0x4f, 0x55, 0x3d, 0x63, 0x65, 0x72, 0x74, + 0x53, 0x49, 0x47, 0x4e, 0x20, 0x52, 0x4f, 0x4f, 0x54, 0x20, 0x43, 0x41, + 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x63, + 0x65, 0x72, 0x74, 0x53, 0x49, 0x47, 0x4e, 0x20, 0x52, 0x4f, 0x4f, 0x54, + 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x33, 0x35, 0x32, 0x31, 0x30, 0x32, 0x32, 0x37, 0x32, + 0x34, 0x39, 0x31, 0x35, 0x34, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x31, 0x38, 0x3a, 0x39, 0x38, 0x3a, 0x63, 0x30, 0x3a, 0x64, 0x36, + 0x3a, 0x65, 0x39, 0x3a, 0x33, 0x61, 0x3a, 0x66, 0x63, 0x3a, 0x66, 0x39, + 0x3a, 0x62, 0x30, 0x3a, 0x66, 0x35, 0x3a, 0x30, 0x63, 0x3a, 0x66, 0x37, + 0x3a, 0x34, 0x62, 0x3a, 0x30, 0x31, 0x3a, 0x34, 0x34, 0x3a, 0x31, 0x37, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x66, 0x61, 0x3a, + 0x62, 0x37, 0x3a, 0x65, 0x65, 0x3a, 0x33, 0x36, 0x3a, 0x39, 0x37, 0x3a, + 0x32, 0x36, 0x3a, 0x36, 0x32, 0x3a, 0x66, 0x62, 0x3a, 0x32, 0x64, 0x3a, + 0x62, 0x30, 0x3a, 0x32, 0x61, 0x3a, 0x66, 0x36, 0x3a, 0x62, 0x66, 0x3a, + 0x30, 0x33, 0x3a, 0x66, 0x64, 0x3a, 0x65, 0x38, 0x3a, 0x37, 0x63, 0x3a, + 0x34, 0x62, 0x3a, 0x32, 0x66, 0x3a, 0x39, 0x62, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x61, 0x3a, 0x61, 0x39, + 0x3a, 0x36, 0x32, 0x3a, 0x63, 0x34, 0x3a, 0x66, 0x61, 0x3a, 0x34, 0x61, + 0x3a, 0x36, 0x62, 0x3a, 0x61, 0x66, 0x3a, 0x65, 0x62, 0x3a, 0x65, 0x34, + 0x3a, 0x31, 0x35, 0x3a, 0x31, 0x39, 0x3a, 0x36, 0x64, 0x3a, 0x33, 0x35, + 0x3a, 0x31, 0x63, 0x3a, 0x63, 0x64, 0x3a, 0x38, 0x38, 0x3a, 0x38, 0x64, + 0x3a, 0x34, 0x66, 0x3a, 0x35, 0x33, 0x3a, 0x66, 0x33, 0x3a, 0x66, 0x61, + 0x3a, 0x38, 0x61, 0x3a, 0x65, 0x36, 0x3a, 0x64, 0x37, 0x3a, 0x63, 0x34, + 0x3a, 0x36, 0x36, 0x3a, 0x61, 0x39, 0x3a, 0x34, 0x65, 0x3a, 0x36, 0x30, + 0x3a, 0x34, 0x32, 0x3a, 0x62, 0x62, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x44, 0x4f, 0x44, 0x43, 0x43, 0x41, 0x69, 0x43, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x47, 0x49, 0x41, 0x59, 0x46, 0x46, + 0x6e, 0x41, 0x43, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, + 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x4d, + 0x44, 0x73, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x59, 0x54, 0x0a, 0x41, 0x6c, 0x4a, 0x50, 0x4d, 0x52, 0x45, 0x77, + 0x44, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x68, 0x6a, + 0x5a, 0x58, 0x4a, 0x30, 0x55, 0x30, 0x6c, 0x48, 0x54, 0x6a, 0x45, 0x5a, + 0x4d, 0x42, 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x51, + 0x59, 0x32, 0x56, 0x79, 0x64, 0x46, 0x4e, 0x4a, 0x52, 0x30, 0x34, 0x67, + 0x55, 0x6b, 0x39, 0x50, 0x56, 0x43, 0x42, 0x44, 0x0a, 0x51, 0x54, 0x41, + 0x65, 0x46, 0x77, 0x30, 0x77, 0x4e, 0x6a, 0x41, 0x33, 0x4d, 0x44, 0x51, + 0x78, 0x4e, 0x7a, 0x49, 0x77, 0x4d, 0x44, 0x52, 0x61, 0x46, 0x77, 0x30, + 0x7a, 0x4d, 0x54, 0x41, 0x33, 0x4d, 0x44, 0x51, 0x78, 0x4e, 0x7a, 0x49, + 0x77, 0x4d, 0x44, 0x52, 0x61, 0x4d, 0x44, 0x73, 0x78, 0x43, 0x7a, 0x41, + 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x4a, + 0x50, 0x0a, 0x4d, 0x52, 0x45, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4b, 0x45, 0x77, 0x68, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x55, 0x30, + 0x6c, 0x48, 0x54, 0x6a, 0x45, 0x5a, 0x4d, 0x42, 0x63, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x78, 0x4d, 0x51, 0x59, 0x32, 0x56, 0x79, 0x64, 0x46, + 0x4e, 0x4a, 0x52, 0x30, 0x34, 0x67, 0x55, 0x6b, 0x39, 0x50, 0x56, 0x43, + 0x42, 0x44, 0x51, 0x54, 0x43, 0x43, 0x0a, 0x41, 0x53, 0x49, 0x77, 0x44, + 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, + 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, + 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, + 0x4c, 0x63, 0x7a, 0x75, 0x58, 0x37, 0x49, 0x4a, 0x55, 0x71, 0x4f, 0x74, + 0x64, 0x75, 0x30, 0x4b, 0x42, 0x75, 0x71, 0x56, 0x35, 0x44, 0x6f, 0x0a, + 0x30, 0x53, 0x4c, 0x54, 0x5a, 0x4c, 0x72, 0x54, 0x6b, 0x2b, 0x6a, 0x55, + 0x72, 0x49, 0x5a, 0x68, 0x51, 0x47, 0x70, 0x67, 0x56, 0x32, 0x68, 0x55, + 0x68, 0x45, 0x32, 0x38, 0x61, 0x6c, 0x51, 0x43, 0x42, 0x66, 0x2f, 0x66, + 0x6d, 0x35, 0x6f, 0x71, 0x72, 0x6c, 0x30, 0x48, 0x6a, 0x30, 0x72, 0x44, + 0x4b, 0x48, 0x2f, 0x76, 0x2b, 0x79, 0x76, 0x36, 0x65, 0x66, 0x48, 0x48, + 0x72, 0x66, 0x41, 0x51, 0x0a, 0x55, 0x79, 0x53, 0x51, 0x69, 0x32, 0x62, + 0x4a, 0x71, 0x49, 0x69, 0x72, 0x72, 0x31, 0x71, 0x6a, 0x41, 0x4f, 0x6d, + 0x2b, 0x75, 0x6b, 0x62, 0x75, 0x57, 0x33, 0x4e, 0x37, 0x4c, 0x42, 0x65, + 0x43, 0x67, 0x56, 0x35, 0x69, 0x4c, 0x4b, 0x45, 0x43, 0x5a, 0x62, 0x4f, + 0x39, 0x78, 0x53, 0x73, 0x41, 0x66, 0x73, 0x54, 0x38, 0x41, 0x7a, 0x4e, + 0x58, 0x44, 0x65, 0x33, 0x69, 0x2b, 0x73, 0x35, 0x64, 0x0a, 0x52, 0x64, + 0x59, 0x34, 0x7a, 0x54, 0x57, 0x32, 0x73, 0x73, 0x48, 0x51, 0x6e, 0x49, + 0x46, 0x4b, 0x71, 0x75, 0x53, 0x79, 0x41, 0x56, 0x77, 0x64, 0x6a, 0x31, + 0x2b, 0x5a, 0x78, 0x4c, 0x47, 0x74, 0x32, 0x34, 0x67, 0x68, 0x36, 0x35, + 0x41, 0x49, 0x67, 0x6f, 0x44, 0x7a, 0x4d, 0x4b, 0x4e, 0x44, 0x35, 0x70, + 0x43, 0x43, 0x72, 0x6c, 0x55, 0x6f, 0x53, 0x65, 0x31, 0x62, 0x31, 0x36, + 0x6b, 0x51, 0x0a, 0x4f, 0x41, 0x37, 0x2b, 0x6a, 0x30, 0x78, 0x62, 0x6d, + 0x30, 0x62, 0x71, 0x51, 0x66, 0x57, 0x77, 0x43, 0x48, 0x54, 0x44, 0x30, + 0x49, 0x67, 0x7a, 0x74, 0x6e, 0x7a, 0x58, 0x64, 0x4e, 0x2f, 0x63, 0x68, + 0x4e, 0x46, 0x44, 0x44, 0x6e, 0x55, 0x35, 0x6f, 0x53, 0x56, 0x41, 0x4b, + 0x4f, 0x70, 0x34, 0x79, 0x77, 0x34, 0x73, 0x4c, 0x6a, 0x6d, 0x64, 0x6a, + 0x49, 0x74, 0x75, 0x46, 0x68, 0x77, 0x76, 0x0a, 0x4a, 0x6f, 0x49, 0x51, + 0x34, 0x75, 0x4e, 0x6c, 0x6c, 0x41, 0x6f, 0x45, 0x77, 0x46, 0x37, 0x33, + 0x58, 0x56, 0x76, 0x34, 0x45, 0x4f, 0x4c, 0x51, 0x75, 0x6e, 0x70, 0x4c, + 0x2b, 0x39, 0x34, 0x33, 0x41, 0x41, 0x41, 0x61, 0x57, 0x79, 0x6a, 0x6a, + 0x30, 0x70, 0x78, 0x7a, 0x50, 0x6a, 0x4b, 0x48, 0x6d, 0x4b, 0x48, 0x4a, + 0x55, 0x53, 0x2f, 0x58, 0x33, 0x71, 0x77, 0x7a, 0x73, 0x30, 0x38, 0x43, + 0x0a, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, 0x43, 0x4d, 0x45, 0x41, + 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, + 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, + 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, + 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x63, 0x59, 0x77, 0x48, 0x51, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x4f, 0x0a, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4f, + 0x43, 0x4d, 0x6d, 0x39, 0x73, 0x6c, 0x53, 0x62, 0x50, 0x78, 0x66, 0x49, + 0x62, 0x57, 0x73, 0x6b, 0x4b, 0x48, 0x43, 0x39, 0x42, 0x72, 0x6f, 0x4e, + 0x6e, 0x6b, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, + 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x41, 0x34, + 0x49, 0x42, 0x41, 0x51, 0x41, 0x2b, 0x30, 0x68, 0x79, 0x4a, 0x0a, 0x4c, + 0x6a, 0x58, 0x38, 0x2b, 0x48, 0x58, 0x64, 0x35, 0x6e, 0x39, 0x6c, 0x69, + 0x50, 0x52, 0x79, 0x54, 0x4d, 0x6b, 0x73, 0x31, 0x7a, 0x4a, 0x4f, 0x38, + 0x39, 0x30, 0x5a, 0x65, 0x55, 0x65, 0x39, 0x6a, 0x6a, 0x74, 0x62, 0x6b, + 0x77, 0x39, 0x51, 0x53, 0x53, 0x51, 0x54, 0x61, 0x78, 0x51, 0x47, 0x63, + 0x75, 0x38, 0x4a, 0x30, 0x36, 0x47, 0x68, 0x34, 0x30, 0x43, 0x45, 0x79, + 0x65, 0x63, 0x59, 0x0a, 0x4d, 0x6e, 0x51, 0x38, 0x53, 0x47, 0x34, 0x50, + 0x6e, 0x30, 0x76, 0x55, 0x39, 0x78, 0x37, 0x54, 0x6b, 0x34, 0x5a, 0x6b, + 0x56, 0x4a, 0x64, 0x6a, 0x63, 0x6c, 0x44, 0x56, 0x56, 0x63, 0x2f, 0x36, + 0x49, 0x4a, 0x4d, 0x43, 0x6f, 0x70, 0x76, 0x44, 0x49, 0x35, 0x4e, 0x4f, + 0x46, 0x6c, 0x56, 0x32, 0x6f, 0x48, 0x42, 0x35, 0x62, 0x63, 0x30, 0x68, + 0x48, 0x38, 0x38, 0x76, 0x4c, 0x62, 0x77, 0x5a, 0x0a, 0x34, 0x34, 0x67, + 0x78, 0x2b, 0x46, 0x6b, 0x61, 0x67, 0x51, 0x6e, 0x49, 0x6c, 0x36, 0x5a, + 0x30, 0x78, 0x32, 0x44, 0x45, 0x57, 0x38, 0x78, 0x58, 0x6a, 0x72, 0x4a, + 0x31, 0x2f, 0x52, 0x73, 0x43, 0x43, 0x64, 0x74, 0x5a, 0x62, 0x33, 0x4b, + 0x54, 0x61, 0x66, 0x63, 0x78, 0x51, 0x64, 0x61, 0x49, 0x4f, 0x4c, 0x2b, + 0x48, 0x73, 0x72, 0x30, 0x57, 0x65, 0x66, 0x6d, 0x71, 0x35, 0x4c, 0x36, + 0x49, 0x0a, 0x4a, 0x64, 0x31, 0x68, 0x4a, 0x79, 0x4d, 0x63, 0x74, 0x54, + 0x45, 0x48, 0x42, 0x44, 0x61, 0x30, 0x47, 0x70, 0x43, 0x39, 0x6f, 0x48, + 0x52, 0x78, 0x55, 0x49, 0x6c, 0x74, 0x76, 0x42, 0x54, 0x6a, 0x44, 0x34, + 0x61, 0x75, 0x38, 0x61, 0x73, 0x2b, 0x78, 0x36, 0x41, 0x4a, 0x7a, 0x4b, + 0x4e, 0x49, 0x30, 0x65, 0x44, 0x62, 0x5a, 0x4f, 0x65, 0x53, 0x74, 0x63, + 0x2b, 0x76, 0x63, 0x6b, 0x4e, 0x77, 0x0a, 0x69, 0x2f, 0x6e, 0x44, 0x68, + 0x44, 0x77, 0x54, 0x71, 0x6e, 0x36, 0x53, 0x6d, 0x31, 0x64, 0x54, 0x6b, + 0x2f, 0x70, 0x77, 0x77, 0x70, 0x45, 0x4f, 0x4d, 0x66, 0x6d, 0x62, 0x5a, + 0x31, 0x33, 0x70, 0x6c, 0x6a, 0x68, 0x65, 0x58, 0x37, 0x4e, 0x7a, 0x54, + 0x6f, 0x67, 0x56, 0x5a, 0x39, 0x36, 0x65, 0x64, 0x68, 0x42, 0x69, 0x49, + 0x4c, 0x35, 0x56, 0x61, 0x5a, 0x56, 0x44, 0x41, 0x44, 0x6c, 0x4e, 0x0a, + 0x39, 0x75, 0x36, 0x77, 0x57, 0x6b, 0x35, 0x4a, 0x52, 0x46, 0x52, 0x59, + 0x58, 0x30, 0x4b, 0x44, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, + 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, + 0x55, 0x3d, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, + 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, + 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x28, 0x63, + 0x29, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x47, 0x65, 0x6f, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, + 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, + 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, + 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x65, 0x6f, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, + 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x32, 0x38, 0x38, 0x30, 0x39, 0x31, + 0x30, 0x35, 0x37, 0x36, 0x39, 0x39, 0x32, 0x38, 0x35, 0x36, 0x34, 0x33, + 0x31, 0x33, 0x39, 0x38, 0x34, 0x30, 0x38, 0x35, 0x32, 0x30, 0x39, 0x39, + 0x37, 0x35, 0x38, 0x38, 0x35, 0x35, 0x39, 0x39, 0x0a, 0x23, 0x20, 0x4d, + 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x35, 0x3a, 0x65, 0x38, 0x3a, 0x33, 0x34, + 0x3a, 0x33, 0x36, 0x3a, 0x63, 0x39, 0x3a, 0x31, 0x30, 0x3a, 0x34, 0x34, + 0x3a, 0x35, 0x38, 0x3a, 0x34, 0x38, 0x3a, 0x37, 0x30, 0x3a, 0x36, 0x64, + 0x3a, 0x32, 0x65, 0x3a, 0x38, 0x33, 0x3a, 0x64, 0x34, 0x3a, 0x62, 0x38, + 0x3a, 0x30, 0x35, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x30, 0x33, 0x3a, 0x39, 0x65, 0x3a, 0x65, 0x64, 0x3a, 0x62, 0x38, 0x3a, + 0x30, 0x62, 0x3a, 0x65, 0x37, 0x3a, 0x61, 0x30, 0x3a, 0x33, 0x63, 0x3a, + 0x36, 0x39, 0x3a, 0x35, 0x33, 0x3a, 0x38, 0x39, 0x3a, 0x33, 0x62, 0x3a, + 0x32, 0x30, 0x3a, 0x64, 0x32, 0x3a, 0x64, 0x39, 0x3a, 0x33, 0x32, 0x3a, + 0x33, 0x61, 0x3a, 0x34, 0x63, 0x3a, 0x32, 0x61, 0x3a, 0x66, 0x64, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x34, + 0x3a, 0x37, 0x38, 0x3a, 0x62, 0x38, 0x3a, 0x31, 0x32, 0x3a, 0x32, 0x35, + 0x3a, 0x30, 0x64, 0x3a, 0x66, 0x38, 0x3a, 0x37, 0x38, 0x3a, 0x36, 0x33, + 0x3a, 0x35, 0x63, 0x3a, 0x32, 0x61, 0x3a, 0x61, 0x37, 0x3a, 0x65, 0x63, + 0x3a, 0x37, 0x64, 0x3a, 0x31, 0x35, 0x3a, 0x35, 0x65, 0x3a, 0x61, 0x61, + 0x3a, 0x36, 0x32, 0x3a, 0x35, 0x65, 0x3a, 0x65, 0x38, 0x3a, 0x32, 0x39, + 0x3a, 0x31, 0x36, 0x3a, 0x65, 0x32, 0x3a, 0x63, 0x64, 0x3a, 0x32, 0x39, + 0x3a, 0x34, 0x33, 0x3a, 0x36, 0x31, 0x3a, 0x38, 0x38, 0x3a, 0x36, 0x63, + 0x3a, 0x64, 0x31, 0x3a, 0x66, 0x62, 0x3a, 0x64, 0x34, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x2f, 0x6a, 0x43, 0x43, 0x41, 0x75, + 0x61, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x46, 0x61, + 0x78, 0x75, 0x6c, 0x42, 0x6d, 0x79, 0x65, 0x55, 0x74, 0x42, 0x39, 0x69, + 0x65, 0x70, 0x77, 0x78, 0x67, 0x50, 0x48, 0x7a, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x73, 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x6d, 0x44, 0x45, 0x4c, 0x4d, + 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, + 0x56, 0x4d, 0x78, 0x46, 0x6a, 0x41, 0x55, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x6f, 0x54, 0x44, 0x55, 0x64, 0x6c, 0x62, 0x31, 0x52, 0x79, 0x64, + 0x58, 0x4e, 0x30, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x4f, + 0x54, 0x41, 0x33, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x0a, + 0x4d, 0x43, 0x68, 0x6a, 0x4b, 0x53, 0x41, 0x79, 0x4d, 0x44, 0x41, 0x34, + 0x49, 0x45, 0x64, 0x6c, 0x62, 0x31, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, + 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x67, 0x4c, 0x53, 0x42, 0x47, + 0x62, 0x33, 0x49, 0x67, 0x59, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, + 0x61, 0x58, 0x70, 0x6c, 0x5a, 0x43, 0x42, 0x31, 0x63, 0x32, 0x55, 0x67, + 0x62, 0x32, 0x35, 0x73, 0x0a, 0x65, 0x54, 0x45, 0x32, 0x4d, 0x44, 0x51, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x74, 0x52, 0x32, 0x56, + 0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x55, 0x48, 0x4a, + 0x70, 0x62, 0x57, 0x46, 0x79, 0x65, 0x53, 0x42, 0x44, 0x5a, 0x58, 0x4a, + 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, + 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x0a, 0x63, 0x6d, + 0x6c, 0x30, 0x65, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x7a, 0x4d, 0x42, + 0x34, 0x58, 0x44, 0x54, 0x41, 0x34, 0x4d, 0x44, 0x51, 0x77, 0x4d, 0x6a, + 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, + 0x4d, 0x33, 0x4d, 0x54, 0x49, 0x77, 0x4d, 0x54, 0x49, 0x7a, 0x4e, 0x54, + 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x67, 0x5a, 0x67, 0x78, 0x43, 0x7a, + 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, + 0x6c, 0x56, 0x54, 0x4d, 0x52, 0x59, 0x77, 0x46, 0x41, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x4b, 0x45, 0x77, 0x31, 0x48, 0x5a, 0x57, 0x39, 0x55, 0x63, + 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, + 0x54, 0x6b, 0x77, 0x4e, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, + 0x7a, 0x41, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x0a, 0x4d, 0x6a, 0x41, 0x77, + 0x4f, 0x43, 0x42, 0x48, 0x5a, 0x57, 0x39, 0x55, 0x63, 0x6e, 0x56, 0x7a, + 0x64, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30, 0x67, + 0x52, 0x6d, 0x39, 0x79, 0x49, 0x47, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, + 0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, 0x58, 0x4e, 0x6c, + 0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x4e, 0x6a, 0x41, 0x30, + 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x4c, 0x55, 0x64, + 0x6c, 0x62, 0x31, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x46, 0x42, + 0x79, 0x61, 0x57, 0x31, 0x68, 0x63, 0x6e, 0x6b, 0x67, 0x51, 0x32, 0x56, + 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, + 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, + 0x70, 0x64, 0x48, 0x6b, 0x67, 0x0a, 0x4c, 0x53, 0x42, 0x48, 0x4d, 0x7a, + 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, + 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, + 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, + 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4e, 0x7a, 0x69, 0x58, 0x6d, + 0x4a, 0x59, 0x48, 0x54, 0x4e, 0x58, 0x4f, 0x54, 0x49, 0x7a, 0x0a, 0x2b, + 0x75, 0x76, 0x4c, 0x68, 0x34, 0x79, 0x6e, 0x31, 0x45, 0x72, 0x64, 0x42, + 0x6f, 0x6a, 0x71, 0x5a, 0x49, 0x34, 0x78, 0x6d, 0x4b, 0x55, 0x34, 0x6b, + 0x42, 0x36, 0x59, 0x7a, 0x79, 0x35, 0x6a, 0x4b, 0x2f, 0x42, 0x47, 0x76, + 0x45, 0x53, 0x79, 0x69, 0x61, 0x48, 0x41, 0x4b, 0x41, 0x78, 0x4a, 0x63, + 0x43, 0x47, 0x56, 0x6e, 0x32, 0x54, 0x41, 0x70, 0x70, 0x4d, 0x53, 0x41, + 0x6d, 0x55, 0x6d, 0x0a, 0x68, 0x73, 0x61, 0x6c, 0x69, 0x66, 0x44, 0x36, + 0x31, 0x34, 0x53, 0x67, 0x63, 0x4b, 0x39, 0x50, 0x47, 0x70, 0x63, 0x2f, + 0x42, 0x6b, 0x54, 0x56, 0x79, 0x65, 0x74, 0x79, 0x45, 0x48, 0x33, 0x6b, + 0x4d, 0x53, 0x6a, 0x37, 0x48, 0x47, 0x48, 0x6d, 0x4b, 0x41, 0x64, 0x45, + 0x63, 0x35, 0x49, 0x69, 0x61, 0x61, 0x63, 0x44, 0x69, 0x47, 0x79, 0x64, + 0x59, 0x38, 0x68, 0x53, 0x32, 0x70, 0x67, 0x6e, 0x0a, 0x35, 0x77, 0x68, + 0x4d, 0x63, 0x44, 0x36, 0x30, 0x79, 0x52, 0x4c, 0x42, 0x78, 0x57, 0x65, + 0x44, 0x58, 0x54, 0x50, 0x7a, 0x41, 0x78, 0x48, 0x73, 0x61, 0x74, 0x42, + 0x54, 0x34, 0x74, 0x47, 0x36, 0x4e, 0x6d, 0x43, 0x55, 0x67, 0x4c, 0x74, + 0x68, 0x59, 0x32, 0x78, 0x62, 0x46, 0x33, 0x37, 0x66, 0x51, 0x4a, 0x51, + 0x65, 0x71, 0x77, 0x33, 0x43, 0x49, 0x53, 0x68, 0x77, 0x69, 0x50, 0x2f, + 0x57, 0x0a, 0x4a, 0x6d, 0x78, 0x73, 0x59, 0x41, 0x51, 0x6c, 0x54, 0x6c, + 0x56, 0x2b, 0x66, 0x65, 0x2b, 0x2f, 0x6c, 0x45, 0x6a, 0x65, 0x74, 0x78, + 0x33, 0x64, 0x63, 0x49, 0x30, 0x46, 0x58, 0x34, 0x69, 0x6c, 0x6d, 0x2f, + 0x4c, 0x43, 0x37, 0x75, 0x72, 0x52, 0x51, 0x45, 0x46, 0x74, 0x59, 0x6a, + 0x67, 0x64, 0x56, 0x67, 0x62, 0x46, 0x41, 0x30, 0x64, 0x52, 0x49, 0x42, + 0x6e, 0x38, 0x65, 0x78, 0x41, 0x4c, 0x0a, 0x44, 0x6d, 0x4b, 0x75, 0x64, + 0x6c, 0x57, 0x2f, 0x58, 0x33, 0x65, 0x2b, 0x50, 0x6b, 0x6b, 0x42, 0x55, + 0x7a, 0x32, 0x59, 0x4a, 0x51, 0x4e, 0x32, 0x4a, 0x46, 0x6f, 0x64, 0x74, + 0x4e, 0x75, 0x4a, 0x36, 0x6e, 0x6e, 0x6c, 0x74, 0x72, 0x4d, 0x37, 0x50, + 0x37, 0x70, 0x4d, 0x4b, 0x45, 0x46, 0x2f, 0x42, 0x71, 0x78, 0x71, 0x6a, + 0x73, 0x48, 0x51, 0x39, 0x67, 0x55, 0x64, 0x66, 0x65, 0x5a, 0x43, 0x0a, + 0x68, 0x75, 0x4f, 0x6c, 0x31, 0x55, 0x63, 0x43, 0x41, 0x77, 0x45, 0x41, + 0x41, 0x61, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77, 0x44, 0x77, 0x59, 0x44, + 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, + 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, + 0x41, 0x51, 0x59, 0x77, 0x0a, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, + 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4d, 0x52, 0x35, 0x79, 0x6f, 0x36, + 0x68, 0x54, 0x67, 0x4d, 0x64, 0x48, 0x4e, 0x78, 0x72, 0x32, 0x7a, 0x46, + 0x62, 0x6c, 0x44, 0x34, 0x2f, 0x4d, 0x48, 0x38, 0x74, 0x4d, 0x41, 0x30, + 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, + 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x0a, 0x41, 0x51, + 0x41, 0x74, 0x78, 0x52, 0x50, 0x50, 0x56, 0x6f, 0x42, 0x37, 0x65, 0x6e, + 0x69, 0x39, 0x6e, 0x36, 0x34, 0x73, 0x6d, 0x65, 0x66, 0x76, 0x32, 0x74, + 0x2b, 0x55, 0x58, 0x67, 0x6c, 0x70, 0x70, 0x2b, 0x64, 0x75, 0x61, 0x49, + 0x79, 0x39, 0x63, 0x72, 0x35, 0x48, 0x71, 0x51, 0x36, 0x58, 0x45, 0x72, + 0x68, 0x4b, 0x38, 0x57, 0x54, 0x54, 0x4f, 0x64, 0x38, 0x6c, 0x4e, 0x4e, + 0x54, 0x42, 0x0a, 0x7a, 0x55, 0x36, 0x42, 0x38, 0x41, 0x38, 0x45, 0x78, + 0x43, 0x53, 0x7a, 0x4e, 0x4a, 0x62, 0x47, 0x70, 0x71, 0x6f, 0x77, 0x33, + 0x32, 0x68, 0x68, 0x63, 0x39, 0x66, 0x35, 0x6a, 0x6f, 0x57, 0x4a, 0x37, + 0x77, 0x35, 0x65, 0x6c, 0x53, 0x68, 0x4b, 0x4b, 0x69, 0x65, 0x50, 0x45, + 0x49, 0x34, 0x75, 0x66, 0x49, 0x62, 0x45, 0x41, 0x70, 0x37, 0x61, 0x44, + 0x48, 0x64, 0x6c, 0x44, 0x6b, 0x51, 0x4e, 0x0a, 0x6b, 0x76, 0x33, 0x39, + 0x73, 0x78, 0x59, 0x32, 0x2b, 0x68, 0x45, 0x4e, 0x48, 0x59, 0x77, 0x4f, + 0x42, 0x34, 0x6c, 0x71, 0x4b, 0x56, 0x62, 0x33, 0x63, 0x76, 0x54, 0x64, + 0x46, 0x5a, 0x78, 0x33, 0x4e, 0x57, 0x5a, 0x58, 0x71, 0x78, 0x4e, 0x54, + 0x32, 0x49, 0x37, 0x42, 0x51, 0x4d, 0x58, 0x58, 0x45, 0x78, 0x5a, 0x61, + 0x63, 0x73, 0x65, 0x33, 0x61, 0x51, 0x48, 0x45, 0x65, 0x72, 0x47, 0x44, + 0x0a, 0x41, 0x57, 0x68, 0x39, 0x6a, 0x55, 0x47, 0x68, 0x6c, 0x42, 0x6a, + 0x42, 0x4a, 0x56, 0x7a, 0x38, 0x38, 0x50, 0x36, 0x44, 0x41, 0x6f, 0x64, + 0x38, 0x44, 0x51, 0x33, 0x50, 0x4c, 0x67, 0x68, 0x63, 0x53, 0x6b, 0x41, + 0x4e, 0x50, 0x75, 0x79, 0x42, 0x59, 0x65, 0x59, 0x6b, 0x32, 0x38, 0x72, + 0x67, 0x44, 0x69, 0x30, 0x48, 0x73, 0x6a, 0x35, 0x57, 0x33, 0x49, 0x33, + 0x31, 0x51, 0x59, 0x55, 0x48, 0x0a, 0x53, 0x4a, 0x73, 0x4d, 0x43, 0x38, + 0x74, 0x4a, 0x50, 0x33, 0x33, 0x73, 0x74, 0x2f, 0x33, 0x4c, 0x6a, 0x57, + 0x65, 0x4a, 0x47, 0x71, 0x76, 0x74, 0x75, 0x78, 0x36, 0x6a, 0x41, 0x41, + 0x67, 0x49, 0x46, 0x79, 0x71, 0x43, 0x58, 0x44, 0x46, 0x64, 0x52, 0x6f, + 0x6f, 0x74, 0x44, 0x34, 0x61, 0x62, 0x64, 0x4e, 0x6c, 0x46, 0x2b, 0x39, + 0x52, 0x41, 0x73, 0x58, 0x71, 0x71, 0x61, 0x43, 0x32, 0x47, 0x0a, 0x73, + 0x70, 0x6b, 0x69, 0x34, 0x63, 0x45, 0x72, 0x78, 0x35, 0x7a, 0x34, 0x38, + 0x31, 0x2b, 0x6f, 0x67, 0x68, 0x4c, 0x72, 0x47, 0x52, 0x45, 0x74, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x74, 0x68, + 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, + 0x55, 0x3d, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x74, + 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, + 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, + 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x74, 0x68, + 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, + 0x55, 0x3d, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x74, + 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, + 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, + 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, + 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, + 0x20, 0x47, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x37, 0x31, 0x37, 0x35, 0x38, 0x33, 0x32, 0x30, 0x36, + 0x37, 0x32, 0x38, 0x32, 0x35, 0x34, 0x31, 0x30, 0x30, 0x32, 0x30, 0x36, + 0x36, 0x31, 0x36, 0x32, 0x31, 0x30, 0x38, 0x35, 0x32, 0x35, 0x36, 0x34, + 0x37, 0x32, 0x34, 0x30, 0x36, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x37, 0x34, 0x3a, 0x39, 0x64, 0x3a, 0x65, 0x61, 0x3a, 0x36, 0x30, + 0x3a, 0x32, 0x34, 0x3a, 0x63, 0x34, 0x3a, 0x66, 0x64, 0x3a, 0x32, 0x32, + 0x3a, 0x35, 0x33, 0x3a, 0x33, 0x65, 0x3a, 0x63, 0x63, 0x3a, 0x33, 0x61, + 0x3a, 0x37, 0x32, 0x3a, 0x64, 0x39, 0x3a, 0x32, 0x39, 0x3a, 0x34, 0x66, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x61, 0x3a, + 0x64, 0x62, 0x3a, 0x62, 0x63, 0x3a, 0x32, 0x32, 0x3a, 0x32, 0x33, 0x3a, + 0x38, 0x66, 0x3a, 0x63, 0x34, 0x3a, 0x30, 0x31, 0x3a, 0x61, 0x31, 0x3a, + 0x32, 0x37, 0x3a, 0x62, 0x62, 0x3a, 0x33, 0x38, 0x3a, 0x64, 0x64, 0x3a, + 0x66, 0x34, 0x3a, 0x31, 0x64, 0x3a, 0x64, 0x62, 0x3a, 0x30, 0x38, 0x3a, + 0x39, 0x65, 0x3a, 0x66, 0x30, 0x3a, 0x31, 0x32, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x34, 0x3a, 0x33, 0x31, + 0x3a, 0x30, 0x64, 0x3a, 0x35, 0x30, 0x3a, 0x61, 0x66, 0x3a, 0x31, 0x38, + 0x3a, 0x61, 0x36, 0x3a, 0x34, 0x34, 0x3a, 0x37, 0x31, 0x3a, 0x39, 0x30, + 0x3a, 0x33, 0x37, 0x3a, 0x32, 0x61, 0x3a, 0x38, 0x36, 0x3a, 0x61, 0x66, + 0x3a, 0x61, 0x66, 0x3a, 0x38, 0x62, 0x3a, 0x39, 0x35, 0x3a, 0x31, 0x66, + 0x3a, 0x66, 0x62, 0x3a, 0x34, 0x33, 0x3a, 0x31, 0x64, 0x3a, 0x38, 0x33, + 0x3a, 0x37, 0x66, 0x3a, 0x31, 0x65, 0x3a, 0x35, 0x36, 0x3a, 0x38, 0x38, + 0x3a, 0x62, 0x34, 0x3a, 0x35, 0x39, 0x3a, 0x37, 0x31, 0x3a, 0x65, 0x64, + 0x3a, 0x31, 0x35, 0x3a, 0x35, 0x37, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x43, 0x69, 0x44, 0x43, 0x43, 0x41, 0x67, 0x32, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x4e, 0x66, 0x77, 0x6d, 0x58, + 0x4e, 0x6d, 0x45, 0x54, 0x38, 0x6b, 0x39, 0x4a, 0x6a, 0x31, 0x58, 0x6d, + 0x36, 0x37, 0x58, 0x56, 0x6a, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, + 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x7a, 0x43, 0x42, 0x68, + 0x44, 0x45, 0x4c, 0x0a, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x54, 0x41, 0x54, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x48, 0x52, 0x6f, + 0x59, 0x58, 0x64, 0x30, 0x5a, 0x53, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, + 0x4c, 0x6a, 0x45, 0x34, 0x4d, 0x44, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x78, 0x4d, 0x76, 0x4b, 0x47, 0x4d, 0x70, 0x0a, 0x49, 0x44, 0x49, + 0x77, 0x4d, 0x44, 0x63, 0x67, 0x64, 0x47, 0x68, 0x68, 0x64, 0x33, 0x52, + 0x6c, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30, + 0x67, 0x52, 0x6d, 0x39, 0x79, 0x49, 0x47, 0x46, 0x31, 0x64, 0x47, 0x68, + 0x76, 0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, 0x58, 0x4e, + 0x6c, 0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x4a, 0x44, 0x41, + 0x69, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x47, 0x33, + 0x52, 0x6f, 0x59, 0x58, 0x64, 0x30, 0x5a, 0x53, 0x42, 0x51, 0x63, 0x6d, + 0x6c, 0x74, 0x59, 0x58, 0x4a, 0x35, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, + 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4c, 0x53, 0x42, 0x48, 0x4d, 0x6a, + 0x41, 0x65, 0x46, 0x77, 0x30, 0x77, 0x4e, 0x7a, 0x45, 0x78, 0x4d, 0x44, + 0x55, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x0a, 0x4d, 0x44, 0x42, 0x61, 0x46, + 0x77, 0x30, 0x7a, 0x4f, 0x44, 0x41, 0x78, 0x4d, 0x54, 0x67, 0x79, 0x4d, + 0x7a, 0x55, 0x35, 0x4e, 0x54, 0x6c, 0x61, 0x4d, 0x49, 0x47, 0x45, 0x4d, + 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, + 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x56, 0x4d, 0x42, 0x4d, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4d, 0x64, 0x47, 0x68, 0x68, 0x0a, + 0x64, 0x33, 0x52, 0x6c, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, + 0x4d, 0x54, 0x67, 0x77, 0x4e, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, + 0x45, 0x79, 0x38, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x6a, 0x41, 0x77, + 0x4e, 0x79, 0x42, 0x30, 0x61, 0x47, 0x46, 0x33, 0x64, 0x47, 0x55, 0x73, + 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x67, 0x4c, 0x53, 0x42, 0x47, + 0x62, 0x33, 0x49, 0x67, 0x0a, 0x59, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, + 0x79, 0x61, 0x58, 0x70, 0x6c, 0x5a, 0x43, 0x42, 0x31, 0x63, 0x32, 0x55, + 0x67, 0x62, 0x32, 0x35, 0x73, 0x65, 0x54, 0x45, 0x6b, 0x4d, 0x43, 0x49, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x62, 0x64, 0x47, 0x68, + 0x68, 0x64, 0x33, 0x52, 0x6c, 0x49, 0x46, 0x42, 0x79, 0x61, 0x57, 0x31, + 0x68, 0x63, 0x6e, 0x6b, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x0a, 0x64, 0x43, + 0x42, 0x44, 0x51, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x79, 0x4d, 0x48, + 0x59, 0x77, 0x45, 0x41, 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, + 0x30, 0x43, 0x41, 0x51, 0x59, 0x46, 0x4b, 0x34, 0x45, 0x45, 0x41, 0x43, + 0x49, 0x44, 0x59, 0x67, 0x41, 0x45, 0x6f, 0x74, 0x57, 0x63, 0x67, 0x6e, + 0x75, 0x56, 0x6e, 0x66, 0x46, 0x53, 0x65, 0x49, 0x66, 0x2b, 0x69, 0x68, + 0x61, 0x2f, 0x0a, 0x42, 0x65, 0x62, 0x66, 0x6f, 0x77, 0x4a, 0x50, 0x44, + 0x51, 0x66, 0x47, 0x41, 0x46, 0x47, 0x36, 0x44, 0x41, 0x4a, 0x53, 0x4c, + 0x53, 0x4b, 0x6b, 0x51, 0x6a, 0x6e, 0x45, 0x2f, 0x6f, 0x2f, 0x71, 0x79, + 0x63, 0x47, 0x2b, 0x31, 0x45, 0x33, 0x2f, 0x6e, 0x33, 0x71, 0x65, 0x34, + 0x72, 0x46, 0x38, 0x6d, 0x71, 0x32, 0x6e, 0x68, 0x67, 0x6c, 0x7a, 0x68, + 0x39, 0x48, 0x6e, 0x6d, 0x75, 0x4e, 0x36, 0x0a, 0x70, 0x61, 0x70, 0x75, + 0x2b, 0x37, 0x71, 0x7a, 0x63, 0x4d, 0x42, 0x6e, 0x69, 0x4b, 0x49, 0x31, + 0x31, 0x4b, 0x4f, 0x61, 0x73, 0x66, 0x32, 0x74, 0x77, 0x75, 0x38, 0x78, + 0x2b, 0x71, 0x69, 0x35, 0x38, 0x2f, 0x73, 0x49, 0x78, 0x70, 0x48, 0x52, + 0x2b, 0x79, 0x6d, 0x56, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x50, + 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, + 0x0a, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, 0x34, + 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, + 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, + 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x6d, 0x74, 0x67, + 0x41, 0x4d, 0x41, 0x44, 0x6e, 0x61, 0x33, 0x2b, 0x46, 0x47, 0x4f, 0x36, + 0x4c, 0x74, 0x73, 0x36, 0x4b, 0x0a, 0x44, 0x50, 0x67, 0x52, 0x34, 0x62, + 0x73, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, + 0x30, 0x45, 0x41, 0x77, 0x4d, 0x44, 0x61, 0x51, 0x41, 0x77, 0x5a, 0x67, + 0x49, 0x78, 0x41, 0x4e, 0x33, 0x34, 0x34, 0x46, 0x64, 0x48, 0x57, 0x36, + 0x66, 0x6d, 0x43, 0x73, 0x4f, 0x39, 0x39, 0x59, 0x43, 0x4b, 0x6c, 0x7a, + 0x55, 0x4e, 0x47, 0x34, 0x6b, 0x38, 0x56, 0x49, 0x5a, 0x33, 0x0a, 0x4b, + 0x4d, 0x71, 0x68, 0x39, 0x48, 0x6e, 0x65, 0x74, 0x65, 0x59, 0x34, 0x73, + 0x50, 0x42, 0x6c, 0x63, 0x49, 0x78, 0x2f, 0x41, 0x6c, 0x54, 0x43, 0x76, + 0x2f, 0x2f, 0x59, 0x6f, 0x54, 0x37, 0x5a, 0x7a, 0x77, 0x49, 0x78, 0x41, + 0x4d, 0x53, 0x4e, 0x6c, 0x50, 0x7a, 0x63, 0x55, 0x39, 0x4c, 0x63, 0x6e, + 0x58, 0x67, 0x57, 0x48, 0x78, 0x55, 0x7a, 0x49, 0x31, 0x4e, 0x53, 0x34, + 0x31, 0x6f, 0x78, 0x0a, 0x58, 0x5a, 0x33, 0x4b, 0x72, 0x72, 0x30, 0x54, + 0x4b, 0x55, 0x51, 0x4e, 0x4a, 0x31, 0x75, 0x6f, 0x35, 0x32, 0x69, 0x63, + 0x45, 0x76, 0x64, 0x59, 0x50, 0x79, 0x35, 0x79, 0x41, 0x6c, 0x65, 0x6a, + 0x6a, 0x36, 0x45, 0x55, 0x4c, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, + 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x69, 0x6d, + 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, + 0x2d, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, + 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, 0x69, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, + 0x30, 0x30, 0x38, 0x20, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, + 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x74, 0x68, 0x61, + 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, + 0x20, 0x4f, 0x3d, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, + 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, + 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x72, 0x69, 0x6d, + 0x61, 0x72, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, + 0x2d, 0x20, 0x47, 0x33, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x36, 0x31, 0x34, 0x31, 0x35, + 0x37, 0x30, 0x35, 0x36, 0x36, 0x38, 0x31, 0x32, 0x39, 0x39, 0x38, 0x30, + 0x35, 0x35, 0x35, 0x36, 0x34, 0x37, 0x36, 0x32, 0x37, 0x35, 0x39, 0x39, + 0x35, 0x34, 0x31, 0x34, 0x37, 0x37, 0x39, 0x0a, 0x23, 0x20, 0x4d, 0x44, + 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x66, 0x62, 0x3a, 0x31, 0x62, 0x3a, 0x35, 0x64, 0x3a, + 0x34, 0x33, 0x3a, 0x38, 0x61, 0x3a, 0x39, 0x34, 0x3a, 0x63, 0x64, 0x3a, + 0x34, 0x34, 0x3a, 0x63, 0x36, 0x3a, 0x37, 0x36, 0x3a, 0x66, 0x32, 0x3a, + 0x34, 0x33, 0x3a, 0x34, 0x62, 0x3a, 0x34, 0x37, 0x3a, 0x65, 0x37, 0x3a, + 0x33, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x66, + 0x31, 0x3a, 0x38, 0x62, 0x3a, 0x35, 0x33, 0x3a, 0x38, 0x64, 0x3a, 0x31, + 0x62, 0x3a, 0x65, 0x39, 0x3a, 0x30, 0x33, 0x3a, 0x62, 0x36, 0x3a, 0x61, + 0x36, 0x3a, 0x66, 0x30, 0x3a, 0x35, 0x36, 0x3a, 0x34, 0x33, 0x3a, 0x35, + 0x62, 0x3a, 0x31, 0x37, 0x3a, 0x31, 0x35, 0x3a, 0x38, 0x39, 0x3a, 0x63, + 0x61, 0x3a, 0x66, 0x33, 0x3a, 0x36, 0x62, 0x3a, 0x66, 0x32, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x62, 0x3a, + 0x30, 0x33, 0x3a, 0x66, 0x34, 0x3a, 0x35, 0x38, 0x3a, 0x30, 0x37, 0x3a, + 0x61, 0x64, 0x3a, 0x37, 0x30, 0x3a, 0x66, 0x32, 0x3a, 0x31, 0x62, 0x3a, + 0x66, 0x63, 0x3a, 0x32, 0x63, 0x3a, 0x61, 0x65, 0x3a, 0x37, 0x31, 0x3a, + 0x63, 0x39, 0x3a, 0x66, 0x64, 0x3a, 0x65, 0x34, 0x3a, 0x36, 0x30, 0x3a, + 0x34, 0x63, 0x3a, 0x30, 0x36, 0x3a, 0x34, 0x63, 0x3a, 0x66, 0x35, 0x3a, + 0x66, 0x66, 0x3a, 0x62, 0x36, 0x3a, 0x38, 0x36, 0x3a, 0x62, 0x61, 0x3a, + 0x65, 0x35, 0x3a, 0x64, 0x62, 0x3a, 0x61, 0x61, 0x3a, 0x64, 0x37, 0x3a, + 0x66, 0x64, 0x3a, 0x64, 0x33, 0x3a, 0x34, 0x63, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x4b, 0x6a, 0x43, 0x43, 0x41, 0x78, 0x4b, + 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x59, 0x41, 0x47, + 0x58, 0x74, 0x30, 0x61, 0x6e, 0x36, 0x72, 0x53, 0x30, 0x6d, 0x74, 0x5a, + 0x4c, 0x4c, 0x2f, 0x65, 0x51, 0x2b, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, + 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, + 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x72, 0x6a, 0x45, 0x4c, 0x4d, 0x41, + 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, + 0x4d, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x6f, 0x54, 0x44, 0x48, 0x52, 0x6f, 0x59, 0x58, 0x64, 0x30, 0x5a, 0x53, + 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x6f, 0x4d, 0x43, + 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x66, 0x0a, 0x51, + 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, + 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x54, 0x5a, 0x58, 0x4a, 0x32, 0x61, + 0x57, 0x4e, 0x6c, 0x63, 0x79, 0x42, 0x45, 0x61, 0x58, 0x5a, 0x70, 0x63, + 0x32, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x34, 0x4d, 0x44, 0x59, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x76, 0x4b, 0x47, 0x4d, 0x70, 0x49, + 0x44, 0x49, 0x77, 0x0a, 0x4d, 0x44, 0x67, 0x67, 0x64, 0x47, 0x68, 0x68, + 0x64, 0x33, 0x52, 0x6c, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, + 0x49, 0x43, 0x30, 0x67, 0x52, 0x6d, 0x39, 0x79, 0x49, 0x47, 0x46, 0x31, + 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, + 0x64, 0x58, 0x4e, 0x6c, 0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, + 0x4a, 0x44, 0x41, 0x69, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x4d, + 0x54, 0x47, 0x33, 0x52, 0x6f, 0x59, 0x58, 0x64, 0x30, 0x5a, 0x53, 0x42, + 0x51, 0x63, 0x6d, 0x6c, 0x74, 0x59, 0x58, 0x4a, 0x35, 0x49, 0x46, 0x4a, + 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4c, 0x53, 0x42, + 0x48, 0x4d, 0x7a, 0x41, 0x65, 0x46, 0x77, 0x30, 0x77, 0x4f, 0x44, 0x41, + 0x30, 0x4d, 0x44, 0x49, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x42, + 0x61, 0x0a, 0x46, 0x77, 0x30, 0x7a, 0x4e, 0x7a, 0x45, 0x79, 0x4d, 0x44, + 0x45, 0x79, 0x4d, 0x7a, 0x55, 0x35, 0x4e, 0x54, 0x6c, 0x61, 0x4d, 0x49, + 0x47, 0x75, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x56, 0x4d, 0x42, + 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4d, 0x64, 0x47, + 0x68, 0x68, 0x64, 0x33, 0x52, 0x6c, 0x0a, 0x4c, 0x43, 0x42, 0x4a, 0x62, + 0x6d, 0x4d, 0x75, 0x4d, 0x53, 0x67, 0x77, 0x4a, 0x67, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x4c, 0x45, 0x78, 0x39, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, + 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, + 0x46, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, 0x7a, 0x49, + 0x45, 0x52, 0x70, 0x64, 0x6d, 0x6c, 0x7a, 0x61, 0x57, 0x39, 0x75, 0x0a, + 0x4d, 0x54, 0x67, 0x77, 0x4e, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, + 0x45, 0x79, 0x38, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x6a, 0x41, 0x77, + 0x4f, 0x43, 0x42, 0x30, 0x61, 0x47, 0x46, 0x33, 0x64, 0x47, 0x55, 0x73, + 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x67, 0x4c, 0x53, 0x42, 0x47, + 0x62, 0x33, 0x49, 0x67, 0x59, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, + 0x61, 0x58, 0x70, 0x6c, 0x0a, 0x5a, 0x43, 0x42, 0x31, 0x63, 0x32, 0x55, + 0x67, 0x62, 0x32, 0x35, 0x73, 0x65, 0x54, 0x45, 0x6b, 0x4d, 0x43, 0x49, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x62, 0x64, 0x47, 0x68, + 0x68, 0x64, 0x33, 0x52, 0x6c, 0x49, 0x46, 0x42, 0x79, 0x61, 0x57, 0x31, + 0x68, 0x63, 0x6e, 0x6b, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, + 0x44, 0x51, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x7a, 0x0a, 0x4d, 0x49, + 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, + 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, + 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, + 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x73, 0x72, 0x38, 0x6e, 0x4c, 0x50, + 0x76, 0x62, 0x32, 0x46, 0x76, 0x64, 0x65, 0x48, 0x73, 0x62, 0x6e, 0x6e, + 0x64, 0x6d, 0x0a, 0x67, 0x63, 0x73, 0x2b, 0x76, 0x48, 0x79, 0x75, 0x38, + 0x36, 0x59, 0x6e, 0x6d, 0x6a, 0x53, 0x6a, 0x61, 0x44, 0x46, 0x78, 0x4f, + 0x44, 0x4e, 0x69, 0x35, 0x50, 0x4e, 0x78, 0x5a, 0x6e, 0x6d, 0x78, 0x71, + 0x57, 0x57, 0x6a, 0x70, 0x59, 0x76, 0x56, 0x6a, 0x32, 0x41, 0x74, 0x50, + 0x30, 0x4c, 0x4d, 0x71, 0x6d, 0x73, 0x79, 0x77, 0x43, 0x50, 0x4c, 0x4c, + 0x45, 0x48, 0x64, 0x35, 0x4e, 0x2f, 0x38, 0x0a, 0x59, 0x5a, 0x7a, 0x69, + 0x63, 0x37, 0x49, 0x69, 0x6c, 0x52, 0x46, 0x44, 0x47, 0x46, 0x2f, 0x45, + 0x74, 0x68, 0x39, 0x58, 0x62, 0x41, 0x6f, 0x46, 0x57, 0x43, 0x4c, 0x49, + 0x4e, 0x6b, 0x77, 0x36, 0x66, 0x4b, 0x58, 0x52, 0x7a, 0x34, 0x61, 0x76, + 0x69, 0x4b, 0x64, 0x45, 0x41, 0x68, 0x4e, 0x30, 0x63, 0x58, 0x4d, 0x4b, + 0x51, 0x6c, 0x6b, 0x43, 0x2b, 0x42, 0x73, 0x55, 0x61, 0x30, 0x4c, 0x66, + 0x0a, 0x62, 0x31, 0x2b, 0x36, 0x61, 0x34, 0x4b, 0x69, 0x6e, 0x56, 0x76, + 0x6e, 0x53, 0x72, 0x30, 0x65, 0x41, 0x58, 0x4c, 0x62, 0x53, 0x33, 0x54, + 0x6f, 0x4f, 0x33, 0x39, 0x2f, 0x66, 0x52, 0x38, 0x45, 0x74, 0x43, 0x61, + 0x62, 0x34, 0x4c, 0x52, 0x61, 0x72, 0x45, 0x63, 0x39, 0x56, 0x62, 0x6a, + 0x58, 0x73, 0x43, 0x5a, 0x53, 0x4b, 0x41, 0x45, 0x78, 0x51, 0x47, 0x62, + 0x59, 0x32, 0x53, 0x53, 0x39, 0x0a, 0x39, 0x69, 0x72, 0x59, 0x37, 0x43, + 0x46, 0x4a, 0x58, 0x4a, 0x76, 0x32, 0x65, 0x75, 0x6c, 0x2f, 0x56, 0x54, + 0x56, 0x2b, 0x6c, 0x6d, 0x75, 0x4e, 0x6b, 0x35, 0x4d, 0x6e, 0x79, 0x35, + 0x4b, 0x37, 0x36, 0x71, 0x78, 0x41, 0x77, 0x4a, 0x2f, 0x43, 0x2b, 0x49, + 0x44, 0x50, 0x58, 0x66, 0x52, 0x61, 0x33, 0x4d, 0x35, 0x30, 0x68, 0x71, + 0x59, 0x2b, 0x62, 0x41, 0x74, 0x54, 0x79, 0x72, 0x32, 0x53, 0x0a, 0x7a, + 0x68, 0x6b, 0x47, 0x63, 0x75, 0x59, 0x4d, 0x58, 0x44, 0x68, 0x70, 0x78, + 0x77, 0x54, 0x57, 0x76, 0x47, 0x7a, 0x4f, 0x57, 0x2f, 0x62, 0x33, 0x61, + 0x4a, 0x7a, 0x63, 0x4a, 0x52, 0x56, 0x49, 0x69, 0x4b, 0x48, 0x70, 0x71, + 0x66, 0x69, 0x59, 0x6e, 0x4f, 0x44, 0x7a, 0x31, 0x54, 0x45, 0x6f, 0x59, + 0x52, 0x46, 0x73, 0x5a, 0x35, 0x61, 0x4e, 0x4f, 0x5a, 0x6e, 0x4c, 0x77, + 0x6b, 0x55, 0x6b, 0x0a, 0x4f, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, + 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, + 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, + 0x42, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x51, 0x34, + 0x45, 0x46, 0x67, 0x51, 0x55, 0x72, 0x57, 0x79, 0x71, 0x6c, 0x47, 0x43, + 0x63, 0x37, 0x65, 0x54, 0x2f, 0x2b, 0x6a, 0x34, 0x4b, 0x64, 0x43, 0x74, + 0x6a, 0x41, 0x2f, 0x65, 0x32, 0x57, 0x62, 0x38, 0x77, 0x44, 0x51, 0x59, + 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, + 0x4c, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x42, 0x70, + 0x41, 0x0a, 0x32, 0x4a, 0x56, 0x6c, 0x72, 0x41, 0x6d, 0x53, 0x69, 0x63, + 0x59, 0x35, 0x39, 0x42, 0x44, 0x6c, 0x71, 0x51, 0x35, 0x6d, 0x55, 0x31, + 0x31, 0x34, 0x33, 0x76, 0x6f, 0x6b, 0x6b, 0x62, 0x76, 0x6e, 0x52, 0x46, + 0x48, 0x66, 0x78, 0x68, 0x59, 0x30, 0x43, 0x75, 0x39, 0x71, 0x52, 0x46, + 0x48, 0x71, 0x4b, 0x77, 0x65, 0x4b, 0x41, 0x33, 0x72, 0x44, 0x36, 0x7a, + 0x38, 0x4b, 0x4c, 0x46, 0x49, 0x57, 0x0a, 0x6f, 0x43, 0x74, 0x44, 0x75, + 0x53, 0x57, 0x51, 0x50, 0x33, 0x43, 0x70, 0x4d, 0x79, 0x56, 0x74, 0x52, + 0x52, 0x6f, 0x6f, 0x4f, 0x79, 0x66, 0x50, 0x71, 0x73, 0x4d, 0x70, 0x51, + 0x68, 0x76, 0x66, 0x4f, 0x30, 0x7a, 0x41, 0x4d, 0x7a, 0x52, 0x62, 0x51, + 0x59, 0x69, 0x2f, 0x61, 0x79, 0x74, 0x6c, 0x72, 0x79, 0x6a, 0x76, 0x73, + 0x76, 0x58, 0x44, 0x71, 0x6d, 0x62, 0x4f, 0x65, 0x31, 0x62, 0x75, 0x0a, + 0x74, 0x38, 0x6a, 0x4c, 0x5a, 0x38, 0x48, 0x4a, 0x6e, 0x42, 0x6f, 0x59, + 0x75, 0x4d, 0x54, 0x44, 0x53, 0x51, 0x50, 0x78, 0x59, 0x41, 0x35, 0x51, + 0x7a, 0x55, 0x62, 0x46, 0x38, 0x33, 0x64, 0x35, 0x39, 0x37, 0x59, 0x56, + 0x34, 0x44, 0x6a, 0x62, 0x78, 0x79, 0x38, 0x6f, 0x6f, 0x41, 0x77, 0x2f, + 0x64, 0x79, 0x5a, 0x30, 0x32, 0x53, 0x55, 0x53, 0x32, 0x6a, 0x48, 0x61, + 0x47, 0x68, 0x37, 0x63, 0x0a, 0x4b, 0x55, 0x47, 0x52, 0x49, 0x6a, 0x78, + 0x70, 0x70, 0x37, 0x73, 0x43, 0x38, 0x72, 0x5a, 0x63, 0x4a, 0x77, 0x4f, + 0x4a, 0x39, 0x41, 0x62, 0x71, 0x6d, 0x2b, 0x52, 0x79, 0x67, 0x75, 0x4f, + 0x68, 0x43, 0x63, 0x48, 0x70, 0x41, 0x42, 0x6e, 0x54, 0x50, 0x74, 0x52, + 0x77, 0x61, 0x37, 0x70, 0x78, 0x70, 0x71, 0x70, 0x59, 0x72, 0x76, 0x53, + 0x37, 0x36, 0x57, 0x79, 0x32, 0x37, 0x34, 0x66, 0x4d, 0x0a, 0x6d, 0x37, + 0x76, 0x2f, 0x4f, 0x65, 0x5a, 0x57, 0x59, 0x64, 0x4d, 0x4b, 0x70, 0x38, + 0x52, 0x63, 0x54, 0x47, 0x42, 0x37, 0x42, 0x58, 0x63, 0x6d, 0x65, 0x72, + 0x2f, 0x59, 0x42, 0x31, 0x49, 0x73, 0x59, 0x76, 0x64, 0x77, 0x59, 0x39, + 0x6b, 0x35, 0x76, 0x47, 0x38, 0x63, 0x77, 0x6e, 0x6e, 0x63, 0x64, 0x69, + 0x6d, 0x76, 0x7a, 0x73, 0x55, 0x73, 0x5a, 0x41, 0x52, 0x65, 0x69, 0x44, + 0x5a, 0x75, 0x0a, 0x4d, 0x64, 0x52, 0x41, 0x47, 0x6d, 0x49, 0x30, 0x4e, + 0x6a, 0x38, 0x31, 0x41, 0x61, 0x36, 0x73, 0x59, 0x36, 0x41, 0x3d, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, + 0x32, 0x20, 0x4f, 0x3d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x28, 0x63, 0x29, + 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, + 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, + 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x69, + 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, + 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, + 0x37, 0x20, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, + 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x38, 0x30, 0x36, 0x38, 0x32, 0x38, 0x36, 0x33, 0x32, 0x30, 0x33, + 0x33, 0x38, 0x31, 0x30, 0x36, 0x35, 0x37, 0x38, 0x32, 0x31, 0x37, 0x37, + 0x39, 0x30, 0x38, 0x37, 0x35, 0x31, 0x37, 0x39, 0x34, 0x36, 0x31, 0x39, + 0x32, 0x34, 0x33, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, + 0x31, 0x3a, 0x35, 0x65, 0x3a, 0x64, 0x38, 0x3a, 0x36, 0x62, 0x3a, 0x62, + 0x64, 0x3a, 0x36, 0x66, 0x3a, 0x33, 0x64, 0x3a, 0x38, 0x65, 0x3a, 0x61, + 0x31, 0x3a, 0x33, 0x31, 0x3a, 0x66, 0x38, 0x3a, 0x31, 0x32, 0x3a, 0x65, + 0x30, 0x3a, 0x39, 0x38, 0x3a, 0x37, 0x33, 0x3a, 0x36, 0x61, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x64, 0x3a, 0x31, 0x37, + 0x3a, 0x38, 0x34, 0x3a, 0x64, 0x35, 0x3a, 0x33, 0x37, 0x3a, 0x66, 0x33, + 0x3a, 0x30, 0x33, 0x3a, 0x37, 0x64, 0x3a, 0x65, 0x63, 0x3a, 0x37, 0x30, + 0x3a, 0x66, 0x65, 0x3a, 0x35, 0x37, 0x3a, 0x38, 0x62, 0x3a, 0x35, 0x31, + 0x3a, 0x39, 0x61, 0x3a, 0x39, 0x39, 0x3a, 0x65, 0x36, 0x3a, 0x31, 0x30, + 0x3a, 0x64, 0x37, 0x3a, 0x62, 0x30, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x65, 0x3a, 0x64, 0x62, 0x3a, 0x37, + 0x61, 0x3a, 0x63, 0x34, 0x3a, 0x33, 0x62, 0x3a, 0x38, 0x32, 0x3a, 0x61, + 0x30, 0x3a, 0x36, 0x61, 0x3a, 0x38, 0x37, 0x3a, 0x36, 0x31, 0x3a, 0x65, + 0x38, 0x3a, 0x64, 0x37, 0x3a, 0x62, 0x65, 0x3a, 0x34, 0x39, 0x3a, 0x37, + 0x39, 0x3a, 0x65, 0x62, 0x3a, 0x66, 0x32, 0x3a, 0x36, 0x31, 0x3a, 0x31, + 0x66, 0x3a, 0x37, 0x64, 0x3a, 0x64, 0x37, 0x3a, 0x39, 0x62, 0x3a, 0x66, + 0x39, 0x3a, 0x31, 0x63, 0x3a, 0x31, 0x63, 0x3a, 0x36, 0x62, 0x3a, 0x35, + 0x36, 0x3a, 0x36, 0x61, 0x3a, 0x32, 0x31, 0x3a, 0x39, 0x65, 0x3a, 0x64, + 0x37, 0x3a, 0x36, 0x36, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x43, 0x72, 0x6a, 0x43, 0x43, 0x41, 0x6a, 0x57, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x51, 0x50, 0x4c, 0x4c, 0x30, 0x53, 0x41, 0x6f, + 0x41, 0x34, 0x76, 0x37, 0x72, 0x4a, 0x44, 0x74, 0x65, 0x59, 0x44, 0x37, + 0x44, 0x61, 0x7a, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, + 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x7a, 0x43, 0x42, 0x6d, 0x44, 0x45, + 0x4c, 0x0a, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, + 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x6a, 0x41, 0x55, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x55, 0x64, 0x6c, 0x62, 0x31, + 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, + 0x34, 0x78, 0x4f, 0x54, 0x41, 0x33, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x73, 0x54, 0x4d, 0x43, 0x68, 0x6a, 0x0a, 0x4b, 0x53, 0x41, 0x79, 0x4d, + 0x44, 0x41, 0x33, 0x49, 0x45, 0x64, 0x6c, 0x62, 0x31, 0x52, 0x79, 0x64, + 0x58, 0x4e, 0x30, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x67, 0x4c, + 0x53, 0x42, 0x47, 0x62, 0x33, 0x49, 0x67, 0x59, 0x58, 0x56, 0x30, 0x61, + 0x47, 0x39, 0x79, 0x61, 0x58, 0x70, 0x6c, 0x5a, 0x43, 0x42, 0x31, 0x63, + 0x32, 0x55, 0x67, 0x62, 0x32, 0x35, 0x73, 0x65, 0x54, 0x45, 0x32, 0x0a, + 0x4d, 0x44, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x74, + 0x52, 0x32, 0x56, 0x76, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, + 0x55, 0x48, 0x4a, 0x70, 0x62, 0x57, 0x46, 0x79, 0x65, 0x53, 0x42, 0x44, + 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, + 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, + 0x63, 0x6d, 0x6c, 0x30, 0x0a, 0x65, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, + 0x79, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x33, 0x4d, 0x54, 0x45, + 0x77, 0x4e, 0x54, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, + 0x58, 0x44, 0x54, 0x4d, 0x34, 0x4d, 0x44, 0x45, 0x78, 0x4f, 0x44, 0x49, + 0x7a, 0x4e, 0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x67, 0x5a, 0x67, + 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, + 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x52, 0x59, 0x77, 0x46, 0x41, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x31, 0x48, 0x5a, 0x57, + 0x39, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4a, 0x62, 0x6d, + 0x4d, 0x75, 0x4d, 0x54, 0x6b, 0x77, 0x4e, 0x77, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4c, 0x45, 0x7a, 0x41, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x6a, + 0x41, 0x77, 0x0a, 0x4e, 0x79, 0x42, 0x48, 0x5a, 0x57, 0x39, 0x55, 0x63, + 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, + 0x43, 0x30, 0x67, 0x52, 0x6d, 0x39, 0x79, 0x49, 0x47, 0x46, 0x31, 0x64, + 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, + 0x58, 0x4e, 0x6c, 0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x4e, + 0x6a, 0x41, 0x30, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x4d, 0x54, + 0x4c, 0x55, 0x64, 0x6c, 0x62, 0x31, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, + 0x49, 0x46, 0x42, 0x79, 0x61, 0x57, 0x31, 0x68, 0x63, 0x6e, 0x6b, 0x67, + 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, + 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, + 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x4c, 0x53, 0x42, 0x48, + 0x0a, 0x4d, 0x6a, 0x42, 0x32, 0x4d, 0x42, 0x41, 0x47, 0x42, 0x79, 0x71, + 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x42, 0x53, 0x75, + 0x42, 0x42, 0x41, 0x41, 0x69, 0x41, 0x32, 0x49, 0x41, 0x42, 0x42, 0x57, + 0x78, 0x36, 0x50, 0x30, 0x44, 0x46, 0x55, 0x50, 0x6c, 0x72, 0x4f, 0x75, + 0x48, 0x4e, 0x78, 0x46, 0x69, 0x37, 0x39, 0x4b, 0x44, 0x4e, 0x6c, 0x4a, + 0x39, 0x52, 0x56, 0x63, 0x4c, 0x0a, 0x53, 0x6f, 0x31, 0x37, 0x56, 0x44, + 0x73, 0x36, 0x62, 0x6c, 0x38, 0x56, 0x41, 0x73, 0x42, 0x51, 0x70, 0x73, + 0x38, 0x6c, 0x4c, 0x33, 0x33, 0x4b, 0x53, 0x4c, 0x6a, 0x48, 0x55, 0x47, + 0x4d, 0x63, 0x4b, 0x69, 0x45, 0x49, 0x66, 0x4a, 0x6f, 0x32, 0x32, 0x41, + 0x76, 0x2b, 0x30, 0x53, 0x62, 0x46, 0x57, 0x44, 0x45, 0x77, 0x4b, 0x43, + 0x58, 0x7a, 0x58, 0x56, 0x32, 0x6a, 0x75, 0x4c, 0x61, 0x6c, 0x0a, 0x74, + 0x4a, 0x4c, 0x74, 0x62, 0x43, 0x79, 0x66, 0x36, 0x39, 0x31, 0x44, 0x69, + 0x61, 0x49, 0x38, 0x53, 0x30, 0x69, 0x52, 0x48, 0x56, 0x44, 0x73, 0x4a, + 0x74, 0x2f, 0x57, 0x59, 0x43, 0x36, 0x39, 0x49, 0x61, 0x4e, 0x43, 0x4d, + 0x45, 0x41, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, + 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, + 0x7a, 0x41, 0x4f, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, + 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, + 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, + 0x46, 0x42, 0x56, 0x66, 0x4e, 0x56, 0x64, 0x52, 0x56, 0x66, 0x73, 0x6c, + 0x73, 0x71, 0x30, 0x44, 0x61, 0x66, 0x77, 0x42, 0x6f, 0x2f, 0x71, 0x2b, + 0x45, 0x56, 0x58, 0x56, 0x4d, 0x41, 0x6f, 0x47, 0x0a, 0x43, 0x43, 0x71, + 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x44, 0x41, 0x32, 0x63, + 0x41, 0x4d, 0x47, 0x51, 0x43, 0x4d, 0x47, 0x53, 0x57, 0x57, 0x61, 0x62, + 0x6f, 0x43, 0x64, 0x36, 0x4c, 0x75, 0x76, 0x70, 0x61, 0x69, 0x49, 0x6a, + 0x77, 0x48, 0x35, 0x48, 0x54, 0x52, 0x71, 0x6a, 0x79, 0x53, 0x6b, 0x77, + 0x43, 0x59, 0x2f, 0x74, 0x73, 0x58, 0x7a, 0x6a, 0x62, 0x4c, 0x6b, 0x47, + 0x54, 0x0a, 0x71, 0x51, 0x37, 0x6d, 0x6e, 0x64, 0x77, 0x78, 0x48, 0x4c, + 0x4b, 0x67, 0x70, 0x78, 0x67, 0x63, 0x65, 0x65, 0x48, 0x48, 0x4e, 0x67, + 0x49, 0x77, 0x4f, 0x6c, 0x61, 0x76, 0x6d, 0x6e, 0x52, 0x73, 0x39, 0x76, + 0x75, 0x44, 0x34, 0x44, 0x50, 0x54, 0x43, 0x46, 0x2b, 0x68, 0x6e, 0x4d, + 0x4a, 0x62, 0x6e, 0x30, 0x62, 0x57, 0x74, 0x73, 0x75, 0x52, 0x42, 0x6d, + 0x4f, 0x69, 0x42, 0x75, 0x63, 0x7a, 0x0a, 0x72, 0x44, 0x36, 0x6f, 0x67, + 0x52, 0x4c, 0x51, 0x79, 0x37, 0x72, 0x51, 0x6b, 0x67, 0x75, 0x32, 0x6e, + 0x70, 0x61, 0x71, 0x42, 0x41, 0x2b, 0x4b, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, + 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x55, 0x6e, 0x69, + 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, + 0x4f, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x65, 0x72, 0x69, + 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, + 0x30, 0x30, 0x38, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, + 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, + 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, + 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x53, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x55, 0x6e, 0x69, 0x76, + 0x65, 0x72, 0x73, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, + 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, + 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, + 0x30, 0x38, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, + 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, + 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, + 0x67, 0x6e, 0x20, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x38, 0x35, 0x32, 0x30, 0x39, 0x35, 0x37, + 0x34, 0x37, 0x33, 0x34, 0x30, 0x38, 0x34, 0x35, 0x38, 0x31, 0x39, 0x31, + 0x37, 0x37, 0x36, 0x33, 0x37, 0x35, 0x32, 0x36, 0x34, 0x34, 0x30, 0x33, + 0x31, 0x37, 0x32, 0x36, 0x38, 0x37, 0x37, 0x0a, 0x23, 0x20, 0x4d, 0x44, + 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x38, 0x65, 0x3a, 0x61, 0x64, 0x3a, 0x62, 0x35, 0x3a, + 0x30, 0x31, 0x3a, 0x61, 0x61, 0x3a, 0x34, 0x64, 0x3a, 0x38, 0x31, 0x3a, + 0x65, 0x34, 0x3a, 0x38, 0x63, 0x3a, 0x31, 0x64, 0x3a, 0x64, 0x31, 0x3a, + 0x65, 0x31, 0x3a, 0x31, 0x34, 0x3a, 0x30, 0x30, 0x3a, 0x39, 0x35, 0x3a, + 0x31, 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, + 0x36, 0x3a, 0x37, 0x39, 0x3a, 0x63, 0x61, 0x3a, 0x33, 0x35, 0x3a, 0x36, + 0x36, 0x3a, 0x38, 0x37, 0x3a, 0x37, 0x32, 0x3a, 0x33, 0x30, 0x3a, 0x34, + 0x64, 0x3a, 0x33, 0x30, 0x3a, 0x61, 0x35, 0x3a, 0x66, 0x62, 0x3a, 0x38, + 0x37, 0x3a, 0x33, 0x62, 0x3a, 0x30, 0x66, 0x3a, 0x61, 0x37, 0x3a, 0x37, + 0x62, 0x3a, 0x62, 0x37, 0x3a, 0x30, 0x64, 0x3a, 0x35, 0x34, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x33, 0x3a, + 0x39, 0x39, 0x3a, 0x35, 0x36, 0x3a, 0x31, 0x31, 0x3a, 0x32, 0x37, 0x3a, + 0x61, 0x35, 0x3a, 0x37, 0x31, 0x3a, 0x32, 0x35, 0x3a, 0x64, 0x65, 0x3a, + 0x38, 0x63, 0x3a, 0x65, 0x66, 0x3a, 0x65, 0x61, 0x3a, 0x36, 0x31, 0x3a, + 0x30, 0x64, 0x3a, 0x64, 0x66, 0x3a, 0x32, 0x66, 0x3a, 0x61, 0x30, 0x3a, + 0x37, 0x38, 0x3a, 0x62, 0x35, 0x3a, 0x63, 0x38, 0x3a, 0x30, 0x36, 0x3a, + 0x37, 0x66, 0x3a, 0x34, 0x65, 0x3a, 0x38, 0x32, 0x3a, 0x38, 0x32, 0x3a, + 0x39, 0x30, 0x3a, 0x62, 0x66, 0x3a, 0x62, 0x38, 0x3a, 0x36, 0x30, 0x3a, + 0x65, 0x38, 0x3a, 0x34, 0x62, 0x3a, 0x33, 0x63, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x75, 0x54, 0x43, 0x43, 0x41, 0x36, 0x47, + 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x51, 0x42, 0x72, + 0x45, 0x5a, 0x43, 0x47, 0x7a, 0x45, 0x79, 0x45, 0x44, 0x44, 0x72, 0x76, + 0x6b, 0x45, 0x68, 0x72, 0x46, 0x48, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, + 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, + 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x76, 0x54, 0x45, 0x4c, 0x4d, 0x41, + 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, + 0x4d, 0x78, 0x46, 0x7a, 0x41, 0x56, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x6f, 0x54, 0x44, 0x6c, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, + 0x64, 0x75, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x52, + 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x0a, 0x45, + 0x78, 0x5a, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62, + 0x69, 0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x4f, 0x5a, + 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x4d, 0x54, 0x6f, 0x77, 0x4f, + 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x7a, 0x45, 0x6f, 0x59, + 0x79, 0x6b, 0x67, 0x4d, 0x6a, 0x41, 0x77, 0x4f, 0x43, 0x42, 0x57, 0x5a, + 0x58, 0x4a, 0x70, 0x0a, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x77, 0x67, + 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x69, 0x41, 0x74, 0x49, 0x45, 0x5a, 0x76, + 0x63, 0x69, 0x42, 0x68, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, + 0x65, 0x6d, 0x56, 0x6b, 0x49, 0x48, 0x56, 0x7a, 0x5a, 0x53, 0x42, 0x76, + 0x62, 0x6d, 0x78, 0x35, 0x4d, 0x54, 0x67, 0x77, 0x4e, 0x67, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x44, 0x45, 0x79, 0x39, 0x57, 0x0a, 0x5a, 0x58, 0x4a, + 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x56, 0x62, 0x6d, 0x6c, + 0x32, 0x5a, 0x58, 0x4a, 0x7a, 0x59, 0x57, 0x77, 0x67, 0x55, 0x6d, 0x39, + 0x76, 0x64, 0x43, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, + 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, + 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, 0x41, + 0x65, 0x0a, 0x46, 0x77, 0x30, 0x77, 0x4f, 0x44, 0x41, 0x30, 0x4d, 0x44, + 0x49, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, + 0x30, 0x7a, 0x4e, 0x7a, 0x45, 0x79, 0x4d, 0x44, 0x45, 0x79, 0x4d, 0x7a, + 0x55, 0x35, 0x4e, 0x54, 0x6c, 0x61, 0x4d, 0x49, 0x47, 0x39, 0x4d, 0x51, + 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, + 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x58, 0x0a, 0x4d, 0x42, 0x55, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4f, 0x56, 0x6d, 0x56, 0x79, 0x61, + 0x56, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, + 0x79, 0x34, 0x78, 0x48, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x73, 0x54, 0x46, 0x6c, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, + 0x57, 0x64, 0x75, 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x0a, + 0x49, 0x45, 0x35, 0x6c, 0x64, 0x48, 0x64, 0x76, 0x63, 0x6d, 0x73, 0x78, + 0x4f, 0x6a, 0x41, 0x34, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, + 0x4d, 0x53, 0x68, 0x6a, 0x4b, 0x53, 0x41, 0x79, 0x4d, 0x44, 0x41, 0x34, + 0x49, 0x46, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, + 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30, 0x67, + 0x52, 0x6d, 0x39, 0x79, 0x0a, 0x49, 0x47, 0x46, 0x31, 0x64, 0x47, 0x68, + 0x76, 0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, 0x58, 0x4e, + 0x6c, 0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x4f, 0x44, 0x41, + 0x32, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x4c, 0x31, 0x5a, + 0x6c, 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x49, 0x46, 0x56, + 0x75, 0x61, 0x58, 0x5a, 0x6c, 0x63, 0x6e, 0x4e, 0x68, 0x0a, 0x62, 0x43, + 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, + 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, + 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, + 0x52, 0x35, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x45, 0x46, 0x0a, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, + 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x78, + 0x32, 0x45, 0x33, 0x58, 0x72, 0x45, 0x42, 0x4e, 0x4e, 0x74, 0x69, 0x31, + 0x78, 0x57, 0x62, 0x2f, 0x31, 0x68, 0x61, 0x6a, 0x43, 0x4d, 0x6a, 0x31, + 0x6d, 0x43, 0x4f, 0x6b, 0x64, 0x65, 0x51, 0x6d, 0x49, 0x4e, 0x36, 0x35, + 0x6c, 0x67, 0x5a, 0x4f, 0x49, 0x7a, 0x46, 0x0a, 0x39, 0x75, 0x56, 0x6b, + 0x68, 0x62, 0x53, 0x69, 0x63, 0x66, 0x76, 0x74, 0x76, 0x62, 0x6e, 0x61, + 0x7a, 0x55, 0x30, 0x41, 0x74, 0x4d, 0x67, 0x74, 0x63, 0x36, 0x58, 0x48, + 0x61, 0x58, 0x47, 0x56, 0x48, 0x7a, 0x6b, 0x38, 0x73, 0x6b, 0x51, 0x48, + 0x6e, 0x4f, 0x67, 0x4f, 0x2b, 0x6b, 0x31, 0x4b, 0x78, 0x43, 0x48, 0x66, + 0x4b, 0x57, 0x47, 0x50, 0x4d, 0x69, 0x4a, 0x68, 0x67, 0x73, 0x57, 0x48, + 0x0a, 0x48, 0x32, 0x36, 0x4d, 0x66, 0x46, 0x38, 0x57, 0x49, 0x46, 0x46, + 0x45, 0x30, 0x58, 0x42, 0x50, 0x56, 0x2b, 0x72, 0x6a, 0x48, 0x4f, 0x50, + 0x4d, 0x65, 0x65, 0x35, 0x59, 0x32, 0x41, 0x37, 0x43, 0x73, 0x30, 0x57, + 0x54, 0x77, 0x43, 0x7a, 0x6e, 0x6d, 0x68, 0x63, 0x72, 0x65, 0x77, 0x41, + 0x33, 0x65, 0x6b, 0x45, 0x7a, 0x65, 0x4f, 0x45, 0x7a, 0x34, 0x76, 0x4d, + 0x51, 0x47, 0x6e, 0x2b, 0x48, 0x0a, 0x4c, 0x4c, 0x37, 0x32, 0x39, 0x66, + 0x64, 0x43, 0x34, 0x75, 0x57, 0x2f, 0x68, 0x32, 0x4b, 0x4a, 0x58, 0x77, + 0x42, 0x4c, 0x33, 0x38, 0x58, 0x64, 0x35, 0x48, 0x56, 0x45, 0x4d, 0x6b, + 0x45, 0x36, 0x48, 0x6e, 0x46, 0x75, 0x61, 0x63, 0x73, 0x4c, 0x64, 0x55, + 0x59, 0x49, 0x30, 0x63, 0x72, 0x53, 0x4b, 0x35, 0x58, 0x51, 0x7a, 0x2f, + 0x75, 0x35, 0x51, 0x47, 0x74, 0x6b, 0x6a, 0x46, 0x64, 0x4e, 0x0a, 0x2f, + 0x42, 0x4d, 0x52, 0x65, 0x59, 0x54, 0x74, 0x58, 0x6c, 0x54, 0x32, 0x4e, + 0x4a, 0x38, 0x49, 0x41, 0x66, 0x4d, 0x51, 0x4a, 0x51, 0x59, 0x58, 0x53, + 0x74, 0x72, 0x78, 0x48, 0x58, 0x70, 0x6d, 0x61, 0x35, 0x68, 0x67, 0x5a, + 0x71, 0x54, 0x5a, 0x37, 0x39, 0x49, 0x75, 0x67, 0x76, 0x48, 0x77, 0x37, + 0x77, 0x6e, 0x71, 0x52, 0x4d, 0x6b, 0x56, 0x61, 0x75, 0x49, 0x44, 0x62, + 0x6a, 0x50, 0x54, 0x0a, 0x72, 0x4a, 0x39, 0x56, 0x41, 0x4d, 0x66, 0x32, + 0x43, 0x47, 0x71, 0x55, 0x75, 0x56, 0x2f, 0x63, 0x34, 0x44, 0x50, 0x78, + 0x68, 0x47, 0x44, 0x35, 0x57, 0x79, 0x63, 0x52, 0x74, 0x50, 0x77, 0x57, + 0x38, 0x72, 0x74, 0x57, 0x61, 0x6f, 0x41, 0x6c, 0x6a, 0x51, 0x49, 0x44, + 0x41, 0x51, 0x41, 0x42, 0x6f, 0x34, 0x47, 0x79, 0x4d, 0x49, 0x47, 0x76, + 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x0a, 0x45, 0x77, 0x45, + 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, + 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, + 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x47, 0x30, + 0x47, 0x43, 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x77, 0x45, + 0x4d, 0x42, 0x47, 0x45, 0x77, 0x58, 0x36, 0x46, 0x64, 0x6f, 0x46, 0x73, + 0x77, 0x0a, 0x57, 0x54, 0x42, 0x58, 0x4d, 0x46, 0x55, 0x57, 0x43, 0x57, + 0x6c, 0x74, 0x59, 0x57, 0x64, 0x6c, 0x4c, 0x32, 0x64, 0x70, 0x5a, 0x6a, + 0x41, 0x68, 0x4d, 0x42, 0x38, 0x77, 0x42, 0x77, 0x59, 0x46, 0x4b, 0x77, + 0x34, 0x44, 0x41, 0x68, 0x6f, 0x45, 0x46, 0x49, 0x2f, 0x6c, 0x30, 0x78, + 0x71, 0x47, 0x72, 0x49, 0x32, 0x4f, 0x61, 0x38, 0x50, 0x50, 0x67, 0x47, + 0x72, 0x55, 0x53, 0x42, 0x67, 0x73, 0x0a, 0x65, 0x78, 0x6b, 0x75, 0x4d, + 0x43, 0x55, 0x57, 0x49, 0x32, 0x68, 0x30, 0x64, 0x48, 0x41, 0x36, 0x4c, + 0x79, 0x39, 0x73, 0x62, 0x32, 0x64, 0x76, 0x4c, 0x6e, 0x5a, 0x6c, 0x63, + 0x6d, 0x6c, 0x7a, 0x61, 0x57, 0x64, 0x75, 0x4c, 0x6d, 0x4e, 0x76, 0x62, + 0x53, 0x39, 0x32, 0x63, 0x32, 0x78, 0x76, 0x5a, 0x32, 0x38, 0x75, 0x5a, + 0x32, 0x6c, 0x6d, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x0a, + 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x53, 0x32, 0x64, 0x2f, 0x70, 0x70, + 0x53, 0x45, 0x65, 0x66, 0x55, 0x78, 0x4c, 0x56, 0x77, 0x75, 0x6f, 0x48, + 0x4d, 0x6e, 0x59, 0x48, 0x30, 0x5a, 0x63, 0x48, 0x47, 0x54, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x73, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, + 0x53, 0x76, 0x6a, 0x34, 0x0a, 0x73, 0x41, 0x50, 0x6d, 0x4c, 0x47, 0x64, + 0x37, 0x35, 0x4a, 0x52, 0x33, 0x59, 0x38, 0x78, 0x75, 0x54, 0x50, 0x6c, + 0x39, 0x44, 0x67, 0x33, 0x63, 0x79, 0x4c, 0x6b, 0x31, 0x75, 0x58, 0x42, + 0x50, 0x59, 0x2f, 0x6f, 0x6b, 0x2b, 0x6d, 0x79, 0x44, 0x6a, 0x45, 0x65, + 0x64, 0x4f, 0x32, 0x50, 0x7a, 0x6d, 0x76, 0x6c, 0x32, 0x4d, 0x70, 0x57, + 0x52, 0x73, 0x58, 0x65, 0x38, 0x72, 0x4a, 0x71, 0x2b, 0x0a, 0x73, 0x65, + 0x51, 0x78, 0x49, 0x63, 0x61, 0x42, 0x6c, 0x56, 0x5a, 0x61, 0x44, 0x72, + 0x48, 0x43, 0x31, 0x4c, 0x47, 0x6d, 0x57, 0x61, 0x7a, 0x78, 0x59, 0x38, + 0x75, 0x34, 0x54, 0x42, 0x31, 0x5a, 0x6b, 0x45, 0x72, 0x76, 0x6b, 0x42, + 0x59, 0x6f, 0x48, 0x31, 0x71, 0x75, 0x45, 0x50, 0x75, 0x42, 0x55, 0x44, + 0x67, 0x4d, 0x62, 0x4d, 0x7a, 0x78, 0x50, 0x63, 0x50, 0x31, 0x59, 0x2b, + 0x4f, 0x7a, 0x0a, 0x34, 0x79, 0x48, 0x4a, 0x4a, 0x44, 0x6e, 0x70, 0x2f, + 0x52, 0x56, 0x6d, 0x52, 0x76, 0x51, 0x62, 0x45, 0x64, 0x42, 0x4e, 0x63, + 0x36, 0x4e, 0x39, 0x52, 0x76, 0x6b, 0x39, 0x37, 0x61, 0x68, 0x66, 0x59, + 0x74, 0x54, 0x78, 0x50, 0x2f, 0x6a, 0x67, 0x64, 0x46, 0x63, 0x72, 0x47, + 0x4a, 0x32, 0x42, 0x74, 0x4d, 0x51, 0x6f, 0x32, 0x70, 0x53, 0x58, 0x70, + 0x58, 0x44, 0x72, 0x72, 0x42, 0x32, 0x2b, 0x0a, 0x42, 0x78, 0x48, 0x77, + 0x31, 0x64, 0x76, 0x64, 0x35, 0x59, 0x7a, 0x77, 0x31, 0x54, 0x4b, 0x77, + 0x67, 0x2b, 0x5a, 0x58, 0x34, 0x6f, 0x2b, 0x2f, 0x76, 0x71, 0x47, 0x71, + 0x76, 0x7a, 0x30, 0x64, 0x74, 0x64, 0x51, 0x34, 0x36, 0x74, 0x65, 0x77, + 0x58, 0x44, 0x70, 0x50, 0x61, 0x6a, 0x2b, 0x50, 0x77, 0x47, 0x5a, 0x73, + 0x59, 0x36, 0x72, 0x70, 0x32, 0x61, 0x51, 0x57, 0x39, 0x49, 0x48, 0x52, + 0x0a, 0x6c, 0x52, 0x51, 0x4f, 0x66, 0x63, 0x32, 0x56, 0x4e, 0x4e, 0x6e, + 0x53, 0x6a, 0x33, 0x42, 0x7a, 0x67, 0x58, 0x75, 0x63, 0x66, 0x72, 0x32, + 0x59, 0x59, 0x64, 0x68, 0x46, 0x68, 0x35, 0x69, 0x51, 0x78, 0x65, 0x75, + 0x47, 0x4d, 0x4d, 0x59, 0x31, 0x76, 0x2f, 0x44, 0x2f, 0x77, 0x31, 0x57, + 0x49, 0x67, 0x30, 0x76, 0x76, 0x42, 0x5a, 0x49, 0x47, 0x63, 0x66, 0x4b, + 0x34, 0x6d, 0x4a, 0x4f, 0x33, 0x0a, 0x37, 0x4d, 0x32, 0x43, 0x59, 0x66, + 0x45, 0x34, 0x35, 0x6b, 0x2b, 0x58, 0x6d, 0x43, 0x70, 0x61, 0x6a, 0x51, + 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, + 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, + 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x34, 0x20, 0x4f, 0x3d, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, + 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, + 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, + 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x34, 0x20, 0x4f, 0x3d, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x20, 0x4f, 0x55, 0x3d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, + 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, + 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, + 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, + 0x20, 0x47, 0x34, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x36, 0x33, 0x31, 0x34, 0x33, 0x34, 0x38, 0x34, 0x33, + 0x34, 0x38, 0x31, 0x35, 0x33, 0x35, 0x30, 0x36, 0x36, 0x36, 0x35, 0x33, + 0x31, 0x31, 0x39, 0x38, 0x35, 0x35, 0x30, 0x31, 0x34, 0x35, 0x38, 0x36, + 0x34, 0x30, 0x30, 0x35, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x33, 0x61, 0x3a, 0x35, 0x32, 0x3a, 0x65, 0x31, 0x3a, 0x65, 0x37, + 0x3a, 0x66, 0x64, 0x3a, 0x36, 0x66, 0x3a, 0x33, 0x61, 0x3a, 0x65, 0x33, + 0x3a, 0x36, 0x66, 0x3a, 0x66, 0x33, 0x3a, 0x36, 0x66, 0x3a, 0x39, 0x39, + 0x3a, 0x31, 0x62, 0x3a, 0x66, 0x39, 0x3a, 0x32, 0x32, 0x3a, 0x34, 0x31, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x32, 0x3a, + 0x64, 0x35, 0x3a, 0x64, 0x38, 0x3a, 0x64, 0x66, 0x3a, 0x38, 0x66, 0x3a, + 0x30, 0x32, 0x3a, 0x33, 0x31, 0x3a, 0x64, 0x31, 0x3a, 0x38, 0x64, 0x3a, + 0x66, 0x37, 0x3a, 0x39, 0x64, 0x3a, 0x62, 0x37, 0x3a, 0x63, 0x66, 0x3a, + 0x38, 0x61, 0x3a, 0x32, 0x64, 0x3a, 0x36, 0x34, 0x3a, 0x63, 0x39, 0x3a, + 0x33, 0x66, 0x3a, 0x36, 0x63, 0x3a, 0x33, 0x61, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x39, 0x3a, 0x64, 0x64, + 0x3a, 0x64, 0x37, 0x3a, 0x65, 0x61, 0x3a, 0x39, 0x30, 0x3a, 0x62, 0x62, + 0x3a, 0x35, 0x37, 0x3a, 0x63, 0x39, 0x3a, 0x33, 0x65, 0x3a, 0x31, 0x33, + 0x3a, 0x35, 0x64, 0x3a, 0x63, 0x38, 0x3a, 0x35, 0x65, 0x3a, 0x61, 0x36, + 0x3a, 0x66, 0x63, 0x3a, 0x64, 0x35, 0x3a, 0x34, 0x38, 0x3a, 0x30, 0x62, + 0x3a, 0x36, 0x30, 0x3a, 0x33, 0x32, 0x3a, 0x33, 0x39, 0x3a, 0x62, 0x64, + 0x3a, 0x63, 0x34, 0x3a, 0x35, 0x34, 0x3a, 0x66, 0x63, 0x3a, 0x37, 0x35, + 0x3a, 0x38, 0x62, 0x3a, 0x32, 0x61, 0x3a, 0x32, 0x36, 0x3a, 0x63, 0x66, + 0x3a, 0x37, 0x66, 0x3a, 0x37, 0x39, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x44, 0x68, 0x44, 0x43, 0x43, 0x41, 0x77, 0x71, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x4c, 0x34, 0x44, 0x2b, 0x49, + 0x34, 0x77, 0x4f, 0x49, 0x67, 0x39, 0x49, 0x5a, 0x78, 0x49, 0x6f, 0x6b, + 0x59, 0x65, 0x73, 0x73, 0x7a, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, + 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x7a, 0x43, 0x42, 0x79, + 0x6a, 0x45, 0x4c, 0x0a, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x7a, 0x41, 0x56, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x6c, 0x5a, 0x6c, + 0x63, 0x6d, 0x6c, 0x54, 0x61, 0x57, 0x64, 0x75, 0x4c, 0x43, 0x42, 0x4a, + 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x52, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x5a, 0x57, 0x0a, 0x5a, 0x58, 0x4a, + 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x55, 0x63, 0x6e, 0x56, + 0x7a, 0x64, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, + 0x72, 0x4d, 0x54, 0x6f, 0x77, 0x4f, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x4c, 0x45, 0x7a, 0x45, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x6a, 0x41, + 0x77, 0x4e, 0x79, 0x42, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, + 0x6e, 0x0a, 0x62, 0x69, 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x69, + 0x41, 0x74, 0x49, 0x45, 0x5a, 0x76, 0x63, 0x69, 0x42, 0x68, 0x64, 0x58, + 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x65, 0x6d, 0x56, 0x6b, 0x49, 0x48, + 0x56, 0x7a, 0x5a, 0x53, 0x42, 0x76, 0x62, 0x6d, 0x78, 0x35, 0x4d, 0x55, + 0x55, 0x77, 0x51, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x7a, + 0x78, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x0a, 0x55, 0x32, 0x6c, 0x6e, 0x62, + 0x69, 0x42, 0x44, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, 0x41, 0x7a, 0x49, + 0x46, 0x42, 0x31, 0x59, 0x6d, 0x78, 0x70, 0x59, 0x79, 0x42, 0x51, 0x63, + 0x6d, 0x6c, 0x74, 0x59, 0x58, 0x4a, 0x35, 0x49, 0x45, 0x4e, 0x6c, 0x63, + 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, + 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x0a, + 0x61, 0x58, 0x52, 0x35, 0x49, 0x43, 0x30, 0x67, 0x52, 0x7a, 0x51, 0x77, + 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x63, 0x78, 0x4d, 0x54, 0x41, 0x31, + 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, + 0x4d, 0x7a, 0x67, 0x77, 0x4d, 0x54, 0x45, 0x34, 0x4d, 0x6a, 0x4d, 0x31, + 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, 0x43, 0x42, 0x79, 0x6a, 0x45, 0x4c, + 0x4d, 0x41, 0x6b, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x7a, 0x41, 0x56, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x6c, 0x5a, 0x6c, 0x63, 0x6d, 0x6c, + 0x54, 0x61, 0x57, 0x64, 0x75, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, + 0x75, 0x4d, 0x52, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x4c, 0x45, 0x78, 0x5a, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x0a, 0x55, 0x32, + 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, + 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x4d, 0x54, + 0x6f, 0x77, 0x4f, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x7a, + 0x45, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x6a, 0x41, 0x77, 0x4e, 0x79, + 0x42, 0x57, 0x5a, 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, + 0x77, 0x67, 0x0a, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x69, 0x41, 0x74, 0x49, + 0x45, 0x5a, 0x76, 0x63, 0x69, 0x42, 0x68, 0x64, 0x58, 0x52, 0x6f, 0x62, + 0x33, 0x4a, 0x70, 0x65, 0x6d, 0x56, 0x6b, 0x49, 0x48, 0x56, 0x7a, 0x5a, + 0x53, 0x42, 0x76, 0x62, 0x6d, 0x78, 0x35, 0x4d, 0x55, 0x55, 0x77, 0x51, + 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x7a, 0x78, 0x57, 0x5a, + 0x58, 0x4a, 0x70, 0x55, 0x32, 0x6c, 0x6e, 0x0a, 0x62, 0x69, 0x42, 0x44, + 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, 0x41, 0x7a, 0x49, 0x46, 0x42, 0x31, + 0x59, 0x6d, 0x78, 0x70, 0x59, 0x79, 0x42, 0x51, 0x63, 0x6d, 0x6c, 0x74, + 0x59, 0x58, 0x4a, 0x35, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, + 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, + 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, + 0x0a, 0x49, 0x43, 0x30, 0x67, 0x52, 0x7a, 0x51, 0x77, 0x64, 0x6a, 0x41, + 0x51, 0x42, 0x67, 0x63, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x49, + 0x42, 0x42, 0x67, 0x55, 0x72, 0x67, 0x51, 0x51, 0x41, 0x49, 0x67, 0x4e, + 0x69, 0x41, 0x41, 0x53, 0x6e, 0x56, 0x6e, 0x70, 0x38, 0x55, 0x74, 0x70, + 0x6b, 0x6d, 0x77, 0x34, 0x74, 0x58, 0x4e, 0x68, 0x65, 0x72, 0x4a, 0x49, + 0x39, 0x2f, 0x67, 0x48, 0x6d, 0x0a, 0x47, 0x55, 0x6f, 0x39, 0x46, 0x41, + 0x4e, 0x4c, 0x2b, 0x6d, 0x41, 0x6e, 0x49, 0x4e, 0x6d, 0x44, 0x69, 0x57, + 0x6e, 0x36, 0x56, 0x4d, 0x61, 0x61, 0x47, 0x46, 0x35, 0x56, 0x4b, 0x6d, + 0x54, 0x65, 0x42, 0x76, 0x61, 0x4e, 0x53, 0x6a, 0x75, 0x74, 0x45, 0x44, + 0x78, 0x6c, 0x50, 0x5a, 0x43, 0x49, 0x42, 0x49, 0x6e, 0x67, 0x4d, 0x47, + 0x47, 0x7a, 0x72, 0x6c, 0x30, 0x42, 0x70, 0x33, 0x76, 0x65, 0x0a, 0x66, + 0x4c, 0x4b, 0x2b, 0x79, 0x6d, 0x56, 0x68, 0x41, 0x49, 0x61, 0x75, 0x32, + 0x6f, 0x39, 0x37, 0x30, 0x49, 0x6d, 0x74, 0x54, 0x52, 0x31, 0x5a, 0x6d, + 0x6b, 0x47, 0x78, 0x76, 0x45, 0x65, 0x41, 0x33, 0x4a, 0x35, 0x69, 0x77, + 0x2f, 0x6d, 0x6a, 0x67, 0x62, 0x49, 0x77, 0x67, 0x61, 0x38, 0x77, 0x44, + 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, + 0x41, 0x55, 0x77, 0x0a, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f, + 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, + 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x62, 0x51, 0x59, 0x49, + 0x4b, 0x77, 0x59, 0x42, 0x42, 0x51, 0x55, 0x48, 0x41, 0x51, 0x77, 0x45, + 0x59, 0x54, 0x42, 0x66, 0x6f, 0x56, 0x32, 0x67, 0x57, 0x7a, 0x42, 0x5a, + 0x4d, 0x46, 0x63, 0x77, 0x56, 0x52, 0x59, 0x4a, 0x0a, 0x61, 0x57, 0x31, + 0x68, 0x5a, 0x32, 0x55, 0x76, 0x5a, 0x32, 0x6c, 0x6d, 0x4d, 0x43, 0x45, + 0x77, 0x48, 0x7a, 0x41, 0x48, 0x42, 0x67, 0x55, 0x72, 0x44, 0x67, 0x4d, + 0x43, 0x47, 0x67, 0x51, 0x55, 0x6a, 0x2b, 0x58, 0x54, 0x47, 0x6f, 0x61, + 0x73, 0x6a, 0x59, 0x35, 0x72, 0x77, 0x38, 0x2b, 0x41, 0x61, 0x74, 0x52, + 0x49, 0x47, 0x43, 0x78, 0x37, 0x47, 0x53, 0x34, 0x77, 0x4a, 0x52, 0x59, + 0x6a, 0x0a, 0x61, 0x48, 0x52, 0x30, 0x63, 0x44, 0x6f, 0x76, 0x4c, 0x32, + 0x78, 0x76, 0x5a, 0x32, 0x38, 0x75, 0x64, 0x6d, 0x56, 0x79, 0x61, 0x58, + 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x33, + 0x5a, 0x7a, 0x62, 0x47, 0x39, 0x6e, 0x62, 0x79, 0x35, 0x6e, 0x61, 0x57, + 0x59, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, + 0x59, 0x45, 0x46, 0x4c, 0x4d, 0x57, 0x0a, 0x6b, 0x66, 0x33, 0x75, 0x70, + 0x6d, 0x37, 0x6b, 0x74, 0x53, 0x35, 0x4a, 0x6a, 0x34, 0x64, 0x34, 0x67, + 0x59, 0x44, 0x73, 0x35, 0x62, 0x47, 0x31, 0x4d, 0x41, 0x6f, 0x47, 0x43, + 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x44, 0x41, + 0x32, 0x67, 0x41, 0x4d, 0x47, 0x55, 0x43, 0x4d, 0x47, 0x59, 0x68, 0x44, + 0x42, 0x67, 0x6d, 0x59, 0x46, 0x6f, 0x34, 0x65, 0x31, 0x5a, 0x43, 0x0a, + 0x34, 0x4b, 0x66, 0x38, 0x4e, 0x6f, 0x52, 0x52, 0x6b, 0x53, 0x41, 0x73, + 0x64, 0x6b, 0x31, 0x44, 0x50, 0x63, 0x51, 0x64, 0x68, 0x43, 0x50, 0x51, + 0x72, 0x4e, 0x5a, 0x38, 0x4e, 0x51, 0x62, 0x4f, 0x7a, 0x57, 0x6d, 0x39, + 0x6b, 0x41, 0x33, 0x62, 0x62, 0x45, 0x68, 0x43, 0x48, 0x51, 0x36, 0x71, + 0x51, 0x67, 0x49, 0x78, 0x41, 0x4a, 0x77, 0x39, 0x53, 0x44, 0x6b, 0x6a, + 0x4f, 0x56, 0x67, 0x61, 0x0a, 0x46, 0x52, 0x4a, 0x5a, 0x61, 0x70, 0x37, + 0x76, 0x31, 0x56, 0x6d, 0x79, 0x48, 0x56, 0x49, 0x73, 0x6d, 0x58, 0x48, + 0x4e, 0x78, 0x79, 0x6e, 0x66, 0x47, 0x79, 0x70, 0x68, 0x65, 0x33, 0x48, + 0x52, 0x33, 0x76, 0x50, 0x41, 0x35, 0x51, 0x30, 0x36, 0x53, 0x71, 0x6f, + 0x74, 0x70, 0x39, 0x69, 0x47, 0x4b, 0x74, 0x30, 0x75, 0x45, 0x41, 0x3d, + 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x4e, 0x65, 0x74, 0x4c, 0x6f, 0x63, + 0x6b, 0x20, 0x41, 0x72, 0x61, 0x6e, 0x79, 0x20, 0x28, 0x43, 0x6c, 0x61, + 0x73, 0x73, 0x20, 0x47, 0x6f, 0x6c, 0x64, 0x29, 0x20, 0x46, 0xc5, 0x91, + 0x74, 0x61, 0x6e, 0xc3, 0xba, 0x73, 0xc3, 0xad, 0x74, 0x76, 0xc3, 0xa1, + 0x6e, 0x79, 0x20, 0x4f, 0x3d, 0x4e, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x6b, + 0x20, 0x4b, 0x66, 0x74, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x54, 0x61, 0x6e, + 0xc3, 0xba, 0x73, 0xc3, 0xad, 0x74, 0x76, 0xc3, 0xa1, 0x6e, 0x79, 0x6b, + 0x69, 0x61, 0x64, 0xc3, 0xb3, 0x6b, 0x20, 0x28, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x29, 0x0a, 0x23, 0x20, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x4e, 0x65, + 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x20, 0x41, 0x72, 0x61, 0x6e, 0x79, 0x20, + 0x28, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x47, 0x6f, 0x6c, 0x64, 0x29, + 0x20, 0x46, 0xc5, 0x91, 0x74, 0x61, 0x6e, 0xc3, 0xba, 0x73, 0xc3, 0xad, + 0x74, 0x76, 0xc3, 0xa1, 0x6e, 0x79, 0x20, 0x4f, 0x3d, 0x4e, 0x65, 0x74, + 0x4c, 0x6f, 0x63, 0x6b, 0x20, 0x4b, 0x66, 0x74, 0x2e, 0x20, 0x4f, 0x55, + 0x3d, 0x54, 0x61, 0x6e, 0xc3, 0xba, 0x73, 0xc3, 0xad, 0x74, 0x76, 0xc3, + 0xa1, 0x6e, 0x79, 0x6b, 0x69, 0x61, 0x64, 0xc3, 0xb3, 0x6b, 0x20, 0x28, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x29, 0x0a, + 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x4e, 0x65, + 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x20, 0x41, 0x72, 0x61, 0x6e, 0x79, 0x20, + 0x28, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x47, 0x6f, 0x6c, 0x64, 0x29, + 0x20, 0x46, 0xc5, 0x91, 0x74, 0x61, 0x6e, 0xc3, 0xba, 0x73, 0xc3, 0xad, + 0x74, 0x76, 0xc3, 0xa1, 0x6e, 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x38, 0x30, 0x35, 0x34, 0x34, 0x32, + 0x37, 0x34, 0x38, 0x34, 0x31, 0x36, 0x31, 0x36, 0x0a, 0x23, 0x20, 0x4d, + 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x35, 0x3a, 0x61, 0x31, 0x3a, 0x62, 0x37, + 0x3a, 0x66, 0x66, 0x3a, 0x37, 0x33, 0x3a, 0x64, 0x64, 0x3a, 0x64, 0x36, + 0x3a, 0x64, 0x37, 0x3a, 0x33, 0x34, 0x3a, 0x33, 0x32, 0x3a, 0x31, 0x38, + 0x3a, 0x64, 0x66, 0x3a, 0x66, 0x63, 0x3a, 0x33, 0x63, 0x3a, 0x61, 0x64, + 0x3a, 0x38, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x30, 0x36, 0x3a, 0x30, 0x38, 0x3a, 0x33, 0x66, 0x3a, 0x35, 0x39, 0x3a, + 0x33, 0x66, 0x3a, 0x31, 0x35, 0x3a, 0x61, 0x31, 0x3a, 0x30, 0x34, 0x3a, + 0x61, 0x30, 0x3a, 0x36, 0x39, 0x3a, 0x61, 0x34, 0x3a, 0x36, 0x62, 0x3a, + 0x61, 0x39, 0x3a, 0x30, 0x33, 0x3a, 0x64, 0x30, 0x3a, 0x30, 0x36, 0x3a, + 0x62, 0x37, 0x3a, 0x39, 0x37, 0x3a, 0x30, 0x39, 0x3a, 0x39, 0x31, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x63, + 0x3a, 0x36, 0x31, 0x3a, 0x64, 0x61, 0x3a, 0x63, 0x33, 0x3a, 0x61, 0x32, + 0x3a, 0x64, 0x65, 0x3a, 0x66, 0x30, 0x3a, 0x33, 0x31, 0x3a, 0x35, 0x30, + 0x3a, 0x36, 0x62, 0x3a, 0x65, 0x30, 0x3a, 0x33, 0x36, 0x3a, 0x64, 0x32, + 0x3a, 0x61, 0x36, 0x3a, 0x66, 0x65, 0x3a, 0x34, 0x30, 0x3a, 0x31, 0x39, + 0x3a, 0x39, 0x34, 0x3a, 0x66, 0x62, 0x3a, 0x64, 0x31, 0x3a, 0x33, 0x64, + 0x3a, 0x66, 0x39, 0x3a, 0x63, 0x38, 0x3a, 0x64, 0x34, 0x3a, 0x36, 0x36, + 0x3a, 0x35, 0x39, 0x3a, 0x39, 0x32, 0x3a, 0x37, 0x34, 0x3a, 0x63, 0x34, + 0x3a, 0x34, 0x36, 0x3a, 0x65, 0x63, 0x3a, 0x39, 0x38, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x46, 0x54, 0x43, 0x43, 0x41, 0x76, + 0x32, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x47, 0x53, 0x55, + 0x45, 0x73, 0x35, 0x41, 0x41, 0x51, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, + 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, + 0x55, 0x41, 0x4d, 0x49, 0x47, 0x6e, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x0a, 0x45, 0x77, 0x4a, 0x49, 0x56, + 0x54, 0x45, 0x52, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x77, 0x77, 0x49, 0x51, 0x6e, 0x56, 0x6b, 0x59, 0x58, 0x42, 0x6c, 0x63, + 0x33, 0x51, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x6f, 0x4d, 0x44, 0x45, 0x35, 0x6c, 0x64, 0x45, 0x78, 0x76, 0x59, + 0x32, 0x73, 0x67, 0x53, 0x32, 0x5a, 0x30, 0x4c, 0x6a, 0x45, 0x33, 0x0a, + 0x4d, 0x44, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x77, 0x77, 0x75, + 0x56, 0x47, 0x46, 0x75, 0x77, 0x37, 0x70, 0x7a, 0x77, 0x36, 0x31, 0x30, + 0x64, 0x73, 0x4f, 0x68, 0x62, 0x6e, 0x6c, 0x72, 0x61, 0x57, 0x46, 0x6b, + 0x77, 0x37, 0x4e, 0x72, 0x49, 0x43, 0x68, 0x44, 0x5a, 0x58, 0x4a, 0x30, + 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, + 0x49, 0x46, 0x4e, 0x6c, 0x0a, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, + 0x7a, 0x4b, 0x54, 0x45, 0x31, 0x4d, 0x44, 0x4d, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x41, 0x77, 0x77, 0x73, 0x54, 0x6d, 0x56, 0x30, 0x54, 0x47, 0x39, + 0x6a, 0x61, 0x79, 0x42, 0x42, 0x63, 0x6d, 0x46, 0x75, 0x65, 0x53, 0x41, + 0x6f, 0x51, 0x32, 0x78, 0x68, 0x63, 0x33, 0x4d, 0x67, 0x52, 0x32, 0x39, + 0x73, 0x5a, 0x43, 0x6b, 0x67, 0x52, 0x73, 0x57, 0x52, 0x0a, 0x64, 0x47, + 0x46, 0x75, 0x77, 0x37, 0x70, 0x7a, 0x77, 0x36, 0x31, 0x30, 0x64, 0x73, + 0x4f, 0x68, 0x62, 0x6e, 0x6b, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, + 0x67, 0x78, 0x4d, 0x6a, 0x45, 0x78, 0x4d, 0x54, 0x55, 0x77, 0x4f, 0x44, + 0x49, 0x78, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x67, 0x78, 0x4d, 0x6a, + 0x41, 0x32, 0x4d, 0x54, 0x55, 0x77, 0x4f, 0x44, 0x49, 0x78, 0x57, 0x6a, + 0x43, 0x42, 0x0a, 0x70, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x53, 0x46, 0x55, 0x78, 0x45, + 0x54, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x4d, 0x43, + 0x45, 0x4a, 0x31, 0x5a, 0x47, 0x46, 0x77, 0x5a, 0x58, 0x4e, 0x30, 0x4d, + 0x52, 0x55, 0x77, 0x45, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, + 0x41, 0x78, 0x4f, 0x5a, 0x58, 0x52, 0x4d, 0x0a, 0x62, 0x32, 0x4e, 0x72, + 0x49, 0x45, 0x74, 0x6d, 0x64, 0x43, 0x34, 0x78, 0x4e, 0x7a, 0x41, 0x31, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x4d, 0x4c, 0x6c, 0x52, 0x68, + 0x62, 0x73, 0x4f, 0x36, 0x63, 0x38, 0x4f, 0x74, 0x64, 0x48, 0x62, 0x44, + 0x6f, 0x57, 0x35, 0x35, 0x61, 0x32, 0x6c, 0x68, 0x5a, 0x4d, 0x4f, 0x7a, + 0x61, 0x79, 0x41, 0x6f, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, + 0x0a, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, + 0x54, 0x5a, 0x58, 0x4a, 0x32, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x79, 0x6b, + 0x78, 0x4e, 0x54, 0x41, 0x7a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, + 0x4d, 0x4c, 0x45, 0x35, 0x6c, 0x64, 0x45, 0x78, 0x76, 0x59, 0x32, 0x73, + 0x67, 0x51, 0x58, 0x4a, 0x68, 0x62, 0x6e, 0x6b, 0x67, 0x4b, 0x45, 0x4e, + 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x0a, 0x49, 0x45, 0x64, 0x76, 0x62, 0x47, + 0x51, 0x70, 0x49, 0x45, 0x62, 0x46, 0x6b, 0x58, 0x52, 0x68, 0x62, 0x73, + 0x4f, 0x36, 0x63, 0x38, 0x4f, 0x74, 0x64, 0x48, 0x62, 0x44, 0x6f, 0x57, + 0x35, 0x35, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x0a, 0x4d, + 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x78, + 0x43, 0x52, 0x65, 0x63, 0x37, 0x35, 0x4c, 0x62, 0x52, 0x54, 0x44, 0x6f, + 0x66, 0x54, 0x6a, 0x6c, 0x35, 0x42, 0x75, 0x30, 0x6a, 0x42, 0x46, 0x48, + 0x6a, 0x7a, 0x75, 0x5a, 0x39, 0x6c, 0x6b, 0x34, 0x42, 0x71, 0x4b, 0x66, + 0x38, 0x6f, 0x77, 0x79, 0x6f, 0x50, 0x6a, 0x49, 0x4d, 0x48, 0x6a, 0x39, + 0x44, 0x72, 0x54, 0x0a, 0x6c, 0x46, 0x38, 0x61, 0x66, 0x46, 0x74, 0x74, + 0x76, 0x7a, 0x42, 0x50, 0x68, 0x43, 0x66, 0x32, 0x6e, 0x78, 0x39, 0x4a, + 0x76, 0x4d, 0x61, 0x5a, 0x43, 0x70, 0x44, 0x79, 0x44, 0x2f, 0x56, 0x2f, + 0x51, 0x34, 0x51, 0x33, 0x59, 0x31, 0x47, 0x4c, 0x65, 0x71, 0x56, 0x77, + 0x2f, 0x48, 0x70, 0x59, 0x7a, 0x59, 0x36, 0x62, 0x37, 0x63, 0x4e, 0x47, + 0x62, 0x49, 0x52, 0x77, 0x58, 0x64, 0x72, 0x7a, 0x0a, 0x41, 0x5a, 0x41, + 0x6a, 0x2f, 0x45, 0x34, 0x77, 0x71, 0x58, 0x37, 0x68, 0x4a, 0x32, 0x50, + 0x6e, 0x37, 0x57, 0x51, 0x38, 0x6f, 0x4c, 0x6a, 0x4a, 0x4d, 0x32, 0x50, + 0x2b, 0x46, 0x70, 0x44, 0x2f, 0x73, 0x4c, 0x6a, 0x39, 0x31, 0x36, 0x6a, + 0x41, 0x77, 0x4a, 0x52, 0x44, 0x43, 0x37, 0x62, 0x56, 0x57, 0x61, 0x61, + 0x65, 0x56, 0x74, 0x41, 0x6b, 0x48, 0x33, 0x42, 0x35, 0x72, 0x39, 0x73, + 0x35, 0x0a, 0x56, 0x41, 0x31, 0x6c, 0x64, 0x64, 0x6b, 0x56, 0x51, 0x5a, + 0x51, 0x42, 0x72, 0x31, 0x37, 0x73, 0x39, 0x6f, 0x33, 0x78, 0x2f, 0x36, + 0x31, 0x6b, 0x2f, 0x69, 0x43, 0x61, 0x31, 0x31, 0x7a, 0x72, 0x2f, 0x71, + 0x59, 0x66, 0x43, 0x47, 0x53, 0x6a, 0x69, 0x33, 0x5a, 0x56, 0x72, 0x52, + 0x34, 0x37, 0x4b, 0x47, 0x41, 0x75, 0x68, 0x79, 0x58, 0x6f, 0x71, 0x71, + 0x38, 0x66, 0x78, 0x6d, 0x52, 0x47, 0x0a, 0x49, 0x4c, 0x64, 0x77, 0x66, + 0x7a, 0x7a, 0x65, 0x53, 0x4e, 0x75, 0x57, 0x55, 0x37, 0x63, 0x35, 0x64, + 0x2b, 0x51, 0x61, 0x34, 0x73, 0x63, 0x57, 0x68, 0x48, 0x61, 0x58, 0x57, + 0x79, 0x2b, 0x37, 0x47, 0x52, 0x57, 0x46, 0x2b, 0x47, 0x6d, 0x46, 0x39, + 0x5a, 0x6d, 0x6e, 0x71, 0x66, 0x49, 0x30, 0x70, 0x36, 0x6d, 0x32, 0x70, + 0x67, 0x50, 0x38, 0x62, 0x34, 0x59, 0x39, 0x56, 0x48, 0x78, 0x32, 0x0a, + 0x42, 0x4a, 0x74, 0x72, 0x2b, 0x55, 0x42, 0x64, 0x41, 0x44, 0x54, 0x48, + 0x4c, 0x70, 0x6c, 0x31, 0x6e, 0x65, 0x57, 0x49, 0x41, 0x36, 0x70, 0x4e, + 0x2b, 0x41, 0x50, 0x53, 0x51, 0x6e, 0x62, 0x41, 0x47, 0x77, 0x49, 0x44, + 0x41, 0x4b, 0x69, 0x4c, 0x6f, 0x30, 0x55, 0x77, 0x51, 0x7a, 0x41, 0x53, + 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, + 0x43, 0x44, 0x41, 0x47, 0x0a, 0x41, 0x51, 0x48, 0x2f, 0x41, 0x67, 0x45, + 0x45, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, + 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, + 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, + 0x55, 0x7a, 0x50, 0x70, 0x6e, 0x6b, 0x2f, 0x43, 0x32, 0x75, 0x4e, 0x43, + 0x6c, 0x77, 0x42, 0x37, 0x7a, 0x55, 0x2f, 0x32, 0x4d, 0x0a, 0x55, 0x39, + 0x2b, 0x44, 0x31, 0x35, 0x59, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, + 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, + 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4b, 0x74, 0x2f, 0x37, 0x68, + 0x77, 0x57, 0x71, 0x5a, 0x77, 0x38, 0x55, 0x51, 0x43, 0x67, 0x77, 0x42, + 0x45, 0x49, 0x42, 0x61, 0x65, 0x5a, 0x35, 0x6d, 0x38, 0x42, 0x69, 0x46, + 0x52, 0x68, 0x0a, 0x62, 0x76, 0x47, 0x35, 0x47, 0x4b, 0x31, 0x4b, 0x72, + 0x66, 0x36, 0x42, 0x51, 0x43, 0x4f, 0x55, 0x4c, 0x2f, 0x74, 0x31, 0x66, + 0x43, 0x38, 0x6f, 0x53, 0x32, 0x49, 0x6b, 0x67, 0x59, 0x49, 0x4c, 0x39, + 0x57, 0x48, 0x78, 0x48, 0x47, 0x36, 0x34, 0x59, 0x54, 0x6a, 0x72, 0x67, + 0x66, 0x70, 0x69, 0x6f, 0x54, 0x74, 0x61, 0x59, 0x74, 0x4f, 0x55, 0x5a, + 0x63, 0x54, 0x68, 0x35, 0x6d, 0x32, 0x43, 0x0a, 0x2b, 0x43, 0x38, 0x6c, + 0x63, 0x4c, 0x49, 0x68, 0x4a, 0x73, 0x46, 0x79, 0x55, 0x52, 0x2b, 0x4d, + 0x4c, 0x4d, 0x4f, 0x45, 0x6b, 0x4d, 0x4e, 0x61, 0x6a, 0x37, 0x72, 0x50, + 0x39, 0x4b, 0x64, 0x6c, 0x70, 0x65, 0x75, 0x59, 0x30, 0x66, 0x73, 0x46, + 0x73, 0x6b, 0x5a, 0x31, 0x46, 0x53, 0x4e, 0x71, 0x62, 0x34, 0x56, 0x6a, + 0x4d, 0x49, 0x44, 0x77, 0x31, 0x5a, 0x34, 0x66, 0x4b, 0x52, 0x7a, 0x43, + 0x0a, 0x62, 0x4c, 0x42, 0x51, 0x57, 0x56, 0x32, 0x51, 0x57, 0x7a, 0x75, + 0x6f, 0x44, 0x54, 0x44, 0x50, 0x76, 0x33, 0x31, 0x2f, 0x7a, 0x76, 0x47, + 0x64, 0x67, 0x37, 0x33, 0x4a, 0x52, 0x6d, 0x34, 0x67, 0x70, 0x76, 0x6c, + 0x68, 0x55, 0x62, 0x6f, 0x68, 0x4c, 0x33, 0x75, 0x2b, 0x70, 0x52, 0x56, + 0x6a, 0x6f, 0x64, 0x53, 0x56, 0x68, 0x2f, 0x47, 0x65, 0x75, 0x66, 0x4f, + 0x4a, 0x38, 0x7a, 0x32, 0x46, 0x0a, 0x75, 0x4c, 0x6a, 0x62, 0x76, 0x72, + 0x57, 0x35, 0x4b, 0x66, 0x6e, 0x61, 0x4e, 0x77, 0x55, 0x41, 0x53, 0x5a, + 0x51, 0x44, 0x68, 0x45, 0x54, 0x6e, 0x76, 0x30, 0x4d, 0x78, 0x7a, 0x33, + 0x57, 0x4c, 0x4a, 0x64, 0x48, 0x30, 0x70, 0x6d, 0x54, 0x31, 0x6b, 0x76, + 0x61, 0x72, 0x42, 0x65, 0x73, 0x39, 0x36, 0x61, 0x55, 0x4c, 0x4e, 0x6d, + 0x4c, 0x61, 0x7a, 0x41, 0x5a, 0x66, 0x4e, 0x6f, 0x75, 0x32, 0x0a, 0x58, + 0x6a, 0x47, 0x34, 0x4b, 0x76, 0x74, 0x65, 0x39, 0x6e, 0x48, 0x66, 0x52, + 0x43, 0x61, 0x65, 0x78, 0x4f, 0x59, 0x4e, 0x6b, 0x62, 0x51, 0x75, 0x64, + 0x5a, 0x57, 0x41, 0x55, 0x57, 0x70, 0x4c, 0x4d, 0x4b, 0x61, 0x77, 0x59, + 0x71, 0x47, 0x54, 0x38, 0x5a, 0x76, 0x59, 0x7a, 0x73, 0x52, 0x6a, 0x64, + 0x54, 0x39, 0x5a, 0x52, 0x37, 0x45, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, + 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x53, 0x74, 0x61, 0x61, 0x74, 0x20, 0x64, 0x65, 0x72, 0x20, 0x4e, 0x65, + 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x65, 0x6e, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, + 0x3d, 0x53, 0x74, 0x61, 0x61, 0x74, 0x20, 0x64, 0x65, 0x72, 0x20, 0x4e, + 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x65, 0x6e, 0x0a, 0x23, + 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x53, 0x74, 0x61, 0x61, 0x74, 0x20, 0x64, 0x65, 0x72, 0x20, 0x4e, + 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x65, 0x6e, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, + 0x4f, 0x3d, 0x53, 0x74, 0x61, 0x61, 0x74, 0x20, 0x64, 0x65, 0x72, 0x20, + 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x65, 0x6e, 0x0a, + 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x53, 0x74, + 0x61, 0x61, 0x74, 0x20, 0x64, 0x65, 0x72, 0x20, 0x4e, 0x65, 0x64, 0x65, + 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x65, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x22, 0x0a, 0x23, 0x20, + 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x31, 0x32, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x37, 0x63, 0x3a, 0x61, 0x35, 0x3a, 0x30, 0x66, 0x3a, 0x66, 0x38, 0x3a, + 0x35, 0x62, 0x3a, 0x39, 0x61, 0x3a, 0x37, 0x64, 0x3a, 0x36, 0x64, 0x3a, + 0x33, 0x30, 0x3a, 0x61, 0x65, 0x3a, 0x35, 0x34, 0x3a, 0x35, 0x61, 0x3a, + 0x65, 0x33, 0x3a, 0x34, 0x32, 0x3a, 0x61, 0x32, 0x3a, 0x38, 0x61, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x39, 0x3a, 0x61, + 0x66, 0x3a, 0x38, 0x32, 0x3a, 0x37, 0x39, 0x3a, 0x39, 0x31, 0x3a, 0x38, + 0x36, 0x3a, 0x63, 0x37, 0x3a, 0x62, 0x34, 0x3a, 0x37, 0x35, 0x3a, 0x30, + 0x37, 0x3a, 0x63, 0x62, 0x3a, 0x63, 0x66, 0x3a, 0x30, 0x33, 0x3a, 0x35, + 0x37, 0x3a, 0x34, 0x36, 0x3a, 0x65, 0x62, 0x3a, 0x30, 0x34, 0x3a, 0x64, + 0x64, 0x3a, 0x62, 0x37, 0x3a, 0x31, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x36, 0x3a, 0x38, 0x63, 0x3a, + 0x38, 0x33, 0x3a, 0x39, 0x34, 0x3a, 0x37, 0x64, 0x3a, 0x61, 0x36, 0x3a, + 0x33, 0x62, 0x3a, 0x37, 0x32, 0x3a, 0x34, 0x62, 0x3a, 0x65, 0x63, 0x3a, + 0x65, 0x31, 0x3a, 0x37, 0x34, 0x3a, 0x33, 0x63, 0x3a, 0x33, 0x31, 0x3a, + 0x61, 0x30, 0x3a, 0x65, 0x36, 0x3a, 0x61, 0x65, 0x3a, 0x64, 0x30, 0x3a, + 0x64, 0x62, 0x3a, 0x38, 0x65, 0x3a, 0x63, 0x35, 0x3a, 0x62, 0x33, 0x3a, + 0x31, 0x62, 0x3a, 0x65, 0x33, 0x3a, 0x37, 0x37, 0x3a, 0x62, 0x62, 0x3a, + 0x37, 0x38, 0x3a, 0x34, 0x66, 0x3a, 0x39, 0x31, 0x3a, 0x62, 0x36, 0x3a, + 0x37, 0x31, 0x3a, 0x36, 0x66, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, + 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, + 0x49, 0x46, 0x79, 0x6a, 0x43, 0x43, 0x41, 0x37, 0x4b, 0x67, 0x41, 0x77, + 0x49, 0x42, 0x41, 0x67, 0x49, 0x45, 0x41, 0x4a, 0x69, 0x57, 0x6a, 0x44, + 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, + 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x61, 0x4d, 0x51, + 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, + 0x4a, 0x4f, 0x0a, 0x54, 0x44, 0x45, 0x65, 0x4d, 0x42, 0x77, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x56, 0x55, 0x33, 0x52, 0x68, 0x59, + 0x58, 0x51, 0x67, 0x5a, 0x47, 0x56, 0x79, 0x49, 0x45, 0x35, 0x6c, 0x5a, + 0x47, 0x56, 0x79, 0x62, 0x47, 0x46, 0x75, 0x5a, 0x47, 0x56, 0x75, 0x4d, + 0x53, 0x73, 0x77, 0x4b, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, + 0x43, 0x4a, 0x54, 0x64, 0x47, 0x46, 0x68, 0x0a, 0x64, 0x43, 0x42, 0x6b, + 0x5a, 0x58, 0x49, 0x67, 0x54, 0x6d, 0x56, 0x6b, 0x5a, 0x58, 0x4a, 0x73, + 0x59, 0x57, 0x35, 0x6b, 0x5a, 0x57, 0x34, 0x67, 0x55, 0x6d, 0x39, 0x76, + 0x64, 0x43, 0x42, 0x44, 0x51, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x79, + 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x34, 0x4d, 0x44, 0x4d, 0x79, + 0x4e, 0x6a, 0x45, 0x78, 0x4d, 0x54, 0x67, 0x78, 0x4e, 0x31, 0x6f, 0x58, + 0x0a, 0x44, 0x54, 0x49, 0x77, 0x4d, 0x44, 0x4d, 0x79, 0x4e, 0x54, 0x45, + 0x78, 0x4d, 0x44, 0x4d, 0x78, 0x4d, 0x46, 0x6f, 0x77, 0x57, 0x6a, 0x45, + 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x54, 0x6b, 0x77, 0x78, 0x48, 0x6a, 0x41, 0x63, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x46, 0x56, 0x4e, 0x30, 0x59, 0x57, 0x46, + 0x30, 0x49, 0x47, 0x52, 0x6c, 0x0a, 0x63, 0x69, 0x42, 0x4f, 0x5a, 0x57, + 0x52, 0x6c, 0x63, 0x6d, 0x78, 0x68, 0x62, 0x6d, 0x52, 0x6c, 0x62, 0x6a, + 0x45, 0x72, 0x4d, 0x43, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, + 0x77, 0x69, 0x55, 0x33, 0x52, 0x68, 0x59, 0x58, 0x51, 0x67, 0x5a, 0x47, + 0x56, 0x79, 0x49, 0x45, 0x35, 0x6c, 0x5a, 0x47, 0x56, 0x79, 0x62, 0x47, + 0x46, 0x75, 0x5a, 0x47, 0x56, 0x75, 0x49, 0x46, 0x4a, 0x76, 0x0a, 0x62, + 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4c, 0x53, 0x42, 0x48, 0x4d, + 0x6a, 0x43, 0x43, 0x41, 0x69, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, + 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, + 0x67, 0x6f, 0x43, 0x67, 0x67, 0x49, 0x42, 0x41, 0x4d, 0x56, 0x5a, 0x35, + 0x32, 0x39, 0x31, 0x0a, 0x71, 0x6a, 0x35, 0x4c, 0x6e, 0x4c, 0x57, 0x34, + 0x72, 0x4a, 0x34, 0x4c, 0x35, 0x50, 0x6e, 0x5a, 0x79, 0x71, 0x74, 0x64, + 0x6a, 0x37, 0x55, 0x35, 0x45, 0x49, 0x4c, 0x58, 0x72, 0x31, 0x48, 0x67, + 0x4f, 0x2b, 0x45, 0x41, 0x53, 0x47, 0x72, 0x50, 0x32, 0x75, 0x45, 0x47, + 0x51, 0x78, 0x47, 0x5a, 0x71, 0x68, 0x51, 0x6c, 0x45, 0x71, 0x30, 0x69, + 0x36, 0x41, 0x42, 0x74, 0x51, 0x38, 0x53, 0x70, 0x0a, 0x75, 0x4f, 0x55, + 0x66, 0x69, 0x55, 0x74, 0x6e, 0x76, 0x57, 0x46, 0x49, 0x37, 0x2f, 0x33, + 0x53, 0x34, 0x47, 0x43, 0x49, 0x35, 0x62, 0x6b, 0x59, 0x59, 0x43, 0x6a, + 0x44, 0x64, 0x79, 0x75, 0x74, 0x73, 0x44, 0x65, 0x71, 0x4e, 0x39, 0x35, + 0x6b, 0x57, 0x53, 0x70, 0x47, 0x56, 0x2b, 0x52, 0x4c, 0x75, 0x66, 0x67, + 0x33, 0x66, 0x4e, 0x55, 0x32, 0x35, 0x34, 0x44, 0x42, 0x74, 0x76, 0x50, + 0x55, 0x0a, 0x5a, 0x35, 0x75, 0x57, 0x36, 0x4d, 0x37, 0x58, 0x78, 0x67, + 0x70, 0x54, 0x30, 0x47, 0x74, 0x4a, 0x6c, 0x76, 0x4f, 0x6a, 0x43, 0x77, + 0x56, 0x33, 0x53, 0x50, 0x63, 0x6c, 0x35, 0x58, 0x43, 0x73, 0x4d, 0x42, + 0x51, 0x67, 0x4a, 0x65, 0x4e, 0x2f, 0x64, 0x56, 0x72, 0x6c, 0x53, 0x50, + 0x68, 0x4f, 0x65, 0x77, 0x4d, 0x48, 0x42, 0x50, 0x71, 0x43, 0x59, 0x59, + 0x64, 0x75, 0x38, 0x44, 0x76, 0x45, 0x0a, 0x70, 0x4d, 0x66, 0x51, 0x39, + 0x58, 0x51, 0x2b, 0x70, 0x56, 0x30, 0x61, 0x43, 0x50, 0x4b, 0x62, 0x4a, + 0x64, 0x4c, 0x32, 0x72, 0x41, 0x51, 0x6d, 0x50, 0x6c, 0x55, 0x36, 0x59, + 0x69, 0x69, 0x6c, 0x65, 0x37, 0x49, 0x77, 0x72, 0x2f, 0x67, 0x33, 0x77, + 0x74, 0x47, 0x36, 0x31, 0x6a, 0x6a, 0x39, 0x39, 0x4f, 0x39, 0x4a, 0x4d, + 0x44, 0x65, 0x5a, 0x4a, 0x69, 0x46, 0x49, 0x68, 0x51, 0x47, 0x70, 0x0a, + 0x35, 0x52, 0x62, 0x6e, 0x33, 0x4a, 0x42, 0x56, 0x33, 0x77, 0x2f, 0x6f, + 0x4f, 0x4d, 0x32, 0x5a, 0x4e, 0x79, 0x46, 0x50, 0x58, 0x66, 0x55, 0x69, + 0x62, 0x32, 0x72, 0x46, 0x45, 0x68, 0x5a, 0x67, 0x46, 0x31, 0x58, 0x79, + 0x5a, 0x57, 0x61, 0x6d, 0x70, 0x7a, 0x43, 0x52, 0x4f, 0x4d, 0x45, 0x34, + 0x48, 0x59, 0x59, 0x45, 0x68, 0x4c, 0x6f, 0x61, 0x4a, 0x58, 0x68, 0x65, + 0x6e, 0x61, 0x2f, 0x4d, 0x0a, 0x55, 0x47, 0x44, 0x57, 0x45, 0x34, 0x64, + 0x53, 0x37, 0x57, 0x4d, 0x66, 0x62, 0x57, 0x56, 0x39, 0x77, 0x68, 0x55, + 0x59, 0x64, 0x4d, 0x72, 0x68, 0x66, 0x6d, 0x51, 0x70, 0x6a, 0x48, 0x4c, + 0x59, 0x46, 0x68, 0x4e, 0x39, 0x43, 0x30, 0x6c, 0x4b, 0x38, 0x53, 0x67, + 0x62, 0x49, 0x48, 0x52, 0x72, 0x78, 0x54, 0x33, 0x64, 0x73, 0x4b, 0x70, + 0x49, 0x43, 0x54, 0x30, 0x75, 0x67, 0x70, 0x54, 0x4e, 0x0a, 0x47, 0x6d, + 0x58, 0x5a, 0x4b, 0x34, 0x69, 0x61, 0x6d, 0x62, 0x77, 0x59, 0x66, 0x70, + 0x2f, 0x75, 0x66, 0x57, 0x5a, 0x38, 0x50, 0x72, 0x32, 0x55, 0x75, 0x49, + 0x48, 0x4f, 0x7a, 0x5a, 0x67, 0x77, 0x65, 0x4d, 0x46, 0x76, 0x5a, 0x39, + 0x43, 0x2b, 0x58, 0x2b, 0x42, 0x6f, 0x37, 0x64, 0x37, 0x69, 0x73, 0x63, + 0x6b, 0x73, 0x57, 0x58, 0x69, 0x53, 0x71, 0x74, 0x38, 0x72, 0x59, 0x47, + 0x50, 0x79, 0x0a, 0x35, 0x56, 0x36, 0x35, 0x34, 0x38, 0x72, 0x36, 0x66, + 0x31, 0x43, 0x47, 0x50, 0x71, 0x49, 0x30, 0x47, 0x41, 0x77, 0x4a, 0x61, + 0x43, 0x67, 0x52, 0x48, 0x4f, 0x54, 0x68, 0x75, 0x56, 0x77, 0x2b, 0x52, + 0x37, 0x6f, 0x79, 0x50, 0x78, 0x6a, 0x4d, 0x57, 0x34, 0x54, 0x31, 0x38, + 0x32, 0x74, 0x30, 0x78, 0x48, 0x4a, 0x30, 0x34, 0x65, 0x4f, 0x4c, 0x6f, + 0x45, 0x71, 0x39, 0x6a, 0x57, 0x59, 0x76, 0x0a, 0x36, 0x71, 0x30, 0x31, + 0x32, 0x69, 0x44, 0x54, 0x69, 0x49, 0x4a, 0x68, 0x38, 0x42, 0x49, 0x69, + 0x74, 0x72, 0x7a, 0x51, 0x31, 0x61, 0x54, 0x73, 0x72, 0x31, 0x53, 0x49, + 0x4a, 0x53, 0x51, 0x38, 0x70, 0x32, 0x32, 0x78, 0x63, 0x69, 0x6b, 0x2f, + 0x50, 0x6c, 0x65, 0x6d, 0x66, 0x31, 0x57, 0x76, 0x62, 0x69, 0x62, 0x47, + 0x2f, 0x75, 0x66, 0x4d, 0x51, 0x46, 0x78, 0x52, 0x52, 0x49, 0x45, 0x4b, + 0x0a, 0x65, 0x4e, 0x35, 0x4b, 0x7a, 0x6c, 0x57, 0x2f, 0x48, 0x64, 0x58, + 0x5a, 0x74, 0x31, 0x62, 0x76, 0x38, 0x48, 0x62, 0x2f, 0x43, 0x33, 0x6d, + 0x31, 0x72, 0x37, 0x33, 0x37, 0x71, 0x57, 0x6d, 0x52, 0x52, 0x70, 0x64, + 0x6f, 0x67, 0x42, 0x51, 0x32, 0x48, 0x62, 0x4e, 0x2f, 0x75, 0x79, 0x6d, + 0x59, 0x4e, 0x71, 0x55, 0x67, 0x2b, 0x6f, 0x4a, 0x67, 0x59, 0x6a, 0x4f, + 0x6b, 0x37, 0x4e, 0x61, 0x36, 0x0a, 0x42, 0x36, 0x64, 0x75, 0x78, 0x63, + 0x38, 0x55, 0x70, 0x75, 0x66, 0x57, 0x6b, 0x6a, 0x54, 0x59, 0x67, 0x66, + 0x58, 0x38, 0x48, 0x56, 0x32, 0x71, 0x58, 0x42, 0x37, 0x32, 0x6f, 0x30, + 0x30, 0x37, 0x75, 0x50, 0x63, 0x35, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, + 0x47, 0x6a, 0x67, 0x5a, 0x63, 0x77, 0x67, 0x5a, 0x51, 0x77, 0x44, 0x77, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x0a, 0x42, + 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x42, 0x53, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x53, 0x41, 0x45, 0x53, 0x7a, 0x42, 0x4a, 0x4d, + 0x45, 0x63, 0x47, 0x42, 0x46, 0x55, 0x64, 0x49, 0x41, 0x41, 0x77, 0x50, + 0x7a, 0x41, 0x39, 0x42, 0x67, 0x67, 0x72, 0x42, 0x67, 0x45, 0x46, 0x42, + 0x51, 0x63, 0x43, 0x41, 0x52, 0x59, 0x78, 0x61, 0x48, 0x52, 0x30, 0x63, + 0x44, 0x6f, 0x76, 0x0a, 0x4c, 0x33, 0x64, 0x33, 0x64, 0x79, 0x35, 0x77, + 0x61, 0x32, 0x6c, 0x76, 0x64, 0x6d, 0x56, 0x79, 0x61, 0x47, 0x56, 0x70, + 0x5a, 0x43, 0x35, 0x75, 0x62, 0x43, 0x39, 0x77, 0x62, 0x32, 0x78, 0x70, + 0x59, 0x32, 0x6c, 0x6c, 0x63, 0x79, 0x39, 0x79, 0x62, 0x32, 0x39, 0x30, + 0x4c, 0x58, 0x42, 0x76, 0x62, 0x47, 0x6c, 0x6a, 0x65, 0x53, 0x31, 0x48, + 0x4d, 0x6a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x51, 0x38, + 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, + 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, + 0x45, 0x46, 0x4a, 0x46, 0x6f, 0x4d, 0x6f, 0x63, 0x56, 0x48, 0x59, 0x6e, + 0x69, 0x74, 0x66, 0x47, 0x73, 0x4e, 0x69, 0x67, 0x30, 0x6a, 0x51, 0x74, + 0x38, 0x59, 0x6f, 0x6a, 0x72, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, + 0x47, 0x0a, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, + 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x41, 0x51, 0x43, 0x6f, 0x51, 0x55, + 0x70, 0x6e, 0x4b, 0x70, 0x4b, 0x42, 0x67, 0x6c, 0x42, 0x75, 0x34, 0x64, + 0x66, 0x59, 0x73, 0x7a, 0x6b, 0x37, 0x38, 0x77, 0x49, 0x56, 0x43, 0x56, + 0x42, 0x52, 0x37, 0x79, 0x32, 0x39, 0x4a, 0x48, 0x75, 0x49, 0x68, 0x6a, + 0x76, 0x35, 0x74, 0x4c, 0x79, 0x53, 0x0a, 0x43, 0x5a, 0x61, 0x35, 0x39, + 0x73, 0x43, 0x72, 0x49, 0x32, 0x41, 0x47, 0x65, 0x59, 0x77, 0x52, 0x54, + 0x6c, 0x48, 0x53, 0x65, 0x59, 0x41, 0x7a, 0x2b, 0x35, 0x31, 0x49, 0x76, + 0x75, 0x78, 0x42, 0x51, 0x34, 0x45, 0x66, 0x66, 0x6b, 0x64, 0x41, 0x48, + 0x4f, 0x56, 0x36, 0x43, 0x4d, 0x71, 0x71, 0x69, 0x33, 0x57, 0x74, 0x46, + 0x4d, 0x54, 0x43, 0x36, 0x47, 0x59, 0x38, 0x67, 0x67, 0x65, 0x6e, 0x0a, + 0x35, 0x69, 0x65, 0x43, 0x57, 0x78, 0x6a, 0x6d, 0x44, 0x32, 0x37, 0x5a, + 0x55, 0x44, 0x36, 0x4b, 0x51, 0x68, 0x67, 0x70, 0x78, 0x72, 0x52, 0x57, + 0x2f, 0x46, 0x59, 0x51, 0x6f, 0x41, 0x55, 0x58, 0x76, 0x51, 0x77, 0x6a, + 0x66, 0x2f, 0x53, 0x54, 0x37, 0x5a, 0x77, 0x61, 0x55, 0x62, 0x37, 0x64, + 0x52, 0x55, 0x47, 0x2f, 0x6b, 0x53, 0x53, 0x30, 0x48, 0x34, 0x7a, 0x70, + 0x58, 0x38, 0x39, 0x37, 0x0a, 0x49, 0x5a, 0x6d, 0x66, 0x6c, 0x5a, 0x38, + 0x35, 0x4f, 0x6b, 0x59, 0x63, 0x62, 0x50, 0x6e, 0x4e, 0x65, 0x35, 0x79, + 0x51, 0x7a, 0x53, 0x69, 0x70, 0x78, 0x36, 0x6c, 0x56, 0x75, 0x36, 0x78, + 0x69, 0x4e, 0x47, 0x49, 0x31, 0x45, 0x30, 0x73, 0x55, 0x4f, 0x6c, 0x57, + 0x44, 0x75, 0x59, 0x61, 0x4e, 0x6b, 0x71, 0x62, 0x47, 0x39, 0x41, 0x63, + 0x6c, 0x56, 0x4d, 0x77, 0x57, 0x56, 0x78, 0x4a, 0x4b, 0x0a, 0x67, 0x6e, + 0x6a, 0x49, 0x46, 0x4e, 0x6b, 0x58, 0x67, 0x69, 0x59, 0x74, 0x58, 0x53, + 0x41, 0x66, 0x65, 0x61, 0x37, 0x2b, 0x31, 0x48, 0x41, 0x57, 0x46, 0x70, + 0x57, 0x44, 0x32, 0x44, 0x55, 0x35, 0x2f, 0x31, 0x4a, 0x64, 0x64, 0x52, + 0x77, 0x57, 0x78, 0x52, 0x4e, 0x56, 0x7a, 0x30, 0x66, 0x4d, 0x64, 0x57, + 0x56, 0x53, 0x53, 0x74, 0x37, 0x77, 0x73, 0x4b, 0x66, 0x6b, 0x43, 0x70, + 0x59, 0x4c, 0x0a, 0x2b, 0x36, 0x33, 0x43, 0x34, 0x69, 0x57, 0x45, 0x73, + 0x74, 0x33, 0x6b, 0x76, 0x58, 0x35, 0x5a, 0x62, 0x4a, 0x76, 0x77, 0x38, + 0x4e, 0x6a, 0x6e, 0x79, 0x76, 0x4c, 0x70, 0x6c, 0x7a, 0x68, 0x2b, 0x69, + 0x62, 0x37, 0x4d, 0x2b, 0x7a, 0x6b, 0x58, 0x59, 0x54, 0x39, 0x79, 0x32, + 0x7a, 0x71, 0x52, 0x32, 0x47, 0x55, 0x42, 0x47, 0x52, 0x32, 0x74, 0x55, + 0x4b, 0x52, 0x58, 0x43, 0x6e, 0x78, 0x4c, 0x0a, 0x76, 0x4a, 0x78, 0x78, + 0x63, 0x79, 0x70, 0x46, 0x55, 0x52, 0x6d, 0x46, 0x7a, 0x49, 0x37, 0x39, + 0x52, 0x36, 0x64, 0x30, 0x6c, 0x52, 0x32, 0x6f, 0x30, 0x61, 0x39, 0x4f, + 0x46, 0x37, 0x46, 0x70, 0x4a, 0x73, 0x4b, 0x71, 0x65, 0x46, 0x64, 0x62, + 0x78, 0x55, 0x32, 0x6e, 0x35, 0x5a, 0x34, 0x46, 0x46, 0x35, 0x54, 0x4b, + 0x73, 0x6c, 0x2b, 0x67, 0x53, 0x52, 0x69, 0x4e, 0x4e, 0x4f, 0x6b, 0x6d, + 0x0a, 0x62, 0x45, 0x67, 0x65, 0x71, 0x6d, 0x69, 0x53, 0x42, 0x65, 0x47, + 0x43, 0x63, 0x31, 0x71, 0x62, 0x33, 0x41, 0x64, 0x62, 0x43, 0x47, 0x31, + 0x39, 0x6e, 0x64, 0x65, 0x4e, 0x49, 0x64, 0x6e, 0x38, 0x46, 0x43, 0x43, + 0x71, 0x77, 0x6b, 0x58, 0x66, 0x50, 0x2b, 0x63, 0x41, 0x73, 0x6c, 0x48, + 0x6b, 0x77, 0x76, 0x67, 0x46, 0x75, 0x58, 0x6b, 0x61, 0x6a, 0x44, 0x54, + 0x7a, 0x6e, 0x6c, 0x76, 0x6b, 0x0a, 0x4e, 0x31, 0x74, 0x72, 0x53, 0x74, + 0x38, 0x73, 0x56, 0x34, 0x70, 0x41, 0x57, 0x6a, 0x61, 0x36, 0x33, 0x58, + 0x56, 0x45, 0x43, 0x44, 0x64, 0x43, 0x63, 0x41, 0x7a, 0x2b, 0x33, 0x46, + 0x34, 0x68, 0x6f, 0x4b, 0x4f, 0x4b, 0x77, 0x4a, 0x43, 0x63, 0x61, 0x4e, + 0x70, 0x51, 0x35, 0x6b, 0x55, 0x51, 0x52, 0x33, 0x69, 0x32, 0x54, 0x74, + 0x4a, 0x6c, 0x79, 0x63, 0x4d, 0x33, 0x33, 0x2b, 0x46, 0x43, 0x0a, 0x59, + 0x37, 0x42, 0x58, 0x4e, 0x30, 0x55, 0x74, 0x65, 0x34, 0x71, 0x63, 0x76, + 0x77, 0x58, 0x71, 0x5a, 0x56, 0x55, 0x7a, 0x39, 0x7a, 0x6b, 0x51, 0x78, + 0x53, 0x67, 0x71, 0x49, 0x58, 0x6f, 0x62, 0x69, 0x73, 0x51, 0x6b, 0x2b, + 0x54, 0x38, 0x56, 0x79, 0x4a, 0x6f, 0x56, 0x49, 0x50, 0x56, 0x56, 0x59, + 0x70, 0x62, 0x74, 0x62, 0x5a, 0x4e, 0x51, 0x76, 0x4f, 0x53, 0x71, 0x65, + 0x4b, 0x33, 0x5a, 0x0a, 0x79, 0x77, 0x70, 0x6c, 0x68, 0x36, 0x5a, 0x6d, + 0x77, 0x63, 0x53, 0x42, 0x6f, 0x33, 0x63, 0x36, 0x57, 0x42, 0x34, 0x4c, + 0x37, 0x6f, 0x4f, 0x4c, 0x6e, 0x52, 0x37, 0x53, 0x55, 0x71, 0x54, 0x4d, + 0x48, 0x57, 0x2b, 0x77, 0x6d, 0x47, 0x32, 0x55, 0x4d, 0x62, 0x58, 0x34, + 0x63, 0x51, 0x72, 0x63, 0x75, 0x66, 0x78, 0x39, 0x4d, 0x6d, 0x44, 0x6d, + 0x36, 0x36, 0x2b, 0x4b, 0x41, 0x51, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, + 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x48, 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x20, 0x50, 0x6f, + 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, + 0x20, 0x4f, 0x3d, 0x48, 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x20, + 0x50, 0x6f, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x48, 0x6f, 0x6e, 0x67, 0x6b, + 0x6f, 0x6e, 0x67, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x20, 0x4f, 0x3d, 0x48, 0x6f, 0x6e, + 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x0a, 0x23, + 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x48, 0x6f, 0x6e, + 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x22, 0x0a, 0x23, 0x20, + 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x30, 0x30, 0x30, + 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x38, 0x3a, 0x30, + 0x64, 0x3a, 0x36, 0x66, 0x3a, 0x33, 0x39, 0x3a, 0x37, 0x38, 0x3a, 0x62, + 0x39, 0x3a, 0x34, 0x33, 0x3a, 0x36, 0x64, 0x3a, 0x37, 0x37, 0x3a, 0x34, + 0x32, 0x3a, 0x36, 0x64, 0x3a, 0x39, 0x38, 0x3a, 0x35, 0x61, 0x3a, 0x63, + 0x63, 0x3a, 0x32, 0x33, 0x3a, 0x63, 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x36, 0x3a, 0x64, 0x61, 0x3a, 0x61, 0x38, + 0x3a, 0x32, 0x30, 0x3a, 0x38, 0x64, 0x3a, 0x30, 0x39, 0x3a, 0x64, 0x32, + 0x3a, 0x31, 0x35, 0x3a, 0x34, 0x64, 0x3a, 0x32, 0x34, 0x3a, 0x62, 0x35, + 0x3a, 0x32, 0x66, 0x3a, 0x63, 0x62, 0x3a, 0x33, 0x34, 0x3a, 0x36, 0x65, + 0x3a, 0x62, 0x32, 0x3a, 0x35, 0x38, 0x3a, 0x62, 0x32, 0x3a, 0x38, 0x61, + 0x3a, 0x35, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x66, 0x39, 0x3a, 0x65, 0x36, 0x3a, 0x37, 0x64, 0x3a, 0x33, + 0x33, 0x3a, 0x36, 0x63, 0x3a, 0x35, 0x31, 0x3a, 0x30, 0x30, 0x3a, 0x32, + 0x61, 0x3a, 0x63, 0x30, 0x3a, 0x35, 0x34, 0x3a, 0x63, 0x36, 0x3a, 0x33, + 0x32, 0x3a, 0x30, 0x32, 0x3a, 0x32, 0x64, 0x3a, 0x36, 0x36, 0x3a, 0x64, + 0x64, 0x3a, 0x61, 0x32, 0x3a, 0x65, 0x37, 0x3a, 0x65, 0x33, 0x3a, 0x66, + 0x66, 0x3a, 0x66, 0x31, 0x3a, 0x30, 0x61, 0x3a, 0x64, 0x30, 0x3a, 0x36, + 0x31, 0x3a, 0x65, 0x64, 0x3a, 0x33, 0x31, 0x3a, 0x64, 0x38, 0x3a, 0x62, + 0x62, 0x3a, 0x62, 0x34, 0x3a, 0x31, 0x30, 0x3a, 0x63, 0x66, 0x3a, 0x62, + 0x32, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x4d, 0x44, + 0x43, 0x43, 0x41, 0x68, 0x69, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, + 0x49, 0x43, 0x41, 0x2b, 0x67, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, + 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, + 0x41, 0x77, 0x52, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x53, 0x45, 0x73, 0x78, 0x0a, 0x46, + 0x6a, 0x41, 0x55, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, + 0x55, 0x68, 0x76, 0x62, 0x6d, 0x64, 0x72, 0x62, 0x32, 0x35, 0x6e, 0x49, + 0x46, 0x42, 0x76, 0x63, 0x33, 0x51, 0x78, 0x49, 0x44, 0x41, 0x65, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x46, 0x30, 0x68, 0x76, 0x62, + 0x6d, 0x64, 0x72, 0x62, 0x32, 0x35, 0x6e, 0x49, 0x46, 0x42, 0x76, 0x63, + 0x33, 0x51, 0x67, 0x0a, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, + 0x51, 0x53, 0x41, 0x78, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x7a, + 0x4d, 0x44, 0x55, 0x78, 0x4e, 0x54, 0x41, 0x31, 0x4d, 0x54, 0x4d, 0x78, + 0x4e, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x7a, 0x4d, 0x44, 0x55, 0x78, + 0x4e, 0x54, 0x41, 0x30, 0x4e, 0x54, 0x49, 0x79, 0x4f, 0x56, 0x6f, 0x77, + 0x52, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x0a, 0x41, 0x31, 0x55, + 0x45, 0x42, 0x68, 0x4d, 0x43, 0x53, 0x45, 0x73, 0x78, 0x46, 0x6a, 0x41, + 0x55, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x55, 0x68, + 0x76, 0x62, 0x6d, 0x64, 0x72, 0x62, 0x32, 0x35, 0x6e, 0x49, 0x46, 0x42, + 0x76, 0x63, 0x33, 0x51, 0x78, 0x49, 0x44, 0x41, 0x65, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x4d, 0x54, 0x46, 0x30, 0x68, 0x76, 0x62, 0x6d, 0x64, + 0x72, 0x0a, 0x62, 0x32, 0x35, 0x6e, 0x49, 0x46, 0x42, 0x76, 0x63, 0x33, + 0x51, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x53, + 0x41, 0x78, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, + 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x0a, 0x41, 0x51, 0x45, 0x41, 0x72, + 0x50, 0x38, 0x34, 0x74, 0x75, 0x6c, 0x6d, 0x41, 0x6b, 0x6e, 0x6a, 0x6f, + 0x72, 0x54, 0x68, 0x6b, 0x50, 0x6c, 0x41, 0x6a, 0x33, 0x6e, 0x35, 0x34, + 0x72, 0x31, 0x35, 0x2f, 0x67, 0x4b, 0x39, 0x37, 0x69, 0x53, 0x53, 0x48, + 0x53, 0x4c, 0x32, 0x32, 0x6f, 0x56, 0x79, 0x61, 0x66, 0x37, 0x58, 0x50, + 0x77, 0x6e, 0x55, 0x33, 0x5a, 0x47, 0x31, 0x41, 0x70, 0x7a, 0x51, 0x0a, + 0x6a, 0x56, 0x72, 0x68, 0x56, 0x63, 0x4e, 0x51, 0x68, 0x72, 0x6b, 0x70, + 0x4a, 0x73, 0x4c, 0x6a, 0x32, 0x61, 0x44, 0x78, 0x61, 0x51, 0x4d, 0x6f, + 0x49, 0x49, 0x42, 0x46, 0x49, 0x69, 0x31, 0x57, 0x70, 0x7a, 0x74, 0x55, + 0x6c, 0x56, 0x59, 0x69, 0x57, 0x52, 0x38, 0x6f, 0x33, 0x78, 0x38, 0x67, + 0x50, 0x57, 0x32, 0x69, 0x4e, 0x72, 0x34, 0x6a, 0x6f, 0x4c, 0x46, 0x75, + 0x74, 0x62, 0x45, 0x6e, 0x0a, 0x50, 0x7a, 0x6c, 0x54, 0x43, 0x65, 0x71, + 0x72, 0x61, 0x75, 0x68, 0x30, 0x73, 0x73, 0x4a, 0x6c, 0x58, 0x49, 0x36, + 0x2f, 0x66, 0x4d, 0x4e, 0x34, 0x68, 0x4d, 0x32, 0x65, 0x46, 0x76, 0x7a, + 0x31, 0x4c, 0x6b, 0x38, 0x67, 0x4b, 0x67, 0x69, 0x66, 0x64, 0x2f, 0x50, + 0x46, 0x48, 0x73, 0x53, 0x61, 0x55, 0x6d, 0x59, 0x65, 0x53, 0x46, 0x37, + 0x6a, 0x45, 0x41, 0x61, 0x50, 0x49, 0x70, 0x6a, 0x68, 0x0a, 0x5a, 0x59, + 0x34, 0x62, 0x58, 0x53, 0x4e, 0x6d, 0x4f, 0x37, 0x69, 0x6c, 0x4d, 0x6c, + 0x48, 0x49, 0x68, 0x71, 0x71, 0x68, 0x71, 0x5a, 0x35, 0x2f, 0x64, 0x70, + 0x54, 0x43, 0x70, 0x6d, 0x79, 0x33, 0x51, 0x66, 0x44, 0x56, 0x79, 0x41, + 0x59, 0x34, 0x35, 0x74, 0x51, 0x4d, 0x34, 0x76, 0x4d, 0x37, 0x54, 0x47, + 0x31, 0x51, 0x6a, 0x4d, 0x53, 0x44, 0x4a, 0x38, 0x45, 0x54, 0x68, 0x46, + 0x6b, 0x39, 0x0a, 0x6e, 0x6e, 0x56, 0x30, 0x74, 0x74, 0x67, 0x43, 0x58, + 0x6a, 0x71, 0x51, 0x65, 0x73, 0x42, 0x43, 0x4e, 0x6e, 0x4c, 0x73, 0x61, + 0x6b, 0x33, 0x63, 0x37, 0x38, 0x51, 0x41, 0x33, 0x78, 0x4d, 0x59, 0x56, + 0x31, 0x38, 0x6d, 0x65, 0x4d, 0x6a, 0x57, 0x43, 0x6e, 0x6c, 0x33, 0x76, + 0x2f, 0x65, 0x76, 0x74, 0x33, 0x61, 0x35, 0x70, 0x51, 0x75, 0x45, 0x46, + 0x31, 0x30, 0x51, 0x36, 0x6d, 0x2f, 0x68, 0x0a, 0x71, 0x35, 0x55, 0x52, + 0x58, 0x32, 0x30, 0x38, 0x6f, 0x31, 0x78, 0x4e, 0x67, 0x31, 0x76, 0x79, + 0x73, 0x78, 0x6d, 0x4b, 0x67, 0x49, 0x73, 0x4c, 0x68, 0x77, 0x49, 0x44, + 0x41, 0x51, 0x41, 0x42, 0x6f, 0x79, 0x59, 0x77, 0x4a, 0x44, 0x41, 0x53, + 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, + 0x43, 0x44, 0x41, 0x47, 0x41, 0x51, 0x48, 0x2f, 0x41, 0x67, 0x45, 0x44, + 0x0a, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, + 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x78, 0x6a, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, + 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, + 0x41, 0x44, 0x6b, 0x62, 0x56, 0x50, 0x4b, 0x37, 0x69, 0x68, 0x39, 0x6c, + 0x65, 0x67, 0x59, 0x73, 0x43, 0x0a, 0x6d, 0x45, 0x45, 0x49, 0x6a, 0x45, + 0x79, 0x38, 0x32, 0x74, 0x76, 0x75, 0x4a, 0x78, 0x75, 0x43, 0x35, 0x32, + 0x70, 0x46, 0x37, 0x42, 0x61, 0x4c, 0x54, 0x34, 0x57, 0x67, 0x38, 0x37, + 0x4a, 0x77, 0x76, 0x56, 0x71, 0x57, 0x75, 0x73, 0x70, 0x75, 0x62, 0x65, + 0x35, 0x47, 0x69, 0x32, 0x37, 0x6e, 0x4b, 0x69, 0x36, 0x57, 0x73, 0x78, + 0x6b, 0x7a, 0x36, 0x37, 0x53, 0x66, 0x71, 0x4c, 0x49, 0x33, 0x0a, 0x37, + 0x70, 0x69, 0x6f, 0x6c, 0x37, 0x59, 0x75, 0x74, 0x6d, 0x63, 0x6e, 0x31, + 0x4b, 0x5a, 0x4a, 0x2f, 0x52, 0x79, 0x54, 0x5a, 0x58, 0x61, 0x65, 0x51, + 0x69, 0x2f, 0x63, 0x49, 0x6d, 0x79, 0x61, 0x54, 0x2f, 0x4a, 0x61, 0x46, + 0x54, 0x6d, 0x78, 0x63, 0x64, 0x63, 0x72, 0x55, 0x65, 0x68, 0x74, 0x48, + 0x4a, 0x6a, 0x41, 0x32, 0x53, 0x72, 0x30, 0x6f, 0x59, 0x4a, 0x37, 0x31, + 0x63, 0x6c, 0x42, 0x0a, 0x6f, 0x69, 0x4d, 0x42, 0x64, 0x44, 0x68, 0x56, + 0x69, 0x77, 0x2b, 0x35, 0x4c, 0x6d, 0x65, 0x69, 0x49, 0x41, 0x51, 0x33, + 0x32, 0x70, 0x77, 0x4c, 0x30, 0x78, 0x63, 0x68, 0x34, 0x49, 0x2b, 0x58, + 0x65, 0x54, 0x52, 0x76, 0x68, 0x45, 0x67, 0x43, 0x49, 0x44, 0x4d, 0x62, + 0x35, 0x6a, 0x52, 0x45, 0x6e, 0x35, 0x46, 0x77, 0x39, 0x49, 0x42, 0x65, + 0x68, 0x45, 0x50, 0x43, 0x4b, 0x64, 0x4a, 0x73, 0x0a, 0x45, 0x68, 0x54, + 0x6b, 0x59, 0x59, 0x32, 0x73, 0x45, 0x4a, 0x43, 0x65, 0x68, 0x46, 0x43, + 0x37, 0x38, 0x4a, 0x5a, 0x76, 0x52, 0x5a, 0x2b, 0x4b, 0x38, 0x38, 0x70, + 0x73, 0x54, 0x2f, 0x6f, 0x52, 0x4f, 0x68, 0x55, 0x56, 0x52, 0x73, 0x50, + 0x4e, 0x48, 0x34, 0x4e, 0x62, 0x4c, 0x55, 0x45, 0x53, 0x37, 0x56, 0x42, + 0x6e, 0x51, 0x52, 0x4d, 0x39, 0x49, 0x61, 0x75, 0x55, 0x69, 0x71, 0x70, + 0x4f, 0x0a, 0x66, 0x4d, 0x47, 0x78, 0x2b, 0x36, 0x66, 0x57, 0x74, 0x53, + 0x63, 0x76, 0x6c, 0x36, 0x74, 0x75, 0x34, 0x42, 0x33, 0x69, 0x30, 0x52, + 0x77, 0x73, 0x48, 0x30, 0x54, 0x69, 0x2f, 0x4c, 0x36, 0x52, 0x6f, 0x5a, + 0x7a, 0x37, 0x31, 0x69, 0x6c, 0x54, 0x63, 0x34, 0x61, 0x66, 0x55, 0x39, + 0x68, 0x44, 0x44, 0x6c, 0x33, 0x57, 0x59, 0x34, 0x4a, 0x78, 0x48, 0x59, + 0x42, 0x30, 0x79, 0x76, 0x62, 0x69, 0x0a, 0x41, 0x6d, 0x76, 0x5a, 0x57, + 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x65, 0x63, 0x75, + 0x72, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, + 0x41, 0x31, 0x31, 0x20, 0x4f, 0x3d, 0x4a, 0x61, 0x70, 0x61, 0x6e, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2c, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x65, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, + 0x31, 0x31, 0x20, 0x4f, 0x3d, 0x4a, 0x61, 0x70, 0x61, 0x6e, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x31, 0x31, 0x22, 0x0a, 0x23, + 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23, + 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x37, 0x3a, 0x35, 0x32, 0x3a, + 0x37, 0x34, 0x3a, 0x65, 0x32, 0x3a, 0x39, 0x32, 0x3a, 0x62, 0x34, 0x3a, + 0x38, 0x30, 0x3a, 0x39, 0x33, 0x3a, 0x66, 0x32, 0x3a, 0x37, 0x35, 0x3a, + 0x65, 0x34, 0x3a, 0x63, 0x63, 0x3a, 0x64, 0x37, 0x3a, 0x66, 0x32, 0x3a, + 0x65, 0x61, 0x3a, 0x32, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x33, 0x62, 0x3a, 0x63, 0x34, 0x3a, 0x39, 0x66, 0x3a, 0x34, + 0x38, 0x3a, 0x66, 0x38, 0x3a, 0x66, 0x33, 0x3a, 0x37, 0x33, 0x3a, 0x61, + 0x30, 0x3a, 0x39, 0x63, 0x3a, 0x31, 0x65, 0x3a, 0x62, 0x64, 0x3a, 0x66, + 0x38, 0x3a, 0x35, 0x62, 0x3a, 0x62, 0x31, 0x3a, 0x63, 0x33, 0x3a, 0x36, + 0x35, 0x3a, 0x63, 0x37, 0x3a, 0x64, 0x38, 0x3a, 0x31, 0x31, 0x3a, 0x62, + 0x33, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x62, 0x66, 0x3a, 0x30, 0x66, 0x3a, 0x65, 0x65, 0x3a, 0x66, 0x62, 0x3a, + 0x39, 0x65, 0x3a, 0x33, 0x61, 0x3a, 0x35, 0x38, 0x3a, 0x31, 0x61, 0x3a, + 0x64, 0x35, 0x3a, 0x66, 0x39, 0x3a, 0x65, 0x39, 0x3a, 0x64, 0x62, 0x3a, + 0x37, 0x35, 0x3a, 0x38, 0x39, 0x3a, 0x39, 0x38, 0x3a, 0x35, 0x37, 0x3a, + 0x34, 0x33, 0x3a, 0x64, 0x32, 0x3a, 0x36, 0x31, 0x3a, 0x30, 0x38, 0x3a, + 0x35, 0x63, 0x3a, 0x34, 0x64, 0x3a, 0x33, 0x31, 0x3a, 0x34, 0x66, 0x3a, + 0x36, 0x66, 0x3a, 0x35, 0x64, 0x3a, 0x37, 0x32, 0x3a, 0x35, 0x39, 0x3a, + 0x61, 0x61, 0x3a, 0x34, 0x32, 0x3a, 0x31, 0x36, 0x3a, 0x31, 0x32, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x62, 0x54, 0x43, 0x43, + 0x41, 0x6c, 0x57, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, + 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, + 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x59, + 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, + 0x45, 0x77, 0x4a, 0x4b, 0x55, 0x44, 0x45, 0x72, 0x0a, 0x4d, 0x43, 0x6b, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x69, 0x53, 0x6d, 0x46, + 0x77, 0x59, 0x57, 0x34, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, + 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, + 0x54, 0x5a, 0x58, 0x4a, 0x32, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x79, 0x77, + 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x63, 0x4d, 0x42, 0x6f, + 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x54, 0x55, 0x32, + 0x56, 0x6a, 0x64, 0x58, 0x4a, 0x6c, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, + 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x51, 0x30, 0x45, 0x78, 0x4d, 0x54, + 0x41, 0x65, 0x46, 0x77, 0x30, 0x77, 0x4f, 0x54, 0x41, 0x30, 0x4d, 0x44, + 0x67, 0x77, 0x4e, 0x44, 0x55, 0x32, 0x4e, 0x44, 0x64, 0x61, 0x46, 0x77, + 0x30, 0x79, 0x4f, 0x54, 0x41, 0x30, 0x0a, 0x4d, 0x44, 0x67, 0x77, 0x4e, + 0x44, 0x55, 0x32, 0x4e, 0x44, 0x64, 0x61, 0x4d, 0x46, 0x67, 0x78, 0x43, + 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, + 0x6b, 0x70, 0x51, 0x4d, 0x53, 0x73, 0x77, 0x4b, 0x51, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x4b, 0x45, 0x79, 0x4a, 0x4b, 0x59, 0x58, 0x42, 0x68, 0x62, + 0x69, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x0a, + 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x46, 0x4e, 0x6c, + 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, 0x7a, 0x4c, 0x43, 0x42, 0x4a, + 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x52, 0x77, 0x77, 0x47, 0x67, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x4e, 0x54, 0x5a, 0x57, 0x4e, 0x31, + 0x63, 0x6d, 0x56, 0x54, 0x61, 0x57, 0x64, 0x75, 0x49, 0x46, 0x4a, 0x76, + 0x62, 0x33, 0x52, 0x44, 0x0a, 0x51, 0x54, 0x45, 0x78, 0x4d, 0x49, 0x49, + 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, + 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, + 0x43, 0x41, 0x51, 0x45, 0x41, 0x2f, 0x58, 0x65, 0x71, 0x70, 0x52, 0x79, + 0x51, 0x42, 0x54, 0x76, 0x4c, 0x54, 0x4a, 0x73, 0x7a, 0x0a, 0x69, 0x31, + 0x6f, 0x55, 0x52, 0x61, 0x54, 0x6e, 0x6b, 0x42, 0x62, 0x52, 0x33, 0x31, + 0x66, 0x53, 0x49, 0x52, 0x43, 0x6b, 0x46, 0x2f, 0x33, 0x66, 0x72, 0x4e, + 0x59, 0x66, 0x70, 0x2b, 0x54, 0x62, 0x66, 0x50, 0x66, 0x73, 0x33, 0x37, + 0x67, 0x44, 0x32, 0x70, 0x52, 0x59, 0x2f, 0x56, 0x31, 0x79, 0x66, 0x49, + 0x77, 0x2f, 0x58, 0x77, 0x46, 0x6e, 0x64, 0x42, 0x57, 0x57, 0x34, 0x77, + 0x49, 0x38, 0x0a, 0x68, 0x39, 0x75, 0x75, 0x79, 0x77, 0x47, 0x4f, 0x77, + 0x76, 0x4e, 0x6d, 0x78, 0x6f, 0x56, 0x46, 0x39, 0x41, 0x4c, 0x47, 0x4f, + 0x72, 0x56, 0x69, 0x73, 0x71, 0x2f, 0x36, 0x6e, 0x4c, 0x2b, 0x6b, 0x35, + 0x74, 0x53, 0x41, 0x4d, 0x4a, 0x6a, 0x7a, 0x44, 0x62, 0x61, 0x54, 0x6a, + 0x36, 0x6e, 0x55, 0x32, 0x44, 0x62, 0x79, 0x73, 0x50, 0x79, 0x4b, 0x79, + 0x69, 0x79, 0x68, 0x46, 0x54, 0x4f, 0x56, 0x0a, 0x4d, 0x64, 0x72, 0x41, + 0x47, 0x2f, 0x4c, 0x75, 0x59, 0x70, 0x6d, 0x47, 0x59, 0x7a, 0x2b, 0x2f, + 0x33, 0x5a, 0x4d, 0x71, 0x67, 0x36, 0x68, 0x32, 0x75, 0x52, 0x4d, 0x66, + 0x74, 0x38, 0x35, 0x4f, 0x51, 0x6f, 0x57, 0x50, 0x49, 0x75, 0x63, 0x75, + 0x47, 0x76, 0x4b, 0x56, 0x43, 0x62, 0x49, 0x46, 0x74, 0x55, 0x52, 0x4f, + 0x64, 0x36, 0x45, 0x67, 0x76, 0x61, 0x6e, 0x79, 0x54, 0x67, 0x70, 0x39, + 0x0a, 0x55, 0x4b, 0x33, 0x31, 0x42, 0x51, 0x31, 0x46, 0x54, 0x30, 0x5a, + 0x78, 0x2f, 0x53, 0x67, 0x2b, 0x55, 0x2f, 0x73, 0x45, 0x32, 0x43, 0x33, + 0x58, 0x5a, 0x52, 0x31, 0x4b, 0x47, 0x2f, 0x72, 0x50, 0x4f, 0x37, 0x41, + 0x78, 0x6d, 0x6a, 0x56, 0x75, 0x79, 0x49, 0x73, 0x47, 0x30, 0x77, 0x43, + 0x52, 0x38, 0x70, 0x51, 0x49, 0x5a, 0x55, 0x79, 0x78, 0x4e, 0x41, 0x59, + 0x41, 0x65, 0x6f, 0x6e, 0x69, 0x0a, 0x38, 0x4d, 0x63, 0x44, 0x57, 0x63, + 0x2f, 0x56, 0x31, 0x75, 0x69, 0x6e, 0x4d, 0x72, 0x50, 0x6d, 0x6d, 0x45, + 0x43, 0x47, 0x78, 0x63, 0x30, 0x6e, 0x45, 0x6f, 0x76, 0x4d, 0x65, 0x38, + 0x36, 0x33, 0x45, 0x54, 0x78, 0x69, 0x59, 0x41, 0x63, 0x6a, 0x50, 0x69, + 0x74, 0x41, 0x62, 0x70, 0x53, 0x41, 0x43, 0x57, 0x32, 0x32, 0x73, 0x32, + 0x39, 0x33, 0x62, 0x7a, 0x55, 0x49, 0x55, 0x50, 0x73, 0x43, 0x0a, 0x68, + 0x38, 0x55, 0x2b, 0x69, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, + 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x57, 0x2f, 0x68, 0x4e, 0x54, + 0x37, 0x4b, 0x6c, 0x68, 0x74, 0x51, 0x36, 0x30, 0x76, 0x46, 0x6a, 0x6d, + 0x71, 0x43, 0x2b, 0x43, 0x66, 0x5a, 0x58, 0x74, 0x39, 0x34, 0x77, 0x44, + 0x67, 0x59, 0x44, 0x0a, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, + 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x41, 0x38, 0x47, + 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, + 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x44, 0x51, 0x59, 0x4a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, + 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x0a, 0x41, 0x4b, 0x43, + 0x68, 0x4f, 0x42, 0x5a, 0x6d, 0x4c, 0x71, 0x64, 0x57, 0x48, 0x79, 0x47, + 0x63, 0x42, 0x76, 0x6f, 0x64, 0x37, 0x62, 0x6b, 0x69, 0x78, 0x54, 0x67, + 0x6d, 0x32, 0x45, 0x35, 0x50, 0x37, 0x4b, 0x4e, 0x2f, 0x65, 0x64, 0x35, + 0x47, 0x49, 0x61, 0x47, 0x48, 0x64, 0x34, 0x38, 0x48, 0x43, 0x4a, 0x71, + 0x79, 0x70, 0x4d, 0x57, 0x76, 0x44, 0x7a, 0x4b, 0x59, 0x43, 0x33, 0x78, + 0x6d, 0x0a, 0x4b, 0x62, 0x61, 0x62, 0x66, 0x53, 0x56, 0x53, 0x53, 0x55, + 0x4f, 0x72, 0x54, 0x43, 0x34, 0x72, 0x62, 0x6e, 0x70, 0x77, 0x72, 0x78, + 0x59, 0x4f, 0x34, 0x77, 0x4a, 0x73, 0x2b, 0x30, 0x4c, 0x6d, 0x47, 0x4a, + 0x31, 0x46, 0x32, 0x46, 0x58, 0x49, 0x36, 0x44, 0x76, 0x64, 0x35, 0x2b, + 0x48, 0x30, 0x4c, 0x67, 0x73, 0x63, 0x4e, 0x46, 0x78, 0x73, 0x57, 0x45, + 0x72, 0x37, 0x6a, 0x49, 0x68, 0x51, 0x0a, 0x58, 0x35, 0x55, 0x63, 0x76, + 0x2b, 0x32, 0x72, 0x49, 0x72, 0x56, 0x6c, 0x73, 0x34, 0x57, 0x36, 0x6e, + 0x67, 0x2b, 0x34, 0x72, 0x65, 0x56, 0x36, 0x47, 0x34, 0x70, 0x51, 0x4f, + 0x68, 0x32, 0x39, 0x44, 0x62, 0x78, 0x37, 0x56, 0x46, 0x41, 0x4c, 0x75, + 0x55, 0x4b, 0x76, 0x56, 0x61, 0x41, 0x59, 0x67, 0x61, 0x31, 0x6c, 0x6d, + 0x65, 0x2b, 0x2b, 0x35, 0x4a, 0x79, 0x2f, 0x78, 0x49, 0x57, 0x72, 0x0a, + 0x51, 0x62, 0x4a, 0x55, 0x62, 0x39, 0x77, 0x6c, 0x7a, 0x65, 0x31, 0x34, + 0x34, 0x6f, 0x34, 0x4d, 0x6a, 0x51, 0x6c, 0x4a, 0x33, 0x57, 0x4e, 0x37, + 0x57, 0x6d, 0x6d, 0x57, 0x41, 0x69, 0x47, 0x6f, 0x76, 0x56, 0x4a, 0x5a, + 0x36, 0x58, 0x30, 0x31, 0x79, 0x38, 0x68, 0x53, 0x79, 0x6e, 0x2b, 0x42, + 0x2f, 0x74, 0x6c, 0x72, 0x30, 0x2f, 0x63, 0x52, 0x37, 0x53, 0x58, 0x66, + 0x2b, 0x4f, 0x66, 0x35, 0x0a, 0x70, 0x50, 0x70, 0x79, 0x6c, 0x34, 0x52, + 0x54, 0x44, 0x61, 0x58, 0x51, 0x4d, 0x68, 0x68, 0x52, 0x64, 0x6c, 0x6b, + 0x55, 0x62, 0x41, 0x2f, 0x72, 0x37, 0x46, 0x2b, 0x41, 0x6a, 0x48, 0x56, + 0x44, 0x67, 0x38, 0x4f, 0x46, 0x6d, 0x50, 0x39, 0x4d, 0x6e, 0x69, 0x30, + 0x4e, 0x35, 0x48, 0x65, 0x44, 0x6b, 0x30, 0x36, 0x31, 0x6c, 0x67, 0x65, + 0x4c, 0x4b, 0x42, 0x4f, 0x62, 0x6a, 0x42, 0x6d, 0x4e, 0x0a, 0x51, 0x53, + 0x64, 0x4a, 0x51, 0x4f, 0x37, 0x65, 0x35, 0x69, 0x4e, 0x45, 0x4f, 0x64, + 0x79, 0x68, 0x49, 0x74, 0x61, 0x36, 0x41, 0x2f, 0x49, 0x3d, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, + 0x65, 0x2d, 0x53, 0x7a, 0x69, 0x67, 0x6e, 0x6f, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x4f, 0x3d, + 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, 0x4c, 0x74, 0x64, + 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x65, 0x63, + 0x20, 0x65, 0x2d, 0x53, 0x7a, 0x69, 0x67, 0x6e, 0x6f, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x4f, + 0x3d, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, 0x4c, 0x74, + 0x64, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, 0x65, 0x2d, + 0x53, 0x7a, 0x69, 0x67, 0x6e, 0x6f, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x20, 0x32, 0x30, 0x30, 0x39, 0x22, 0x0a, 0x23, 0x20, 0x53, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x34, 0x30, 0x31, 0x34, + 0x37, 0x31, 0x32, 0x37, 0x37, 0x36, 0x31, 0x39, 0x35, 0x37, 0x38, 0x34, + 0x34, 0x37, 0x33, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x66, + 0x38, 0x3a, 0x34, 0x39, 0x3a, 0x66, 0x34, 0x3a, 0x30, 0x33, 0x3a, 0x62, + 0x63, 0x3a, 0x34, 0x34, 0x3a, 0x32, 0x64, 0x3a, 0x38, 0x33, 0x3a, 0x62, + 0x65, 0x3a, 0x34, 0x38, 0x3a, 0x36, 0x39, 0x3a, 0x37, 0x64, 0x3a, 0x32, + 0x39, 0x3a, 0x36, 0x34, 0x3a, 0x66, 0x63, 0x3a, 0x62, 0x31, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x39, 0x3a, 0x64, 0x66, + 0x3a, 0x37, 0x34, 0x3a, 0x66, 0x65, 0x3a, 0x35, 0x63, 0x3a, 0x66, 0x34, + 0x3a, 0x30, 0x66, 0x3a, 0x34, 0x61, 0x3a, 0x38, 0x30, 0x3a, 0x66, 0x39, + 0x3a, 0x65, 0x33, 0x3a, 0x33, 0x37, 0x3a, 0x37, 0x64, 0x3a, 0x35, 0x34, + 0x3a, 0x64, 0x61, 0x3a, 0x39, 0x31, 0x3a, 0x65, 0x31, 0x3a, 0x30, 0x31, + 0x3a, 0x33, 0x31, 0x3a, 0x38, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x63, 0x3a, 0x35, 0x66, 0x3a, 0x38, + 0x31, 0x3a, 0x66, 0x65, 0x3a, 0x61, 0x35, 0x3a, 0x66, 0x61, 0x3a, 0x62, + 0x38, 0x3a, 0x32, 0x63, 0x3a, 0x36, 0x34, 0x3a, 0x62, 0x66, 0x3a, 0x61, + 0x32, 0x3a, 0x65, 0x61, 0x3a, 0x65, 0x63, 0x3a, 0x61, 0x66, 0x3a, 0x63, + 0x64, 0x3a, 0x65, 0x38, 0x3a, 0x65, 0x30, 0x3a, 0x37, 0x37, 0x3a, 0x66, + 0x63, 0x3a, 0x38, 0x36, 0x3a, 0x32, 0x30, 0x3a, 0x61, 0x37, 0x3a, 0x63, + 0x61, 0x3a, 0x65, 0x35, 0x3a, 0x33, 0x37, 0x3a, 0x31, 0x36, 0x3a, 0x33, + 0x64, 0x3a, 0x66, 0x33, 0x3a, 0x36, 0x65, 0x3a, 0x64, 0x62, 0x3a, 0x66, + 0x33, 0x3a, 0x37, 0x38, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x45, 0x43, 0x6a, 0x43, 0x43, 0x41, 0x76, 0x4b, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x4a, 0x41, 0x4d, 0x4a, 0x2b, 0x51, 0x77, 0x52, + 0x4f, 0x52, 0x7a, 0x38, 0x5a, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, + 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, + 0x41, 0x4d, 0x49, 0x47, 0x43, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, + 0x44, 0x0a, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x49, 0x56, 0x54, + 0x45, 0x52, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x77, + 0x77, 0x49, 0x51, 0x6e, 0x56, 0x6b, 0x59, 0x58, 0x42, 0x6c, 0x63, 0x33, + 0x51, 0x78, 0x46, 0x6a, 0x41, 0x55, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x6f, 0x4d, 0x44, 0x55, 0x31, 0x70, 0x59, 0x33, 0x4a, 0x76, 0x63, 0x32, + 0x56, 0x6a, 0x49, 0x45, 0x78, 0x30, 0x0a, 0x5a, 0x43, 0x34, 0x78, 0x4a, + 0x7a, 0x41, 0x6c, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x48, + 0x6b, 0x31, 0x70, 0x59, 0x33, 0x4a, 0x76, 0x63, 0x32, 0x56, 0x6a, 0x49, + 0x47, 0x55, 0x74, 0x55, 0x33, 0x70, 0x70, 0x5a, 0x32, 0x35, 0x76, 0x49, + 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4d, + 0x6a, 0x41, 0x77, 0x4f, 0x54, 0x45, 0x66, 0x4d, 0x42, 0x30, 0x47, 0x0a, + 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x4a, + 0x41, 0x52, 0x59, 0x51, 0x61, 0x57, 0x35, 0x6d, 0x62, 0x30, 0x42, 0x6c, + 0x4c, 0x58, 0x4e, 0x36, 0x61, 0x57, 0x64, 0x75, 0x62, 0x79, 0x35, 0x6f, + 0x64, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, 0x77, 0x4f, 0x54, 0x41, 0x32, + 0x4d, 0x54, 0x59, 0x78, 0x4d, 0x54, 0x4d, 0x77, 0x4d, 0x54, 0x68, 0x61, + 0x46, 0x77, 0x30, 0x79, 0x0a, 0x4f, 0x54, 0x45, 0x79, 0x4d, 0x7a, 0x41, + 0x78, 0x4d, 0x54, 0x4d, 0x77, 0x4d, 0x54, 0x68, 0x61, 0x4d, 0x49, 0x47, + 0x43, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x47, 0x45, 0x77, 0x4a, 0x49, 0x56, 0x54, 0x45, 0x52, 0x4d, 0x41, 0x38, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x77, 0x77, 0x49, 0x51, 0x6e, 0x56, + 0x6b, 0x59, 0x58, 0x42, 0x6c, 0x63, 0x33, 0x51, 0x78, 0x0a, 0x46, 0x6a, + 0x41, 0x55, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x44, 0x55, + 0x31, 0x70, 0x59, 0x33, 0x4a, 0x76, 0x63, 0x32, 0x56, 0x6a, 0x49, 0x45, + 0x78, 0x30, 0x5a, 0x43, 0x34, 0x78, 0x4a, 0x7a, 0x41, 0x6c, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x48, 0x6b, 0x31, 0x70, 0x59, 0x33, + 0x4a, 0x76, 0x63, 0x32, 0x56, 0x6a, 0x49, 0x47, 0x55, 0x74, 0x55, 0x33, + 0x70, 0x70, 0x0a, 0x5a, 0x32, 0x35, 0x76, 0x49, 0x46, 0x4a, 0x76, 0x62, + 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4d, 0x6a, 0x41, 0x77, 0x4f, + 0x54, 0x45, 0x66, 0x4d, 0x42, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, + 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x4a, 0x41, 0x52, 0x59, 0x51, 0x61, + 0x57, 0x35, 0x6d, 0x62, 0x30, 0x42, 0x6c, 0x4c, 0x58, 0x4e, 0x36, 0x61, + 0x57, 0x64, 0x75, 0x62, 0x79, 0x35, 0x6f, 0x0a, 0x64, 0x54, 0x43, 0x43, + 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, + 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, + 0x67, 0x67, 0x45, 0x42, 0x41, 0x4f, 0x6e, 0x34, 0x6a, 0x2f, 0x4e, 0x6a, + 0x72, 0x64, 0x71, 0x47, 0x32, 0x4b, 0x66, 0x67, 0x51, 0x76, 0x76, 0x50, + 0x0a, 0x6b, 0x64, 0x36, 0x6d, 0x4a, 0x76, 0x69, 0x5a, 0x70, 0x57, 0x4e, + 0x77, 0x72, 0x5a, 0x75, 0x75, 0x79, 0x6a, 0x4e, 0x41, 0x66, 0x57, 0x32, + 0x57, 0x62, 0x71, 0x45, 0x4f, 0x52, 0x4f, 0x37, 0x68, 0x45, 0x35, 0x32, + 0x55, 0x51, 0x6c, 0x4b, 0x61, 0x76, 0x58, 0x57, 0x46, 0x64, 0x43, 0x79, + 0x6f, 0x44, 0x68, 0x32, 0x54, 0x74, 0x68, 0x69, 0x33, 0x6a, 0x43, 0x79, + 0x6f, 0x7a, 0x2f, 0x74, 0x63, 0x0a, 0x63, 0x62, 0x6e, 0x61, 0x37, 0x50, + 0x37, 0x6f, 0x66, 0x6f, 0x2f, 0x6b, 0x4c, 0x78, 0x32, 0x79, 0x71, 0x48, + 0x57, 0x48, 0x32, 0x4c, 0x65, 0x68, 0x35, 0x54, 0x76, 0x50, 0x6d, 0x55, + 0x70, 0x47, 0x30, 0x49, 0x4d, 0x5a, 0x66, 0x63, 0x43, 0x68, 0x45, 0x68, + 0x79, 0x56, 0x62, 0x55, 0x72, 0x30, 0x32, 0x4d, 0x65, 0x6c, 0x54, 0x54, + 0x4d, 0x75, 0x68, 0x54, 0x6c, 0x41, 0x64, 0x58, 0x34, 0x55, 0x0a, 0x66, + 0x49, 0x41, 0x53, 0x6d, 0x46, 0x44, 0x48, 0x51, 0x57, 0x65, 0x34, 0x6f, + 0x49, 0x42, 0x68, 0x56, 0x4b, 0x5a, 0x73, 0x54, 0x68, 0x2f, 0x67, 0x6e, + 0x51, 0x34, 0x48, 0x36, 0x63, 0x6d, 0x36, 0x4d, 0x2b, 0x66, 0x2b, 0x77, + 0x46, 0x55, 0x6f, 0x4c, 0x41, 0x4b, 0x41, 0x70, 0x78, 0x6e, 0x31, 0x6e, + 0x74, 0x78, 0x56, 0x55, 0x77, 0x4f, 0x58, 0x65, 0x77, 0x64, 0x49, 0x2f, + 0x35, 0x6e, 0x37, 0x0a, 0x4e, 0x34, 0x6f, 0x6b, 0x78, 0x46, 0x6e, 0x4d, + 0x55, 0x42, 0x42, 0x6a, 0x6a, 0x71, 0x71, 0x70, 0x47, 0x72, 0x43, 0x45, + 0x47, 0x6f, 0x62, 0x35, 0x58, 0x37, 0x75, 0x78, 0x55, 0x47, 0x36, 0x6b, + 0x30, 0x51, 0x72, 0x4d, 0x31, 0x58, 0x46, 0x2b, 0x48, 0x36, 0x63, 0x62, + 0x66, 0x50, 0x56, 0x54, 0x62, 0x69, 0x4a, 0x66, 0x79, 0x79, 0x76, 0x6d, + 0x31, 0x48, 0x78, 0x64, 0x72, 0x74, 0x62, 0x43, 0x0a, 0x78, 0x6b, 0x7a, + 0x6c, 0x42, 0x51, 0x48, 0x5a, 0x37, 0x56, 0x66, 0x38, 0x77, 0x53, 0x4e, + 0x35, 0x2f, 0x50, 0x72, 0x49, 0x4a, 0x49, 0x4f, 0x56, 0x38, 0x37, 0x56, + 0x71, 0x55, 0x51, 0x48, 0x51, 0x64, 0x39, 0x62, 0x70, 0x45, 0x71, 0x48, + 0x35, 0x47, 0x6f, 0x50, 0x37, 0x67, 0x68, 0x75, 0x35, 0x73, 0x4a, 0x66, + 0x30, 0x64, 0x67, 0x59, 0x7a, 0x51, 0x30, 0x6d, 0x67, 0x2f, 0x77, 0x75, + 0x31, 0x0a, 0x2b, 0x72, 0x55, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, + 0x4f, 0x42, 0x67, 0x44, 0x42, 0x2b, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, + 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, + 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, + 0x45, 0x47, 0x4d, 0x42, 0x30, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x64, 0x44, + 0x67, 0x51, 0x57, 0x42, 0x42, 0x54, 0x4c, 0x44, 0x38, 0x62, 0x66, 0x51, + 0x6b, 0x50, 0x4d, 0x50, 0x63, 0x75, 0x31, 0x53, 0x43, 0x4f, 0x68, 0x47, + 0x6e, 0x71, 0x6d, 0x4b, 0x72, 0x73, 0x30, 0x61, 0x44, 0x41, 0x66, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, + 0x42, 0x54, 0x4c, 0x44, 0x38, 0x62, 0x66, 0x51, 0x6b, 0x50, 0x4d, 0x0a, + 0x50, 0x63, 0x75, 0x31, 0x53, 0x43, 0x4f, 0x68, 0x47, 0x6e, 0x71, 0x6d, + 0x4b, 0x72, 0x73, 0x30, 0x61, 0x44, 0x41, 0x62, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x52, 0x45, 0x45, 0x46, 0x44, 0x41, 0x53, 0x67, 0x52, 0x42, 0x70, + 0x62, 0x6d, 0x5a, 0x76, 0x51, 0x47, 0x55, 0x74, 0x63, 0x33, 0x70, 0x70, + 0x5a, 0x32, 0x35, 0x76, 0x4c, 0x6d, 0x68, 0x31, 0x4d, 0x41, 0x30, 0x47, + 0x43, 0x53, 0x71, 0x47, 0x0a, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, + 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x44, + 0x4a, 0x30, 0x51, 0x35, 0x65, 0x4c, 0x74, 0x58, 0x4d, 0x73, 0x33, 0x77, + 0x2b, 0x79, 0x2f, 0x77, 0x39, 0x2f, 0x77, 0x30, 0x6f, 0x6c, 0x5a, 0x4d, + 0x45, 0x79, 0x4c, 0x2f, 0x61, 0x7a, 0x58, 0x6d, 0x34, 0x51, 0x35, 0x44, + 0x77, 0x70, 0x4c, 0x37, 0x76, 0x38, 0x75, 0x38, 0x68, 0x0a, 0x6d, 0x4c, + 0x7a, 0x55, 0x31, 0x46, 0x30, 0x47, 0x39, 0x75, 0x35, 0x43, 0x37, 0x44, + 0x42, 0x73, 0x6f, 0x4b, 0x71, 0x70, 0x79, 0x76, 0x47, 0x76, 0x69, 0x76, + 0x6f, 0x2f, 0x43, 0x33, 0x4e, 0x71, 0x50, 0x75, 0x6f, 0x75, 0x51, 0x48, + 0x34, 0x66, 0x72, 0x6c, 0x52, 0x68, 0x65, 0x65, 0x73, 0x75, 0x43, 0x44, + 0x66, 0x58, 0x49, 0x2f, 0x4f, 0x4d, 0x6e, 0x37, 0x34, 0x64, 0x73, 0x65, + 0x47, 0x6b, 0x0a, 0x64, 0x64, 0x75, 0x67, 0x34, 0x6c, 0x51, 0x55, 0x73, + 0x62, 0x6f, 0x63, 0x4b, 0x61, 0x51, 0x59, 0x39, 0x68, 0x4b, 0x36, 0x6f, + 0x68, 0x51, 0x55, 0x34, 0x7a, 0x45, 0x31, 0x79, 0x45, 0x44, 0x2f, 0x74, + 0x2b, 0x41, 0x46, 0x64, 0x6c, 0x66, 0x42, 0x48, 0x46, 0x6e, 0x79, 0x2b, + 0x4c, 0x2f, 0x6b, 0x37, 0x53, 0x56, 0x69, 0x58, 0x49, 0x54, 0x77, 0x66, + 0x6e, 0x34, 0x66, 0x73, 0x37, 0x37, 0x35, 0x0a, 0x74, 0x79, 0x45, 0x52, + 0x7a, 0x41, 0x4d, 0x42, 0x56, 0x6e, 0x43, 0x6e, 0x45, 0x4a, 0x49, 0x65, + 0x47, 0x7a, 0x53, 0x42, 0x48, 0x71, 0x32, 0x63, 0x47, 0x73, 0x4d, 0x45, + 0x50, 0x4f, 0x30, 0x43, 0x59, 0x64, 0x59, 0x65, 0x42, 0x76, 0x4e, 0x66, + 0x4f, 0x6f, 0x66, 0x79, 0x4b, 0x2f, 0x46, 0x46, 0x68, 0x2b, 0x55, 0x39, + 0x72, 0x4e, 0x48, 0x48, 0x56, 0x34, 0x53, 0x39, 0x61, 0x36, 0x37, 0x63, + 0x0a, 0x32, 0x50, 0x6d, 0x32, 0x47, 0x32, 0x4a, 0x77, 0x43, 0x7a, 0x30, + 0x32, 0x79, 0x55, 0x4c, 0x79, 0x4d, 0x74, 0x64, 0x36, 0x59, 0x65, 0x62, + 0x53, 0x32, 0x7a, 0x33, 0x50, 0x79, 0x4b, 0x6e, 0x4a, 0x6d, 0x39, 0x7a, + 0x62, 0x57, 0x45, 0x54, 0x58, 0x62, 0x7a, 0x69, 0x76, 0x66, 0x33, 0x6a, + 0x54, 0x6f, 0x36, 0x30, 0x61, 0x64, 0x62, 0x6f, 0x63, 0x77, 0x54, 0x5a, + 0x38, 0x6a, 0x78, 0x35, 0x74, 0x0a, 0x48, 0x4d, 0x4e, 0x31, 0x52, 0x71, + 0x34, 0x31, 0x42, 0x61, 0x62, 0x32, 0x58, 0x44, 0x30, 0x68, 0x37, 0x6c, + 0x62, 0x77, 0x79, 0x59, 0x49, 0x69, 0x4c, 0x58, 0x70, 0x55, 0x71, 0x33, + 0x44, 0x44, 0x66, 0x53, 0x4a, 0x6c, 0x67, 0x6e, 0x43, 0x57, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, + 0x6e, 0x20, 0x4f, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, + 0x67, 0x6e, 0x20, 0x4f, 0x55, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x20, 0x2d, 0x20, 0x52, 0x33, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x3d, 0x47, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x55, 0x3d, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x33, 0x0a, 0x23, + 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x33, 0x22, 0x0a, 0x23, 0x20, + 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x34, 0x38, 0x33, 0x35, + 0x37, 0x30, 0x33, 0x32, 0x37, 0x38, 0x34, 0x35, 0x39, 0x37, 0x35, 0x39, + 0x34, 0x32, 0x36, 0x32, 0x30, 0x39, 0x39, 0x35, 0x34, 0x0a, 0x23, 0x20, + 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x35, 0x3a, 0x64, 0x66, 0x3a, 0x62, + 0x38, 0x3a, 0x34, 0x39, 0x3a, 0x63, 0x61, 0x3a, 0x30, 0x35, 0x3a, 0x31, + 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x65, 0x65, 0x3a, 0x32, 0x64, 0x3a, 0x62, + 0x61, 0x3a, 0x31, 0x61, 0x3a, 0x63, 0x33, 0x3a, 0x33, 0x65, 0x3a, 0x62, + 0x30, 0x3a, 0x32, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x64, 0x36, 0x3a, 0x39, 0x62, 0x3a, 0x35, 0x36, 0x3a, 0x31, 0x31, + 0x3a, 0x34, 0x38, 0x3a, 0x66, 0x30, 0x3a, 0x31, 0x63, 0x3a, 0x37, 0x37, + 0x3a, 0x63, 0x35, 0x3a, 0x34, 0x35, 0x3a, 0x37, 0x38, 0x3a, 0x63, 0x31, + 0x3a, 0x30, 0x39, 0x3a, 0x32, 0x36, 0x3a, 0x64, 0x66, 0x3a, 0x35, 0x62, + 0x3a, 0x38, 0x35, 0x3a, 0x36, 0x39, 0x3a, 0x37, 0x36, 0x3a, 0x61, 0x64, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, + 0x62, 0x3a, 0x62, 0x35, 0x3a, 0x32, 0x32, 0x3a, 0x64, 0x37, 0x3a, 0x62, + 0x37, 0x3a, 0x66, 0x31, 0x3a, 0x32, 0x37, 0x3a, 0x61, 0x64, 0x3a, 0x36, + 0x61, 0x3a, 0x30, 0x31, 0x3a, 0x31, 0x33, 0x3a, 0x38, 0x36, 0x3a, 0x35, + 0x62, 0x3a, 0x64, 0x66, 0x3a, 0x31, 0x63, 0x3a, 0x64, 0x34, 0x3a, 0x31, + 0x30, 0x3a, 0x32, 0x65, 0x3a, 0x37, 0x64, 0x3a, 0x30, 0x37, 0x3a, 0x35, + 0x39, 0x3a, 0x61, 0x66, 0x3a, 0x36, 0x33, 0x3a, 0x35, 0x61, 0x3a, 0x37, + 0x63, 0x3a, 0x66, 0x34, 0x3a, 0x37, 0x32, 0x3a, 0x30, 0x64, 0x3a, 0x63, + 0x39, 0x3a, 0x36, 0x33, 0x3a, 0x63, 0x35, 0x3a, 0x33, 0x62, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x58, 0x7a, 0x43, 0x43, 0x41, + 0x6b, 0x65, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x4c, 0x42, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x49, 0x56, 0x68, 0x54, 0x43, + 0x4b, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x77, 0x54, + 0x44, 0x45, 0x67, 0x4d, 0x42, 0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x78, 0x4d, 0x58, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, + 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, + 0x49, 0x45, 0x4e, 0x42, 0x49, 0x43, 0x30, 0x67, 0x55, 0x6a, 0x4d, 0x78, + 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, + 0x43, 0x6b, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62, 0x46, 0x4e, 0x70, + 0x0a, 0x5a, 0x32, 0x34, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x4d, 0x54, 0x43, 0x6b, 0x64, 0x73, 0x62, 0x32, 0x4a, + 0x68, 0x62, 0x46, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x77, 0x48, 0x68, 0x63, + 0x4e, 0x4d, 0x44, 0x6b, 0x77, 0x4d, 0x7a, 0x45, 0x34, 0x4d, 0x54, 0x41, + 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x6b, + 0x77, 0x4d, 0x7a, 0x45, 0x34, 0x0a, 0x4d, 0x54, 0x41, 0x77, 0x4d, 0x44, + 0x41, 0x77, 0x57, 0x6a, 0x42, 0x4d, 0x4d, 0x53, 0x41, 0x77, 0x48, 0x67, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x64, 0x48, 0x62, 0x47, + 0x39, 0x69, 0x59, 0x57, 0x78, 0x54, 0x61, 0x57, 0x64, 0x75, 0x49, 0x46, + 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4c, 0x53, + 0x42, 0x53, 0x4d, 0x7a, 0x45, 0x54, 0x4d, 0x42, 0x45, 0x47, 0x0a, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4b, 0x52, 0x32, 0x78, 0x76, 0x59, + 0x6d, 0x46, 0x73, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x6a, 0x45, 0x54, 0x4d, + 0x42, 0x45, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x4b, 0x52, + 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, 0x55, 0x32, 0x6c, 0x6e, 0x62, + 0x6a, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, + 0x6f, 0x5a, 0x49, 0x0a, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, + 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, + 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4d, 0x77, 0x6c, + 0x64, 0x70, 0x42, 0x35, 0x42, 0x6e, 0x67, 0x69, 0x46, 0x76, 0x58, 0x41, + 0x67, 0x37, 0x61, 0x45, 0x79, 0x69, 0x69, 0x65, 0x2f, 0x51, 0x56, 0x32, + 0x45, 0x63, 0x57, 0x74, 0x69, 0x48, 0x4c, 0x38, 0x0a, 0x52, 0x67, 0x4a, + 0x44, 0x78, 0x37, 0x4b, 0x4b, 0x6e, 0x51, 0x52, 0x66, 0x4a, 0x4d, 0x73, + 0x75, 0x53, 0x2b, 0x46, 0x67, 0x67, 0x6b, 0x62, 0x68, 0x55, 0x71, 0x73, + 0x4d, 0x67, 0x55, 0x64, 0x77, 0x62, 0x4e, 0x31, 0x6b, 0x30, 0x65, 0x76, + 0x31, 0x4c, 0x4b, 0x4d, 0x50, 0x67, 0x6a, 0x30, 0x4d, 0x4b, 0x36, 0x36, + 0x58, 0x31, 0x37, 0x59, 0x55, 0x68, 0x68, 0x42, 0x35, 0x75, 0x7a, 0x73, + 0x54, 0x0a, 0x67, 0x48, 0x65, 0x4d, 0x43, 0x4f, 0x46, 0x4a, 0x30, 0x6d, + 0x70, 0x69, 0x4c, 0x78, 0x39, 0x65, 0x2b, 0x70, 0x5a, 0x6f, 0x33, 0x34, + 0x6b, 0x6e, 0x6c, 0x54, 0x69, 0x66, 0x42, 0x74, 0x63, 0x2b, 0x79, 0x63, + 0x73, 0x6d, 0x57, 0x51, 0x31, 0x7a, 0x33, 0x72, 0x44, 0x49, 0x36, 0x53, + 0x59, 0x4f, 0x67, 0x78, 0x58, 0x47, 0x37, 0x31, 0x75, 0x4c, 0x30, 0x67, + 0x52, 0x67, 0x79, 0x6b, 0x6d, 0x6d, 0x0a, 0x4b, 0x50, 0x5a, 0x70, 0x4f, + 0x2f, 0x62, 0x4c, 0x79, 0x43, 0x69, 0x52, 0x35, 0x5a, 0x32, 0x4b, 0x59, + 0x56, 0x63, 0x33, 0x72, 0x48, 0x51, 0x55, 0x33, 0x48, 0x54, 0x67, 0x4f, + 0x75, 0x35, 0x79, 0x4c, 0x79, 0x36, 0x63, 0x2b, 0x39, 0x43, 0x37, 0x76, + 0x2f, 0x55, 0x39, 0x41, 0x4f, 0x45, 0x47, 0x4d, 0x2b, 0x69, 0x43, 0x4b, + 0x36, 0x35, 0x54, 0x70, 0x6a, 0x6f, 0x57, 0x63, 0x34, 0x7a, 0x64, 0x0a, + 0x51, 0x51, 0x34, 0x67, 0x4f, 0x73, 0x43, 0x30, 0x70, 0x36, 0x48, 0x70, + 0x73, 0x6b, 0x2b, 0x51, 0x4c, 0x6a, 0x4a, 0x67, 0x36, 0x56, 0x66, 0x4c, + 0x75, 0x51, 0x53, 0x53, 0x61, 0x47, 0x6a, 0x6c, 0x4f, 0x43, 0x5a, 0x67, + 0x64, 0x62, 0x4b, 0x66, 0x64, 0x2f, 0x2b, 0x52, 0x46, 0x4f, 0x2b, 0x75, + 0x49, 0x45, 0x6e, 0x38, 0x72, 0x55, 0x41, 0x56, 0x53, 0x4e, 0x45, 0x43, + 0x4d, 0x57, 0x45, 0x5a, 0x0a, 0x58, 0x72, 0x69, 0x58, 0x37, 0x36, 0x31, + 0x33, 0x74, 0x32, 0x53, 0x61, 0x65, 0x72, 0x39, 0x66, 0x77, 0x52, 0x50, + 0x76, 0x6d, 0x32, 0x4c, 0x37, 0x44, 0x57, 0x7a, 0x67, 0x56, 0x47, 0x6b, + 0x57, 0x71, 0x51, 0x50, 0x61, 0x62, 0x75, 0x6d, 0x44, 0x6b, 0x33, 0x46, + 0x32, 0x78, 0x6d, 0x6d, 0x46, 0x67, 0x68, 0x63, 0x43, 0x41, 0x77, 0x45, + 0x41, 0x41, 0x61, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77, 0x0a, 0x44, 0x67, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, + 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, + 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, + 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x49, 0x2f, 0x77, 0x53, 0x33, + 0x2b, 0x6f, 0x0a, 0x4c, 0x6b, 0x55, 0x6b, 0x72, 0x6b, 0x31, 0x51, 0x2b, + 0x6d, 0x4f, 0x61, 0x69, 0x39, 0x37, 0x69, 0x33, 0x52, 0x75, 0x38, 0x4d, + 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, + 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x41, + 0x51, 0x42, 0x4c, 0x51, 0x4e, 0x76, 0x41, 0x55, 0x4b, 0x72, 0x2b, 0x79, + 0x41, 0x7a, 0x76, 0x39, 0x35, 0x5a, 0x55, 0x0a, 0x52, 0x55, 0x6d, 0x37, + 0x6c, 0x67, 0x41, 0x4a, 0x51, 0x61, 0x79, 0x7a, 0x45, 0x34, 0x61, 0x47, + 0x4b, 0x41, 0x63, 0x7a, 0x79, 0x6d, 0x76, 0x6d, 0x64, 0x4c, 0x6d, 0x36, + 0x41, 0x43, 0x32, 0x75, 0x70, 0x41, 0x72, 0x54, 0x39, 0x66, 0x48, 0x78, + 0x44, 0x34, 0x71, 0x2f, 0x63, 0x32, 0x64, 0x4b, 0x67, 0x38, 0x64, 0x45, + 0x65, 0x33, 0x6a, 0x67, 0x72, 0x32, 0x35, 0x73, 0x62, 0x77, 0x4d, 0x70, + 0x0a, 0x6a, 0x6a, 0x4d, 0x35, 0x52, 0x63, 0x4f, 0x4f, 0x35, 0x4c, 0x6c, + 0x58, 0x62, 0x4b, 0x72, 0x38, 0x45, 0x70, 0x62, 0x73, 0x55, 0x38, 0x59, + 0x74, 0x35, 0x43, 0x52, 0x73, 0x75, 0x5a, 0x52, 0x6a, 0x2b, 0x39, 0x78, + 0x54, 0x61, 0x47, 0x64, 0x57, 0x50, 0x6f, 0x4f, 0x34, 0x7a, 0x7a, 0x55, + 0x68, 0x77, 0x38, 0x6c, 0x6f, 0x2f, 0x73, 0x37, 0x61, 0x77, 0x6c, 0x4f, + 0x71, 0x7a, 0x4a, 0x43, 0x4b, 0x0a, 0x36, 0x66, 0x42, 0x64, 0x52, 0x6f, + 0x79, 0x56, 0x33, 0x58, 0x70, 0x59, 0x4b, 0x42, 0x6f, 0x76, 0x48, 0x64, + 0x37, 0x4e, 0x41, 0x44, 0x64, 0x42, 0x6a, 0x2b, 0x31, 0x45, 0x62, 0x64, + 0x64, 0x54, 0x4b, 0x4a, 0x64, 0x2b, 0x38, 0x32, 0x63, 0x45, 0x48, 0x68, + 0x58, 0x58, 0x69, 0x70, 0x61, 0x30, 0x30, 0x39, 0x35, 0x4d, 0x4a, 0x36, + 0x52, 0x4d, 0x47, 0x33, 0x4e, 0x7a, 0x64, 0x76, 0x51, 0x58, 0x0a, 0x6d, + 0x63, 0x49, 0x66, 0x65, 0x67, 0x37, 0x6a, 0x4c, 0x51, 0x69, 0x74, 0x43, + 0x68, 0x77, 0x73, 0x2f, 0x7a, 0x79, 0x72, 0x56, 0x51, 0x34, 0x50, 0x6b, + 0x58, 0x34, 0x32, 0x36, 0x38, 0x4e, 0x58, 0x53, 0x62, 0x37, 0x68, 0x4c, + 0x69, 0x31, 0x38, 0x59, 0x49, 0x76, 0x44, 0x51, 0x56, 0x45, 0x54, 0x49, + 0x35, 0x33, 0x4f, 0x39, 0x7a, 0x4a, 0x72, 0x6c, 0x41, 0x47, 0x6f, 0x6d, + 0x65, 0x63, 0x73, 0x0a, 0x4d, 0x78, 0x38, 0x36, 0x4f, 0x79, 0x58, 0x53, + 0x68, 0x6b, 0x44, 0x4f, 0x4f, 0x79, 0x79, 0x47, 0x65, 0x4d, 0x6c, 0x68, + 0x4c, 0x78, 0x53, 0x36, 0x37, 0x74, 0x74, 0x56, 0x62, 0x39, 0x2b, 0x45, + 0x37, 0x67, 0x55, 0x4a, 0x54, 0x62, 0x30, 0x6f, 0x32, 0x48, 0x4c, 0x4f, + 0x30, 0x32, 0x4a, 0x51, 0x5a, 0x52, 0x37, 0x72, 0x6b, 0x70, 0x65, 0x44, + 0x4d, 0x64, 0x6d, 0x7a, 0x74, 0x63, 0x70, 0x48, 0x0a, 0x57, 0x44, 0x39, + 0x66, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x75, 0x74, 0x6f, 0x72, 0x69, + 0x64, 0x61, 0x64, 0x20, 0x64, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x63, 0x69, 0x6f, 0x6e, 0x20, 0x46, 0x69, 0x72, + 0x6d, 0x61, 0x70, 0x72, 0x6f, 0x66, 0x65, 0x73, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x20, 0x43, 0x49, 0x46, 0x20, 0x41, 0x36, 0x32, 0x36, 0x33, 0x34, + 0x30, 0x36, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x75, 0x74, 0x6f, 0x72, 0x69, + 0x64, 0x61, 0x64, 0x20, 0x64, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x63, 0x69, 0x6f, 0x6e, 0x20, 0x46, 0x69, 0x72, + 0x6d, 0x61, 0x70, 0x72, 0x6f, 0x66, 0x65, 0x73, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x20, 0x43, 0x49, 0x46, 0x20, 0x41, 0x36, 0x32, 0x36, 0x33, 0x34, + 0x30, 0x36, 0x38, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x41, 0x75, 0x74, 0x6f, 0x72, 0x69, 0x64, 0x61, 0x64, 0x20, + 0x64, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x63, 0x69, 0x6f, 0x6e, 0x20, 0x46, 0x69, 0x72, 0x6d, 0x61, 0x70, 0x72, + 0x6f, 0x66, 0x65, 0x73, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x43, 0x49, + 0x46, 0x20, 0x41, 0x36, 0x32, 0x36, 0x33, 0x34, 0x30, 0x36, 0x38, 0x22, + 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x36, + 0x30, 0x34, 0x37, 0x32, 0x37, 0x34, 0x32, 0x39, 0x37, 0x32, 0x36, 0x32, + 0x37, 0x35, 0x33, 0x38, 0x38, 0x37, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x37, 0x33, 0x3a, 0x33, 0x61, 0x3a, 0x37, 0x34, 0x3a, 0x37, + 0x61, 0x3a, 0x65, 0x63, 0x3a, 0x62, 0x62, 0x3a, 0x61, 0x33, 0x3a, 0x39, + 0x36, 0x3a, 0x61, 0x36, 0x3a, 0x63, 0x32, 0x3a, 0x65, 0x34, 0x3a, 0x65, + 0x32, 0x3a, 0x63, 0x38, 0x3a, 0x39, 0x62, 0x3a, 0x63, 0x30, 0x3a, 0x63, + 0x33, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x65, + 0x3a, 0x63, 0x35, 0x3a, 0x66, 0x62, 0x3a, 0x33, 0x66, 0x3a, 0x63, 0x38, + 0x3a, 0x65, 0x31, 0x3a, 0x62, 0x66, 0x3a, 0x63, 0x34, 0x3a, 0x65, 0x35, + 0x3a, 0x34, 0x66, 0x3a, 0x30, 0x33, 0x3a, 0x30, 0x37, 0x3a, 0x35, 0x61, + 0x3a, 0x39, 0x61, 0x3a, 0x65, 0x38, 0x3a, 0x30, 0x30, 0x3a, 0x62, 0x37, + 0x3a, 0x66, 0x37, 0x3a, 0x62, 0x36, 0x3a, 0x66, 0x61, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x34, 0x3a, 0x30, + 0x34, 0x3a, 0x38, 0x30, 0x3a, 0x32, 0x38, 0x3a, 0x62, 0x66, 0x3a, 0x31, + 0x66, 0x3a, 0x32, 0x38, 0x3a, 0x36, 0x34, 0x3a, 0x64, 0x34, 0x3a, 0x38, + 0x66, 0x3a, 0x39, 0x61, 0x3a, 0x64, 0x34, 0x3a, 0x64, 0x38, 0x3a, 0x33, + 0x32, 0x3a, 0x39, 0x34, 0x3a, 0x33, 0x36, 0x3a, 0x36, 0x61, 0x3a, 0x38, + 0x32, 0x3a, 0x38, 0x38, 0x3a, 0x35, 0x36, 0x3a, 0x35, 0x35, 0x3a, 0x33, + 0x66, 0x3a, 0x33, 0x62, 0x3a, 0x31, 0x34, 0x3a, 0x33, 0x30, 0x3a, 0x33, + 0x66, 0x3a, 0x39, 0x30, 0x3a, 0x31, 0x34, 0x3a, 0x37, 0x66, 0x3a, 0x35, + 0x64, 0x3a, 0x34, 0x30, 0x3a, 0x65, 0x66, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x47, 0x46, 0x44, 0x43, 0x43, 0x41, 0x2f, 0x79, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x49, 0x55, 0x2b, 0x77, 0x37, + 0x37, 0x76, 0x75, 0x79, 0x53, 0x46, 0x38, 0x77, 0x44, 0x51, 0x59, 0x4a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, + 0x42, 0x51, 0x41, 0x77, 0x55, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x0a, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x56, 0x4d, + 0x78, 0x51, 0x6a, 0x42, 0x41, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, + 0x4d, 0x4f, 0x55, 0x46, 0x31, 0x64, 0x47, 0x39, 0x79, 0x61, 0x57, 0x52, + 0x68, 0x5a, 0x43, 0x42, 0x6b, 0x5a, 0x53, 0x42, 0x44, 0x5a, 0x58, 0x4a, + 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x6a, 0x61, 0x57, 0x39, + 0x75, 0x49, 0x45, 0x5a, 0x70, 0x63, 0x6d, 0x31, 0x68, 0x0a, 0x63, 0x48, + 0x4a, 0x76, 0x5a, 0x6d, 0x56, 0x7a, 0x61, 0x57, 0x39, 0x75, 0x59, 0x57, + 0x77, 0x67, 0x51, 0x30, 0x6c, 0x47, 0x49, 0x45, 0x45, 0x32, 0x4d, 0x6a, + 0x59, 0x7a, 0x4e, 0x44, 0x41, 0x32, 0x4f, 0x44, 0x41, 0x65, 0x46, 0x77, + 0x30, 0x77, 0x4f, 0x54, 0x41, 0x31, 0x4d, 0x6a, 0x41, 0x77, 0x4f, 0x44, + 0x4d, 0x34, 0x4d, 0x54, 0x56, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4d, 0x44, + 0x45, 0x79, 0x0a, 0x4d, 0x7a, 0x45, 0x77, 0x4f, 0x44, 0x4d, 0x34, 0x4d, + 0x54, 0x56, 0x61, 0x4d, 0x46, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x56, 0x54, 0x4d, + 0x55, 0x49, 0x77, 0x51, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, + 0x44, 0x6c, 0x42, 0x64, 0x58, 0x52, 0x76, 0x63, 0x6d, 0x6c, 0x6b, 0x59, + 0x57, 0x51, 0x67, 0x5a, 0x47, 0x55, 0x67, 0x0a, 0x51, 0x32, 0x56, 0x79, + 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x59, 0x32, 0x6c, 0x76, + 0x62, 0x69, 0x42, 0x47, 0x61, 0x58, 0x4a, 0x74, 0x59, 0x58, 0x42, 0x79, + 0x62, 0x32, 0x5a, 0x6c, 0x63, 0x32, 0x6c, 0x76, 0x62, 0x6d, 0x46, 0x73, + 0x49, 0x45, 0x4e, 0x4a, 0x52, 0x69, 0x42, 0x42, 0x4e, 0x6a, 0x49, 0x32, + 0x4d, 0x7a, 0x51, 0x77, 0x4e, 0x6a, 0x67, 0x77, 0x67, 0x67, 0x49, 0x69, + 0x0a, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, + 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, + 0x43, 0x41, 0x51, 0x44, 0x4b, 0x6c, 0x6d, 0x75, 0x4f, 0x36, 0x76, 0x6a, + 0x37, 0x38, 0x61, 0x49, 0x31, 0x34, 0x48, 0x39, 0x4d, 0x32, 0x75, 0x44, + 0x44, 0x55, 0x74, 0x64, 0x39, 0x0a, 0x74, 0x68, 0x44, 0x49, 0x41, 0x6c, + 0x36, 0x7a, 0x51, 0x79, 0x72, 0x45, 0x54, 0x32, 0x71, 0x79, 0x79, 0x68, + 0x78, 0x64, 0x4b, 0x4a, 0x70, 0x34, 0x45, 0x52, 0x70, 0x70, 0x57, 0x56, + 0x65, 0x76, 0x74, 0x53, 0x42, 0x43, 0x35, 0x49, 0x73, 0x50, 0x35, 0x74, + 0x39, 0x62, 0x70, 0x67, 0x4f, 0x53, 0x4c, 0x2f, 0x55, 0x52, 0x35, 0x47, + 0x4c, 0x58, 0x4d, 0x6e, 0x45, 0x34, 0x32, 0x51, 0x51, 0x4d, 0x0a, 0x63, + 0x61, 0x73, 0x39, 0x55, 0x58, 0x34, 0x50, 0x42, 0x39, 0x39, 0x6a, 0x42, + 0x56, 0x7a, 0x70, 0x76, 0x35, 0x52, 0x76, 0x77, 0x53, 0x6d, 0x43, 0x77, + 0x4c, 0x54, 0x61, 0x55, 0x62, 0x44, 0x42, 0x50, 0x4c, 0x75, 0x74, 0x4e, + 0x30, 0x70, 0x63, 0x79, 0x76, 0x46, 0x4c, 0x4e, 0x67, 0x34, 0x6b, 0x71, + 0x37, 0x2f, 0x44, 0x68, 0x48, 0x66, 0x39, 0x71, 0x46, 0x44, 0x30, 0x73, + 0x65, 0x66, 0x47, 0x0a, 0x4c, 0x39, 0x49, 0x74, 0x57, 0x59, 0x31, 0x36, + 0x43, 0x6b, 0x36, 0x57, 0x61, 0x56, 0x49, 0x43, 0x71, 0x6a, 0x61, 0x59, + 0x37, 0x50, 0x7a, 0x36, 0x46, 0x49, 0x4d, 0x4d, 0x4e, 0x78, 0x2f, 0x4a, + 0x6b, 0x6a, 0x64, 0x2f, 0x31, 0x34, 0x45, 0x74, 0x35, 0x63, 0x53, 0x35, + 0x34, 0x44, 0x34, 0x30, 0x2f, 0x6d, 0x66, 0x30, 0x50, 0x6d, 0x62, 0x52, + 0x30, 0x2f, 0x52, 0x41, 0x7a, 0x31, 0x35, 0x69, 0x0a, 0x4e, 0x41, 0x39, + 0x77, 0x42, 0x6a, 0x34, 0x67, 0x47, 0x46, 0x72, 0x4f, 0x39, 0x33, 0x49, + 0x62, 0x4a, 0x57, 0x79, 0x54, 0x64, 0x42, 0x53, 0x54, 0x6f, 0x33, 0x4f, + 0x78, 0x44, 0x71, 0x71, 0x48, 0x45, 0x43, 0x4e, 0x5a, 0x58, 0x79, 0x41, + 0x46, 0x47, 0x55, 0x66, 0x74, 0x61, 0x49, 0x36, 0x53, 0x45, 0x73, 0x70, + 0x64, 0x2f, 0x4e, 0x59, 0x72, 0x73, 0x70, 0x49, 0x38, 0x49, 0x4d, 0x2f, + 0x68, 0x0a, 0x58, 0x36, 0x38, 0x67, 0x76, 0x71, 0x42, 0x32, 0x66, 0x33, + 0x62, 0x6c, 0x37, 0x42, 0x71, 0x47, 0x59, 0x54, 0x4d, 0x2b, 0x35, 0x33, + 0x75, 0x30, 0x50, 0x36, 0x41, 0x50, 0x6a, 0x71, 0x4b, 0x35, 0x61, 0x6d, + 0x2b, 0x35, 0x68, 0x79, 0x5a, 0x76, 0x51, 0x57, 0x79, 0x49, 0x70, 0x6c, + 0x44, 0x39, 0x61, 0x6d, 0x4d, 0x4c, 0x39, 0x5a, 0x4d, 0x57, 0x47, 0x78, + 0x6d, 0x50, 0x73, 0x75, 0x32, 0x62, 0x0a, 0x6d, 0x38, 0x6d, 0x51, 0x39, + 0x51, 0x45, 0x4d, 0x33, 0x78, 0x6b, 0x39, 0x44, 0x7a, 0x34, 0x34, 0x49, + 0x38, 0x6b, 0x76, 0x6a, 0x77, 0x7a, 0x52, 0x41, 0x76, 0x34, 0x62, 0x56, + 0x64, 0x5a, 0x4f, 0x30, 0x49, 0x30, 0x38, 0x72, 0x30, 0x2b, 0x6b, 0x38, + 0x2f, 0x36, 0x76, 0x4b, 0x74, 0x4d, 0x46, 0x6e, 0x58, 0x6b, 0x49, 0x6f, + 0x63, 0x74, 0x58, 0x4d, 0x62, 0x53, 0x63, 0x79, 0x4a, 0x43, 0x79, 0x0a, + 0x5a, 0x2f, 0x51, 0x59, 0x46, 0x70, 0x4d, 0x36, 0x2f, 0x45, 0x66, 0x59, + 0x30, 0x58, 0x69, 0x57, 0x4d, 0x52, 0x2b, 0x36, 0x4b, 0x77, 0x78, 0x66, + 0x58, 0x5a, 0x6d, 0x74, 0x59, 0x34, 0x6c, 0x61, 0x4a, 0x43, 0x42, 0x32, + 0x32, 0x4e, 0x2f, 0x39, 0x71, 0x30, 0x36, 0x6d, 0x49, 0x71, 0x71, 0x64, + 0x58, 0x75, 0x59, 0x6e, 0x69, 0x6e, 0x31, 0x6f, 0x4b, 0x61, 0x50, 0x6e, + 0x69, 0x72, 0x6a, 0x61, 0x0a, 0x45, 0x62, 0x73, 0x58, 0x4c, 0x5a, 0x6d, + 0x64, 0x45, 0x79, 0x52, 0x47, 0x39, 0x38, 0x58, 0x69, 0x32, 0x4a, 0x2b, + 0x4f, 0x66, 0x38, 0x65, 0x50, 0x64, 0x47, 0x31, 0x61, 0x73, 0x75, 0x68, + 0x79, 0x39, 0x61, 0x7a, 0x75, 0x4a, 0x42, 0x43, 0x74, 0x4c, 0x78, 0x54, + 0x61, 0x2f, 0x79, 0x32, 0x61, 0x52, 0x6e, 0x46, 0x48, 0x76, 0x6b, 0x4c, + 0x66, 0x75, 0x77, 0x48, 0x62, 0x39, 0x48, 0x2f, 0x54, 0x0a, 0x4b, 0x49, + 0x38, 0x78, 0x57, 0x56, 0x76, 0x54, 0x79, 0x51, 0x4b, 0x6d, 0x74, 0x46, + 0x4c, 0x4b, 0x62, 0x70, 0x66, 0x37, 0x51, 0x38, 0x55, 0x49, 0x4a, 0x6d, + 0x2b, 0x4b, 0x39, 0x4c, 0x76, 0x39, 0x6e, 0x79, 0x69, 0x71, 0x44, 0x64, + 0x56, 0x46, 0x38, 0x78, 0x4d, 0x36, 0x48, 0x64, 0x6a, 0x41, 0x65, 0x49, + 0x39, 0x42, 0x5a, 0x7a, 0x77, 0x65, 0x6c, 0x47, 0x53, 0x75, 0x65, 0x77, + 0x76, 0x46, 0x0a, 0x36, 0x4e, 0x6b, 0x42, 0x69, 0x44, 0x6b, 0x61, 0x6c, + 0x34, 0x5a, 0x6b, 0x51, 0x64, 0x55, 0x37, 0x68, 0x77, 0x78, 0x75, 0x2b, + 0x67, 0x2f, 0x47, 0x76, 0x55, 0x67, 0x55, 0x76, 0x7a, 0x6c, 0x4e, 0x31, + 0x4a, 0x35, 0x42, 0x74, 0x6f, 0x2b, 0x57, 0x48, 0x57, 0x4f, 0x57, 0x6b, + 0x39, 0x6d, 0x56, 0x42, 0x6e, 0x67, 0x78, 0x61, 0x4a, 0x34, 0x33, 0x42, + 0x6a, 0x75, 0x41, 0x69, 0x55, 0x56, 0x68, 0x0a, 0x4f, 0x53, 0x50, 0x48, + 0x47, 0x30, 0x53, 0x6a, 0x46, 0x65, 0x55, 0x63, 0x2b, 0x4a, 0x49, 0x77, + 0x75, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x34, 0x48, 0x76, + 0x4d, 0x49, 0x48, 0x73, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x49, 0x4d, 0x41, 0x59, 0x42, + 0x41, 0x66, 0x38, 0x43, 0x41, 0x51, 0x45, 0x77, 0x44, 0x67, 0x59, 0x44, + 0x0a, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, + 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x52, 0x6c, 0x7a, 0x65, 0x75, + 0x72, 0x4e, 0x52, 0x34, 0x41, 0x50, 0x6e, 0x37, 0x56, 0x64, 0x4d, 0x41, + 0x63, 0x74, 0x48, 0x4e, 0x48, 0x44, 0x68, 0x70, 0x6b, 0x4c, 0x7a, 0x43, + 0x42, 0x70, 0x67, 0x59, 0x44, 0x0a, 0x56, 0x52, 0x30, 0x67, 0x42, 0x49, + 0x47, 0x65, 0x4d, 0x49, 0x47, 0x62, 0x4d, 0x49, 0x47, 0x59, 0x42, 0x67, + 0x52, 0x56, 0x48, 0x53, 0x41, 0x41, 0x4d, 0x49, 0x47, 0x50, 0x4d, 0x43, + 0x38, 0x47, 0x43, 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x77, + 0x49, 0x42, 0x46, 0x69, 0x4e, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69, + 0x38, 0x76, 0x64, 0x33, 0x64, 0x33, 0x4c, 0x6d, 0x5a, 0x70, 0x0a, 0x63, + 0x6d, 0x31, 0x68, 0x63, 0x48, 0x4a, 0x76, 0x5a, 0x6d, 0x56, 0x7a, 0x61, + 0x57, 0x39, 0x75, 0x59, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, + 0x32, 0x4e, 0x77, 0x63, 0x7a, 0x42, 0x63, 0x42, 0x67, 0x67, 0x72, 0x42, + 0x67, 0x45, 0x46, 0x42, 0x51, 0x63, 0x43, 0x41, 0x6a, 0x42, 0x51, 0x48, + 0x6b, 0x34, 0x41, 0x55, 0x41, 0x42, 0x68, 0x41, 0x48, 0x4d, 0x41, 0x5a, + 0x51, 0x42, 0x76, 0x0a, 0x41, 0x43, 0x41, 0x41, 0x5a, 0x41, 0x42, 0x6c, + 0x41, 0x43, 0x41, 0x41, 0x62, 0x41, 0x42, 0x68, 0x41, 0x43, 0x41, 0x41, + 0x51, 0x67, 0x42, 0x76, 0x41, 0x47, 0x34, 0x41, 0x59, 0x51, 0x42, 0x75, + 0x41, 0x47, 0x38, 0x41, 0x64, 0x67, 0x42, 0x68, 0x41, 0x43, 0x41, 0x41, + 0x4e, 0x41, 0x41, 0x33, 0x41, 0x43, 0x41, 0x41, 0x51, 0x67, 0x42, 0x68, + 0x41, 0x48, 0x49, 0x41, 0x59, 0x77, 0x42, 0x6c, 0x0a, 0x41, 0x47, 0x77, + 0x41, 0x62, 0x77, 0x42, 0x75, 0x41, 0x47, 0x45, 0x41, 0x49, 0x41, 0x41, + 0x77, 0x41, 0x44, 0x67, 0x41, 0x4d, 0x41, 0x41, 0x78, 0x41, 0x44, 0x63, + 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, + 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, + 0x42, 0x41, 0x42, 0x64, 0x39, 0x6f, 0x50, 0x6d, 0x30, 0x33, 0x63, 0x58, + 0x46, 0x0a, 0x36, 0x36, 0x31, 0x4c, 0x4a, 0x4c, 0x57, 0x68, 0x41, 0x71, + 0x76, 0x64, 0x70, 0x59, 0x68, 0x4b, 0x73, 0x67, 0x39, 0x56, 0x53, 0x79, + 0x74, 0x58, 0x6a, 0x44, 0x76, 0x6c, 0x4d, 0x64, 0x33, 0x2b, 0x78, 0x44, + 0x4c, 0x78, 0x35, 0x31, 0x74, 0x6b, 0x6c, 0x6a, 0x59, 0x79, 0x47, 0x4f, + 0x79, 0x6c, 0x4d, 0x6e, 0x66, 0x58, 0x34, 0x30, 0x53, 0x32, 0x77, 0x42, + 0x45, 0x71, 0x67, 0x4c, 0x6b, 0x39, 0x0a, 0x61, 0x6d, 0x35, 0x38, 0x6d, + 0x39, 0x4f, 0x74, 0x2f, 0x4d, 0x50, 0x57, 0x6f, 0x2b, 0x5a, 0x6b, 0x4b, + 0x58, 0x7a, 0x52, 0x34, 0x54, 0x67, 0x65, 0x67, 0x69, 0x76, 0x2f, 0x4a, + 0x32, 0x57, 0x76, 0x2b, 0x78, 0x59, 0x56, 0x78, 0x43, 0x35, 0x78, 0x68, + 0x4f, 0x57, 0x31, 0x2f, 0x2f, 0x71, 0x6b, 0x52, 0x37, 0x31, 0x6b, 0x4d, + 0x72, 0x76, 0x32, 0x4a, 0x59, 0x53, 0x69, 0x4a, 0x30, 0x4c, 0x31, 0x0a, + 0x49, 0x4c, 0x44, 0x43, 0x45, 0x78, 0x41, 0x52, 0x7a, 0x52, 0x41, 0x56, + 0x75, 0x6b, 0x4b, 0x51, 0x4b, 0x74, 0x4a, 0x45, 0x34, 0x5a, 0x59, 0x6d, + 0x36, 0x7a, 0x46, 0x49, 0x45, 0x76, 0x30, 0x71, 0x32, 0x73, 0x6b, 0x47, + 0x7a, 0x33, 0x51, 0x65, 0x71, 0x55, 0x76, 0x56, 0x68, 0x79, 0x6a, 0x35, + 0x65, 0x54, 0x53, 0x53, 0x50, 0x69, 0x35, 0x45, 0x36, 0x50, 0x61, 0x50, + 0x54, 0x34, 0x38, 0x31, 0x0a, 0x50, 0x79, 0x57, 0x7a, 0x4f, 0x64, 0x78, + 0x6a, 0x4b, 0x70, 0x42, 0x72, 0x49, 0x46, 0x2f, 0x45, 0x55, 0x68, 0x4a, + 0x4f, 0x6c, 0x79, 0x77, 0x71, 0x72, 0x4a, 0x32, 0x58, 0x33, 0x6b, 0x6a, + 0x79, 0x6f, 0x32, 0x62, 0x62, 0x77, 0x74, 0x4b, 0x44, 0x6c, 0x61, 0x5a, + 0x6d, 0x70, 0x35, 0x34, 0x6c, 0x44, 0x2b, 0x6b, 0x4c, 0x4d, 0x35, 0x46, + 0x6c, 0x43, 0x6c, 0x72, 0x44, 0x32, 0x56, 0x51, 0x53, 0x0a, 0x33, 0x61, + 0x2f, 0x44, 0x54, 0x67, 0x34, 0x66, 0x4a, 0x6c, 0x34, 0x4e, 0x33, 0x4c, + 0x4f, 0x4e, 0x37, 0x4e, 0x57, 0x42, 0x63, 0x4e, 0x37, 0x53, 0x54, 0x79, + 0x51, 0x46, 0x38, 0x32, 0x78, 0x4f, 0x39, 0x55, 0x78, 0x4a, 0x5a, 0x6f, + 0x33, 0x52, 0x2f, 0x39, 0x49, 0x4c, 0x4a, 0x55, 0x46, 0x49, 0x2f, 0x6c, + 0x47, 0x45, 0x78, 0x6b, 0x4b, 0x76, 0x67, 0x41, 0x54, 0x50, 0x30, 0x48, + 0x35, 0x6b, 0x0a, 0x53, 0x65, 0x54, 0x79, 0x33, 0x36, 0x4c, 0x73, 0x73, + 0x55, 0x7a, 0x41, 0x4b, 0x68, 0x33, 0x6e, 0x74, 0x4c, 0x46, 0x6c, 0x6f, + 0x73, 0x53, 0x38, 0x38, 0x5a, 0x6a, 0x30, 0x71, 0x6e, 0x41, 0x48, 0x59, + 0x37, 0x53, 0x34, 0x32, 0x6a, 0x74, 0x4d, 0x2b, 0x6b, 0x41, 0x69, 0x4d, + 0x46, 0x73, 0x52, 0x70, 0x76, 0x41, 0x46, 0x44, 0x73, 0x59, 0x43, 0x41, + 0x30, 0x69, 0x72, 0x68, 0x70, 0x75, 0x46, 0x0a, 0x33, 0x64, 0x76, 0x64, + 0x36, 0x71, 0x4a, 0x32, 0x67, 0x48, 0x4e, 0x39, 0x39, 0x5a, 0x77, 0x45, + 0x78, 0x45, 0x57, 0x4e, 0x35, 0x37, 0x6b, 0x63, 0x69, 0x35, 0x37, 0x71, + 0x31, 0x33, 0x58, 0x52, 0x63, 0x72, 0x48, 0x65, 0x64, 0x55, 0x54, 0x6e, + 0x51, 0x6e, 0x33, 0x69, 0x56, 0x32, 0x74, 0x39, 0x33, 0x4a, 0x6d, 0x38, + 0x50, 0x59, 0x4d, 0x6f, 0x36, 0x6f, 0x43, 0x54, 0x6a, 0x63, 0x56, 0x4d, + 0x0a, 0x5a, 0x63, 0x46, 0x77, 0x67, 0x62, 0x67, 0x34, 0x2f, 0x45, 0x4d, + 0x78, 0x73, 0x76, 0x59, 0x44, 0x4e, 0x45, 0x65, 0x79, 0x72, 0x50, 0x73, + 0x69, 0x42, 0x73, 0x73, 0x65, 0x33, 0x52, 0x64, 0x48, 0x48, 0x46, 0x39, + 0x6d, 0x75, 0x64, 0x4d, 0x61, 0x6f, 0x74, 0x6f, 0x52, 0x73, 0x61, 0x53, + 0x38, 0x49, 0x38, 0x6e, 0x6b, 0x76, 0x6f, 0x66, 0x2f, 0x75, 0x5a, 0x53, + 0x32, 0x2b, 0x46, 0x30, 0x67, 0x0a, 0x53, 0x74, 0x52, 0x66, 0x35, 0x37, + 0x31, 0x6f, 0x65, 0x32, 0x58, 0x79, 0x46, 0x52, 0x37, 0x53, 0x4f, 0x71, + 0x6b, 0x74, 0x36, 0x64, 0x68, 0x72, 0x4a, 0x4b, 0x79, 0x58, 0x57, 0x45, + 0x52, 0x48, 0x72, 0x56, 0x6b, 0x59, 0x38, 0x53, 0x46, 0x6c, 0x63, 0x4e, + 0x37, 0x4f, 0x4e, 0x47, 0x43, 0x6f, 0x51, 0x50, 0x48, 0x7a, 0x50, 0x4b, + 0x54, 0x44, 0x4b, 0x43, 0x4f, 0x4d, 0x2f, 0x69, 0x63, 0x7a, 0x0a, 0x51, + 0x30, 0x43, 0x67, 0x46, 0x7a, 0x7a, 0x72, 0x36, 0x6a, 0x75, 0x77, 0x63, + 0x71, 0x61, 0x6a, 0x75, 0x55, 0x70, 0x4c, 0x58, 0x68, 0x5a, 0x49, 0x39, + 0x4c, 0x4b, 0x38, 0x79, 0x49, 0x79, 0x53, 0x78, 0x5a, 0x32, 0x66, 0x72, + 0x48, 0x49, 0x32, 0x76, 0x44, 0x53, 0x41, 0x4e, 0x47, 0x75, 0x70, 0x69, + 0x35, 0x4c, 0x41, 0x75, 0x42, 0x66, 0x74, 0x37, 0x48, 0x5a, 0x54, 0x39, + 0x53, 0x51, 0x42, 0x0a, 0x6a, 0x4c, 0x4d, 0x69, 0x36, 0x45, 0x74, 0x38, + 0x56, 0x63, 0x61, 0x64, 0x2b, 0x71, 0x4d, 0x55, 0x75, 0x32, 0x57, 0x46, + 0x62, 0x6d, 0x35, 0x50, 0x45, 0x6e, 0x34, 0x4b, 0x50, 0x4a, 0x32, 0x56, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x49, 0x7a, 0x65, 0x6e, 0x70, 0x65, 0x2e, + 0x63, 0x6f, 0x6d, 0x20, 0x4f, 0x3d, 0x49, 0x5a, 0x45, 0x4e, 0x50, 0x45, + 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x49, 0x7a, 0x65, 0x6e, + 0x70, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x4f, 0x3d, 0x49, 0x5a, 0x45, + 0x4e, 0x50, 0x45, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x49, 0x7a, 0x65, 0x6e, 0x70, + 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x39, 0x31, 0x37, 0x35, 0x36, 0x33, 0x30, + 0x36, 0x35, 0x34, 0x39, 0x30, 0x33, 0x38, 0x39, 0x32, 0x34, 0x31, 0x35, + 0x39, 0x35, 0x35, 0x33, 0x36, 0x36, 0x38, 0x36, 0x39, 0x39, 0x31, 0x34, + 0x30, 0x32, 0x36, 0x32, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x61, 0x36, 0x3a, 0x62, 0x30, 0x3a, 0x63, 0x64, 0x3a, 0x38, 0x35, + 0x3a, 0x38, 0x30, 0x3a, 0x64, 0x61, 0x3a, 0x35, 0x63, 0x3a, 0x35, 0x30, + 0x3a, 0x33, 0x34, 0x3a, 0x61, 0x33, 0x3a, 0x33, 0x39, 0x3a, 0x39, 0x30, + 0x3a, 0x32, 0x66, 0x3a, 0x35, 0x35, 0x3a, 0x36, 0x37, 0x3a, 0x37, 0x33, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x66, 0x3a, + 0x37, 0x38, 0x3a, 0x33, 0x64, 0x3a, 0x32, 0x35, 0x3a, 0x35, 0x32, 0x3a, + 0x31, 0x38, 0x3a, 0x61, 0x37, 0x3a, 0x34, 0x61, 0x3a, 0x36, 0x35, 0x3a, + 0x33, 0x39, 0x3a, 0x37, 0x31, 0x3a, 0x62, 0x35, 0x3a, 0x32, 0x63, 0x3a, + 0x61, 0x32, 0x3a, 0x39, 0x63, 0x3a, 0x34, 0x35, 0x3a, 0x31, 0x35, 0x3a, + 0x36, 0x66, 0x3a, 0x65, 0x39, 0x3a, 0x31, 0x39, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x35, 0x3a, 0x33, 0x30, + 0x3a, 0x63, 0x63, 0x3a, 0x38, 0x65, 0x3a, 0x39, 0x38, 0x3a, 0x33, 0x32, + 0x3a, 0x31, 0x35, 0x3a, 0x30, 0x32, 0x3a, 0x62, 0x61, 0x3a, 0x64, 0x39, + 0x3a, 0x36, 0x66, 0x3a, 0x39, 0x62, 0x3a, 0x31, 0x66, 0x3a, 0x62, 0x61, + 0x3a, 0x31, 0x62, 0x3a, 0x30, 0x39, 0x3a, 0x39, 0x65, 0x3a, 0x32, 0x64, + 0x3a, 0x32, 0x39, 0x3a, 0x39, 0x65, 0x3a, 0x30, 0x66, 0x3a, 0x34, 0x35, + 0x3a, 0x34, 0x38, 0x3a, 0x62, 0x62, 0x3a, 0x39, 0x31, 0x3a, 0x34, 0x66, + 0x3a, 0x33, 0x36, 0x3a, 0x33, 0x62, 0x3a, 0x63, 0x30, 0x3a, 0x64, 0x34, + 0x3a, 0x35, 0x33, 0x3a, 0x31, 0x66, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x46, 0x38, 0x54, 0x43, 0x43, 0x41, 0x39, 0x6d, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x41, 0x4c, 0x43, 0x33, 0x57, + 0x68, 0x5a, 0x49, 0x58, 0x37, 0x2f, 0x68, 0x79, 0x2f, 0x57, 0x4c, 0x31, + 0x78, 0x6e, 0x6d, 0x66, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, + 0x44, 0x41, 0x34, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x46, 0x55, 0x7a, 0x45, 0x55, + 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x4c, + 0x53, 0x56, 0x70, 0x46, 0x54, 0x6c, 0x42, 0x46, 0x49, 0x46, 0x4d, 0x75, + 0x51, 0x53, 0x34, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x4d, 0x4d, 0x43, 0x6b, 0x6c, 0x36, 0x0a, 0x5a, 0x57, 0x35, + 0x77, 0x5a, 0x53, 0x35, 0x6a, 0x62, 0x32, 0x30, 0x77, 0x48, 0x68, 0x63, + 0x4e, 0x4d, 0x44, 0x63, 0x78, 0x4d, 0x6a, 0x45, 0x7a, 0x4d, 0x54, 0x4d, + 0x77, 0x4f, 0x44, 0x49, 0x34, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x63, + 0x78, 0x4d, 0x6a, 0x45, 0x7a, 0x4d, 0x44, 0x67, 0x79, 0x4e, 0x7a, 0x49, + 0x31, 0x57, 0x6a, 0x41, 0x34, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, + 0x44, 0x0a, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x46, 0x55, 0x7a, + 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, + 0x77, 0x4c, 0x53, 0x56, 0x70, 0x46, 0x54, 0x6c, 0x42, 0x46, 0x49, 0x46, + 0x4d, 0x75, 0x51, 0x53, 0x34, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x43, 0x6b, 0x6c, 0x36, 0x5a, 0x57, + 0x35, 0x77, 0x5a, 0x53, 0x35, 0x6a, 0x0a, 0x62, 0x32, 0x30, 0x77, 0x67, + 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, + 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, + 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, + 0x6f, 0x49, 0x43, 0x41, 0x51, 0x44, 0x4a, 0x30, 0x33, 0x72, 0x4b, 0x44, + 0x78, 0x36, 0x73, 0x70, 0x34, 0x62, 0x6f, 0x46, 0x6d, 0x56, 0x71, 0x0a, + 0x73, 0x63, 0x49, 0x62, 0x52, 0x54, 0x4a, 0x78, 0x6c, 0x64, 0x6e, 0x2b, + 0x45, 0x46, 0x76, 0x4d, 0x72, 0x2b, 0x65, 0x6c, 0x65, 0x51, 0x47, 0x50, + 0x69, 0x63, 0x50, 0x4b, 0x38, 0x6c, 0x56, 0x78, 0x39, 0x33, 0x65, 0x2b, + 0x64, 0x35, 0x54, 0x7a, 0x63, 0x71, 0x51, 0x73, 0x52, 0x4e, 0x69, 0x65, + 0x6b, 0x70, 0x73, 0x55, 0x4f, 0x71, 0x48, 0x6e, 0x4a, 0x4a, 0x41, 0x4b, + 0x43, 0x6c, 0x61, 0x4f, 0x0a, 0x78, 0x64, 0x67, 0x6d, 0x6c, 0x4f, 0x48, + 0x5a, 0x53, 0x4f, 0x45, 0x74, 0x50, 0x74, 0x6f, 0x4b, 0x63, 0x74, 0x32, + 0x6a, 0x6d, 0x52, 0x58, 0x61, 0x67, 0x61, 0x4b, 0x48, 0x39, 0x48, 0x74, + 0x75, 0x4a, 0x6e, 0x65, 0x4a, 0x57, 0x4b, 0x33, 0x57, 0x36, 0x77, 0x79, + 0x79, 0x51, 0x58, 0x70, 0x7a, 0x62, 0x6d, 0x33, 0x62, 0x65, 0x6e, 0x68, + 0x42, 0x36, 0x51, 0x69, 0x49, 0x45, 0x6e, 0x36, 0x48, 0x0a, 0x4c, 0x6d, + 0x59, 0x52, 0x59, 0x32, 0x78, 0x55, 0x2b, 0x7a, 0x79, 0x64, 0x63, 0x73, + 0x43, 0x38, 0x4c, 0x76, 0x2f, 0x43, 0x74, 0x39, 0x30, 0x4e, 0x64, 0x75, + 0x4d, 0x36, 0x31, 0x2f, 0x65, 0x30, 0x61, 0x4c, 0x36, 0x69, 0x39, 0x65, + 0x4f, 0x42, 0x62, 0x73, 0x46, 0x47, 0x62, 0x31, 0x32, 0x4e, 0x34, 0x45, + 0x33, 0x47, 0x56, 0x46, 0x57, 0x4a, 0x47, 0x6a, 0x4d, 0x78, 0x43, 0x72, + 0x46, 0x58, 0x0a, 0x75, 0x61, 0x4f, 0x4b, 0x6d, 0x4d, 0x50, 0x73, 0x4f, + 0x7a, 0x54, 0x46, 0x6c, 0x55, 0x46, 0x70, 0x66, 0x6e, 0x58, 0x43, 0x50, + 0x43, 0x44, 0x46, 0x59, 0x62, 0x70, 0x52, 0x52, 0x36, 0x41, 0x67, 0x6b, + 0x4a, 0x4f, 0x68, 0x6b, 0x45, 0x76, 0x7a, 0x54, 0x6e, 0x79, 0x46, 0x52, + 0x56, 0x53, 0x61, 0x30, 0x51, 0x55, 0x6d, 0x51, 0x62, 0x43, 0x31, 0x54, + 0x52, 0x30, 0x7a, 0x76, 0x73, 0x51, 0x44, 0x0a, 0x79, 0x43, 0x56, 0x38, + 0x77, 0x58, 0x44, 0x62, 0x4f, 0x2f, 0x51, 0x4a, 0x4c, 0x56, 0x51, 0x6e, + 0x53, 0x4b, 0x77, 0x76, 0x34, 0x63, 0x53, 0x73, 0x50, 0x73, 0x6a, 0x4c, + 0x6b, 0x6b, 0x78, 0x54, 0x4f, 0x54, 0x63, 0x6a, 0x37, 0x4e, 0x4d, 0x42, + 0x2b, 0x65, 0x41, 0x4a, 0x52, 0x45, 0x31, 0x4e, 0x5a, 0x4d, 0x44, 0x68, + 0x44, 0x56, 0x71, 0x48, 0x49, 0x72, 0x79, 0x74, 0x47, 0x36, 0x50, 0x2b, + 0x0a, 0x4a, 0x72, 0x55, 0x56, 0x38, 0x36, 0x66, 0x38, 0x68, 0x42, 0x6e, + 0x70, 0x37, 0x4b, 0x47, 0x49, 0x74, 0x45, 0x52, 0x70, 0x68, 0x49, 0x50, + 0x7a, 0x69, 0x64, 0x46, 0x30, 0x42, 0x71, 0x6e, 0x4d, 0x43, 0x39, 0x62, + 0x43, 0x33, 0x69, 0x65, 0x46, 0x55, 0x43, 0x62, 0x4b, 0x46, 0x37, 0x6a, + 0x4a, 0x65, 0x6f, 0x64, 0x57, 0x4c, 0x42, 0x6f, 0x42, 0x48, 0x6d, 0x79, + 0x2b, 0x45, 0x36, 0x30, 0x51, 0x0a, 0x72, 0x4c, 0x55, 0x6b, 0x39, 0x54, + 0x69, 0x52, 0x6f, 0x64, 0x5a, 0x4c, 0x32, 0x76, 0x47, 0x37, 0x30, 0x74, + 0x35, 0x48, 0x74, 0x66, 0x47, 0x38, 0x67, 0x66, 0x5a, 0x5a, 0x61, 0x38, + 0x38, 0x5a, 0x55, 0x2b, 0x6d, 0x4e, 0x46, 0x63, 0x74, 0x4b, 0x79, 0x36, + 0x6c, 0x76, 0x52, 0x4f, 0x55, 0x62, 0x51, 0x63, 0x2f, 0x68, 0x68, 0x71, + 0x66, 0x4b, 0x30, 0x47, 0x71, 0x66, 0x76, 0x45, 0x79, 0x4e, 0x0a, 0x42, + 0x6a, 0x4e, 0x61, 0x6f, 0x6f, 0x58, 0x6c, 0x6b, 0x44, 0x57, 0x67, 0x59, + 0x6c, 0x77, 0x57, 0x54, 0x76, 0x44, 0x6a, 0x6f, 0x76, 0x6f, 0x44, 0x47, + 0x72, 0x51, 0x73, 0x63, 0x62, 0x4e, 0x59, 0x4c, 0x4e, 0x35, 0x37, 0x43, + 0x39, 0x73, 0x61, 0x44, 0x2b, 0x76, 0x65, 0x49, 0x52, 0x38, 0x47, 0x64, + 0x77, 0x59, 0x44, 0x73, 0x4d, 0x6e, 0x76, 0x6d, 0x66, 0x7a, 0x41, 0x75, + 0x55, 0x38, 0x4c, 0x0a, 0x68, 0x69, 0x6a, 0x2b, 0x30, 0x72, 0x6e, 0x71, + 0x34, 0x39, 0x71, 0x6c, 0x77, 0x30, 0x64, 0x70, 0x45, 0x75, 0x44, 0x62, + 0x38, 0x50, 0x59, 0x5a, 0x69, 0x2b, 0x31, 0x37, 0x63, 0x4e, 0x63, 0x43, + 0x31, 0x75, 0x32, 0x48, 0x47, 0x43, 0x67, 0x73, 0x42, 0x43, 0x52, 0x4d, + 0x64, 0x2b, 0x52, 0x49, 0x69, 0x68, 0x72, 0x47, 0x4f, 0x35, 0x72, 0x55, + 0x44, 0x38, 0x72, 0x36, 0x64, 0x64, 0x49, 0x42, 0x0a, 0x51, 0x46, 0x71, + 0x4e, 0x65, 0x62, 0x2b, 0x4c, 0x7a, 0x30, 0x76, 0x50, 0x71, 0x68, 0x62, + 0x42, 0x6c, 0x65, 0x53, 0x74, 0x54, 0x49, 0x6f, 0x2b, 0x46, 0x35, 0x48, + 0x55, 0x73, 0x57, 0x4c, 0x6c, 0x67, 0x75, 0x57, 0x41, 0x42, 0x4b, 0x51, + 0x44, 0x66, 0x6f, 0x32, 0x2f, 0x32, 0x6e, 0x2b, 0x69, 0x44, 0x35, 0x64, + 0x50, 0x44, 0x4e, 0x4d, 0x4e, 0x2b, 0x39, 0x66, 0x52, 0x35, 0x58, 0x4a, + 0x2b, 0x0a, 0x48, 0x4d, 0x68, 0x33, 0x2f, 0x31, 0x75, 0x61, 0x44, 0x37, + 0x65, 0x75, 0x42, 0x55, 0x62, 0x6c, 0x38, 0x61, 0x67, 0x57, 0x37, 0x45, + 0x65, 0x6b, 0x46, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x34, + 0x48, 0x32, 0x4d, 0x49, 0x48, 0x7a, 0x4d, 0x49, 0x47, 0x77, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x45, 0x45, 0x67, 0x61, 0x67, 0x77, 0x67, 0x61, + 0x57, 0x42, 0x44, 0x32, 0x6c, 0x75, 0x0a, 0x5a, 0x6d, 0x39, 0x41, 0x61, + 0x58, 0x70, 0x6c, 0x62, 0x6e, 0x42, 0x6c, 0x4c, 0x6d, 0x4e, 0x76, 0x62, + 0x61, 0x53, 0x42, 0x6b, 0x54, 0x43, 0x42, 0x6a, 0x6a, 0x46, 0x48, 0x4d, + 0x45, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x2b, 0x53, + 0x56, 0x70, 0x46, 0x54, 0x6c, 0x42, 0x46, 0x49, 0x46, 0x4d, 0x75, 0x51, + 0x53, 0x34, 0x67, 0x4c, 0x53, 0x42, 0x44, 0x53, 0x55, 0x59, 0x67, 0x0a, + 0x51, 0x54, 0x41, 0x78, 0x4d, 0x7a, 0x4d, 0x33, 0x4d, 0x6a, 0x59, 0x77, + 0x4c, 0x56, 0x4a, 0x4e, 0x5a, 0x58, 0x4a, 0x6a, 0x4c, 0x6c, 0x5a, 0x70, + 0x64, 0x47, 0x39, 0x79, 0x61, 0x57, 0x45, 0x74, 0x52, 0x32, 0x46, 0x7a, + 0x64, 0x47, 0x56, 0x70, 0x65, 0x69, 0x42, 0x55, 0x4d, 0x54, 0x41, 0x31, + 0x4e, 0x53, 0x42, 0x47, 0x4e, 0x6a, 0x49, 0x67, 0x55, 0x7a, 0x67, 0x78, + 0x51, 0x7a, 0x42, 0x42, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6b, + 0x4d, 0x4f, 0x6b, 0x46, 0x32, 0x5a, 0x47, 0x45, 0x67, 0x5a, 0x47, 0x56, + 0x73, 0x49, 0x45, 0x31, 0x6c, 0x5a, 0x47, 0x6c, 0x30, 0x5a, 0x58, 0x4a, + 0x79, 0x59, 0x57, 0x35, 0x6c, 0x62, 0x79, 0x42, 0x46, 0x64, 0x47, 0x39, + 0x79, 0x59, 0x6d, 0x6c, 0x6b, 0x5a, 0x57, 0x45, 0x67, 0x4d, 0x54, 0x51, + 0x67, 0x4c, 0x53, 0x41, 0x77, 0x4d, 0x54, 0x41, 0x78, 0x0a, 0x4d, 0x43, + 0x42, 0x57, 0x61, 0x58, 0x52, 0x76, 0x63, 0x6d, 0x6c, 0x68, 0x4c, 0x55, + 0x64, 0x68, 0x63, 0x33, 0x52, 0x6c, 0x61, 0x58, 0x6f, 0x77, 0x44, 0x77, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, + 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, + 0x4d, 0x43, 0x0a, 0x41, 0x51, 0x59, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x42, 0x30, 0x63, 0x5a, + 0x51, 0x36, 0x6f, 0x38, 0x69, 0x56, 0x37, 0x74, 0x4a, 0x48, 0x50, 0x35, + 0x4c, 0x47, 0x78, 0x35, 0x72, 0x31, 0x56, 0x64, 0x47, 0x77, 0x46, 0x4d, + 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, + 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x0a, 0x41, 0x34, 0x49, 0x43, + 0x41, 0x51, 0x42, 0x34, 0x70, 0x67, 0x77, 0x57, 0x53, 0x70, 0x39, 0x4d, + 0x69, 0x44, 0x72, 0x41, 0x79, 0x77, 0x36, 0x6c, 0x46, 0x6e, 0x32, 0x66, + 0x75, 0x55, 0x68, 0x66, 0x47, 0x49, 0x38, 0x4e, 0x59, 0x6a, 0x62, 0x32, + 0x7a, 0x52, 0x6c, 0x72, 0x72, 0x4b, 0x76, 0x56, 0x39, 0x70, 0x46, 0x39, + 0x72, 0x6e, 0x48, 0x7a, 0x50, 0x37, 0x4d, 0x4f, 0x65, 0x49, 0x57, 0x62, + 0x0a, 0x6c, 0x61, 0x51, 0x6e, 0x49, 0x55, 0x64, 0x43, 0x53, 0x6e, 0x78, + 0x49, 0x4f, 0x76, 0x56, 0x46, 0x66, 0x4c, 0x4d, 0x4d, 0x6a, 0x6c, 0x46, + 0x34, 0x72, 0x4a, 0x55, 0x54, 0x33, 0x73, 0x62, 0x39, 0x66, 0x62, 0x67, + 0x61, 0x6b, 0x45, 0x79, 0x72, 0x6b, 0x67, 0x50, 0x48, 0x37, 0x55, 0x49, + 0x42, 0x7a, 0x67, 0x2f, 0x59, 0x73, 0x66, 0x71, 0x69, 0x6b, 0x75, 0x46, + 0x67, 0x62, 0x61, 0x35, 0x36, 0x0a, 0x61, 0x77, 0x6d, 0x71, 0x78, 0x69, + 0x6e, 0x75, 0x61, 0x45, 0x6c, 0x6e, 0x4d, 0x49, 0x41, 0x6b, 0x65, 0x6a, + 0x45, 0x57, 0x4f, 0x56, 0x74, 0x2b, 0x38, 0x52, 0x77, 0x75, 0x33, 0x57, + 0x77, 0x4a, 0x72, 0x66, 0x49, 0x78, 0x77, 0x59, 0x4a, 0x4f, 0x75, 0x62, + 0x76, 0x35, 0x76, 0x72, 0x38, 0x71, 0x68, 0x54, 0x2f, 0x41, 0x51, 0x4b, + 0x4d, 0x36, 0x57, 0x66, 0x78, 0x5a, 0x53, 0x7a, 0x77, 0x6f, 0x0a, 0x4a, + 0x4e, 0x75, 0x30, 0x46, 0x58, 0x57, 0x75, 0x44, 0x59, 0x69, 0x36, 0x4c, + 0x6e, 0x50, 0x41, 0x76, 0x56, 0x69, 0x48, 0x35, 0x55, 0x4c, 0x79, 0x36, + 0x31, 0x37, 0x75, 0x48, 0x6a, 0x41, 0x69, 0x6d, 0x63, 0x73, 0x33, 0x30, + 0x63, 0x51, 0x68, 0x62, 0x49, 0x48, 0x73, 0x76, 0x6d, 0x30, 0x6d, 0x35, + 0x68, 0x7a, 0x6b, 0x51, 0x69, 0x43, 0x65, 0x52, 0x37, 0x43, 0x73, 0x67, + 0x31, 0x6c, 0x77, 0x0a, 0x4c, 0x44, 0x58, 0x57, 0x72, 0x7a, 0x59, 0x30, + 0x74, 0x4d, 0x30, 0x37, 0x2b, 0x44, 0x4b, 0x6f, 0x37, 0x2b, 0x4e, 0x34, + 0x69, 0x66, 0x75, 0x4e, 0x52, 0x53, 0x7a, 0x61, 0x6e, 0x4c, 0x68, 0x2b, + 0x51, 0x42, 0x78, 0x68, 0x35, 0x7a, 0x36, 0x69, 0x6b, 0x69, 0x78, 0x4c, + 0x38, 0x73, 0x33, 0x36, 0x6d, 0x4c, 0x59, 0x70, 0x2f, 0x2f, 0x50, 0x79, + 0x65, 0x36, 0x6b, 0x66, 0x4c, 0x71, 0x43, 0x54, 0x0a, 0x56, 0x79, 0x76, + 0x65, 0x68, 0x51, 0x50, 0x35, 0x61, 0x54, 0x66, 0x4c, 0x6e, 0x6e, 0x68, + 0x71, 0x42, 0x62, 0x54, 0x46, 0x4d, 0x58, 0x69, 0x4a, 0x37, 0x48, 0x71, + 0x6e, 0x68, 0x65, 0x47, 0x35, 0x65, 0x7a, 0x7a, 0x65, 0x76, 0x68, 0x35, + 0x35, 0x68, 0x4d, 0x36, 0x66, 0x63, 0x41, 0x35, 0x5a, 0x77, 0x6a, 0x55, + 0x75, 0x6b, 0x43, 0x6f, 0x78, 0x32, 0x65, 0x52, 0x46, 0x65, 0x6b, 0x47, + 0x6b, 0x0a, 0x4c, 0x68, 0x4f, 0x62, 0x4e, 0x41, 0x35, 0x6d, 0x65, 0x30, + 0x6d, 0x72, 0x5a, 0x4a, 0x66, 0x51, 0x52, 0x73, 0x4e, 0x35, 0x6e, 0x58, + 0x4a, 0x51, 0x59, 0x36, 0x61, 0x59, 0x57, 0x77, 0x61, 0x39, 0x53, 0x47, + 0x33, 0x59, 0x4f, 0x59, 0x4e, 0x77, 0x36, 0x44, 0x58, 0x77, 0x42, 0x64, + 0x47, 0x71, 0x76, 0x4f, 0x50, 0x62, 0x79, 0x41, 0x4c, 0x71, 0x66, 0x50, + 0x32, 0x43, 0x32, 0x73, 0x4a, 0x62, 0x0a, 0x55, 0x6a, 0x57, 0x75, 0x6d, + 0x44, 0x71, 0x74, 0x75, 0x6a, 0x57, 0x54, 0x49, 0x36, 0x63, 0x66, 0x53, + 0x4e, 0x30, 0x31, 0x52, 0x70, 0x69, 0x79, 0x45, 0x47, 0x6a, 0x6b, 0x70, + 0x54, 0x48, 0x43, 0x43, 0x6c, 0x67, 0x75, 0x47, 0x59, 0x45, 0x51, 0x79, + 0x56, 0x42, 0x31, 0x2f, 0x4f, 0x70, 0x61, 0x46, 0x73, 0x34, 0x52, 0x31, + 0x2b, 0x37, 0x76, 0x55, 0x49, 0x67, 0x74, 0x59, 0x66, 0x38, 0x2f, 0x0a, + 0x51, 0x6e, 0x4d, 0x46, 0x6c, 0x45, 0x50, 0x56, 0x6a, 0x6a, 0x78, 0x4f, + 0x41, 0x54, 0x6f, 0x5a, 0x70, 0x52, 0x39, 0x47, 0x54, 0x6e, 0x66, 0x51, + 0x58, 0x65, 0x57, 0x42, 0x49, 0x69, 0x47, 0x48, 0x2f, 0x70, 0x52, 0x39, + 0x68, 0x4e, 0x69, 0x54, 0x72, 0x64, 0x5a, 0x6f, 0x51, 0x30, 0x69, 0x79, + 0x32, 0x2b, 0x74, 0x7a, 0x4a, 0x4f, 0x65, 0x52, 0x66, 0x31, 0x53, 0x6b, + 0x74, 0x6f, 0x41, 0x2b, 0x0a, 0x6e, 0x61, 0x4d, 0x38, 0x54, 0x48, 0x4c, + 0x43, 0x56, 0x38, 0x53, 0x67, 0x31, 0x4d, 0x77, 0x34, 0x4a, 0x38, 0x37, + 0x56, 0x42, 0x70, 0x36, 0x69, 0x53, 0x4e, 0x6e, 0x70, 0x6e, 0x38, 0x36, + 0x43, 0x63, 0x44, 0x61, 0x54, 0x6d, 0x6a, 0x76, 0x66, 0x6c, 0x69, 0x48, + 0x6a, 0x57, 0x62, 0x63, 0x4d, 0x32, 0x70, 0x45, 0x33, 0x38, 0x50, 0x31, + 0x5a, 0x57, 0x72, 0x4f, 0x5a, 0x79, 0x47, 0x6c, 0x73, 0x0a, 0x51, 0x79, + 0x59, 0x42, 0x4e, 0x57, 0x4e, 0x67, 0x56, 0x59, 0x6b, 0x44, 0x4f, 0x6e, + 0x58, 0x59, 0x75, 0x6b, 0x72, 0x5a, 0x56, 0x50, 0x2f, 0x75, 0x33, 0x6f, + 0x44, 0x59, 0x4c, 0x64, 0x45, 0x34, 0x31, 0x56, 0x34, 0x74, 0x43, 0x35, + 0x68, 0x39, 0x50, 0x6d, 0x7a, 0x62, 0x2f, 0x43, 0x61, 0x49, 0x78, 0x77, + 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x68, 0x61, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, + 0x72, 0x63, 0x65, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x2d, 0x20, 0x32, + 0x30, 0x30, 0x38, 0x20, 0x4f, 0x3d, 0x41, 0x43, 0x20, 0x43, 0x61, 0x6d, + 0x65, 0x72, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x20, 0x53, 0x2e, 0x41, 0x2e, + 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x43, 0x68, 0x61, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x20, + 0x6f, 0x66, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x65, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x2d, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, + 0x4f, 0x3d, 0x41, 0x43, 0x20, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x66, 0x69, + 0x72, 0x6d, 0x61, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x68, 0x61, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, + 0x72, 0x63, 0x65, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x2d, 0x20, 0x32, + 0x30, 0x30, 0x38, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x31, 0x31, 0x38, 0x30, 0x36, 0x38, 0x32, 0x32, 0x34, + 0x38, 0x34, 0x38, 0x30, 0x31, 0x35, 0x39, 0x37, 0x31, 0x34, 0x36, 0x0a, + 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x65, 0x3a, 0x38, 0x30, + 0x3a, 0x39, 0x65, 0x3a, 0x38, 0x34, 0x3a, 0x35, 0x61, 0x3a, 0x30, 0x65, + 0x3a, 0x36, 0x35, 0x3a, 0x30, 0x62, 0x3a, 0x31, 0x37, 0x3a, 0x30, 0x32, + 0x3a, 0x66, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x31, 0x38, 0x3a, 0x32, 0x61, + 0x3a, 0x33, 0x65, 0x3a, 0x64, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x37, 0x38, 0x3a, 0x36, 0x61, 0x3a, 0x37, 0x34, 0x3a, + 0x61, 0x63, 0x3a, 0x37, 0x36, 0x3a, 0x61, 0x62, 0x3a, 0x31, 0x34, 0x3a, + 0x37, 0x66, 0x3a, 0x39, 0x63, 0x3a, 0x36, 0x61, 0x3a, 0x33, 0x30, 0x3a, + 0x35, 0x30, 0x3a, 0x62, 0x61, 0x3a, 0x39, 0x65, 0x3a, 0x61, 0x38, 0x3a, + 0x37, 0x65, 0x3a, 0x66, 0x65, 0x3a, 0x39, 0x61, 0x3a, 0x63, 0x65, 0x3a, + 0x33, 0x63, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x30, 0x36, 0x3a, 0x33, 0x65, 0x3a, 0x34, 0x61, 0x3a, 0x66, 0x61, + 0x3a, 0x63, 0x34, 0x3a, 0x39, 0x31, 0x3a, 0x64, 0x66, 0x3a, 0x64, 0x33, + 0x3a, 0x33, 0x32, 0x3a, 0x66, 0x33, 0x3a, 0x30, 0x38, 0x3a, 0x39, 0x62, + 0x3a, 0x38, 0x35, 0x3a, 0x34, 0x32, 0x3a, 0x65, 0x39, 0x3a, 0x34, 0x36, + 0x3a, 0x31, 0x37, 0x3a, 0x64, 0x38, 0x3a, 0x39, 0x33, 0x3a, 0x64, 0x37, + 0x3a, 0x66, 0x65, 0x3a, 0x39, 0x34, 0x3a, 0x34, 0x65, 0x3a, 0x31, 0x30, + 0x3a, 0x61, 0x37, 0x3a, 0x39, 0x33, 0x3a, 0x37, 0x65, 0x3a, 0x65, 0x32, + 0x3a, 0x39, 0x64, 0x3a, 0x39, 0x36, 0x3a, 0x39, 0x33, 0x3a, 0x63, 0x30, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x48, 0x54, 0x7a, 0x43, + 0x43, 0x42, 0x54, 0x65, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x4a, 0x41, 0x4b, 0x50, 0x61, 0x51, 0x6e, 0x36, 0x6b, 0x73, 0x61, 0x37, + 0x61, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x4d, 0x49, 0x47, + 0x75, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x0a, 0x56, 0x51, + 0x51, 0x47, 0x45, 0x77, 0x4a, 0x46, 0x56, 0x54, 0x46, 0x44, 0x4d, 0x45, + 0x45, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x78, 0x4d, 0x36, 0x54, 0x57, + 0x46, 0x6b, 0x63, 0x6d, 0x6c, 0x6b, 0x49, 0x43, 0x68, 0x7a, 0x5a, 0x57, + 0x55, 0x67, 0x59, 0x33, 0x56, 0x79, 0x63, 0x6d, 0x56, 0x75, 0x64, 0x43, + 0x42, 0x68, 0x5a, 0x47, 0x52, 0x79, 0x5a, 0x58, 0x4e, 0x7a, 0x49, 0x47, + 0x46, 0x30, 0x0a, 0x49, 0x48, 0x64, 0x33, 0x64, 0x79, 0x35, 0x6a, 0x59, + 0x57, 0x31, 0x6c, 0x63, 0x6d, 0x5a, 0x70, 0x63, 0x6d, 0x31, 0x68, 0x4c, + 0x6d, 0x4e, 0x76, 0x62, 0x53, 0x39, 0x68, 0x5a, 0x47, 0x52, 0x79, 0x5a, + 0x58, 0x4e, 0x7a, 0x4b, 0x54, 0x45, 0x53, 0x4d, 0x42, 0x41, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x52, 0x4d, 0x4a, 0x51, 0x54, 0x67, 0x79, 0x4e, + 0x7a, 0x51, 0x7a, 0x4d, 0x6a, 0x67, 0x33, 0x0a, 0x4d, 0x52, 0x73, 0x77, + 0x47, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x4a, 0x42, + 0x51, 0x79, 0x42, 0x44, 0x59, 0x57, 0x31, 0x6c, 0x63, 0x6d, 0x5a, 0x70, + 0x63, 0x6d, 0x31, 0x68, 0x49, 0x46, 0x4d, 0x75, 0x51, 0x53, 0x34, 0x78, + 0x4b, 0x54, 0x41, 0x6e, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, + 0x49, 0x45, 0x4e, 0x6f, 0x59, 0x57, 0x31, 0x69, 0x5a, 0x58, 0x4a, 0x7a, + 0x0a, 0x49, 0x47, 0x39, 0x6d, 0x49, 0x45, 0x4e, 0x76, 0x62, 0x57, 0x31, + 0x6c, 0x63, 0x6d, 0x4e, 0x6c, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, + 0x67, 0x4c, 0x53, 0x41, 0x79, 0x4d, 0x44, 0x41, 0x34, 0x4d, 0x42, 0x34, + 0x58, 0x44, 0x54, 0x41, 0x34, 0x4d, 0x44, 0x67, 0x77, 0x4d, 0x54, 0x45, + 0x79, 0x4d, 0x6a, 0x6b, 0x31, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x4d, + 0x34, 0x4d, 0x44, 0x63, 0x7a, 0x0a, 0x4d, 0x54, 0x45, 0x79, 0x4d, 0x6a, + 0x6b, 0x31, 0x4d, 0x46, 0x6f, 0x77, 0x67, 0x61, 0x34, 0x78, 0x43, 0x7a, + 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, + 0x56, 0x56, 0x4d, 0x55, 0x4d, 0x77, 0x51, 0x51, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x48, 0x45, 0x7a, 0x70, 0x4e, 0x59, 0x57, 0x52, 0x79, 0x61, 0x57, + 0x51, 0x67, 0x4b, 0x48, 0x4e, 0x6c, 0x5a, 0x53, 0x42, 0x6a, 0x0a, 0x64, + 0x58, 0x4a, 0x79, 0x5a, 0x57, 0x35, 0x30, 0x49, 0x47, 0x46, 0x6b, 0x5a, + 0x48, 0x4a, 0x6c, 0x63, 0x33, 0x4d, 0x67, 0x59, 0x58, 0x51, 0x67, 0x64, + 0x33, 0x64, 0x33, 0x4c, 0x6d, 0x4e, 0x68, 0x62, 0x57, 0x56, 0x79, 0x5a, + 0x6d, 0x6c, 0x79, 0x62, 0x57, 0x45, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, + 0x32, 0x46, 0x6b, 0x5a, 0x48, 0x4a, 0x6c, 0x63, 0x33, 0x4d, 0x70, 0x4d, + 0x52, 0x49, 0x77, 0x0a, 0x45, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x46, + 0x45, 0x77, 0x6c, 0x42, 0x4f, 0x44, 0x49, 0x33, 0x4e, 0x44, 0x4d, 0x79, + 0x4f, 0x44, 0x63, 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x6f, 0x54, 0x45, 0x6b, 0x46, 0x44, 0x49, 0x45, 0x4e, 0x68, + 0x62, 0x57, 0x56, 0x79, 0x5a, 0x6d, 0x6c, 0x79, 0x62, 0x57, 0x45, 0x67, + 0x55, 0x79, 0x35, 0x42, 0x4c, 0x6a, 0x45, 0x70, 0x0a, 0x4d, 0x43, 0x63, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x67, 0x51, 0x32, 0x68, + 0x68, 0x62, 0x57, 0x4a, 0x6c, 0x63, 0x6e, 0x4d, 0x67, 0x62, 0x32, 0x59, + 0x67, 0x51, 0x32, 0x39, 0x74, 0x62, 0x57, 0x56, 0x79, 0x59, 0x32, 0x55, + 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x41, 0x74, 0x49, 0x44, 0x49, + 0x77, 0x4d, 0x44, 0x67, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, + 0x47, 0x0a, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, + 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, + 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51, + 0x43, 0x76, 0x41, 0x4d, 0x74, 0x77, 0x4e, 0x79, 0x75, 0x41, 0x57, 0x6b, + 0x6f, 0x36, 0x62, 0x48, 0x69, 0x55, 0x66, 0x61, 0x4e, 0x2f, 0x47, 0x68, + 0x2f, 0x32, 0x4e, 0x64, 0x57, 0x39, 0x0a, 0x32, 0x38, 0x73, 0x4e, 0x52, + 0x48, 0x49, 0x2b, 0x4a, 0x72, 0x4b, 0x51, 0x55, 0x72, 0x70, 0x6a, 0x4f, + 0x79, 0x68, 0x59, 0x62, 0x36, 0x57, 0x7a, 0x62, 0x5a, 0x53, 0x6d, 0x38, + 0x39, 0x31, 0x6b, 0x44, 0x46, 0x58, 0x32, 0x39, 0x75, 0x66, 0x79, 0x49, + 0x69, 0x4b, 0x41, 0x58, 0x75, 0x46, 0x69, 0x78, 0x72, 0x59, 0x70, 0x34, + 0x59, 0x46, 0x73, 0x38, 0x72, 0x2f, 0x6c, 0x66, 0x54, 0x4a, 0x71, 0x0a, + 0x56, 0x4b, 0x41, 0x79, 0x47, 0x56, 0x6e, 0x2b, 0x48, 0x34, 0x76, 0x58, + 0x50, 0x57, 0x43, 0x47, 0x68, 0x53, 0x52, 0x76, 0x34, 0x78, 0x47, 0x7a, + 0x64, 0x7a, 0x34, 0x67, 0x6c, 0x6a, 0x55, 0x68, 0x61, 0x37, 0x4d, 0x49, + 0x32, 0x58, 0x41, 0x75, 0x5a, 0x50, 0x65, 0x45, 0x6b, 0x6c, 0x50, 0x57, + 0x44, 0x72, 0x43, 0x51, 0x69, 0x6f, 0x72, 0x6a, 0x68, 0x34, 0x30, 0x47, + 0x30, 0x37, 0x32, 0x51, 0x0a, 0x44, 0x75, 0x4b, 0x5a, 0x6f, 0x52, 0x75, + 0x47, 0x44, 0x74, 0x71, 0x61, 0x43, 0x72, 0x73, 0x4c, 0x59, 0x56, 0x41, + 0x47, 0x55, 0x76, 0x47, 0x65, 0x66, 0x33, 0x62, 0x73, 0x79, 0x77, 0x2f, + 0x51, 0x48, 0x67, 0x33, 0x50, 0x6d, 0x54, 0x41, 0x39, 0x48, 0x4d, 0x52, + 0x46, 0x45, 0x46, 0x69, 0x73, 0x31, 0x74, 0x50, 0x6f, 0x31, 0x2b, 0x58, + 0x71, 0x78, 0x51, 0x45, 0x48, 0x64, 0x39, 0x5a, 0x52, 0x0a, 0x35, 0x67, + 0x4e, 0x2f, 0x69, 0x6b, 0x69, 0x6c, 0x54, 0x57, 0x68, 0x31, 0x75, 0x65, + 0x6d, 0x38, 0x6e, 0x6b, 0x34, 0x5a, 0x63, 0x66, 0x55, 0x79, 0x53, 0x35, + 0x78, 0x74, 0x59, 0x42, 0x6b, 0x4c, 0x2b, 0x38, 0x79, 0x64, 0x64, 0x64, + 0x79, 0x2f, 0x4a, 0x73, 0x32, 0x50, 0x6b, 0x33, 0x67, 0x35, 0x65, 0x58, + 0x4e, 0x65, 0x4a, 0x51, 0x37, 0x4b, 0x58, 0x4f, 0x74, 0x33, 0x45, 0x67, + 0x66, 0x4c, 0x0a, 0x5a, 0x45, 0x46, 0x48, 0x63, 0x70, 0x4f, 0x72, 0x55, + 0x4d, 0x50, 0x72, 0x43, 0x58, 0x5a, 0x6b, 0x4e, 0x4e, 0x49, 0x35, 0x74, + 0x33, 0x59, 0x52, 0x43, 0x51, 0x31, 0x32, 0x52, 0x63, 0x53, 0x70, 0x72, + 0x6a, 0x31, 0x71, 0x72, 0x37, 0x56, 0x39, 0x5a, 0x53, 0x2b, 0x55, 0x57, + 0x42, 0x44, 0x73, 0x58, 0x48, 0x79, 0x76, 0x66, 0x75, 0x4b, 0x32, 0x47, + 0x4e, 0x6e, 0x51, 0x6d, 0x30, 0x35, 0x61, 0x0a, 0x53, 0x64, 0x2b, 0x70, + 0x5a, 0x67, 0x76, 0x4d, 0x50, 0x4d, 0x5a, 0x34, 0x66, 0x4b, 0x65, 0x63, + 0x48, 0x65, 0x50, 0x4f, 0x6a, 0x6c, 0x4f, 0x2b, 0x42, 0x64, 0x35, 0x67, + 0x44, 0x32, 0x76, 0x6c, 0x47, 0x74, 0x73, 0x2f, 0x34, 0x2b, 0x45, 0x68, + 0x79, 0x53, 0x6e, 0x42, 0x38, 0x65, 0x73, 0x48, 0x6e, 0x46, 0x49, 0x62, + 0x41, 0x55, 0x52, 0x52, 0x50, 0x48, 0x73, 0x6c, 0x31, 0x38, 0x54, 0x6c, + 0x0a, 0x55, 0x6c, 0x52, 0x64, 0x4a, 0x51, 0x66, 0x4b, 0x46, 0x69, 0x43, + 0x34, 0x72, 0x65, 0x52, 0x42, 0x37, 0x6e, 0x6f, 0x49, 0x2f, 0x70, 0x6c, + 0x76, 0x67, 0x36, 0x61, 0x52, 0x41, 0x72, 0x42, 0x73, 0x4e, 0x6c, 0x56, + 0x71, 0x35, 0x33, 0x33, 0x31, 0x6c, 0x75, 0x62, 0x4b, 0x67, 0x64, 0x61, + 0x58, 0x38, 0x5a, 0x53, 0x44, 0x36, 0x65, 0x32, 0x77, 0x73, 0x57, 0x73, + 0x53, 0x61, 0x52, 0x36, 0x73, 0x0a, 0x2b, 0x31, 0x32, 0x70, 0x78, 0x5a, + 0x6a, 0x70, 0x74, 0x46, 0x74, 0x59, 0x65, 0x72, 0x34, 0x39, 0x6f, 0x6b, + 0x51, 0x36, 0x59, 0x31, 0x6e, 0x55, 0x43, 0x79, 0x58, 0x65, 0x47, 0x30, + 0x2b, 0x39, 0x35, 0x51, 0x47, 0x65, 0x7a, 0x64, 0x49, 0x70, 0x31, 0x5a, + 0x38, 0x58, 0x47, 0x51, 0x70, 0x76, 0x76, 0x77, 0x79, 0x51, 0x30, 0x77, + 0x6c, 0x66, 0x32, 0x65, 0x4f, 0x4b, 0x4e, 0x63, 0x78, 0x35, 0x0a, 0x57, + 0x6b, 0x30, 0x5a, 0x4e, 0x35, 0x4b, 0x33, 0x78, 0x4d, 0x47, 0x74, 0x72, + 0x2f, 0x52, 0x35, 0x4a, 0x4a, 0x71, 0x79, 0x41, 0x51, 0x75, 0x78, 0x72, + 0x31, 0x79, 0x57, 0x38, 0x34, 0x41, 0x79, 0x2b, 0x31, 0x77, 0x39, 0x6d, + 0x50, 0x47, 0x67, 0x50, 0x30, 0x72, 0x65, 0x76, 0x71, 0x2b, 0x55, 0x4c, + 0x74, 0x6c, 0x56, 0x6d, 0x68, 0x64, 0x75, 0x59, 0x4a, 0x31, 0x6a, 0x62, + 0x4c, 0x68, 0x6a, 0x0a, 0x79, 0x61, 0x36, 0x42, 0x58, 0x42, 0x67, 0x31, + 0x34, 0x4a, 0x43, 0x37, 0x76, 0x6a, 0x78, 0x50, 0x4e, 0x79, 0x4b, 0x35, + 0x66, 0x75, 0x76, 0x50, 0x6e, 0x6e, 0x63, 0x68, 0x70, 0x6a, 0x30, 0x34, + 0x67, 0x66, 0x74, 0x49, 0x32, 0x6a, 0x45, 0x39, 0x4b, 0x2b, 0x4f, 0x4a, + 0x39, 0x64, 0x43, 0x31, 0x76, 0x58, 0x37, 0x67, 0x55, 0x4d, 0x51, 0x53, + 0x69, 0x62, 0x4d, 0x6a, 0x6d, 0x68, 0x41, 0x78, 0x0a, 0x68, 0x64, 0x75, + 0x75, 0x62, 0x2b, 0x38, 0x34, 0x4d, 0x78, 0x68, 0x32, 0x45, 0x51, 0x49, + 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x34, 0x49, 0x42, 0x62, 0x44, 0x43, + 0x43, 0x41, 0x57, 0x67, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, + 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x67, 0x77, 0x42, 0x67, 0x45, + 0x42, 0x2f, 0x77, 0x49, 0x42, 0x44, 0x44, 0x41, 0x64, 0x42, 0x67, 0x4e, + 0x56, 0x0a, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x2b, 0x53, + 0x53, 0x73, 0x44, 0x37, 0x4b, 0x31, 0x2b, 0x48, 0x6e, 0x41, 0x2b, 0x6d, + 0x43, 0x49, 0x47, 0x38, 0x54, 0x5a, 0x54, 0x51, 0x4b, 0x65, 0x46, 0x78, + 0x6b, 0x77, 0x67, 0x65, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x64, 0x49, 0x77, + 0x53, 0x42, 0x32, 0x7a, 0x43, 0x42, 0x32, 0x49, 0x41, 0x55, 0x2b, 0x53, + 0x53, 0x73, 0x44, 0x37, 0x4b, 0x31, 0x0a, 0x2b, 0x48, 0x6e, 0x41, 0x2b, + 0x6d, 0x43, 0x49, 0x47, 0x38, 0x54, 0x5a, 0x54, 0x51, 0x4b, 0x65, 0x46, + 0x78, 0x6d, 0x68, 0x67, 0x62, 0x53, 0x6b, 0x67, 0x62, 0x45, 0x77, 0x67, + 0x61, 0x34, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x59, 0x54, 0x41, 0x6b, 0x56, 0x56, 0x4d, 0x55, 0x4d, 0x77, 0x51, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x45, 0x7a, 0x70, 0x4e, 0x0a, + 0x59, 0x57, 0x52, 0x79, 0x61, 0x57, 0x51, 0x67, 0x4b, 0x48, 0x4e, 0x6c, + 0x5a, 0x53, 0x42, 0x6a, 0x64, 0x58, 0x4a, 0x79, 0x5a, 0x57, 0x35, 0x30, + 0x49, 0x47, 0x46, 0x6b, 0x5a, 0x48, 0x4a, 0x6c, 0x63, 0x33, 0x4d, 0x67, + 0x59, 0x58, 0x51, 0x67, 0x64, 0x33, 0x64, 0x33, 0x4c, 0x6d, 0x4e, 0x68, + 0x62, 0x57, 0x56, 0x79, 0x5a, 0x6d, 0x6c, 0x79, 0x62, 0x57, 0x45, 0x75, + 0x59, 0x32, 0x39, 0x74, 0x0a, 0x4c, 0x32, 0x46, 0x6b, 0x5a, 0x48, 0x4a, + 0x6c, 0x63, 0x33, 0x4d, 0x70, 0x4d, 0x52, 0x49, 0x77, 0x45, 0x41, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x46, 0x45, 0x77, 0x6c, 0x42, 0x4f, 0x44, 0x49, + 0x33, 0x4e, 0x44, 0x4d, 0x79, 0x4f, 0x44, 0x63, 0x78, 0x47, 0x7a, 0x41, + 0x5a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x45, 0x6b, 0x46, + 0x44, 0x49, 0x45, 0x4e, 0x68, 0x62, 0x57, 0x56, 0x79, 0x0a, 0x5a, 0x6d, + 0x6c, 0x79, 0x62, 0x57, 0x45, 0x67, 0x55, 0x79, 0x35, 0x42, 0x4c, 0x6a, + 0x45, 0x70, 0x4d, 0x43, 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, + 0x4d, 0x67, 0x51, 0x32, 0x68, 0x68, 0x62, 0x57, 0x4a, 0x6c, 0x63, 0x6e, + 0x4d, 0x67, 0x62, 0x32, 0x59, 0x67, 0x51, 0x32, 0x39, 0x74, 0x62, 0x57, + 0x56, 0x79, 0x59, 0x32, 0x55, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, + 0x41, 0x74, 0x0a, 0x49, 0x44, 0x49, 0x77, 0x4d, 0x44, 0x69, 0x43, 0x43, + 0x51, 0x43, 0x6a, 0x32, 0x6b, 0x4a, 0x2b, 0x70, 0x4c, 0x47, 0x75, 0x32, + 0x6a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, + 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x50, + 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x67, 0x42, 0x44, 0x59, 0x77, 0x4e, + 0x44, 0x41, 0x79, 0x42, 0x67, 0x52, 0x56, 0x0a, 0x48, 0x53, 0x41, 0x41, + 0x4d, 0x43, 0x6f, 0x77, 0x4b, 0x41, 0x59, 0x49, 0x4b, 0x77, 0x59, 0x42, + 0x42, 0x51, 0x55, 0x48, 0x41, 0x67, 0x45, 0x57, 0x48, 0x47, 0x68, 0x30, + 0x64, 0x48, 0x41, 0x36, 0x4c, 0x79, 0x39, 0x77, 0x62, 0x32, 0x78, 0x70, + 0x59, 0x33, 0x6b, 0x75, 0x59, 0x32, 0x46, 0x74, 0x5a, 0x58, 0x4a, 0x6d, + 0x61, 0x58, 0x4a, 0x74, 0x59, 0x53, 0x35, 0x6a, 0x62, 0x32, 0x30, 0x77, + 0x0a, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, + 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, + 0x42, 0x41, 0x4a, 0x41, 0x53, 0x72, 0x79, 0x49, 0x31, 0x77, 0x71, 0x4d, + 0x35, 0x38, 0x43, 0x37, 0x65, 0x36, 0x62, 0x58, 0x70, 0x65, 0x48, 0x78, + 0x49, 0x76, 0x6a, 0x39, 0x39, 0x52, 0x5a, 0x4a, 0x65, 0x36, 0x64, 0x71, + 0x78, 0x47, 0x66, 0x77, 0x57, 0x0a, 0x50, 0x4a, 0x2b, 0x30, 0x57, 0x32, + 0x61, 0x65, 0x61, 0x75, 0x66, 0x44, 0x75, 0x56, 0x32, 0x49, 0x36, 0x41, + 0x2b, 0x74, 0x7a, 0x79, 0x4d, 0x50, 0x33, 0x69, 0x55, 0x36, 0x58, 0x73, + 0x78, 0x50, 0x70, 0x63, 0x47, 0x31, 0x4c, 0x61, 0x77, 0x6b, 0x30, 0x6c, + 0x67, 0x48, 0x33, 0x71, 0x4c, 0x50, 0x61, 0x59, 0x52, 0x67, 0x4d, 0x2b, + 0x67, 0x51, 0x44, 0x52, 0x4f, 0x70, 0x49, 0x39, 0x43, 0x46, 0x0a, 0x35, + 0x59, 0x35, 0x37, 0x70, 0x70, 0x34, 0x39, 0x63, 0x68, 0x4e, 0x79, 0x4d, + 0x2f, 0x57, 0x71, 0x66, 0x63, 0x5a, 0x6a, 0x48, 0x77, 0x6a, 0x30, 0x2f, + 0x67, 0x46, 0x2f, 0x4a, 0x4d, 0x38, 0x72, 0x4c, 0x46, 0x51, 0x4a, 0x33, + 0x75, 0x49, 0x72, 0x62, 0x5a, 0x4c, 0x47, 0x4f, 0x55, 0x38, 0x57, 0x36, + 0x6a, 0x78, 0x2b, 0x65, 0x6b, 0x62, 0x55, 0x52, 0x57, 0x70, 0x47, 0x71, + 0x4f, 0x74, 0x31, 0x0a, 0x67, 0x6c, 0x61, 0x6e, 0x71, 0x36, 0x42, 0x38, + 0x61, 0x42, 0x4d, 0x7a, 0x39, 0x70, 0x30, 0x77, 0x38, 0x47, 0x38, 0x6e, + 0x4f, 0x53, 0x51, 0x6a, 0x4b, 0x70, 0x44, 0x39, 0x6b, 0x43, 0x6b, 0x31, + 0x38, 0x70, 0x50, 0x66, 0x4e, 0x4b, 0x58, 0x47, 0x39, 0x2f, 0x6a, 0x76, + 0x6a, 0x41, 0x39, 0x69, 0x53, 0x6e, 0x79, 0x75, 0x30, 0x2f, 0x56, 0x55, + 0x2b, 0x49, 0x32, 0x32, 0x6d, 0x6c, 0x61, 0x48, 0x0a, 0x46, 0x6f, 0x49, + 0x36, 0x4d, 0x36, 0x74, 0x61, 0x49, 0x67, 0x6a, 0x33, 0x67, 0x72, 0x72, + 0x71, 0x4c, 0x75, 0x42, 0x48, 0x6d, 0x72, 0x53, 0x31, 0x52, 0x61, 0x4d, + 0x46, 0x4f, 0x39, 0x6e, 0x63, 0x4c, 0x6b, 0x56, 0x41, 0x4f, 0x2b, 0x72, + 0x63, 0x66, 0x2b, 0x67, 0x37, 0x36, 0x39, 0x48, 0x73, 0x4a, 0x74, 0x67, + 0x31, 0x70, 0x44, 0x44, 0x46, 0x4f, 0x71, 0x78, 0x58, 0x6e, 0x72, 0x4e, + 0x32, 0x0a, 0x70, 0x53, 0x42, 0x37, 0x2b, 0x52, 0x35, 0x4b, 0x42, 0x57, + 0x49, 0x42, 0x70, 0x69, 0x68, 0x31, 0x59, 0x4a, 0x65, 0x53, 0x44, 0x57, + 0x34, 0x2b, 0x54, 0x54, 0x64, 0x44, 0x44, 0x5a, 0x49, 0x56, 0x6e, 0x42, + 0x67, 0x69, 0x7a, 0x56, 0x47, 0x5a, 0x6f, 0x43, 0x6b, 0x61, 0x50, 0x46, + 0x2b, 0x4b, 0x4d, 0x6a, 0x4e, 0x62, 0x4d, 0x4d, 0x65, 0x4a, 0x4c, 0x30, + 0x65, 0x59, 0x44, 0x36, 0x4d, 0x44, 0x0a, 0x78, 0x76, 0x62, 0x78, 0x72, + 0x4e, 0x38, 0x79, 0x38, 0x4e, 0x6d, 0x42, 0x47, 0x75, 0x53, 0x63, 0x76, + 0x66, 0x61, 0x41, 0x46, 0x50, 0x44, 0x52, 0x4c, 0x4c, 0x6d, 0x46, 0x39, + 0x64, 0x69, 0x6a, 0x73, 0x63, 0x69, 0x6c, 0x49, 0x65, 0x55, 0x63, 0x45, + 0x35, 0x66, 0x75, 0x44, 0x72, 0x33, 0x66, 0x4b, 0x61, 0x6e, 0x76, 0x4e, + 0x46, 0x4e, 0x62, 0x30, 0x2b, 0x52, 0x71, 0x45, 0x34, 0x51, 0x47, 0x0a, + 0x74, 0x6a, 0x49, 0x43, 0x78, 0x46, 0x4b, 0x75, 0x49, 0x74, 0x4c, 0x63, + 0x73, 0x69, 0x46, 0x43, 0x47, 0x74, 0x70, 0x41, 0x38, 0x43, 0x6e, 0x4a, + 0x37, 0x41, 0x6f, 0x4d, 0x58, 0x4f, 0x4c, 0x51, 0x75, 0x73, 0x78, 0x49, + 0x30, 0x7a, 0x63, 0x4b, 0x7a, 0x42, 0x49, 0x4b, 0x69, 0x6e, 0x6d, 0x77, + 0x50, 0x51, 0x4e, 0x2f, 0x61, 0x55, 0x76, 0x30, 0x4e, 0x43, 0x42, 0x39, + 0x73, 0x7a, 0x54, 0x71, 0x0a, 0x6a, 0x6b, 0x74, 0x6b, 0x39, 0x54, 0x37, + 0x39, 0x73, 0x79, 0x4e, 0x6e, 0x46, 0x51, 0x30, 0x45, 0x75, 0x50, 0x41, + 0x74, 0x77, 0x51, 0x6c, 0x52, 0x50, 0x4c, 0x4a, 0x73, 0x46, 0x66, 0x43, + 0x6c, 0x49, 0x39, 0x65, 0x44, 0x64, 0x4f, 0x54, 0x6c, 0x4c, 0x73, 0x6e, + 0x2b, 0x6d, 0x43, 0x64, 0x43, 0x78, 0x71, 0x76, 0x47, 0x6e, 0x72, 0x44, + 0x51, 0x57, 0x7a, 0x69, 0x6c, 0x6d, 0x31, 0x44, 0x65, 0x0a, 0x66, 0x68, + 0x69, 0x59, 0x74, 0x55, 0x55, 0x37, 0x39, 0x6e, 0x6d, 0x30, 0x36, 0x50, + 0x63, 0x61, 0x65, 0x77, 0x61, 0x44, 0x2b, 0x39, 0x43, 0x4c, 0x32, 0x72, + 0x76, 0x48, 0x76, 0x52, 0x69, 0x72, 0x43, 0x47, 0x38, 0x38, 0x67, 0x47, + 0x74, 0x41, 0x50, 0x78, 0x6b, 0x5a, 0x75, 0x6d, 0x57, 0x4b, 0x35, 0x72, + 0x37, 0x56, 0x58, 0x4e, 0x4d, 0x32, 0x31, 0x2b, 0x39, 0x41, 0x55, 0x69, + 0x52, 0x67, 0x0a, 0x4f, 0x47, 0x63, 0x45, 0x4d, 0x65, 0x79, 0x50, 0x38, + 0x34, 0x4c, 0x47, 0x33, 0x72, 0x6c, 0x56, 0x38, 0x7a, 0x73, 0x78, 0x6b, + 0x56, 0x72, 0x63, 0x74, 0x51, 0x67, 0x56, 0x72, 0x58, 0x59, 0x6c, 0x43, + 0x67, 0x31, 0x37, 0x4c, 0x6f, 0x66, 0x69, 0x44, 0x4b, 0x59, 0x47, 0x76, + 0x43, 0x59, 0x51, 0x62, 0x54, 0x65, 0x64, 0x37, 0x4e, 0x31, 0x34, 0x6a, + 0x48, 0x79, 0x41, 0x78, 0x66, 0x44, 0x5a, 0x0a, 0x64, 0x30, 0x6a, 0x51, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, + 0x43, 0x68, 0x61, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x69, 0x67, 0x6e, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x2d, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, + 0x4f, 0x3d, 0x41, 0x43, 0x20, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x66, 0x69, + 0x72, 0x6d, 0x61, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x0a, 0x23, 0x20, 0x53, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x68, 0x61, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x2d, + 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x4f, 0x3d, 0x41, 0x43, 0x20, 0x43, + 0x61, 0x6d, 0x65, 0x72, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x20, 0x53, 0x2e, + 0x41, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x68, 0x61, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x2d, 0x20, 0x32, 0x30, 0x30, 0x38, 0x22, 0x0a, 0x23, 0x20, 0x53, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x34, 0x35, 0x34, 0x31, + 0x35, 0x31, 0x31, 0x37, 0x37, 0x33, 0x31, 0x31, 0x31, 0x37, 0x38, 0x38, + 0x34, 0x39, 0x34, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, + 0x65, 0x3a, 0x38, 0x30, 0x3a, 0x66, 0x66, 0x3a, 0x37, 0x38, 0x3a, 0x30, + 0x31, 0x3a, 0x30, 0x63, 0x3a, 0x32, 0x65, 0x3a, 0x63, 0x31, 0x3a, 0x33, + 0x36, 0x3a, 0x62, 0x64, 0x3a, 0x66, 0x65, 0x3a, 0x39, 0x36, 0x3a, 0x39, + 0x30, 0x3a, 0x36, 0x65, 0x3a, 0x30, 0x38, 0x3a, 0x66, 0x33, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x61, 0x3a, 0x62, 0x64, + 0x3a, 0x65, 0x65, 0x3a, 0x65, 0x63, 0x3a, 0x39, 0x35, 0x3a, 0x30, 0x64, + 0x3a, 0x33, 0x35, 0x3a, 0x39, 0x63, 0x3a, 0x38, 0x39, 0x3a, 0x61, 0x65, + 0x3a, 0x63, 0x37, 0x3a, 0x35, 0x32, 0x3a, 0x61, 0x31, 0x3a, 0x32, 0x63, + 0x3a, 0x35, 0x62, 0x3a, 0x32, 0x39, 0x3a, 0x66, 0x36, 0x3a, 0x64, 0x36, + 0x3a, 0x61, 0x61, 0x3a, 0x30, 0x63, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x33, 0x3a, 0x36, 0x33, 0x3a, 0x33, + 0x35, 0x3a, 0x34, 0x33, 0x3a, 0x39, 0x33, 0x3a, 0x33, 0x34, 0x3a, 0x61, + 0x37, 0x3a, 0x36, 0x39, 0x3a, 0x38, 0x30, 0x3a, 0x31, 0x36, 0x3a, 0x61, + 0x30, 0x3a, 0x64, 0x33, 0x3a, 0x32, 0x34, 0x3a, 0x64, 0x65, 0x3a, 0x37, + 0x32, 0x3a, 0x32, 0x38, 0x3a, 0x34, 0x65, 0x3a, 0x30, 0x37, 0x3a, 0x39, + 0x64, 0x3a, 0x37, 0x62, 0x3a, 0x35, 0x32, 0x3a, 0x32, 0x30, 0x3a, 0x62, + 0x62, 0x3a, 0x38, 0x66, 0x3a, 0x62, 0x64, 0x3a, 0x37, 0x34, 0x3a, 0x37, + 0x38, 0x3a, 0x31, 0x36, 0x3a, 0x65, 0x65, 0x3a, 0x62, 0x65, 0x3a, 0x62, + 0x61, 0x3a, 0x63, 0x61, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x48, 0x53, 0x54, 0x43, 0x43, 0x42, 0x54, 0x47, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x4a, 0x41, 0x4d, 0x6e, 0x4e, 0x30, 0x2b, 0x6e, + 0x56, 0x66, 0x53, 0x50, 0x4f, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, + 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, + 0x41, 0x4d, 0x49, 0x47, 0x73, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, + 0x44, 0x0a, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x46, 0x56, 0x54, + 0x46, 0x44, 0x4d, 0x45, 0x45, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x78, + 0x4d, 0x36, 0x54, 0x57, 0x46, 0x6b, 0x63, 0x6d, 0x6c, 0x6b, 0x49, 0x43, + 0x68, 0x7a, 0x5a, 0x57, 0x55, 0x67, 0x59, 0x33, 0x56, 0x79, 0x63, 0x6d, + 0x56, 0x75, 0x64, 0x43, 0x42, 0x68, 0x5a, 0x47, 0x52, 0x79, 0x5a, 0x58, + 0x4e, 0x7a, 0x49, 0x47, 0x46, 0x30, 0x0a, 0x49, 0x48, 0x64, 0x33, 0x64, + 0x79, 0x35, 0x6a, 0x59, 0x57, 0x31, 0x6c, 0x63, 0x6d, 0x5a, 0x70, 0x63, + 0x6d, 0x31, 0x68, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x53, 0x39, 0x68, 0x5a, + 0x47, 0x52, 0x79, 0x5a, 0x58, 0x4e, 0x7a, 0x4b, 0x54, 0x45, 0x53, 0x4d, + 0x42, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x52, 0x4d, 0x4a, 0x51, + 0x54, 0x67, 0x79, 0x4e, 0x7a, 0x51, 0x7a, 0x4d, 0x6a, 0x67, 0x33, 0x0a, + 0x4d, 0x52, 0x73, 0x77, 0x47, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, + 0x45, 0x78, 0x4a, 0x42, 0x51, 0x79, 0x42, 0x44, 0x59, 0x57, 0x31, 0x6c, + 0x63, 0x6d, 0x5a, 0x70, 0x63, 0x6d, 0x31, 0x68, 0x49, 0x46, 0x4d, 0x75, + 0x51, 0x53, 0x34, 0x78, 0x4a, 0x7a, 0x41, 0x6c, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x4d, 0x54, 0x48, 0x6b, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, + 0x62, 0x43, 0x42, 0x44, 0x0a, 0x61, 0x47, 0x46, 0x74, 0x59, 0x6d, 0x56, + 0x79, 0x63, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x53, 0x62, 0x32, 0x39, + 0x30, 0x49, 0x43, 0x30, 0x67, 0x4d, 0x6a, 0x41, 0x77, 0x4f, 0x44, 0x41, + 0x65, 0x46, 0x77, 0x30, 0x77, 0x4f, 0x44, 0x41, 0x34, 0x4d, 0x44, 0x45, + 0x78, 0x4d, 0x6a, 0x4d, 0x78, 0x4e, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, + 0x7a, 0x4f, 0x44, 0x41, 0x33, 0x4d, 0x7a, 0x45, 0x78, 0x0a, 0x4d, 0x6a, + 0x4d, 0x78, 0x4e, 0x44, 0x42, 0x61, 0x4d, 0x49, 0x47, 0x73, 0x4d, 0x51, + 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, + 0x4a, 0x46, 0x56, 0x54, 0x46, 0x44, 0x4d, 0x45, 0x45, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x42, 0x78, 0x4d, 0x36, 0x54, 0x57, 0x46, 0x6b, 0x63, 0x6d, + 0x6c, 0x6b, 0x49, 0x43, 0x68, 0x7a, 0x5a, 0x57, 0x55, 0x67, 0x59, 0x33, + 0x56, 0x79, 0x0a, 0x63, 0x6d, 0x56, 0x75, 0x64, 0x43, 0x42, 0x68, 0x5a, + 0x47, 0x52, 0x79, 0x5a, 0x58, 0x4e, 0x7a, 0x49, 0x47, 0x46, 0x30, 0x49, + 0x48, 0x64, 0x33, 0x64, 0x79, 0x35, 0x6a, 0x59, 0x57, 0x31, 0x6c, 0x63, + 0x6d, 0x5a, 0x70, 0x63, 0x6d, 0x31, 0x68, 0x4c, 0x6d, 0x4e, 0x76, 0x62, + 0x53, 0x39, 0x68, 0x5a, 0x47, 0x52, 0x79, 0x5a, 0x58, 0x4e, 0x7a, 0x4b, + 0x54, 0x45, 0x53, 0x4d, 0x42, 0x41, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, + 0x42, 0x52, 0x4d, 0x4a, 0x51, 0x54, 0x67, 0x79, 0x4e, 0x7a, 0x51, 0x7a, + 0x4d, 0x6a, 0x67, 0x33, 0x4d, 0x52, 0x73, 0x77, 0x47, 0x51, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x4a, 0x42, 0x51, 0x79, 0x42, 0x44, + 0x59, 0x57, 0x31, 0x6c, 0x63, 0x6d, 0x5a, 0x70, 0x63, 0x6d, 0x31, 0x68, + 0x49, 0x46, 0x4d, 0x75, 0x51, 0x53, 0x34, 0x78, 0x4a, 0x7a, 0x41, 0x6c, + 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x48, 0x6b, 0x64, + 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62, 0x43, 0x42, 0x44, 0x61, 0x47, 0x46, + 0x74, 0x59, 0x6d, 0x56, 0x79, 0x63, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, + 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x43, 0x30, 0x67, 0x4d, 0x6a, 0x41, + 0x77, 0x4f, 0x44, 0x43, 0x43, 0x41, 0x69, 0x49, 0x77, 0x44, 0x51, 0x59, + 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x0a, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, + 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x50, 0x41, 0x44, + 0x43, 0x43, 0x41, 0x67, 0x6f, 0x43, 0x67, 0x67, 0x49, 0x42, 0x41, 0x4d, + 0x44, 0x66, 0x56, 0x74, 0x50, 0x6b, 0x4f, 0x70, 0x74, 0x32, 0x52, 0x62, + 0x51, 0x54, 0x32, 0x2f, 0x2f, 0x42, 0x74, 0x68, 0x6d, 0x4c, 0x4e, 0x30, + 0x45, 0x59, 0x6c, 0x56, 0x4a, 0x48, 0x36, 0x78, 0x65, 0x64, 0x0a, 0x4b, + 0x59, 0x69, 0x4f, 0x4e, 0x57, 0x77, 0x47, 0x4d, 0x69, 0x35, 0x48, 0x59, + 0x76, 0x4e, 0x4a, 0x42, 0x4c, 0x39, 0x39, 0x52, 0x44, 0x61, 0x78, 0x63, + 0x63, 0x79, 0x39, 0x57, 0x67, 0x6c, 0x7a, 0x31, 0x64, 0x6d, 0x46, 0x52, + 0x50, 0x2b, 0x52, 0x56, 0x79, 0x58, 0x66, 0x58, 0x6a, 0x61, 0x4f, 0x63, + 0x4e, 0x46, 0x63, 0x63, 0x55, 0x4d, 0x64, 0x32, 0x64, 0x72, 0x76, 0x58, + 0x4e, 0x4c, 0x37, 0x0a, 0x47, 0x37, 0x30, 0x36, 0x74, 0x63, 0x75, 0x74, + 0x6f, 0x38, 0x78, 0x45, 0x70, 0x77, 0x32, 0x75, 0x49, 0x52, 0x55, 0x2f, + 0x75, 0x58, 0x70, 0x62, 0x6b, 0x6e, 0x58, 0x59, 0x70, 0x42, 0x49, 0x34, + 0x69, 0x52, 0x6d, 0x4b, 0x74, 0x34, 0x44, 0x53, 0x34, 0x6a, 0x4a, 0x76, + 0x56, 0x70, 0x79, 0x52, 0x31, 0x6f, 0x67, 0x51, 0x43, 0x37, 0x4e, 0x30, + 0x5a, 0x4a, 0x4a, 0x30, 0x59, 0x50, 0x50, 0x32, 0x0a, 0x7a, 0x78, 0x68, + 0x50, 0x59, 0x4c, 0x49, 0x6a, 0x30, 0x4d, 0x63, 0x37, 0x7a, 0x6d, 0x46, + 0x4c, 0x6d, 0x59, 0x2f, 0x43, 0x44, 0x4e, 0x42, 0x41, 0x73, 0x70, 0x6a, + 0x63, 0x44, 0x61, 0x68, 0x4f, 0x6f, 0x37, 0x6b, 0x4b, 0x72, 0x6d, 0x43, + 0x67, 0x72, 0x55, 0x56, 0x53, 0x59, 0x37, 0x70, 0x6d, 0x76, 0x57, 0x6a, + 0x67, 0x2b, 0x62, 0x34, 0x61, 0x71, 0x49, 0x47, 0x37, 0x48, 0x6b, 0x46, + 0x34, 0x0a, 0x64, 0x64, 0x50, 0x42, 0x2f, 0x67, 0x42, 0x56, 0x73, 0x49, + 0x64, 0x55, 0x36, 0x43, 0x65, 0x51, 0x4e, 0x52, 0x31, 0x4d, 0x4d, 0x36, + 0x32, 0x58, 0x2f, 0x4a, 0x63, 0x75, 0x6d, 0x49, 0x53, 0x2f, 0x4c, 0x4d, + 0x6d, 0x6a, 0x76, 0x39, 0x47, 0x59, 0x45, 0x52, 0x54, 0x74, 0x59, 0x2f, + 0x6a, 0x4b, 0x6d, 0x49, 0x68, 0x59, 0x46, 0x35, 0x6e, 0x74, 0x52, 0x51, + 0x4f, 0x58, 0x66, 0x6a, 0x79, 0x47, 0x0a, 0x48, 0x6f, 0x69, 0x4d, 0x76, + 0x76, 0x4b, 0x52, 0x68, 0x49, 0x39, 0x6c, 0x4e, 0x4e, 0x67, 0x41, 0x54, + 0x48, 0x32, 0x33, 0x4d, 0x52, 0x64, 0x61, 0x4b, 0x58, 0x6f, 0x4b, 0x47, + 0x43, 0x51, 0x77, 0x6f, 0x7a, 0x65, 0x31, 0x65, 0x71, 0x6b, 0x42, 0x66, + 0x53, 0x62, 0x57, 0x2b, 0x51, 0x36, 0x4f, 0x57, 0x66, 0x48, 0x39, 0x47, + 0x7a, 0x4f, 0x31, 0x4b, 0x54, 0x73, 0x58, 0x4f, 0x30, 0x47, 0x32, 0x0a, + 0x49, 0x64, 0x33, 0x55, 0x77, 0x44, 0x32, 0x6c, 0x6e, 0x35, 0x38, 0x66, + 0x51, 0x31, 0x44, 0x4a, 0x75, 0x37, 0x78, 0x73, 0x65, 0x70, 0x65, 0x59, + 0x37, 0x73, 0x32, 0x4d, 0x48, 0x2f, 0x75, 0x63, 0x55, 0x61, 0x36, 0x4c, + 0x63, 0x4c, 0x30, 0x6e, 0x6e, 0x33, 0x48, 0x41, 0x61, 0x36, 0x78, 0x39, + 0x6b, 0x47, 0x62, 0x6f, 0x31, 0x31, 0x30, 0x36, 0x44, 0x62, 0x44, 0x56, + 0x77, 0x6f, 0x33, 0x56, 0x0a, 0x79, 0x4a, 0x32, 0x64, 0x77, 0x57, 0x33, + 0x51, 0x30, 0x4c, 0x39, 0x52, 0x35, 0x4f, 0x50, 0x34, 0x77, 0x7a, 0x67, + 0x32, 0x72, 0x74, 0x61, 0x6e, 0x64, 0x65, 0x61, 0x76, 0x68, 0x45, 0x4e, + 0x64, 0x6b, 0x35, 0x49, 0x4d, 0x61, 0x67, 0x66, 0x65, 0x4f, 0x78, 0x32, + 0x59, 0x49, 0x74, 0x61, 0x73, 0x77, 0x54, 0x58, 0x62, 0x6f, 0x36, 0x41, + 0x6c, 0x2f, 0x33, 0x4b, 0x31, 0x64, 0x68, 0x33, 0x65, 0x0a, 0x62, 0x65, + 0x6b, 0x73, 0x5a, 0x69, 0x78, 0x53, 0x68, 0x4e, 0x42, 0x46, 0x6b, 0x73, + 0x34, 0x63, 0x35, 0x65, 0x55, 0x7a, 0x48, 0x64, 0x77, 0x48, 0x55, 0x31, + 0x53, 0x6a, 0x71, 0x6f, 0x49, 0x37, 0x6d, 0x6a, 0x63, 0x76, 0x33, 0x4e, + 0x32, 0x67, 0x5a, 0x4f, 0x6e, 0x6d, 0x33, 0x62, 0x32, 0x75, 0x2f, 0x47, + 0x53, 0x46, 0x48, 0x54, 0x79, 0x6e, 0x79, 0x51, 0x62, 0x65, 0x68, 0x50, + 0x39, 0x72, 0x0a, 0x36, 0x47, 0x73, 0x61, 0x50, 0x4d, 0x57, 0x69, 0x73, + 0x30, 0x4c, 0x37, 0x69, 0x77, 0x6b, 0x2b, 0x58, 0x77, 0x68, 0x53, 0x78, + 0x32, 0x4c, 0x45, 0x31, 0x41, 0x56, 0x78, 0x76, 0x38, 0x52, 0x6b, 0x35, + 0x50, 0x69, 0x68, 0x67, 0x2b, 0x67, 0x2b, 0x45, 0x70, 0x75, 0x6f, 0x48, + 0x74, 0x51, 0x32, 0x54, 0x53, 0x39, 0x78, 0x39, 0x6f, 0x30, 0x6f, 0x39, + 0x6f, 0x4f, 0x70, 0x45, 0x39, 0x4a, 0x68, 0x0a, 0x77, 0x5a, 0x47, 0x37, + 0x53, 0x4d, 0x41, 0x30, 0x6a, 0x30, 0x47, 0x4d, 0x53, 0x30, 0x7a, 0x62, + 0x61, 0x52, 0x4c, 0x2f, 0x55, 0x4a, 0x53, 0x63, 0x49, 0x49, 0x4e, 0x5a, + 0x63, 0x2b, 0x31, 0x38, 0x6f, 0x66, 0x4c, 0x78, 0x2f, 0x64, 0x33, 0x33, + 0x53, 0x64, 0x4e, 0x44, 0x57, 0x4b, 0x42, 0x57, 0x59, 0x38, 0x6f, 0x39, + 0x50, 0x65, 0x55, 0x31, 0x56, 0x6c, 0x6e, 0x70, 0x44, 0x73, 0x6f, 0x67, + 0x0a, 0x7a, 0x43, 0x74, 0x4c, 0x6b, 0x79, 0x6b, 0x50, 0x41, 0x67, 0x4d, + 0x42, 0x41, 0x41, 0x47, 0x6a, 0x67, 0x67, 0x46, 0x71, 0x4d, 0x49, 0x49, + 0x42, 0x5a, 0x6a, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, + 0x42, 0x41, 0x66, 0x38, 0x45, 0x43, 0x44, 0x41, 0x47, 0x41, 0x51, 0x48, + 0x2f, 0x41, 0x67, 0x45, 0x4d, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x44, 0x67, 0x51, 0x57, 0x0a, 0x42, 0x42, 0x53, 0x35, 0x43, 0x63, + 0x71, 0x63, 0x48, 0x74, 0x76, 0x54, 0x62, 0x44, 0x70, 0x72, 0x72, 0x75, + 0x31, 0x55, 0x38, 0x56, 0x75, 0x54, 0x42, 0x6a, 0x55, 0x75, 0x58, 0x6a, + 0x43, 0x42, 0x34, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6a, 0x42, 0x49, + 0x48, 0x5a, 0x4d, 0x49, 0x48, 0x57, 0x67, 0x42, 0x53, 0x35, 0x43, 0x63, + 0x71, 0x63, 0x48, 0x74, 0x76, 0x54, 0x62, 0x44, 0x70, 0x72, 0x0a, 0x72, + 0x75, 0x31, 0x55, 0x38, 0x56, 0x75, 0x54, 0x42, 0x6a, 0x55, 0x75, 0x58, + 0x71, 0x47, 0x42, 0x73, 0x71, 0x53, 0x42, 0x72, 0x7a, 0x43, 0x42, 0x72, + 0x44, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x68, 0x4d, 0x43, 0x52, 0x56, 0x55, 0x78, 0x51, 0x7a, 0x42, 0x42, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x4f, 0x6b, 0x31, 0x68, 0x5a, + 0x48, 0x4a, 0x70, 0x0a, 0x5a, 0x43, 0x41, 0x6f, 0x63, 0x32, 0x56, 0x6c, + 0x49, 0x47, 0x4e, 0x31, 0x63, 0x6e, 0x4a, 0x6c, 0x62, 0x6e, 0x51, 0x67, + 0x59, 0x57, 0x52, 0x6b, 0x63, 0x6d, 0x56, 0x7a, 0x63, 0x79, 0x42, 0x68, + 0x64, 0x43, 0x42, 0x33, 0x64, 0x33, 0x63, 0x75, 0x59, 0x32, 0x46, 0x74, + 0x5a, 0x58, 0x4a, 0x6d, 0x61, 0x58, 0x4a, 0x74, 0x59, 0x53, 0x35, 0x6a, + 0x62, 0x32, 0x30, 0x76, 0x59, 0x57, 0x52, 0x6b, 0x0a, 0x63, 0x6d, 0x56, + 0x7a, 0x63, 0x79, 0x6b, 0x78, 0x45, 0x6a, 0x41, 0x51, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x55, 0x54, 0x43, 0x55, 0x45, 0x34, 0x4d, 0x6a, 0x63, + 0x30, 0x4d, 0x7a, 0x49, 0x34, 0x4e, 0x7a, 0x45, 0x62, 0x4d, 0x42, 0x6b, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x53, 0x51, 0x55, 0x4d, + 0x67, 0x51, 0x32, 0x46, 0x74, 0x5a, 0x58, 0x4a, 0x6d, 0x61, 0x58, 0x4a, + 0x74, 0x0a, 0x59, 0x53, 0x42, 0x54, 0x4c, 0x6b, 0x45, 0x75, 0x4d, 0x53, + 0x63, 0x77, 0x4a, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, + 0x35, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x77, 0x67, 0x51, 0x32, + 0x68, 0x68, 0x62, 0x57, 0x4a, 0x6c, 0x63, 0x6e, 0x4e, 0x70, 0x5a, 0x32, + 0x34, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x41, 0x74, 0x49, 0x44, + 0x49, 0x77, 0x4d, 0x44, 0x69, 0x43, 0x0a, 0x43, 0x51, 0x44, 0x4a, 0x7a, + 0x64, 0x50, 0x70, 0x31, 0x58, 0x30, 0x6a, 0x7a, 0x6a, 0x41, 0x4f, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, + 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x50, 0x51, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x67, 0x42, 0x44, 0x59, 0x77, 0x4e, 0x44, 0x41, 0x79, 0x42, + 0x67, 0x52, 0x56, 0x48, 0x53, 0x41, 0x41, 0x4d, 0x43, 0x6f, 0x77, 0x0a, + 0x4b, 0x41, 0x59, 0x49, 0x4b, 0x77, 0x59, 0x42, 0x42, 0x51, 0x55, 0x48, + 0x41, 0x67, 0x45, 0x57, 0x48, 0x47, 0x68, 0x30, 0x64, 0x48, 0x41, 0x36, + 0x4c, 0x79, 0x39, 0x77, 0x62, 0x32, 0x78, 0x70, 0x59, 0x33, 0x6b, 0x75, + 0x59, 0x32, 0x46, 0x74, 0x5a, 0x58, 0x4a, 0x6d, 0x61, 0x58, 0x4a, 0x74, + 0x59, 0x53, 0x35, 0x6a, 0x62, 0x32, 0x30, 0x77, 0x44, 0x51, 0x59, 0x4a, + 0x4b, 0x6f, 0x5a, 0x49, 0x0a, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, + 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x42, 0x41, 0x49, 0x43, + 0x49, 0x66, 0x33, 0x44, 0x65, 0x6b, 0x69, 0x6a, 0x5a, 0x42, 0x5a, 0x52, + 0x47, 0x2f, 0x35, 0x42, 0x58, 0x71, 0x66, 0x45, 0x76, 0x33, 0x78, 0x6f, + 0x4e, 0x61, 0x2f, 0x70, 0x38, 0x44, 0x68, 0x78, 0x4a, 0x4a, 0x48, 0x6b, + 0x6e, 0x32, 0x45, 0x61, 0x71, 0x62, 0x79, 0x6c, 0x5a, 0x0a, 0x55, 0x6f, + 0x68, 0x77, 0x45, 0x75, 0x72, 0x64, 0x50, 0x66, 0x57, 0x62, 0x55, 0x31, + 0x52, 0x76, 0x34, 0x57, 0x43, 0x69, 0x71, 0x41, 0x6d, 0x35, 0x37, 0x4f, + 0x74, 0x5a, 0x66, 0x4d, 0x59, 0x31, 0x38, 0x64, 0x77, 0x59, 0x36, 0x66, + 0x46, 0x6e, 0x35, 0x61, 0x2b, 0x36, 0x52, 0x65, 0x41, 0x4a, 0x33, 0x73, + 0x70, 0x45, 0x44, 0x38, 0x49, 0x58, 0x44, 0x6e, 0x65, 0x52, 0x52, 0x58, + 0x6f, 0x7a, 0x0a, 0x58, 0x31, 0x2b, 0x57, 0x4c, 0x47, 0x69, 0x4c, 0x77, + 0x55, 0x65, 0x50, 0x6d, 0x4a, 0x73, 0x39, 0x77, 0x4f, 0x7a, 0x4c, 0x39, + 0x64, 0x57, 0x43, 0x6b, 0x6f, 0x51, 0x31, 0x30, 0x62, 0x34, 0x32, 0x4f, + 0x46, 0x5a, 0x79, 0x4d, 0x56, 0x74, 0x48, 0x4c, 0x61, 0x6f, 0x58, 0x70, + 0x47, 0x4e, 0x52, 0x36, 0x77, 0x6f, 0x42, 0x72, 0x58, 0x2f, 0x73, 0x64, + 0x5a, 0x37, 0x4c, 0x6f, 0x52, 0x2f, 0x78, 0x0a, 0x66, 0x78, 0x4b, 0x78, + 0x75, 0x65, 0x52, 0x6b, 0x66, 0x32, 0x66, 0x57, 0x49, 0x79, 0x72, 0x30, + 0x75, 0x44, 0x6c, 0x64, 0x6d, 0x4f, 0x67, 0x68, 0x70, 0x2b, 0x47, 0x39, + 0x50, 0x55, 0x49, 0x61, 0x64, 0x4a, 0x70, 0x77, 0x72, 0x32, 0x68, 0x73, + 0x55, 0x46, 0x31, 0x4a, 0x7a, 0x2f, 0x2f, 0x37, 0x44, 0x6c, 0x33, 0x6d, + 0x4c, 0x45, 0x66, 0x58, 0x67, 0x54, 0x70, 0x5a, 0x41, 0x4c, 0x56, 0x7a, + 0x0a, 0x61, 0x32, 0x4d, 0x67, 0x39, 0x6a, 0x46, 0x46, 0x43, 0x44, 0x6b, + 0x4f, 0x39, 0x48, 0x42, 0x2b, 0x51, 0x48, 0x42, 0x61, 0x50, 0x39, 0x42, + 0x72, 0x51, 0x71, 0x6c, 0x30, 0x50, 0x53, 0x67, 0x76, 0x41, 0x6d, 0x31, + 0x31, 0x63, 0x70, 0x55, 0x4a, 0x6a, 0x55, 0x68, 0x6a, 0x78, 0x73, 0x59, + 0x6a, 0x56, 0x35, 0x4b, 0x54, 0x58, 0x6a, 0x58, 0x42, 0x6a, 0x66, 0x6b, + 0x4b, 0x39, 0x79, 0x79, 0x64, 0x0a, 0x59, 0x68, 0x7a, 0x32, 0x72, 0x58, + 0x7a, 0x64, 0x70, 0x6a, 0x45, 0x65, 0x74, 0x72, 0x48, 0x48, 0x66, 0x6f, + 0x55, 0x6d, 0x2b, 0x71, 0x52, 0x71, 0x74, 0x64, 0x70, 0x6a, 0x4d, 0x4e, + 0x48, 0x76, 0x6b, 0x7a, 0x65, 0x79, 0x5a, 0x69, 0x39, 0x39, 0x42, 0x66, + 0x66, 0x6e, 0x74, 0x30, 0x75, 0x59, 0x6c, 0x44, 0x58, 0x41, 0x32, 0x54, + 0x6f, 0x70, 0x77, 0x5a, 0x32, 0x79, 0x55, 0x44, 0x4d, 0x64, 0x0a, 0x53, + 0x71, 0x6c, 0x61, 0x70, 0x73, 0x6b, 0x44, 0x37, 0x2b, 0x33, 0x30, 0x35, + 0x36, 0x68, 0x75, 0x69, 0x72, 0x52, 0x58, 0x68, 0x4f, 0x75, 0x6b, 0x50, + 0x39, 0x44, 0x75, 0x71, 0x71, 0x71, 0x48, 0x57, 0x32, 0x50, 0x6f, 0x6b, + 0x2b, 0x4a, 0x72, 0x71, 0x4e, 0x53, 0x34, 0x63, 0x6e, 0x68, 0x72, 0x47, + 0x2b, 0x30, 0x35, 0x35, 0x46, 0x33, 0x4c, 0x6d, 0x36, 0x71, 0x48, 0x31, + 0x55, 0x39, 0x4f, 0x0a, 0x41, 0x50, 0x37, 0x5a, 0x61, 0x70, 0x38, 0x38, + 0x4d, 0x51, 0x38, 0x6f, 0x41, 0x67, 0x46, 0x39, 0x6d, 0x4f, 0x69, 0x6e, + 0x73, 0x4b, 0x4a, 0x6b, 0x6e, 0x6e, 0x6e, 0x34, 0x53, 0x50, 0x49, 0x56, + 0x71, 0x63, 0x7a, 0x6d, 0x79, 0x45, 0x54, 0x72, 0x50, 0x33, 0x69, 0x5a, + 0x38, 0x6e, 0x74, 0x78, 0x50, 0x6a, 0x7a, 0x78, 0x6d, 0x4b, 0x66, 0x46, + 0x47, 0x42, 0x49, 0x2f, 0x35, 0x72, 0x73, 0x6f, 0x0a, 0x4d, 0x30, 0x4c, + 0x70, 0x52, 0x51, 0x70, 0x38, 0x62, 0x66, 0x4b, 0x47, 0x65, 0x53, 0x2f, + 0x46, 0x67, 0x68, 0x6c, 0x39, 0x43, 0x59, 0x6c, 0x38, 0x73, 0x6c, 0x52, + 0x32, 0x69, 0x4b, 0x37, 0x65, 0x77, 0x66, 0x50, 0x4d, 0x34, 0x57, 0x37, + 0x62, 0x4d, 0x64, 0x61, 0x54, 0x72, 0x70, 0x6d, 0x67, 0x37, 0x79, 0x56, + 0x71, 0x63, 0x35, 0x69, 0x4a, 0x57, 0x7a, 0x6f, 0x75, 0x45, 0x34, 0x67, + 0x65, 0x0a, 0x76, 0x38, 0x43, 0x53, 0x6c, 0x44, 0x51, 0x62, 0x34, 0x79, + 0x65, 0x33, 0x69, 0x78, 0x35, 0x76, 0x51, 0x76, 0x2f, 0x6e, 0x36, 0x54, + 0x65, 0x62, 0x55, 0x42, 0x30, 0x74, 0x6f, 0x76, 0x6b, 0x43, 0x37, 0x73, + 0x74, 0x59, 0x57, 0x44, 0x70, 0x78, 0x76, 0x47, 0x6a, 0x6a, 0x71, 0x73, + 0x47, 0x76, 0x48, 0x43, 0x67, 0x66, 0x6f, 0x74, 0x77, 0x6a, 0x5a, 0x54, + 0x2b, 0x42, 0x36, 0x71, 0x36, 0x5a, 0x0a, 0x30, 0x39, 0x67, 0x77, 0x7a, + 0x78, 0x4d, 0x4e, 0x54, 0x78, 0x58, 0x4a, 0x68, 0x4c, 0x79, 0x6e, 0x53, + 0x43, 0x33, 0x34, 0x4d, 0x43, 0x4e, 0x33, 0x32, 0x45, 0x5a, 0x4c, 0x65, + 0x57, 0x33, 0x32, 0x6a, 0x4f, 0x30, 0x36, 0x66, 0x32, 0x41, 0x52, 0x65, + 0x50, 0x54, 0x70, 0x6d, 0x36, 0x37, 0x56, 0x56, 0x4d, 0x42, 0x30, 0x67, + 0x4e, 0x45, 0x4c, 0x51, 0x70, 0x2f, 0x42, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, + 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, + 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x47, 0x6f, 0x44, 0x61, 0x64, + 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x47, 0x6f, + 0x44, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, + 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x38, 0x30, 0x3a, 0x33, 0x61, 0x3a, 0x62, 0x63, 0x3a, + 0x32, 0x32, 0x3a, 0x63, 0x31, 0x3a, 0x65, 0x36, 0x3a, 0x66, 0x62, 0x3a, + 0x38, 0x64, 0x3a, 0x39, 0x62, 0x3a, 0x33, 0x62, 0x3a, 0x32, 0x37, 0x3a, + 0x34, 0x61, 0x3a, 0x33, 0x32, 0x3a, 0x31, 0x62, 0x3a, 0x39, 0x61, 0x3a, + 0x30, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, + 0x37, 0x3a, 0x62, 0x65, 0x3a, 0x61, 0x62, 0x3a, 0x63, 0x39, 0x3a, 0x32, + 0x32, 0x3a, 0x65, 0x61, 0x3a, 0x65, 0x38, 0x3a, 0x30, 0x65, 0x3a, 0x37, + 0x38, 0x3a, 0x37, 0x38, 0x3a, 0x33, 0x34, 0x3a, 0x36, 0x32, 0x3a, 0x61, + 0x37, 0x3a, 0x39, 0x66, 0x3a, 0x34, 0x35, 0x3a, 0x63, 0x32, 0x3a, 0x35, + 0x34, 0x3a, 0x66, 0x64, 0x3a, 0x65, 0x36, 0x3a, 0x38, 0x62, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x35, 0x3a, + 0x31, 0x34, 0x3a, 0x30, 0x62, 0x3a, 0x33, 0x32, 0x3a, 0x34, 0x37, 0x3a, + 0x65, 0x62, 0x3a, 0x39, 0x63, 0x3a, 0x63, 0x38, 0x3a, 0x63, 0x35, 0x3a, + 0x62, 0x34, 0x3a, 0x66, 0x30, 0x3a, 0x64, 0x37, 0x3a, 0x62, 0x35, 0x3a, + 0x33, 0x30, 0x3a, 0x39, 0x31, 0x3a, 0x66, 0x37, 0x3a, 0x33, 0x32, 0x3a, + 0x39, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x39, 0x65, 0x3a, 0x36, 0x65, 0x3a, + 0x35, 0x61, 0x3a, 0x36, 0x33, 0x3a, 0x65, 0x32, 0x3a, 0x37, 0x34, 0x3a, + 0x39, 0x64, 0x3a, 0x64, 0x33, 0x3a, 0x61, 0x63, 0x3a, 0x61, 0x39, 0x3a, + 0x31, 0x39, 0x3a, 0x38, 0x65, 0x3a, 0x64, 0x61, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x78, 0x54, 0x43, 0x43, 0x41, 0x71, 0x32, + 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x44, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, + 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x43, 0x42, 0x67, 0x7a, 0x45, + 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x56, 0x56, 0x4d, 0x78, 0x0a, 0x45, 0x44, 0x41, 0x4f, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x67, 0x54, 0x42, 0x30, 0x46, 0x79, 0x61, 0x58, + 0x70, 0x76, 0x62, 0x6d, 0x45, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x43, 0x6c, 0x4e, 0x6a, 0x62, 0x33, + 0x52, 0x30, 0x63, 0x32, 0x52, 0x68, 0x62, 0x47, 0x55, 0x78, 0x47, 0x6a, + 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x0a, 0x45, + 0x55, 0x64, 0x76, 0x52, 0x47, 0x46, 0x6b, 0x5a, 0x48, 0x6b, 0x75, 0x59, + 0x32, 0x39, 0x74, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, + 0x54, 0x45, 0x77, 0x4c, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, + 0x79, 0x68, 0x48, 0x62, 0x79, 0x42, 0x45, 0x59, 0x57, 0x52, 0x6b, 0x65, + 0x53, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x6c, 0x63, + 0x6e, 0x52, 0x70, 0x0a, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, + 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, + 0x65, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x79, 0x4d, 0x42, 0x34, 0x58, + 0x44, 0x54, 0x41, 0x35, 0x4d, 0x44, 0x6b, 0x77, 0x4d, 0x54, 0x41, 0x77, + 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x4d, 0x33, + 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x7a, 0x0a, 0x4e, 0x54, 0x6b, + 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x67, 0x59, 0x4d, 0x78, 0x43, 0x7a, 0x41, + 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, + 0x54, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x49, 0x45, 0x77, 0x64, 0x42, 0x63, 0x6d, 0x6c, 0x36, 0x62, 0x32, 0x35, + 0x68, 0x4d, 0x52, 0x4d, 0x77, 0x45, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x48, 0x0a, 0x45, 0x77, 0x70, 0x54, 0x59, 0x32, 0x39, 0x30, 0x64, 0x48, + 0x4e, 0x6b, 0x59, 0x57, 0x78, 0x6c, 0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x46, 0x48, 0x62, 0x30, + 0x52, 0x68, 0x5a, 0x47, 0x52, 0x35, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x53, + 0x77, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x78, 0x4d, 0x43, + 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x41, 0x78, 0x4d, 0x6f, 0x52, + 0x32, 0x38, 0x67, 0x52, 0x47, 0x46, 0x6b, 0x5a, 0x48, 0x6b, 0x67, 0x55, + 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, + 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, 0x53, 0x42, 0x42, 0x64, + 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x4c, + 0x53, 0x42, 0x48, 0x4d, 0x6a, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x0a, + 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, + 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, + 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, + 0x41, 0x4c, 0x39, 0x78, 0x59, 0x67, 0x6a, 0x78, 0x2b, 0x6c, 0x6b, 0x30, + 0x39, 0x78, 0x76, 0x4a, 0x47, 0x4b, 0x50, 0x33, 0x67, 0x45, 0x6c, 0x59, + 0x36, 0x53, 0x4b, 0x44, 0x0a, 0x45, 0x36, 0x62, 0x46, 0x49, 0x45, 0x4d, + 0x42, 0x4f, 0x34, 0x54, 0x78, 0x35, 0x6f, 0x56, 0x4a, 0x6e, 0x79, 0x66, + 0x71, 0x39, 0x6f, 0x51, 0x62, 0x54, 0x71, 0x43, 0x30, 0x32, 0x33, 0x43, + 0x59, 0x78, 0x7a, 0x49, 0x42, 0x73, 0x51, 0x55, 0x2b, 0x42, 0x30, 0x37, + 0x75, 0x39, 0x50, 0x70, 0x50, 0x4c, 0x31, 0x6b, 0x77, 0x49, 0x75, 0x65, + 0x72, 0x47, 0x56, 0x5a, 0x72, 0x34, 0x6f, 0x41, 0x48, 0x0a, 0x2f, 0x50, + 0x4d, 0x57, 0x64, 0x59, 0x41, 0x35, 0x55, 0x58, 0x76, 0x6c, 0x2b, 0x54, + 0x57, 0x32, 0x64, 0x45, 0x36, 0x70, 0x6a, 0x59, 0x49, 0x54, 0x35, 0x4c, + 0x59, 0x2f, 0x71, 0x51, 0x4f, 0x44, 0x2b, 0x71, 0x4b, 0x2b, 0x69, 0x68, + 0x56, 0x71, 0x66, 0x39, 0x34, 0x4c, 0x77, 0x37, 0x59, 0x5a, 0x46, 0x41, + 0x58, 0x4b, 0x36, 0x73, 0x4f, 0x6f, 0x42, 0x4a, 0x51, 0x37, 0x52, 0x6e, + 0x77, 0x79, 0x0a, 0x44, 0x66, 0x4d, 0x41, 0x5a, 0x69, 0x4c, 0x49, 0x6a, + 0x57, 0x6c, 0x74, 0x4e, 0x6f, 0x77, 0x52, 0x47, 0x4c, 0x66, 0x54, 0x73, + 0x68, 0x78, 0x67, 0x74, 0x44, 0x6a, 0x36, 0x41, 0x6f, 0x7a, 0x4f, 0x30, + 0x39, 0x31, 0x47, 0x42, 0x39, 0x34, 0x4b, 0x50, 0x75, 0x74, 0x64, 0x66, + 0x4d, 0x68, 0x38, 0x2b, 0x37, 0x41, 0x72, 0x55, 0x36, 0x53, 0x53, 0x59, + 0x6d, 0x6c, 0x52, 0x4a, 0x51, 0x56, 0x68, 0x0a, 0x47, 0x6b, 0x53, 0x42, + 0x6a, 0x43, 0x79, 0x70, 0x51, 0x35, 0x59, 0x6a, 0x33, 0x36, 0x77, 0x36, + 0x67, 0x5a, 0x6f, 0x4f, 0x4b, 0x63, 0x55, 0x63, 0x71, 0x65, 0x6c, 0x64, + 0x48, 0x72, 0x61, 0x65, 0x6e, 0x6a, 0x41, 0x4b, 0x4f, 0x63, 0x37, 0x78, + 0x69, 0x49, 0x44, 0x37, 0x53, 0x31, 0x33, 0x4d, 0x4d, 0x75, 0x79, 0x46, + 0x59, 0x6b, 0x4d, 0x6c, 0x4e, 0x41, 0x4a, 0x57, 0x4a, 0x77, 0x47, 0x52, + 0x0a, 0x74, 0x44, 0x74, 0x77, 0x4b, 0x6a, 0x39, 0x75, 0x73, 0x65, 0x69, + 0x63, 0x69, 0x41, 0x46, 0x39, 0x6e, 0x39, 0x54, 0x35, 0x32, 0x31, 0x4e, + 0x74, 0x59, 0x4a, 0x32, 0x2f, 0x4c, 0x4f, 0x64, 0x59, 0x71, 0x37, 0x68, + 0x66, 0x52, 0x76, 0x7a, 0x4f, 0x78, 0x42, 0x73, 0x44, 0x50, 0x41, 0x6e, + 0x72, 0x53, 0x54, 0x46, 0x63, 0x61, 0x55, 0x61, 0x7a, 0x34, 0x45, 0x63, + 0x43, 0x41, 0x77, 0x45, 0x41, 0x0a, 0x41, 0x61, 0x4e, 0x43, 0x4d, 0x45, + 0x41, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, + 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, + 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x48, 0x51, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x0a, 0x46, + 0x44, 0x71, 0x61, 0x68, 0x51, 0x63, 0x51, 0x5a, 0x79, 0x69, 0x32, 0x37, + 0x2f, 0x61, 0x39, 0x42, 0x55, 0x46, 0x75, 0x49, 0x4d, 0x47, 0x55, 0x32, + 0x67, 0x2f, 0x65, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, + 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, + 0x34, 0x49, 0x42, 0x41, 0x51, 0x43, 0x5a, 0x32, 0x31, 0x31, 0x35, 0x31, + 0x66, 0x6d, 0x58, 0x0a, 0x57, 0x57, 0x63, 0x44, 0x59, 0x66, 0x46, 0x2b, + 0x4f, 0x77, 0x59, 0x78, 0x64, 0x53, 0x32, 0x68, 0x49, 0x49, 0x35, 0x50, + 0x5a, 0x59, 0x65, 0x30, 0x39, 0x36, 0x61, 0x63, 0x76, 0x4e, 0x6a, 0x70, + 0x4c, 0x39, 0x44, 0x62, 0x57, 0x75, 0x37, 0x50, 0x64, 0x49, 0x78, 0x7a, + 0x74, 0x44, 0x68, 0x43, 0x32, 0x67, 0x56, 0x37, 0x2b, 0x41, 0x4a, 0x31, + 0x75, 0x50, 0x32, 0x6c, 0x73, 0x64, 0x65, 0x75, 0x0a, 0x39, 0x74, 0x66, + 0x65, 0x45, 0x38, 0x74, 0x54, 0x45, 0x48, 0x36, 0x4b, 0x52, 0x74, 0x47, + 0x58, 0x2b, 0x72, 0x63, 0x75, 0x4b, 0x78, 0x47, 0x72, 0x6b, 0x4c, 0x41, + 0x6e, 0x67, 0x50, 0x6e, 0x6f, 0x6e, 0x31, 0x72, 0x70, 0x4e, 0x35, 0x2b, + 0x72, 0x35, 0x4e, 0x39, 0x73, 0x73, 0x34, 0x55, 0x58, 0x6e, 0x54, 0x33, + 0x5a, 0x4a, 0x45, 0x39, 0x35, 0x6b, 0x54, 0x58, 0x57, 0x58, 0x77, 0x54, + 0x72, 0x0a, 0x67, 0x49, 0x4f, 0x72, 0x6d, 0x67, 0x49, 0x74, 0x74, 0x52, + 0x44, 0x30, 0x32, 0x4a, 0x44, 0x48, 0x42, 0x48, 0x4e, 0x41, 0x37, 0x58, + 0x49, 0x6c, 0x6f, 0x4b, 0x6d, 0x66, 0x37, 0x4a, 0x36, 0x72, 0x61, 0x42, + 0x4b, 0x5a, 0x56, 0x38, 0x61, 0x50, 0x45, 0x6a, 0x6f, 0x4a, 0x70, 0x4c, + 0x31, 0x45, 0x2f, 0x51, 0x59, 0x56, 0x4e, 0x38, 0x47, 0x62, 0x35, 0x44, + 0x4b, 0x6a, 0x37, 0x54, 0x6a, 0x6f, 0x0a, 0x32, 0x47, 0x54, 0x7a, 0x4c, + 0x48, 0x34, 0x55, 0x2f, 0x41, 0x4c, 0x71, 0x6e, 0x38, 0x33, 0x2f, 0x42, + 0x32, 0x67, 0x58, 0x32, 0x79, 0x4b, 0x51, 0x4f, 0x43, 0x31, 0x36, 0x6a, + 0x64, 0x46, 0x55, 0x38, 0x57, 0x6e, 0x6a, 0x58, 0x7a, 0x50, 0x4b, 0x65, + 0x6a, 0x31, 0x37, 0x43, 0x75, 0x50, 0x4b, 0x66, 0x31, 0x38, 0x35, 0x35, + 0x65, 0x4a, 0x31, 0x75, 0x73, 0x56, 0x32, 0x47, 0x44, 0x50, 0x4f, 0x0a, + 0x4c, 0x50, 0x41, 0x76, 0x54, 0x4b, 0x33, 0x33, 0x73, 0x65, 0x66, 0x4f, + 0x54, 0x36, 0x6a, 0x45, 0x6d, 0x30, 0x70, 0x55, 0x42, 0x73, 0x56, 0x2f, + 0x66, 0x64, 0x55, 0x49, 0x44, 0x2b, 0x49, 0x63, 0x2f, 0x6e, 0x34, 0x58, + 0x75, 0x4b, 0x78, 0x65, 0x39, 0x74, 0x51, 0x57, 0x73, 0x6b, 0x4d, 0x4a, + 0x44, 0x45, 0x33, 0x32, 0x70, 0x32, 0x75, 0x30, 0x6d, 0x59, 0x52, 0x6c, + 0x79, 0x6e, 0x71, 0x49, 0x0a, 0x34, 0x75, 0x4a, 0x45, 0x76, 0x6c, 0x7a, + 0x33, 0x36, 0x68, 0x7a, 0x31, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x74, + 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, + 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, + 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, + 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x53, 0x74, 0x61, + 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, + 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x20, 0x2d, 0x20, 0x47, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x64, 0x36, 0x3a, 0x33, 0x39, 0x3a, 0x38, 0x31, 0x3a, 0x63, + 0x36, 0x3a, 0x35, 0x32, 0x3a, 0x37, 0x65, 0x3a, 0x39, 0x36, 0x3a, 0x36, + 0x39, 0x3a, 0x66, 0x63, 0x3a, 0x66, 0x63, 0x3a, 0x63, 0x61, 0x3a, 0x36, + 0x36, 0x3a, 0x65, 0x64, 0x3a, 0x30, 0x35, 0x3a, 0x66, 0x32, 0x3a, 0x39, + 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x35, + 0x3a, 0x31, 0x63, 0x3a, 0x30, 0x36, 0x3a, 0x37, 0x63, 0x3a, 0x65, 0x65, + 0x3a, 0x32, 0x62, 0x3a, 0x30, 0x63, 0x3a, 0x33, 0x64, 0x3a, 0x66, 0x38, + 0x3a, 0x35, 0x35, 0x3a, 0x61, 0x62, 0x3a, 0x32, 0x64, 0x3a, 0x39, 0x32, + 0x3a, 0x66, 0x34, 0x3a, 0x66, 0x65, 0x3a, 0x33, 0x39, 0x3a, 0x64, 0x34, + 0x3a, 0x65, 0x37, 0x3a, 0x30, 0x66, 0x3a, 0x30, 0x65, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x63, 0x3a, 0x65, + 0x31, 0x3a, 0x63, 0x62, 0x3a, 0x30, 0x62, 0x3a, 0x66, 0x39, 0x3a, 0x64, + 0x32, 0x3a, 0x66, 0x39, 0x3a, 0x65, 0x31, 0x3a, 0x30, 0x32, 0x3a, 0x39, + 0x39, 0x3a, 0x33, 0x66, 0x3a, 0x62, 0x65, 0x3a, 0x32, 0x31, 0x3a, 0x35, + 0x31, 0x3a, 0x35, 0x32, 0x3a, 0x63, 0x33, 0x3a, 0x62, 0x32, 0x3a, 0x64, + 0x64, 0x3a, 0x30, 0x63, 0x3a, 0x61, 0x62, 0x3a, 0x64, 0x65, 0x3a, 0x31, + 0x63, 0x3a, 0x36, 0x38, 0x3a, 0x65, 0x35, 0x3a, 0x33, 0x31, 0x3a, 0x39, + 0x62, 0x3a, 0x38, 0x33, 0x3a, 0x39, 0x31, 0x3a, 0x35, 0x34, 0x3a, 0x64, + 0x62, 0x3a, 0x62, 0x37, 0x3a, 0x66, 0x35, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x44, 0x33, 0x54, 0x43, 0x43, 0x41, 0x73, 0x57, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x44, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x43, 0x42, 0x6a, 0x7a, 0x45, 0x4c, + 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, + 0x56, 0x56, 0x4d, 0x78, 0x0a, 0x45, 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x67, 0x54, 0x42, 0x30, 0x46, 0x79, 0x61, 0x58, 0x70, + 0x76, 0x62, 0x6d, 0x45, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x63, 0x54, 0x43, 0x6c, 0x4e, 0x6a, 0x62, 0x33, 0x52, + 0x30, 0x63, 0x32, 0x52, 0x68, 0x62, 0x47, 0x55, 0x78, 0x4a, 0x54, 0x41, + 0x6a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x0a, 0x48, 0x46, + 0x4e, 0x30, 0x59, 0x58, 0x4a, 0x6d, 0x61, 0x57, 0x56, 0x73, 0x5a, 0x43, + 0x42, 0x55, 0x5a, 0x57, 0x4e, 0x6f, 0x62, 0x6d, 0x39, 0x73, 0x62, 0x32, + 0x64, 0x70, 0x5a, 0x58, 0x4d, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, + 0x34, 0x78, 0x4d, 0x6a, 0x41, 0x77, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x4d, 0x54, 0x4b, 0x56, 0x4e, 0x30, 0x59, 0x58, 0x4a, 0x6d, 0x61, 0x57, + 0x56, 0x73, 0x0a, 0x5a, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, + 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, + 0x58, 0x52, 0x6c, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, + 0x6d, 0x6c, 0x30, 0x65, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x79, 0x4d, + 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x35, 0x4d, 0x44, 0x6b, 0x77, 0x4d, + 0x54, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x0a, 0x4d, 0x46, 0x6f, 0x58, + 0x44, 0x54, 0x4d, 0x33, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x7a, + 0x4e, 0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x67, 0x59, 0x38, 0x78, + 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, + 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x49, 0x45, 0x77, 0x64, 0x42, 0x63, 0x6d, 0x6c, 0x36, + 0x0a, 0x62, 0x32, 0x35, 0x68, 0x4d, 0x52, 0x4d, 0x77, 0x45, 0x51, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x48, 0x45, 0x77, 0x70, 0x54, 0x59, 0x32, 0x39, + 0x30, 0x64, 0x48, 0x4e, 0x6b, 0x59, 0x57, 0x78, 0x6c, 0x4d, 0x53, 0x55, + 0x77, 0x49, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x78, + 0x54, 0x64, 0x47, 0x46, 0x79, 0x5a, 0x6d, 0x6c, 0x6c, 0x62, 0x47, 0x51, + 0x67, 0x56, 0x47, 0x56, 0x6a, 0x0a, 0x61, 0x47, 0x35, 0x76, 0x62, 0x47, + 0x39, 0x6e, 0x61, 0x57, 0x56, 0x7a, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, + 0x4d, 0x75, 0x4d, 0x54, 0x49, 0x77, 0x4d, 0x41, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x44, 0x45, 0x79, 0x6c, 0x54, 0x64, 0x47, 0x46, 0x79, 0x5a, 0x6d, + 0x6c, 0x6c, 0x62, 0x47, 0x51, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, + 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x0a, 0x59, + 0x32, 0x46, 0x30, 0x5a, 0x53, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, + 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x4c, 0x53, 0x42, 0x48, 0x4d, + 0x6a, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, + 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, + 0x51, 0x6f, 0x43, 0x0a, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4c, 0x33, 0x74, + 0x77, 0x51, 0x50, 0x38, 0x39, 0x6f, 0x2f, 0x38, 0x41, 0x72, 0x46, 0x76, + 0x57, 0x35, 0x39, 0x49, 0x32, 0x5a, 0x31, 0x35, 0x34, 0x71, 0x4b, 0x33, + 0x41, 0x32, 0x46, 0x57, 0x47, 0x4d, 0x4e, 0x48, 0x74, 0x74, 0x66, 0x4b, + 0x50, 0x54, 0x55, 0x75, 0x69, 0x55, 0x50, 0x33, 0x6f, 0x57, 0x6d, 0x62, + 0x33, 0x6f, 0x6f, 0x61, 0x2f, 0x52, 0x4d, 0x67, 0x0a, 0x6e, 0x4c, 0x52, + 0x4a, 0x64, 0x7a, 0x49, 0x70, 0x56, 0x76, 0x32, 0x35, 0x37, 0x49, 0x7a, + 0x64, 0x49, 0x76, 0x70, 0x79, 0x33, 0x43, 0x64, 0x68, 0x6c, 0x2b, 0x37, + 0x32, 0x57, 0x6f, 0x54, 0x73, 0x62, 0x68, 0x6d, 0x35, 0x69, 0x53, 0x7a, + 0x63, 0x68, 0x46, 0x76, 0x56, 0x64, 0x50, 0x74, 0x72, 0x58, 0x38, 0x57, + 0x4a, 0x70, 0x52, 0x42, 0x53, 0x69, 0x55, 0x5a, 0x56, 0x39, 0x4c, 0x68, + 0x31, 0x0a, 0x48, 0x4f, 0x5a, 0x2f, 0x35, 0x46, 0x53, 0x75, 0x53, 0x2f, + 0x68, 0x56, 0x63, 0x6c, 0x63, 0x43, 0x47, 0x66, 0x67, 0x58, 0x63, 0x56, + 0x6e, 0x72, 0x48, 0x69, 0x67, 0x48, 0x64, 0x4d, 0x57, 0x64, 0x53, 0x4c, + 0x35, 0x73, 0x74, 0x50, 0x53, 0x6b, 0x73, 0x50, 0x4e, 0x6b, 0x4e, 0x33, + 0x6d, 0x53, 0x77, 0x4f, 0x78, 0x47, 0x58, 0x6e, 0x2f, 0x68, 0x62, 0x56, + 0x4e, 0x4d, 0x59, 0x71, 0x2f, 0x4e, 0x0a, 0x48, 0x77, 0x74, 0x6a, 0x75, + 0x7a, 0x71, 0x64, 0x2b, 0x2f, 0x78, 0x35, 0x41, 0x4a, 0x68, 0x68, 0x64, + 0x4d, 0x38, 0x6d, 0x67, 0x6b, 0x42, 0x6a, 0x38, 0x37, 0x4a, 0x79, 0x61, + 0x68, 0x6b, 0x4e, 0x6d, 0x63, 0x72, 0x55, 0x44, 0x6e, 0x58, 0x4d, 0x4e, + 0x2f, 0x75, 0x4c, 0x69, 0x63, 0x46, 0x5a, 0x38, 0x57, 0x4a, 0x2f, 0x58, + 0x37, 0x4e, 0x66, 0x5a, 0x54, 0x44, 0x34, 0x70, 0x37, 0x64, 0x4e, 0x0a, + 0x64, 0x6c, 0x6f, 0x65, 0x64, 0x6c, 0x34, 0x30, 0x77, 0x4f, 0x69, 0x57, + 0x56, 0x70, 0x6d, 0x4b, 0x73, 0x2f, 0x42, 0x2f, 0x70, 0x4d, 0x32, 0x39, + 0x33, 0x44, 0x49, 0x78, 0x66, 0x4a, 0x48, 0x50, 0x34, 0x46, 0x38, 0x52, + 0x2b, 0x47, 0x75, 0x71, 0x53, 0x56, 0x7a, 0x52, 0x6d, 0x5a, 0x54, 0x52, + 0x6f, 0x75, 0x4e, 0x6a, 0x57, 0x77, 0x6c, 0x32, 0x74, 0x56, 0x5a, 0x69, + 0x34, 0x55, 0x74, 0x30, 0x0a, 0x48, 0x5a, 0x62, 0x55, 0x4a, 0x74, 0x51, + 0x49, 0x42, 0x46, 0x6e, 0x51, 0x6d, 0x41, 0x34, 0x4f, 0x35, 0x74, 0x37, + 0x38, 0x77, 0x2b, 0x77, 0x66, 0x6b, 0x50, 0x45, 0x43, 0x41, 0x77, 0x45, + 0x41, 0x41, 0x61, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77, 0x44, 0x77, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, + 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x0a, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, + 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, + 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x48, 0x77, 0x4d, 0x4d, 0x68, + 0x2b, 0x6e, 0x32, 0x54, 0x42, 0x2f, 0x78, 0x48, 0x31, 0x6f, 0x6f, 0x32, + 0x4b, 0x6f, 0x6f, 0x63, 0x36, 0x72, 0x42, 0x31, 0x73, 0x6e, 0x4d, 0x41, + 0x30, 0x47, 0x0a, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, + 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x41, + 0x51, 0x41, 0x52, 0x57, 0x66, 0x6f, 0x6c, 0x54, 0x77, 0x4e, 0x76, 0x6c, + 0x4a, 0x6b, 0x37, 0x6d, 0x68, 0x2b, 0x43, 0x68, 0x54, 0x6e, 0x55, 0x64, + 0x67, 0x57, 0x55, 0x58, 0x75, 0x45, 0x6f, 0x6b, 0x32, 0x31, 0x69, 0x58, + 0x51, 0x6e, 0x43, 0x6f, 0x4b, 0x6a, 0x55, 0x0a, 0x73, 0x48, 0x55, 0x34, + 0x38, 0x54, 0x52, 0x71, 0x6e, 0x65, 0x53, 0x66, 0x69, 0x6f, 0x59, 0x6d, + 0x55, 0x65, 0x59, 0x73, 0x30, 0x63, 0x59, 0x74, 0x62, 0x70, 0x55, 0x67, + 0x53, 0x70, 0x49, 0x42, 0x37, 0x4c, 0x69, 0x4b, 0x5a, 0x33, 0x73, 0x78, + 0x34, 0x6d, 0x63, 0x75, 0x6a, 0x4a, 0x55, 0x44, 0x4a, 0x69, 0x35, 0x44, + 0x6e, 0x55, 0x6f, 0x78, 0x39, 0x67, 0x36, 0x31, 0x44, 0x4c, 0x75, 0x33, + 0x0a, 0x34, 0x6a, 0x64, 0x2f, 0x49, 0x72, 0x6f, 0x41, 0x6f, 0x77, 0x35, + 0x37, 0x55, 0x76, 0x74, 0x72, 0x75, 0x7a, 0x76, 0x45, 0x30, 0x33, 0x6c, + 0x52, 0x54, 0x73, 0x32, 0x51, 0x39, 0x47, 0x63, 0x48, 0x47, 0x63, 0x67, + 0x38, 0x52, 0x6e, 0x6f, 0x4e, 0x41, 0x58, 0x33, 0x46, 0x57, 0x4f, 0x64, + 0x74, 0x35, 0x6f, 0x55, 0x77, 0x46, 0x35, 0x6f, 0x6b, 0x78, 0x42, 0x44, + 0x67, 0x42, 0x50, 0x66, 0x67, 0x0a, 0x38, 0x6e, 0x2f, 0x55, 0x71, 0x67, + 0x72, 0x2f, 0x51, 0x68, 0x30, 0x33, 0x37, 0x5a, 0x54, 0x6c, 0x5a, 0x46, + 0x6b, 0x53, 0x49, 0x48, 0x63, 0x34, 0x30, 0x7a, 0x49, 0x2b, 0x4f, 0x49, + 0x46, 0x31, 0x6c, 0x6e, 0x50, 0x36, 0x61, 0x49, 0x2b, 0x78, 0x79, 0x38, + 0x34, 0x66, 0x78, 0x65, 0x7a, 0x36, 0x6e, 0x48, 0x37, 0x50, 0x66, 0x72, + 0x48, 0x78, 0x42, 0x79, 0x32, 0x32, 0x2f, 0x4c, 0x2f, 0x4b, 0x0a, 0x70, + 0x4c, 0x2f, 0x51, 0x6c, 0x77, 0x56, 0x4b, 0x76, 0x4f, 0x6f, 0x59, 0x4b, + 0x41, 0x4b, 0x51, 0x76, 0x56, 0x52, 0x34, 0x43, 0x53, 0x46, 0x78, 0x30, + 0x39, 0x46, 0x39, 0x48, 0x64, 0x6b, 0x57, 0x73, 0x4b, 0x6c, 0x68, 0x50, + 0x64, 0x41, 0x4b, 0x41, 0x43, 0x4c, 0x38, 0x78, 0x33, 0x76, 0x4c, 0x43, + 0x57, 0x52, 0x46, 0x43, 0x7a, 0x74, 0x41, 0x67, 0x66, 0x64, 0x39, 0x66, + 0x44, 0x4c, 0x31, 0x0a, 0x6d, 0x4d, 0x70, 0x59, 0x6a, 0x6e, 0x30, 0x71, + 0x37, 0x70, 0x42, 0x5a, 0x63, 0x32, 0x54, 0x35, 0x4e, 0x6e, 0x52, 0x65, + 0x4a, 0x61, 0x48, 0x31, 0x5a, 0x67, 0x55, 0x75, 0x66, 0x7a, 0x6b, 0x56, + 0x71, 0x53, 0x72, 0x37, 0x55, 0x49, 0x75, 0x4f, 0x68, 0x57, 0x6e, 0x30, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x53, 0x74, + 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, + 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x53, 0x74, + 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, + 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, + 0x20, 0x47, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x31, 0x37, 0x3a, 0x33, 0x35, 0x3a, 0x37, 0x34, 0x3a, 0x61, 0x66, 0x3a, + 0x37, 0x62, 0x3a, 0x36, 0x31, 0x3a, 0x31, 0x63, 0x3a, 0x65, 0x62, 0x3a, + 0x66, 0x34, 0x3a, 0x66, 0x39, 0x3a, 0x33, 0x63, 0x3a, 0x65, 0x32, 0x3a, + 0x65, 0x65, 0x3a, 0x34, 0x30, 0x3a, 0x66, 0x39, 0x3a, 0x61, 0x32, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x32, 0x3a, 0x35, + 0x61, 0x3a, 0x38, 0x66, 0x3a, 0x38, 0x64, 0x3a, 0x32, 0x63, 0x3a, 0x36, + 0x64, 0x3a, 0x30, 0x34, 0x3a, 0x65, 0x30, 0x3a, 0x36, 0x36, 0x3a, 0x35, + 0x66, 0x3a, 0x35, 0x39, 0x3a, 0x36, 0x61, 0x3a, 0x66, 0x66, 0x3a, 0x32, + 0x32, 0x3a, 0x64, 0x38, 0x3a, 0x36, 0x33, 0x3a, 0x65, 0x38, 0x3a, 0x32, + 0x35, 0x3a, 0x36, 0x66, 0x3a, 0x33, 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x36, 0x3a, 0x38, 0x64, 0x3a, + 0x36, 0x39, 0x3a, 0x30, 0x35, 0x3a, 0x61, 0x32, 0x3a, 0x63, 0x38, 0x3a, + 0x38, 0x37, 0x3a, 0x30, 0x38, 0x3a, 0x61, 0x34, 0x3a, 0x62, 0x33, 0x3a, + 0x30, 0x32, 0x3a, 0x35, 0x31, 0x3a, 0x39, 0x30, 0x3a, 0x65, 0x64, 0x3a, + 0x63, 0x66, 0x3a, 0x65, 0x64, 0x3a, 0x62, 0x31, 0x3a, 0x39, 0x37, 0x3a, + 0x34, 0x61, 0x3a, 0x36, 0x30, 0x3a, 0x36, 0x61, 0x3a, 0x31, 0x33, 0x3a, + 0x63, 0x36, 0x3a, 0x65, 0x35, 0x3a, 0x32, 0x39, 0x3a, 0x30, 0x66, 0x3a, + 0x63, 0x62, 0x3a, 0x32, 0x61, 0x3a, 0x65, 0x36, 0x3a, 0x33, 0x65, 0x3a, + 0x64, 0x61, 0x3a, 0x62, 0x35, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, + 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, + 0x49, 0x44, 0x37, 0x7a, 0x43, 0x43, 0x41, 0x74, 0x65, 0x67, 0x41, 0x77, + 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x44, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x73, 0x46, 0x41, 0x44, 0x43, 0x42, 0x6d, 0x44, 0x45, 0x4c, 0x4d, 0x41, + 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, + 0x4d, 0x78, 0x0a, 0x45, 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x67, 0x54, 0x42, 0x30, 0x46, 0x79, 0x61, 0x58, 0x70, 0x76, 0x62, + 0x6d, 0x45, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x63, 0x54, 0x43, 0x6c, 0x4e, 0x6a, 0x62, 0x33, 0x52, 0x30, 0x63, + 0x32, 0x52, 0x68, 0x62, 0x47, 0x55, 0x78, 0x4a, 0x54, 0x41, 0x6a, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x0a, 0x48, 0x46, 0x4e, 0x30, + 0x59, 0x58, 0x4a, 0x6d, 0x61, 0x57, 0x56, 0x73, 0x5a, 0x43, 0x42, 0x55, + 0x5a, 0x57, 0x4e, 0x6f, 0x62, 0x6d, 0x39, 0x73, 0x62, 0x32, 0x64, 0x70, + 0x5a, 0x58, 0x4d, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, + 0x4f, 0x7a, 0x41, 0x35, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, + 0x4d, 0x6c, 0x4e, 0x30, 0x59, 0x58, 0x4a, 0x6d, 0x61, 0x57, 0x56, 0x73, + 0x0a, 0x5a, 0x43, 0x42, 0x54, 0x5a, 0x58, 0x4a, 0x32, 0x61, 0x57, 0x4e, + 0x6c, 0x63, 0x79, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, + 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, + 0x6c, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, + 0x30, 0x65, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x79, 0x4d, 0x42, 0x34, + 0x58, 0x44, 0x54, 0x41, 0x35, 0x0a, 0x4d, 0x44, 0x6b, 0x77, 0x4d, 0x54, + 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, + 0x4d, 0x33, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x7a, 0x4e, 0x54, + 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x67, 0x5a, 0x67, 0x78, 0x43, 0x7a, + 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, + 0x56, 0x54, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, 0x0a, 0x56, + 0x51, 0x51, 0x49, 0x45, 0x77, 0x64, 0x42, 0x63, 0x6d, 0x6c, 0x36, 0x62, + 0x32, 0x35, 0x68, 0x4d, 0x52, 0x4d, 0x77, 0x45, 0x51, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x48, 0x45, 0x77, 0x70, 0x54, 0x59, 0x32, 0x39, 0x30, 0x64, + 0x48, 0x4e, 0x6b, 0x59, 0x57, 0x78, 0x6c, 0x4d, 0x53, 0x55, 0x77, 0x49, + 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x78, 0x54, 0x64, + 0x47, 0x46, 0x79, 0x0a, 0x5a, 0x6d, 0x6c, 0x6c, 0x62, 0x47, 0x51, 0x67, + 0x56, 0x47, 0x56, 0x6a, 0x61, 0x47, 0x35, 0x76, 0x62, 0x47, 0x39, 0x6e, + 0x61, 0x57, 0x56, 0x7a, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, + 0x4d, 0x54, 0x73, 0x77, 0x4f, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, + 0x45, 0x7a, 0x4a, 0x54, 0x64, 0x47, 0x46, 0x79, 0x5a, 0x6d, 0x6c, 0x6c, + 0x62, 0x47, 0x51, 0x67, 0x55, 0x32, 0x56, 0x79, 0x0a, 0x64, 0x6d, 0x6c, + 0x6a, 0x5a, 0x58, 0x4d, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, + 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, + 0x30, 0x5a, 0x53, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, + 0x70, 0x64, 0x48, 0x6b, 0x67, 0x4c, 0x53, 0x42, 0x48, 0x4d, 0x6a, 0x43, + 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, + 0x49, 0x0a, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, + 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, + 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4e, 0x55, 0x4d, 0x4f, 0x73, + 0x51, 0x71, 0x2b, 0x55, 0x37, 0x69, 0x39, 0x62, 0x34, 0x5a, 0x6c, 0x31, + 0x2b, 0x4f, 0x69, 0x46, 0x4f, 0x78, 0x48, 0x7a, 0x2f, 0x4c, 0x7a, 0x35, + 0x38, 0x67, 0x45, 0x32, 0x30, 0x70, 0x0a, 0x4f, 0x73, 0x67, 0x50, 0x66, + 0x54, 0x7a, 0x33, 0x61, 0x33, 0x59, 0x34, 0x59, 0x39, 0x6b, 0x32, 0x59, + 0x4b, 0x69, 0x62, 0x58, 0x6c, 0x77, 0x41, 0x67, 0x4c, 0x49, 0x76, 0x57, + 0x58, 0x2f, 0x32, 0x68, 0x2f, 0x6b, 0x6c, 0x51, 0x34, 0x62, 0x6e, 0x61, + 0x52, 0x74, 0x53, 0x6d, 0x70, 0x44, 0x68, 0x63, 0x65, 0x50, 0x59, 0x4c, + 0x51, 0x31, 0x4f, 0x62, 0x2f, 0x62, 0x49, 0x53, 0x64, 0x6d, 0x32, 0x0a, + 0x38, 0x78, 0x70, 0x57, 0x72, 0x69, 0x75, 0x32, 0x64, 0x42, 0x54, 0x72, + 0x7a, 0x2f, 0x73, 0x6d, 0x34, 0x78, 0x71, 0x36, 0x48, 0x5a, 0x59, 0x75, + 0x61, 0x6a, 0x74, 0x59, 0x6c, 0x49, 0x6c, 0x48, 0x56, 0x76, 0x38, 0x6c, + 0x6f, 0x4a, 0x4e, 0x77, 0x55, 0x34, 0x50, 0x61, 0x68, 0x48, 0x51, 0x55, + 0x77, 0x32, 0x65, 0x65, 0x42, 0x47, 0x67, 0x36, 0x33, 0x34, 0x35, 0x41, + 0x57, 0x68, 0x31, 0x4b, 0x0a, 0x54, 0x73, 0x39, 0x44, 0x6b, 0x54, 0x76, + 0x6e, 0x56, 0x74, 0x59, 0x41, 0x63, 0x4d, 0x74, 0x53, 0x37, 0x6e, 0x74, + 0x39, 0x72, 0x6a, 0x72, 0x6e, 0x76, 0x44, 0x48, 0x35, 0x52, 0x66, 0x62, + 0x43, 0x59, 0x4d, 0x38, 0x54, 0x57, 0x51, 0x49, 0x72, 0x67, 0x4d, 0x77, + 0x30, 0x52, 0x39, 0x2b, 0x35, 0x33, 0x70, 0x42, 0x6c, 0x62, 0x51, 0x4c, + 0x50, 0x4c, 0x4a, 0x47, 0x6d, 0x70, 0x75, 0x66, 0x65, 0x0a, 0x68, 0x52, + 0x68, 0x4a, 0x66, 0x47, 0x5a, 0x4f, 0x6f, 0x7a, 0x70, 0x74, 0x71, 0x62, + 0x58, 0x75, 0x4e, 0x43, 0x36, 0x36, 0x44, 0x51, 0x4f, 0x34, 0x4d, 0x39, + 0x39, 0x48, 0x36, 0x37, 0x46, 0x72, 0x6a, 0x53, 0x58, 0x5a, 0x6d, 0x38, + 0x36, 0x42, 0x30, 0x55, 0x56, 0x47, 0x4d, 0x70, 0x5a, 0x77, 0x68, 0x39, + 0x34, 0x43, 0x44, 0x6b, 0x6c, 0x44, 0x68, 0x62, 0x5a, 0x73, 0x63, 0x37, + 0x74, 0x6b, 0x0a, 0x36, 0x6d, 0x46, 0x42, 0x72, 0x4d, 0x6e, 0x55, 0x56, + 0x4e, 0x2b, 0x48, 0x4c, 0x38, 0x63, 0x69, 0x73, 0x69, 0x62, 0x4d, 0x6e, + 0x31, 0x6c, 0x55, 0x61, 0x4a, 0x2f, 0x38, 0x76, 0x69, 0x6f, 0x76, 0x78, + 0x46, 0x55, 0x63, 0x64, 0x55, 0x42, 0x67, 0x46, 0x34, 0x55, 0x43, 0x56, + 0x54, 0x6d, 0x4c, 0x66, 0x77, 0x55, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, + 0x61, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77, 0x0a, 0x44, 0x77, 0x59, 0x44, + 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, + 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, + 0x41, 0x51, 0x59, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, + 0x42, 0x42, 0x59, 0x45, 0x46, 0x4a, 0x78, 0x66, 0x41, 0x4e, 0x2b, 0x71, + 0x0a, 0x41, 0x64, 0x63, 0x77, 0x4b, 0x7a, 0x69, 0x49, 0x6f, 0x72, 0x68, + 0x74, 0x53, 0x70, 0x7a, 0x79, 0x45, 0x5a, 0x47, 0x44, 0x4d, 0x41, 0x30, + 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, + 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x41, 0x51, 0x42, + 0x4c, 0x4e, 0x71, 0x61, 0x45, 0x64, 0x32, 0x6e, 0x64, 0x4f, 0x78, 0x6d, + 0x66, 0x5a, 0x79, 0x4d, 0x49, 0x0a, 0x62, 0x77, 0x35, 0x68, 0x79, 0x66, + 0x32, 0x45, 0x33, 0x46, 0x2f, 0x59, 0x4e, 0x6f, 0x48, 0x4e, 0x32, 0x42, + 0x74, 0x42, 0x4c, 0x5a, 0x39, 0x67, 0x33, 0x63, 0x63, 0x61, 0x61, 0x4e, + 0x6e, 0x52, 0x62, 0x6f, 0x62, 0x68, 0x69, 0x43, 0x50, 0x50, 0x45, 0x39, + 0x35, 0x44, 0x7a, 0x2b, 0x49, 0x30, 0x73, 0x77, 0x53, 0x64, 0x48, 0x79, + 0x6e, 0x56, 0x76, 0x2f, 0x68, 0x65, 0x79, 0x4e, 0x58, 0x42, 0x0a, 0x76, + 0x65, 0x36, 0x53, 0x62, 0x7a, 0x4a, 0x30, 0x38, 0x70, 0x47, 0x43, 0x4c, + 0x37, 0x32, 0x43, 0x51, 0x6e, 0x71, 0x74, 0x4b, 0x72, 0x63, 0x67, 0x66, + 0x55, 0x32, 0x38, 0x65, 0x6c, 0x55, 0x53, 0x77, 0x68, 0x58, 0x71, 0x76, + 0x66, 0x64, 0x71, 0x6c, 0x53, 0x35, 0x73, 0x64, 0x4a, 0x2f, 0x50, 0x48, + 0x4c, 0x54, 0x79, 0x78, 0x51, 0x47, 0x6a, 0x68, 0x64, 0x42, 0x79, 0x50, + 0x71, 0x31, 0x7a, 0x0a, 0x71, 0x77, 0x75, 0x62, 0x64, 0x51, 0x78, 0x74, + 0x52, 0x62, 0x65, 0x4f, 0x6c, 0x4b, 0x79, 0x57, 0x4e, 0x37, 0x57, 0x67, + 0x30, 0x49, 0x38, 0x56, 0x52, 0x77, 0x37, 0x6a, 0x36, 0x49, 0x50, 0x64, + 0x6a, 0x2f, 0x33, 0x76, 0x51, 0x51, 0x46, 0x33, 0x7a, 0x43, 0x65, 0x70, + 0x59, 0x6f, 0x55, 0x7a, 0x38, 0x6a, 0x63, 0x49, 0x37, 0x33, 0x48, 0x50, + 0x64, 0x77, 0x62, 0x65, 0x79, 0x42, 0x6b, 0x64, 0x0a, 0x69, 0x45, 0x44, + 0x50, 0x66, 0x55, 0x59, 0x64, 0x2f, 0x78, 0x37, 0x48, 0x34, 0x63, 0x37, + 0x2f, 0x49, 0x39, 0x76, 0x47, 0x2b, 0x6f, 0x31, 0x56, 0x54, 0x71, 0x6b, + 0x43, 0x35, 0x30, 0x63, 0x52, 0x52, 0x6a, 0x37, 0x30, 0x2f, 0x62, 0x31, + 0x37, 0x4b, 0x53, 0x61, 0x37, 0x71, 0x57, 0x46, 0x69, 0x4e, 0x79, 0x69, + 0x32, 0x4c, 0x53, 0x72, 0x32, 0x45, 0x49, 0x5a, 0x6b, 0x79, 0x58, 0x43, + 0x6e, 0x0a, 0x30, 0x71, 0x32, 0x33, 0x4b, 0x58, 0x42, 0x35, 0x36, 0x6a, + 0x7a, 0x61, 0x59, 0x79, 0x57, 0x66, 0x2f, 0x57, 0x69, 0x33, 0x4d, 0x4f, + 0x78, 0x77, 0x2b, 0x33, 0x57, 0x4b, 0x74, 0x32, 0x31, 0x67, 0x5a, 0x37, + 0x49, 0x65, 0x79, 0x4c, 0x6e, 0x70, 0x32, 0x4b, 0x68, 0x76, 0x41, 0x6f, + 0x74, 0x6e, 0x44, 0x55, 0x30, 0x6d, 0x56, 0x33, 0x48, 0x61, 0x49, 0x50, + 0x7a, 0x42, 0x53, 0x6c, 0x43, 0x4e, 0x0a, 0x73, 0x53, 0x69, 0x36, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, + 0x61, 0x6c, 0x20, 0x4f, 0x3d, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x66, 0x66, 0x69, 0x72, + 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, + 0x72, 0x63, 0x69, 0x61, 0x6c, 0x20, 0x4f, 0x3d, 0x41, 0x66, 0x66, 0x69, + 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, + 0x63, 0x69, 0x61, 0x6c, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x38, 0x36, 0x30, 0x38, 0x33, 0x35, 0x35, 0x39, + 0x37, 0x37, 0x39, 0x36, 0x34, 0x31, 0x33, 0x38, 0x38, 0x37, 0x36, 0x0a, + 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x32, 0x3a, 0x39, 0x32, + 0x3a, 0x62, 0x61, 0x3a, 0x35, 0x62, 0x3a, 0x65, 0x66, 0x3a, 0x63, 0x64, + 0x3a, 0x38, 0x61, 0x3a, 0x36, 0x66, 0x3a, 0x61, 0x36, 0x3a, 0x33, 0x64, + 0x3a, 0x35, 0x35, 0x3a, 0x66, 0x39, 0x3a, 0x38, 0x34, 0x3a, 0x66, 0x36, + 0x3a, 0x64, 0x36, 0x3a, 0x62, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x66, 0x39, 0x3a, 0x62, 0x35, 0x3a, 0x62, 0x36, 0x3a, + 0x33, 0x32, 0x3a, 0x34, 0x35, 0x3a, 0x35, 0x66, 0x3a, 0x39, 0x63, 0x3a, + 0x62, 0x65, 0x3a, 0x65, 0x63, 0x3a, 0x35, 0x37, 0x3a, 0x35, 0x66, 0x3a, + 0x38, 0x30, 0x3a, 0x64, 0x63, 0x3a, 0x65, 0x39, 0x3a, 0x36, 0x65, 0x3a, + 0x32, 0x63, 0x3a, 0x63, 0x37, 0x3a, 0x62, 0x32, 0x3a, 0x37, 0x38, 0x3a, + 0x62, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x30, 0x33, 0x3a, 0x37, 0x36, 0x3a, 0x61, 0x62, 0x3a, 0x31, 0x64, + 0x3a, 0x35, 0x34, 0x3a, 0x63, 0x35, 0x3a, 0x66, 0x39, 0x3a, 0x38, 0x30, + 0x3a, 0x33, 0x63, 0x3a, 0x65, 0x34, 0x3a, 0x62, 0x32, 0x3a, 0x65, 0x32, + 0x3a, 0x30, 0x31, 0x3a, 0x61, 0x30, 0x3a, 0x65, 0x65, 0x3a, 0x37, 0x65, + 0x3a, 0x65, 0x66, 0x3a, 0x37, 0x62, 0x3a, 0x35, 0x37, 0x3a, 0x62, 0x36, + 0x3a, 0x33, 0x36, 0x3a, 0x65, 0x38, 0x3a, 0x61, 0x39, 0x3a, 0x33, 0x63, + 0x3a, 0x39, 0x62, 0x3a, 0x38, 0x64, 0x3a, 0x34, 0x38, 0x3a, 0x36, 0x30, + 0x3a, 0x63, 0x39, 0x3a, 0x36, 0x66, 0x3a, 0x35, 0x66, 0x3a, 0x61, 0x37, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x54, 0x44, 0x43, + 0x43, 0x41, 0x6a, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x49, 0x64, 0x33, 0x63, 0x47, 0x4a, 0x79, 0x61, 0x70, 0x73, 0x58, 0x77, + 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, + 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x77, 0x52, 0x44, 0x45, + 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x42, 0x68, + 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x43, 0x30, 0x46, 0x6d, 0x5a, 0x6d, + 0x6c, 0x79, 0x62, 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4d, 0x52, + 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, + 0x5a, 0x42, 0x5a, 0x6d, 0x5a, 0x70, 0x63, 0x6d, 0x31, 0x55, 0x63, 0x6e, + 0x56, 0x7a, 0x0a, 0x64, 0x43, 0x42, 0x44, 0x62, 0x32, 0x31, 0x74, 0x5a, + 0x58, 0x4a, 0x6a, 0x61, 0x57, 0x46, 0x73, 0x4d, 0x42, 0x34, 0x58, 0x44, + 0x54, 0x45, 0x77, 0x4d, 0x44, 0x45, 0x79, 0x4f, 0x54, 0x45, 0x30, 0x4d, + 0x44, 0x59, 0x77, 0x4e, 0x6c, 0x6f, 0x58, 0x44, 0x54, 0x4d, 0x77, 0x4d, + 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x45, 0x30, 0x4d, 0x44, 0x59, 0x77, 0x4e, + 0x6c, 0x6f, 0x77, 0x52, 0x44, 0x45, 0x4c, 0x0a, 0x4d, 0x41, 0x6b, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, + 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, + 0x43, 0x30, 0x46, 0x6d, 0x5a, 0x6d, 0x6c, 0x79, 0x62, 0x56, 0x52, 0x79, + 0x64, 0x58, 0x4e, 0x30, 0x4d, 0x52, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, 0x5a, 0x42, 0x5a, 0x6d, 0x5a, 0x70, + 0x0a, 0x63, 0x6d, 0x31, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, + 0x44, 0x62, 0x32, 0x31, 0x74, 0x5a, 0x58, 0x4a, 0x6a, 0x61, 0x57, 0x46, + 0x73, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, + 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, + 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, + 0x42, 0x43, 0x67, 0x4b, 0x43, 0x0a, 0x41, 0x51, 0x45, 0x41, 0x39, 0x68, + 0x74, 0x50, 0x5a, 0x77, 0x63, 0x72, 0x6f, 0x52, 0x58, 0x31, 0x42, 0x69, + 0x4c, 0x4c, 0x48, 0x77, 0x47, 0x79, 0x34, 0x33, 0x4e, 0x46, 0x42, 0x6b, + 0x52, 0x4a, 0x4c, 0x4c, 0x74, 0x4a, 0x4a, 0x52, 0x54, 0x57, 0x7a, 0x73, + 0x4f, 0x33, 0x71, 0x79, 0x78, 0x50, 0x78, 0x6b, 0x45, 0x79, 0x6c, 0x46, + 0x66, 0x36, 0x45, 0x71, 0x64, 0x62, 0x44, 0x75, 0x4b, 0x50, 0x0a, 0x48, + 0x78, 0x36, 0x47, 0x47, 0x61, 0x65, 0x71, 0x74, 0x53, 0x32, 0x35, 0x58, + 0x77, 0x32, 0x4b, 0x77, 0x71, 0x2b, 0x46, 0x4e, 0x58, 0x6b, 0x79, 0x4c, + 0x62, 0x73, 0x63, 0x59, 0x6a, 0x66, 0x79, 0x73, 0x56, 0x74, 0x4b, 0x50, + 0x63, 0x72, 0x4e, 0x63, 0x56, 0x2f, 0x70, 0x51, 0x72, 0x36, 0x55, 0x36, + 0x4d, 0x6a, 0x65, 0x2b, 0x53, 0x4a, 0x49, 0x5a, 0x4d, 0x62, 0x6c, 0x71, + 0x38, 0x59, 0x72, 0x0a, 0x62, 0x61, 0x30, 0x46, 0x38, 0x50, 0x72, 0x56, + 0x43, 0x38, 0x2b, 0x61, 0x35, 0x66, 0x42, 0x51, 0x70, 0x49, 0x73, 0x37, + 0x52, 0x36, 0x55, 0x6a, 0x57, 0x33, 0x70, 0x36, 0x2b, 0x44, 0x4d, 0x2f, + 0x75, 0x4f, 0x2b, 0x5a, 0x6c, 0x2b, 0x4d, 0x67, 0x77, 0x64, 0x59, 0x6f, + 0x69, 0x63, 0x2b, 0x55, 0x2b, 0x37, 0x6c, 0x46, 0x37, 0x65, 0x4e, 0x41, + 0x46, 0x78, 0x48, 0x55, 0x64, 0x50, 0x41, 0x4c, 0x0a, 0x4d, 0x65, 0x49, + 0x72, 0x4a, 0x6d, 0x71, 0x62, 0x54, 0x46, 0x65, 0x75, 0x72, 0x43, 0x41, + 0x2b, 0x75, 0x6b, 0x56, 0x36, 0x42, 0x66, 0x4f, 0x39, 0x6d, 0x32, 0x6b, + 0x56, 0x72, 0x6e, 0x31, 0x4f, 0x49, 0x47, 0x50, 0x45, 0x4e, 0x58, 0x59, + 0x36, 0x42, 0x77, 0x4c, 0x4a, 0x4e, 0x2f, 0x33, 0x48, 0x52, 0x2b, 0x37, + 0x6f, 0x38, 0x58, 0x59, 0x64, 0x63, 0x78, 0x58, 0x79, 0x6c, 0x36, 0x53, + 0x31, 0x0a, 0x79, 0x48, 0x70, 0x35, 0x32, 0x55, 0x4b, 0x71, 0x4b, 0x33, + 0x39, 0x63, 0x2f, 0x73, 0x34, 0x6d, 0x54, 0x36, 0x4e, 0x6d, 0x67, 0x54, + 0x57, 0x76, 0x52, 0x4c, 0x70, 0x55, 0x48, 0x68, 0x77, 0x77, 0x4d, 0x6d, + 0x57, 0x64, 0x35, 0x6a, 0x79, 0x54, 0x58, 0x6c, 0x42, 0x4f, 0x65, 0x75, + 0x4d, 0x36, 0x31, 0x47, 0x37, 0x4d, 0x47, 0x76, 0x76, 0x35, 0x30, 0x6a, + 0x65, 0x75, 0x4a, 0x43, 0x71, 0x72, 0x0a, 0x56, 0x77, 0x4d, 0x69, 0x4b, + 0x41, 0x31, 0x4a, 0x64, 0x58, 0x2b, 0x33, 0x4b, 0x4e, 0x70, 0x31, 0x76, + 0x34, 0x37, 0x6a, 0x33, 0x41, 0x35, 0x35, 0x4d, 0x51, 0x49, 0x44, 0x41, + 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x64, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x6e, + 0x5a, 0x50, 0x47, 0x55, 0x34, 0x74, 0x65, 0x79, 0x71, 0x38, 0x2f, 0x0a, + 0x6e, 0x78, 0x34, 0x50, 0x35, 0x5a, 0x6d, 0x56, 0x76, 0x43, 0x54, 0x32, + 0x6c, 0x49, 0x38, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, + 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, + 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, + 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, + 0x44, 0x51, 0x59, 0x4a, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, + 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, + 0x42, 0x41, 0x46, 0x69, 0x73, 0x39, 0x41, 0x51, 0x4f, 0x7a, 0x63, 0x41, + 0x4e, 0x2f, 0x77, 0x72, 0x39, 0x31, 0x4c, 0x6f, 0x57, 0x58, 0x79, 0x6d, + 0x39, 0x65, 0x32, 0x69, 0x5a, 0x57, 0x45, 0x6e, 0x53, 0x74, 0x42, 0x30, + 0x33, 0x54, 0x58, 0x38, 0x6e, 0x66, 0x55, 0x59, 0x47, 0x0a, 0x58, 0x55, + 0x50, 0x47, 0x68, 0x69, 0x34, 0x2b, 0x63, 0x37, 0x49, 0x6d, 0x66, 0x55, + 0x2b, 0x54, 0x71, 0x62, 0x62, 0x45, 0x4b, 0x70, 0x71, 0x72, 0x49, 0x5a, + 0x63, 0x55, 0x73, 0x64, 0x36, 0x4d, 0x30, 0x36, 0x75, 0x4a, 0x46, 0x64, + 0x68, 0x72, 0x4a, 0x4e, 0x54, 0x78, 0x46, 0x71, 0x37, 0x59, 0x70, 0x46, + 0x7a, 0x55, 0x66, 0x31, 0x47, 0x4f, 0x37, 0x52, 0x67, 0x42, 0x73, 0x5a, + 0x4e, 0x6a, 0x0a, 0x76, 0x62, 0x7a, 0x34, 0x59, 0x59, 0x43, 0x61, 0x6e, + 0x72, 0x48, 0x4f, 0x51, 0x6e, 0x44, 0x69, 0x71, 0x58, 0x30, 0x47, 0x4a, + 0x58, 0x30, 0x6e, 0x6f, 0x66, 0x35, 0x76, 0x37, 0x4c, 0x4d, 0x65, 0x4a, + 0x4e, 0x72, 0x6a, 0x53, 0x31, 0x55, 0x61, 0x41, 0x44, 0x73, 0x31, 0x74, + 0x44, 0x76, 0x5a, 0x31, 0x31, 0x30, 0x77, 0x2f, 0x59, 0x45, 0x54, 0x69, + 0x66, 0x4c, 0x43, 0x42, 0x69, 0x76, 0x74, 0x0a, 0x5a, 0x38, 0x53, 0x4f, + 0x79, 0x55, 0x4f, 0x79, 0x58, 0x47, 0x73, 0x56, 0x69, 0x51, 0x4b, 0x38, + 0x59, 0x76, 0x78, 0x4f, 0x38, 0x72, 0x55, 0x7a, 0x71, 0x72, 0x4a, 0x76, + 0x30, 0x77, 0x71, 0x69, 0x55, 0x4f, 0x50, 0x32, 0x4f, 0x2b, 0x67, 0x75, + 0x52, 0x4d, 0x4c, 0x62, 0x5a, 0x6a, 0x69, 0x70, 0x4d, 0x31, 0x5a, 0x49, + 0x38, 0x57, 0x30, 0x62, 0x4d, 0x34, 0x30, 0x4e, 0x6a, 0x44, 0x39, 0x67, + 0x0a, 0x4e, 0x35, 0x33, 0x54, 0x79, 0x6d, 0x31, 0x2b, 0x4e, 0x48, 0x34, + 0x4e, 0x6e, 0x33, 0x4a, 0x32, 0x69, 0x78, 0x75, 0x66, 0x63, 0x76, 0x31, + 0x53, 0x4e, 0x55, 0x46, 0x46, 0x41, 0x70, 0x59, 0x76, 0x48, 0x4c, 0x4b, + 0x61, 0x63, 0x30, 0x6b, 0x68, 0x73, 0x55, 0x6c, 0x48, 0x52, 0x55, 0x65, + 0x30, 0x37, 0x32, 0x6f, 0x30, 0x45, 0x63, 0x6c, 0x4e, 0x6d, 0x73, 0x78, + 0x5a, 0x74, 0x39, 0x59, 0x43, 0x0a, 0x6e, 0x6c, 0x70, 0x4f, 0x5a, 0x62, + 0x57, 0x55, 0x72, 0x68, 0x76, 0x66, 0x4b, 0x62, 0x41, 0x57, 0x38, 0x62, + 0x38, 0x41, 0x6e, 0x67, 0x63, 0x36, 0x46, 0x32, 0x53, 0x31, 0x42, 0x4c, + 0x55, 0x6a, 0x49, 0x5a, 0x6b, 0x4b, 0x6c, 0x54, 0x75, 0x58, 0x66, 0x4f, + 0x38, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x66, 0x66, 0x69, 0x72, + 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x4f, 0x3d, 0x41, 0x66, 0x66, 0x69, + 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x66, + 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x4f, 0x3d, 0x41, + 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, + 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, 0x66, 0x66, + 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x22, 0x0a, 0x23, 0x20, 0x53, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x38, 0x39, 0x35, 0x37, 0x33, + 0x38, 0x32, 0x38, 0x32, 0x37, 0x32, 0x30, 0x36, 0x35, 0x34, 0x37, 0x37, + 0x35, 0x37, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x32, + 0x3a, 0x36, 0x35, 0x3a, 0x63, 0x61, 0x3a, 0x62, 0x65, 0x3a, 0x30, 0x31, + 0x3a, 0x39, 0x61, 0x3a, 0x39, 0x61, 0x3a, 0x34, 0x63, 0x3a, 0x61, 0x39, + 0x3a, 0x38, 0x63, 0x3a, 0x34, 0x31, 0x3a, 0x34, 0x39, 0x3a, 0x63, 0x64, + 0x3a, 0x63, 0x30, 0x3a, 0x64, 0x35, 0x3a, 0x37, 0x66, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x39, 0x3a, 0x33, 0x36, 0x3a, + 0x32, 0x31, 0x3a, 0x30, 0x32, 0x3a, 0x38, 0x62, 0x3a, 0x32, 0x30, 0x3a, + 0x65, 0x64, 0x3a, 0x30, 0x32, 0x3a, 0x66, 0x35, 0x3a, 0x36, 0x36, 0x3a, + 0x63, 0x35, 0x3a, 0x33, 0x32, 0x3a, 0x64, 0x31, 0x3a, 0x64, 0x36, 0x3a, + 0x65, 0x64, 0x3a, 0x39, 0x30, 0x3a, 0x39, 0x66, 0x3a, 0x34, 0x35, 0x3a, + 0x30, 0x30, 0x3a, 0x32, 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x61, 0x3a, 0x38, 0x31, 0x3a, 0x65, 0x63, + 0x3a, 0x35, 0x61, 0x3a, 0x39, 0x32, 0x3a, 0x39, 0x37, 0x3a, 0x37, 0x37, + 0x3a, 0x66, 0x31, 0x3a, 0x34, 0x35, 0x3a, 0x39, 0x30, 0x3a, 0x34, 0x61, + 0x3a, 0x66, 0x33, 0x3a, 0x38, 0x64, 0x3a, 0x35, 0x64, 0x3a, 0x35, 0x30, + 0x3a, 0x39, 0x66, 0x3a, 0x36, 0x36, 0x3a, 0x62, 0x35, 0x3a, 0x65, 0x32, + 0x3a, 0x63, 0x35, 0x3a, 0x38, 0x66, 0x3a, 0x63, 0x64, 0x3a, 0x62, 0x35, + 0x3a, 0x33, 0x31, 0x3a, 0x30, 0x35, 0x3a, 0x38, 0x62, 0x3a, 0x30, 0x65, + 0x3a, 0x31, 0x37, 0x3a, 0x66, 0x33, 0x3a, 0x66, 0x30, 0x3a, 0x62, 0x34, + 0x3a, 0x31, 0x62, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, + 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, + 0x54, 0x44, 0x43, 0x43, 0x41, 0x6a, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, + 0x41, 0x67, 0x49, 0x49, 0x66, 0x45, 0x38, 0x45, 0x4f, 0x52, 0x7a, 0x55, + 0x6d, 0x53, 0x30, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x77, + 0x52, 0x44, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x0a, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x44, 0x41, + 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x43, 0x30, 0x46, + 0x6d, 0x5a, 0x6d, 0x6c, 0x79, 0x62, 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, + 0x30, 0x4d, 0x52, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x44, 0x44, 0x42, 0x5a, 0x42, 0x5a, 0x6d, 0x5a, 0x70, 0x63, 0x6d, 0x31, + 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x0a, 0x64, 0x43, 0x42, 0x4f, 0x5a, 0x58, + 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, 0x61, 0x57, 0x35, 0x6e, 0x4d, 0x42, + 0x34, 0x58, 0x44, 0x54, 0x45, 0x77, 0x4d, 0x44, 0x45, 0x79, 0x4f, 0x54, + 0x45, 0x30, 0x4d, 0x44, 0x67, 0x79, 0x4e, 0x46, 0x6f, 0x58, 0x44, 0x54, + 0x4d, 0x77, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x45, 0x30, 0x4d, 0x44, + 0x67, 0x79, 0x4e, 0x46, 0x6f, 0x77, 0x52, 0x44, 0x45, 0x4c, 0x0a, 0x4d, + 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, + 0x56, 0x4d, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x6f, 0x4d, 0x43, 0x30, 0x46, 0x6d, 0x5a, 0x6d, 0x6c, 0x79, 0x62, + 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4d, 0x52, 0x38, 0x77, 0x48, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, 0x5a, 0x42, 0x5a, + 0x6d, 0x5a, 0x70, 0x0a, 0x63, 0x6d, 0x31, 0x55, 0x63, 0x6e, 0x56, 0x7a, + 0x64, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, 0x72, + 0x61, 0x57, 0x35, 0x6e, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, + 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x0a, 0x41, 0x51, 0x45, + 0x41, 0x74, 0x49, 0x54, 0x4d, 0x4d, 0x78, 0x63, 0x75, 0x61, 0x35, 0x52, + 0x73, 0x61, 0x32, 0x46, 0x53, 0x6f, 0x4f, 0x75, 0x6a, 0x7a, 0x33, 0x6d, + 0x55, 0x54, 0x4f, 0x57, 0x55, 0x67, 0x4a, 0x6e, 0x4c, 0x56, 0x57, 0x52, + 0x45, 0x5a, 0x59, 0x39, 0x6e, 0x5a, 0x4f, 0x49, 0x47, 0x34, 0x31, 0x77, + 0x33, 0x53, 0x66, 0x59, 0x76, 0x6d, 0x34, 0x53, 0x45, 0x48, 0x69, 0x33, + 0x79, 0x0a, 0x59, 0x4a, 0x30, 0x77, 0x54, 0x73, 0x79, 0x45, 0x68, 0x65, + 0x49, 0x73, 0x7a, 0x78, 0x36, 0x65, 0x2f, 0x6a, 0x61, 0x72, 0x4d, 0x33, + 0x63, 0x31, 0x52, 0x4e, 0x67, 0x31, 0x6c, 0x68, 0x6f, 0x39, 0x4e, 0x75, + 0x68, 0x36, 0x44, 0x74, 0x6a, 0x56, 0x52, 0x36, 0x46, 0x71, 0x61, 0x59, + 0x76, 0x5a, 0x2f, 0x4c, 0x73, 0x36, 0x72, 0x6e, 0x6c, 0x61, 0x31, 0x66, + 0x54, 0x57, 0x63, 0x62, 0x75, 0x61, 0x0a, 0x6b, 0x43, 0x4e, 0x72, 0x6d, + 0x72, 0x65, 0x49, 0x64, 0x49, 0x63, 0x4d, 0x48, 0x6c, 0x2b, 0x35, 0x6e, + 0x69, 0x33, 0x36, 0x71, 0x31, 0x4d, 0x72, 0x33, 0x4c, 0x74, 0x32, 0x50, + 0x70, 0x4e, 0x4d, 0x43, 0x41, 0x69, 0x4d, 0x48, 0x71, 0x49, 0x6a, 0x48, + 0x4e, 0x52, 0x71, 0x72, 0x53, 0x4b, 0x36, 0x6d, 0x51, 0x45, 0x75, 0x62, + 0x57, 0x58, 0x4c, 0x76, 0x69, 0x52, 0x6d, 0x56, 0x53, 0x52, 0x4c, 0x0a, + 0x51, 0x45, 0x53, 0x78, 0x47, 0x39, 0x66, 0x68, 0x77, 0x6f, 0x58, 0x41, + 0x33, 0x68, 0x41, 0x2f, 0x50, 0x65, 0x32, 0x34, 0x2f, 0x50, 0x48, 0x78, + 0x49, 0x31, 0x50, 0x63, 0x76, 0x32, 0x57, 0x58, 0x62, 0x39, 0x6e, 0x35, + 0x51, 0x48, 0x47, 0x4e, 0x66, 0x62, 0x32, 0x56, 0x31, 0x4d, 0x36, 0x2b, + 0x6f, 0x46, 0x34, 0x6e, 0x49, 0x39, 0x37, 0x39, 0x70, 0x74, 0x41, 0x6d, + 0x44, 0x67, 0x41, 0x70, 0x0a, 0x36, 0x7a, 0x78, 0x47, 0x38, 0x44, 0x31, + 0x67, 0x76, 0x7a, 0x39, 0x51, 0x30, 0x74, 0x77, 0x6d, 0x51, 0x56, 0x47, + 0x65, 0x46, 0x44, 0x64, 0x43, 0x42, 0x4b, 0x4e, 0x77, 0x56, 0x36, 0x67, + 0x62, 0x68, 0x2b, 0x30, 0x74, 0x2b, 0x6e, 0x76, 0x75, 0x6a, 0x41, 0x72, + 0x6a, 0x71, 0x57, 0x61, 0x4a, 0x47, 0x63, 0x74, 0x42, 0x2b, 0x64, 0x31, + 0x45, 0x4e, 0x6d, 0x48, 0x50, 0x34, 0x6e, 0x64, 0x47, 0x0a, 0x79, 0x48, + 0x33, 0x32, 0x39, 0x4a, 0x4b, 0x42, 0x4e, 0x76, 0x33, 0x62, 0x4e, 0x50, + 0x46, 0x79, 0x66, 0x76, 0x4d, 0x4d, 0x46, 0x72, 0x32, 0x30, 0x46, 0x51, + 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, + 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, + 0x51, 0x55, 0x42, 0x78, 0x2f, 0x53, 0x35, 0x35, 0x7a, 0x61, 0x77, 0x6d, + 0x36, 0x69, 0x0a, 0x51, 0x4c, 0x53, 0x77, 0x65, 0x6c, 0x41, 0x51, 0x55, + 0x48, 0x54, 0x45, 0x79, 0x4c, 0x30, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, + 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, + 0x51, 0x59, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, + 0x67, 0x67, 0x45, 0x42, 0x41, 0x49, 0x6c, 0x58, 0x73, 0x68, 0x5a, 0x36, + 0x71, 0x4d, 0x4c, 0x39, 0x31, 0x74, 0x6d, 0x62, 0x6d, 0x7a, 0x54, 0x43, + 0x6e, 0x4c, 0x51, 0x79, 0x46, 0x45, 0x32, 0x6e, 0x70, 0x4e, 0x2f, 0x73, + 0x76, 0x71, 0x65, 0x2b, 0x2b, 0x45, 0x50, 0x62, 0x6b, 0x54, 0x66, 0x4f, + 0x0a, 0x74, 0x44, 0x49, 0x75, 0x55, 0x46, 0x55, 0x61, 0x4e, 0x55, 0x35, + 0x32, 0x51, 0x33, 0x45, 0x67, 0x37, 0x35, 0x4e, 0x33, 0x54, 0x68, 0x56, + 0x77, 0x4c, 0x6f, 0x66, 0x44, 0x77, 0x52, 0x31, 0x74, 0x33, 0x4d, 0x75, + 0x31, 0x4a, 0x39, 0x51, 0x73, 0x56, 0x74, 0x46, 0x53, 0x55, 0x7a, 0x70, + 0x45, 0x30, 0x6e, 0x50, 0x49, 0x78, 0x42, 0x73, 0x46, 0x5a, 0x56, 0x70, + 0x69, 0x6b, 0x70, 0x7a, 0x75, 0x0a, 0x51, 0x59, 0x30, 0x78, 0x32, 0x2b, + 0x63, 0x30, 0x36, 0x6c, 0x6b, 0x68, 0x31, 0x51, 0x46, 0x36, 0x31, 0x32, + 0x53, 0x34, 0x5a, 0x44, 0x6e, 0x4e, 0x79, 0x65, 0x32, 0x76, 0x37, 0x55, + 0x73, 0x44, 0x53, 0x4b, 0x65, 0x67, 0x6d, 0x51, 0x47, 0x41, 0x33, 0x47, + 0x57, 0x6a, 0x4e, 0x71, 0x35, 0x6c, 0x57, 0x55, 0x68, 0x50, 0x67, 0x6b, + 0x76, 0x49, 0x5a, 0x66, 0x46, 0x58, 0x48, 0x65, 0x56, 0x5a, 0x0a, 0x4c, + 0x67, 0x6f, 0x2f, 0x62, 0x4e, 0x6a, 0x52, 0x39, 0x65, 0x55, 0x4a, 0x74, + 0x47, 0x78, 0x55, 0x41, 0x41, 0x72, 0x67, 0x46, 0x55, 0x32, 0x48, 0x64, + 0x57, 0x32, 0x33, 0x57, 0x4a, 0x5a, 0x61, 0x33, 0x57, 0x33, 0x53, 0x41, + 0x4b, 0x44, 0x30, 0x6d, 0x30, 0x69, 0x2b, 0x77, 0x7a, 0x65, 0x6b, 0x75, + 0x6a, 0x62, 0x67, 0x66, 0x49, 0x65, 0x46, 0x6c, 0x78, 0x6f, 0x56, 0x6f, + 0x74, 0x34, 0x75, 0x0a, 0x6f, 0x6c, 0x75, 0x39, 0x72, 0x78, 0x6a, 0x35, + 0x6b, 0x46, 0x44, 0x4e, 0x63, 0x46, 0x6e, 0x34, 0x4a, 0x32, 0x64, 0x48, + 0x79, 0x38, 0x65, 0x67, 0x42, 0x7a, 0x70, 0x39, 0x30, 0x53, 0x78, 0x64, + 0x62, 0x42, 0x6b, 0x36, 0x5a, 0x72, 0x56, 0x39, 0x2f, 0x5a, 0x46, 0x76, + 0x67, 0x72, 0x47, 0x2b, 0x43, 0x4a, 0x50, 0x62, 0x46, 0x45, 0x66, 0x78, + 0x6f, 0x6a, 0x66, 0x48, 0x52, 0x5a, 0x34, 0x38, 0x0a, 0x78, 0x33, 0x65, + 0x76, 0x5a, 0x4b, 0x69, 0x54, 0x33, 0x2f, 0x5a, 0x70, 0x67, 0x34, 0x4a, + 0x67, 0x38, 0x6b, 0x6c, 0x43, 0x4e, 0x4f, 0x31, 0x61, 0x41, 0x46, 0x53, + 0x46, 0x48, 0x42, 0x59, 0x32, 0x6b, 0x67, 0x78, 0x63, 0x2b, 0x71, 0x61, + 0x74, 0x76, 0x39, 0x73, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x66, + 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, + 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x4f, 0x3d, 0x41, 0x66, 0x66, 0x69, + 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x66, + 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, + 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x4f, 0x3d, 0x41, 0x66, 0x66, 0x69, + 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75, + 0x6d, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x37, 0x38, 0x39, 0x33, 0x37, 0x30, 0x36, 0x35, 0x34, 0x30, 0x37, + 0x33, 0x34, 0x33, 0x35, 0x32, 0x31, 0x31, 0x30, 0x0a, 0x23, 0x20, 0x4d, + 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x34, 0x3a, 0x35, 0x64, 0x3a, 0x30, 0x65, + 0x3a, 0x34, 0x38, 0x3a, 0x62, 0x36, 0x3a, 0x61, 0x63, 0x3a, 0x32, 0x38, + 0x3a, 0x33, 0x30, 0x3a, 0x34, 0x65, 0x3a, 0x30, 0x61, 0x3a, 0x62, 0x63, + 0x3a, 0x66, 0x39, 0x3a, 0x33, 0x38, 0x3a, 0x31, 0x36, 0x3a, 0x38, 0x37, + 0x3a, 0x35, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x64, 0x38, 0x3a, 0x61, 0x36, 0x3a, 0x33, 0x33, 0x3a, 0x32, 0x63, 0x3a, + 0x65, 0x30, 0x3a, 0x30, 0x33, 0x3a, 0x36, 0x66, 0x3a, 0x62, 0x31, 0x3a, + 0x38, 0x35, 0x3a, 0x66, 0x36, 0x3a, 0x36, 0x33, 0x3a, 0x34, 0x66, 0x3a, + 0x37, 0x64, 0x3a, 0x36, 0x61, 0x3a, 0x30, 0x36, 0x3a, 0x36, 0x35, 0x3a, + 0x32, 0x36, 0x3a, 0x33, 0x32, 0x3a, 0x32, 0x38, 0x3a, 0x32, 0x37, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x30, + 0x3a, 0x61, 0x37, 0x3a, 0x33, 0x66, 0x3a, 0x37, 0x66, 0x3a, 0x33, 0x37, + 0x3a, 0x36, 0x62, 0x3a, 0x36, 0x30, 0x3a, 0x30, 0x37, 0x3a, 0x34, 0x32, + 0x3a, 0x34, 0x38, 0x3a, 0x39, 0x30, 0x3a, 0x34, 0x35, 0x3a, 0x33, 0x34, + 0x3a, 0x62, 0x31, 0x3a, 0x31, 0x34, 0x3a, 0x38, 0x32, 0x3a, 0x64, 0x35, + 0x3a, 0x62, 0x66, 0x3a, 0x30, 0x65, 0x3a, 0x36, 0x39, 0x3a, 0x38, 0x65, + 0x3a, 0x63, 0x63, 0x3a, 0x34, 0x39, 0x3a, 0x38, 0x64, 0x3a, 0x66, 0x35, + 0x3a, 0x32, 0x35, 0x3a, 0x37, 0x37, 0x3a, 0x65, 0x62, 0x3a, 0x66, 0x32, + 0x3a, 0x65, 0x39, 0x3a, 0x33, 0x62, 0x3a, 0x39, 0x61, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x52, 0x6a, 0x43, 0x43, 0x41, 0x79, + 0x36, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x49, 0x62, 0x59, + 0x77, 0x55, 0x52, 0x72, 0x47, 0x6d, 0x43, 0x75, 0x34, 0x77, 0x44, 0x51, + 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, + 0x45, 0x4d, 0x42, 0x51, 0x41, 0x77, 0x51, 0x54, 0x45, 0x4c, 0x4d, 0x41, + 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x42, 0x68, 0x4d, 0x43, 0x56, + 0x56, 0x4d, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x6f, 0x4d, 0x43, 0x30, 0x46, 0x6d, 0x5a, 0x6d, 0x6c, 0x79, 0x62, + 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4d, 0x52, 0x77, 0x77, 0x47, + 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, 0x4e, 0x42, 0x5a, + 0x6d, 0x5a, 0x70, 0x63, 0x6d, 0x31, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x0a, + 0x64, 0x43, 0x42, 0x51, 0x63, 0x6d, 0x56, 0x74, 0x61, 0x58, 0x56, 0x74, + 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x77, 0x4d, 0x44, 0x45, 0x79, + 0x4f, 0x54, 0x45, 0x30, 0x4d, 0x54, 0x41, 0x7a, 0x4e, 0x6c, 0x6f, 0x58, + 0x44, 0x54, 0x51, 0x77, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x45, 0x30, + 0x4d, 0x54, 0x41, 0x7a, 0x4e, 0x6c, 0x6f, 0x77, 0x51, 0x54, 0x45, 0x4c, + 0x4d, 0x41, 0x6b, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x43, 0x30, 0x46, 0x6d, 0x5a, 0x6d, 0x6c, + 0x79, 0x62, 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4d, 0x52, 0x77, + 0x77, 0x47, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, 0x4e, + 0x42, 0x5a, 0x6d, 0x5a, 0x70, 0x63, 0x6d, 0x31, 0x55, 0x0a, 0x63, 0x6e, + 0x56, 0x7a, 0x64, 0x43, 0x42, 0x51, 0x63, 0x6d, 0x56, 0x74, 0x61, 0x58, + 0x56, 0x74, 0x4d, 0x49, 0x49, 0x43, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x38, 0x41, 0x4d, 0x49, + 0x49, 0x43, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x67, 0x45, 0x41, 0x78, 0x42, + 0x4c, 0x66, 0x0a, 0x71, 0x56, 0x2f, 0x2b, 0x51, 0x64, 0x33, 0x64, 0x39, + 0x5a, 0x2b, 0x4b, 0x34, 0x2f, 0x61, 0x73, 0x34, 0x54, 0x78, 0x34, 0x6d, + 0x72, 0x7a, 0x59, 0x38, 0x48, 0x39, 0x36, 0x6f, 0x44, 0x4d, 0x71, 0x33, + 0x49, 0x30, 0x67, 0x57, 0x36, 0x34, 0x74, 0x62, 0x2b, 0x65, 0x54, 0x32, + 0x54, 0x5a, 0x77, 0x61, 0x6d, 0x6a, 0x50, 0x6a, 0x6c, 0x47, 0x6a, 0x68, + 0x56, 0x74, 0x6e, 0x42, 0x4b, 0x41, 0x51, 0x0a, 0x4a, 0x47, 0x39, 0x64, + 0x4b, 0x49, 0x4c, 0x42, 0x6c, 0x31, 0x66, 0x59, 0x53, 0x43, 0x6b, 0x54, + 0x74, 0x75, 0x47, 0x2b, 0x6b, 0x55, 0x33, 0x66, 0x68, 0x51, 0x78, 0x54, + 0x47, 0x4a, 0x6f, 0x65, 0x4a, 0x4b, 0x4a, 0x50, 0x6a, 0x2f, 0x43, 0x69, + 0x68, 0x51, 0x76, 0x4c, 0x39, 0x43, 0x6c, 0x2f, 0x30, 0x71, 0x52, 0x59, + 0x37, 0x69, 0x5a, 0x4e, 0x79, 0x61, 0x71, 0x6f, 0x65, 0x35, 0x72, 0x5a, + 0x0a, 0x2b, 0x6a, 0x6a, 0x65, 0x52, 0x46, 0x63, 0x56, 0x35, 0x66, 0x69, + 0x4d, 0x79, 0x4e, 0x6c, 0x49, 0x34, 0x67, 0x30, 0x57, 0x4a, 0x78, 0x30, + 0x65, 0x79, 0x49, 0x4f, 0x46, 0x4a, 0x62, 0x65, 0x36, 0x71, 0x6c, 0x56, + 0x42, 0x7a, 0x41, 0x4d, 0x69, 0x53, 0x79, 0x32, 0x52, 0x6a, 0x59, 0x76, + 0x6d, 0x69, 0x61, 0x39, 0x6d, 0x78, 0x2b, 0x6e, 0x2f, 0x4b, 0x2b, 0x6b, + 0x38, 0x72, 0x4e, 0x72, 0x53, 0x0a, 0x73, 0x38, 0x50, 0x68, 0x61, 0x4a, + 0x79, 0x4a, 0x2b, 0x48, 0x6f, 0x41, 0x56, 0x74, 0x37, 0x30, 0x56, 0x5a, + 0x56, 0x73, 0x2b, 0x37, 0x70, 0x6b, 0x33, 0x57, 0x4b, 0x4c, 0x33, 0x77, + 0x74, 0x33, 0x4d, 0x75, 0x74, 0x69, 0x7a, 0x43, 0x61, 0x61, 0x6d, 0x37, + 0x75, 0x71, 0x59, 0x6f, 0x4e, 0x4d, 0x74, 0x41, 0x5a, 0x36, 0x4d, 0x4d, + 0x67, 0x70, 0x76, 0x2b, 0x30, 0x47, 0x54, 0x5a, 0x65, 0x35, 0x0a, 0x48, + 0x4d, 0x51, 0x78, 0x4b, 0x39, 0x56, 0x66, 0x76, 0x46, 0x4d, 0x53, 0x46, + 0x35, 0x79, 0x5a, 0x56, 0x79, 0x6c, 0x6d, 0x64, 0x32, 0x45, 0x68, 0x4d, + 0x51, 0x63, 0x75, 0x4a, 0x55, 0x6d, 0x64, 0x47, 0x50, 0x4c, 0x75, 0x38, + 0x79, 0x74, 0x78, 0x6a, 0x4c, 0x57, 0x36, 0x4f, 0x51, 0x64, 0x4a, 0x64, + 0x2f, 0x7a, 0x76, 0x4c, 0x70, 0x4b, 0x51, 0x42, 0x59, 0x30, 0x74, 0x4c, + 0x33, 0x64, 0x37, 0x0a, 0x37, 0x30, 0x4f, 0x2f, 0x4e, 0x62, 0x75, 0x61, + 0x32, 0x50, 0x6c, 0x7a, 0x70, 0x79, 0x7a, 0x79, 0x30, 0x46, 0x66, 0x75, + 0x4b, 0x45, 0x34, 0x6d, 0x58, 0x34, 0x2b, 0x51, 0x61, 0x41, 0x6b, 0x76, + 0x75, 0x50, 0x6a, 0x63, 0x42, 0x75, 0x6b, 0x75, 0x6d, 0x6a, 0x35, 0x52, + 0x70, 0x39, 0x45, 0x69, 0x78, 0x41, 0x71, 0x6e, 0x4f, 0x45, 0x68, 0x73, + 0x73, 0x2f, 0x6e, 0x2f, 0x66, 0x61, 0x75, 0x47, 0x0a, 0x56, 0x2b, 0x4f, + 0x36, 0x31, 0x6f, 0x56, 0x34, 0x64, 0x37, 0x70, 0x44, 0x36, 0x6b, 0x68, + 0x2f, 0x39, 0x74, 0x69, 0x2b, 0x49, 0x32, 0x30, 0x65, 0x76, 0x39, 0x45, + 0x32, 0x62, 0x46, 0x68, 0x63, 0x38, 0x65, 0x36, 0x6b, 0x47, 0x56, 0x51, + 0x61, 0x39, 0x51, 0x50, 0x53, 0x64, 0x75, 0x62, 0x68, 0x6a, 0x4c, 0x30, + 0x38, 0x73, 0x39, 0x4e, 0x49, 0x53, 0x2b, 0x4c, 0x49, 0x2b, 0x48, 0x2b, + 0x53, 0x0a, 0x71, 0x48, 0x5a, 0x47, 0x6e, 0x45, 0x4a, 0x6c, 0x50, 0x71, + 0x51, 0x65, 0x77, 0x51, 0x63, 0x44, 0x57, 0x6b, 0x59, 0x74, 0x75, 0x4a, + 0x66, 0x7a, 0x74, 0x39, 0x57, 0x79, 0x56, 0x53, 0x48, 0x76, 0x75, 0x74, + 0x78, 0x4d, 0x41, 0x4a, 0x66, 0x37, 0x46, 0x4a, 0x55, 0x6e, 0x4d, 0x37, + 0x2f, 0x6f, 0x51, 0x30, 0x64, 0x47, 0x30, 0x67, 0x69, 0x5a, 0x46, 0x6d, + 0x41, 0x37, 0x6d, 0x6e, 0x37, 0x53, 0x0a, 0x35, 0x75, 0x30, 0x34, 0x36, + 0x75, 0x77, 0x42, 0x48, 0x6a, 0x78, 0x49, 0x56, 0x6b, 0x6b, 0x4a, 0x78, + 0x30, 0x77, 0x33, 0x41, 0x4a, 0x36, 0x49, 0x44, 0x73, 0x42, 0x7a, 0x34, + 0x57, 0x39, 0x6d, 0x36, 0x58, 0x4a, 0x48, 0x4d, 0x44, 0x34, 0x51, 0x35, + 0x51, 0x73, 0x44, 0x79, 0x5a, 0x70, 0x43, 0x41, 0x47, 0x7a, 0x46, 0x6c, + 0x48, 0x35, 0x68, 0x78, 0x49, 0x72, 0x66, 0x66, 0x34, 0x49, 0x61, 0x0a, + 0x43, 0x31, 0x6e, 0x45, 0x57, 0x54, 0x4a, 0x33, 0x73, 0x37, 0x78, 0x67, + 0x61, 0x56, 0x59, 0x35, 0x2f, 0x62, 0x51, 0x47, 0x65, 0x79, 0x7a, 0x57, + 0x5a, 0x44, 0x62, 0x5a, 0x76, 0x55, 0x6a, 0x74, 0x68, 0x42, 0x39, 0x2b, + 0x70, 0x53, 0x4b, 0x50, 0x4b, 0x72, 0x68, 0x43, 0x39, 0x49, 0x4b, 0x33, + 0x31, 0x46, 0x4f, 0x51, 0x65, 0x45, 0x34, 0x74, 0x47, 0x76, 0x32, 0x42, + 0x62, 0x30, 0x54, 0x58, 0x0a, 0x4f, 0x77, 0x46, 0x30, 0x6c, 0x6b, 0x4c, + 0x67, 0x41, 0x4f, 0x49, 0x75, 0x61, 0x2b, 0x72, 0x46, 0x37, 0x6e, 0x4b, + 0x73, 0x75, 0x37, 0x2f, 0x2b, 0x36, 0x71, 0x71, 0x6f, 0x2b, 0x4e, 0x7a, + 0x32, 0x73, 0x6e, 0x6d, 0x4b, 0x74, 0x6d, 0x63, 0x43, 0x41, 0x77, 0x45, + 0x41, 0x41, 0x61, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77, 0x48, 0x51, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x0a, 0x46, 0x4a, + 0x33, 0x41, 0x5a, 0x36, 0x59, 0x4d, 0x49, 0x74, 0x6b, 0x6d, 0x39, 0x55, + 0x57, 0x72, 0x70, 0x6d, 0x56, 0x53, 0x45, 0x53, 0x66, 0x59, 0x52, 0x61, + 0x78, 0x6a, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, + 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, + 0x38, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, + 0x48, 0x2f, 0x0a, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, + 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, + 0x51, 0x45, 0x42, 0x44, 0x41, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x41, + 0x51, 0x43, 0x7a, 0x56, 0x30, 0x30, 0x51, 0x59, 0x6b, 0x34, 0x36, 0x35, + 0x4b, 0x7a, 0x71, 0x75, 0x42, 0x79, 0x76, 0x4d, 0x69, 0x50, 0x49, 0x73, + 0x30, 0x6c, 0x61, 0x55, 0x5a, 0x78, 0x32, 0x0a, 0x4b, 0x49, 0x31, 0x35, + 0x71, 0x6c, 0x64, 0x47, 0x46, 0x39, 0x58, 0x31, 0x55, 0x76, 0x61, 0x33, + 0x52, 0x4f, 0x67, 0x49, 0x52, 0x4c, 0x38, 0x59, 0x68, 0x4e, 0x49, 0x4c, + 0x67, 0x4d, 0x33, 0x46, 0x45, 0x76, 0x30, 0x41, 0x56, 0x51, 0x56, 0x68, + 0x68, 0x30, 0x48, 0x63, 0x74, 0x53, 0x53, 0x65, 0x50, 0x4d, 0x54, 0x59, + 0x79, 0x50, 0x74, 0x77, 0x6e, 0x69, 0x39, 0x34, 0x6c, 0x6f, 0x4d, 0x67, + 0x0a, 0x4e, 0x74, 0x35, 0x38, 0x44, 0x32, 0x6b, 0x54, 0x69, 0x4b, 0x56, + 0x31, 0x4e, 0x70, 0x67, 0x49, 0x70, 0x73, 0x62, 0x66, 0x72, 0x4d, 0x37, + 0x6a, 0x57, 0x4e, 0x61, 0x33, 0x50, 0x74, 0x36, 0x36, 0x38, 0x2b, 0x73, + 0x30, 0x51, 0x4e, 0x69, 0x69, 0x67, 0x66, 0x56, 0x34, 0x50, 0x79, 0x2f, + 0x56, 0x70, 0x66, 0x7a, 0x5a, 0x6f, 0x74, 0x52, 0x65, 0x42, 0x41, 0x34, + 0x58, 0x72, 0x66, 0x35, 0x42, 0x0a, 0x38, 0x4f, 0x57, 0x79, 0x63, 0x76, + 0x70, 0x45, 0x67, 0x6a, 0x4e, 0x43, 0x36, 0x43, 0x31, 0x59, 0x39, 0x31, + 0x61, 0x4d, 0x59, 0x6a, 0x2b, 0x36, 0x51, 0x72, 0x43, 0x63, 0x44, 0x46, + 0x78, 0x2b, 0x4c, 0x6d, 0x55, 0x6d, 0x58, 0x46, 0x4e, 0x50, 0x41, 0x4c, + 0x4a, 0x34, 0x66, 0x71, 0x45, 0x4e, 0x6d, 0x53, 0x32, 0x4e, 0x75, 0x42, + 0x32, 0x4f, 0x6f, 0x73, 0x53, 0x77, 0x2f, 0x57, 0x44, 0x51, 0x0a, 0x4d, + 0x4b, 0x53, 0x4f, 0x79, 0x41, 0x52, 0x69, 0x71, 0x63, 0x54, 0x74, 0x4e, + 0x64, 0x35, 0x36, 0x6c, 0x2b, 0x30, 0x4f, 0x4f, 0x46, 0x36, 0x53, 0x4c, + 0x35, 0x4e, 0x77, 0x70, 0x61, 0x6d, 0x63, 0x62, 0x36, 0x64, 0x39, 0x45, + 0x78, 0x31, 0x2b, 0x78, 0x67, 0x68, 0x49, 0x73, 0x56, 0x35, 0x6e, 0x36, + 0x31, 0x45, 0x49, 0x4a, 0x65, 0x6e, 0x6d, 0x4a, 0x57, 0x74, 0x53, 0x4b, + 0x5a, 0x47, 0x63, 0x0a, 0x30, 0x6a, 0x6c, 0x7a, 0x43, 0x46, 0x66, 0x65, + 0x6d, 0x51, 0x61, 0x30, 0x57, 0x35, 0x30, 0x51, 0x42, 0x75, 0x48, 0x43, + 0x41, 0x4b, 0x69, 0x34, 0x48, 0x45, 0x6f, 0x43, 0x43, 0x68, 0x54, 0x51, + 0x77, 0x55, 0x48, 0x4b, 0x2b, 0x34, 0x77, 0x31, 0x49, 0x58, 0x32, 0x43, + 0x4f, 0x50, 0x4b, 0x70, 0x56, 0x4a, 0x45, 0x5a, 0x4e, 0x5a, 0x4f, 0x55, + 0x62, 0x57, 0x6f, 0x36, 0x78, 0x62, 0x4c, 0x51, 0x0a, 0x75, 0x34, 0x6d, + 0x47, 0x6b, 0x2b, 0x69, 0x62, 0x79, 0x51, 0x38, 0x36, 0x70, 0x33, 0x71, + 0x34, 0x6f, 0x66, 0x42, 0x34, 0x52, 0x76, 0x72, 0x38, 0x4e, 0x79, 0x2f, + 0x6c, 0x69, 0x6f, 0x54, 0x7a, 0x33, 0x2f, 0x34, 0x45, 0x32, 0x61, 0x46, + 0x6f, 0x6f, 0x43, 0x38, 0x6b, 0x34, 0x67, 0x6d, 0x56, 0x42, 0x74, 0x57, + 0x56, 0x79, 0x75, 0x45, 0x6b, 0x6c, 0x75, 0x74, 0x38, 0x39, 0x70, 0x4d, + 0x46, 0x0a, 0x75, 0x2b, 0x31, 0x7a, 0x36, 0x53, 0x33, 0x52, 0x64, 0x54, + 0x6e, 0x58, 0x35, 0x79, 0x54, 0x62, 0x32, 0x45, 0x35, 0x66, 0x51, 0x34, + 0x2b, 0x65, 0x30, 0x42, 0x51, 0x35, 0x76, 0x31, 0x56, 0x77, 0x53, 0x4a, + 0x6c, 0x58, 0x4d, 0x62, 0x53, 0x63, 0x37, 0x6b, 0x71, 0x59, 0x41, 0x35, + 0x59, 0x77, 0x48, 0x32, 0x41, 0x47, 0x37, 0x68, 0x73, 0x6a, 0x2f, 0x6f, + 0x46, 0x67, 0x49, 0x78, 0x70, 0x48, 0x0a, 0x59, 0x6f, 0x57, 0x6c, 0x7a, + 0x42, 0x6b, 0x30, 0x67, 0x47, 0x2b, 0x7a, 0x72, 0x42, 0x72, 0x6a, 0x6e, + 0x2f, 0x42, 0x37, 0x53, 0x4b, 0x33, 0x56, 0x41, 0x64, 0x6c, 0x6e, 0x74, + 0x71, 0x6c, 0x79, 0x6b, 0x2b, 0x6f, 0x74, 0x5a, 0x72, 0x57, 0x79, 0x75, + 0x4f, 0x51, 0x39, 0x50, 0x4c, 0x4c, 0x76, 0x54, 0x49, 0x7a, 0x71, 0x36, + 0x77, 0x65, 0x2f, 0x71, 0x7a, 0x57, 0x61, 0x56, 0x59, 0x61, 0x38, 0x0a, + 0x47, 0x4b, 0x61, 0x31, 0x71, 0x46, 0x36, 0x30, 0x67, 0x32, 0x78, 0x72, + 0x61, 0x55, 0x44, 0x54, 0x6e, 0x39, 0x7a, 0x78, 0x77, 0x32, 0x6c, 0x72, + 0x75, 0x65, 0x46, 0x74, 0x43, 0x66, 0x54, 0x78, 0x71, 0x6c, 0x42, 0x32, + 0x43, 0x6e, 0x70, 0x39, 0x65, 0x68, 0x65, 0x68, 0x56, 0x5a, 0x5a, 0x43, + 0x6d, 0x54, 0x45, 0x4a, 0x33, 0x57, 0x41, 0x52, 0x6a, 0x51, 0x55, 0x77, + 0x66, 0x75, 0x61, 0x4f, 0x0a, 0x52, 0x74, 0x47, 0x64, 0x46, 0x4e, 0x72, + 0x48, 0x46, 0x2b, 0x51, 0x46, 0x6c, 0x6f, 0x7a, 0x45, 0x4a, 0x4c, 0x55, + 0x62, 0x7a, 0x78, 0x51, 0x48, 0x73, 0x6b, 0x44, 0x34, 0x6f, 0x35, 0x35, + 0x42, 0x68, 0x72, 0x77, 0x45, 0x30, 0x47, 0x75, 0x57, 0x79, 0x43, 0x71, + 0x41, 0x4e, 0x50, 0x32, 0x2f, 0x37, 0x77, 0x61, 0x6a, 0x33, 0x56, 0x6a, + 0x46, 0x68, 0x54, 0x30, 0x2b, 0x6a, 0x2f, 0x36, 0x65, 0x0a, 0x4b, 0x65, + 0x43, 0x32, 0x75, 0x41, 0x6c, 0x6f, 0x47, 0x52, 0x77, 0x59, 0x51, 0x77, + 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x66, 0x66, 0x69, 0x72, + 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, + 0x75, 0x6d, 0x20, 0x45, 0x43, 0x43, 0x20, 0x4f, 0x3d, 0x41, 0x66, 0x66, + 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x53, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, + 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, + 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x45, 0x43, 0x43, 0x20, 0x4f, + 0x3d, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, + 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, + 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x45, 0x43, 0x43, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x38, 0x34, + 0x30, 0x31, 0x32, 0x32, 0x34, 0x39, 0x30, 0x37, 0x38, 0x36, 0x31, 0x34, + 0x39, 0x30, 0x32, 0x36, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x36, 0x34, 0x3a, 0x62, 0x30, 0x3a, 0x30, 0x39, 0x3a, 0x35, 0x35, + 0x3a, 0x63, 0x66, 0x3a, 0x62, 0x31, 0x3a, 0x64, 0x35, 0x3a, 0x39, 0x39, + 0x3a, 0x65, 0x32, 0x3a, 0x62, 0x65, 0x3a, 0x31, 0x33, 0x3a, 0x61, 0x62, + 0x3a, 0x61, 0x36, 0x3a, 0x35, 0x64, 0x3a, 0x65, 0x61, 0x3a, 0x34, 0x64, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x38, 0x3a, + 0x32, 0x33, 0x3a, 0x36, 0x62, 0x3a, 0x30, 0x30, 0x3a, 0x32, 0x66, 0x3a, + 0x31, 0x64, 0x3a, 0x31, 0x36, 0x3a, 0x38, 0x36, 0x3a, 0x35, 0x33, 0x3a, + 0x30, 0x31, 0x3a, 0x35, 0x35, 0x3a, 0x36, 0x63, 0x3a, 0x31, 0x31, 0x3a, + 0x61, 0x34, 0x3a, 0x33, 0x37, 0x3a, 0x63, 0x61, 0x3a, 0x65, 0x62, 0x3a, + 0x66, 0x66, 0x3a, 0x63, 0x33, 0x3a, 0x62, 0x62, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x64, 0x3a, 0x37, 0x31, + 0x3a, 0x66, 0x64, 0x3a, 0x66, 0x36, 0x3a, 0x64, 0x61, 0x3a, 0x39, 0x37, + 0x3a, 0x65, 0x34, 0x3a, 0x63, 0x66, 0x3a, 0x36, 0x32, 0x3a, 0x64, 0x31, + 0x3a, 0x36, 0x34, 0x3a, 0x37, 0x61, 0x3a, 0x64, 0x64, 0x3a, 0x32, 0x35, + 0x3a, 0x38, 0x31, 0x3a, 0x62, 0x30, 0x3a, 0x37, 0x64, 0x3a, 0x37, 0x39, + 0x3a, 0x61, 0x64, 0x3a, 0x66, 0x38, 0x3a, 0x33, 0x39, 0x3a, 0x37, 0x65, + 0x3a, 0x62, 0x34, 0x3a, 0x65, 0x63, 0x3a, 0x62, 0x61, 0x3a, 0x39, 0x63, + 0x3a, 0x35, 0x65, 0x3a, 0x38, 0x34, 0x3a, 0x38, 0x38, 0x3a, 0x38, 0x32, + 0x3a, 0x31, 0x34, 0x3a, 0x32, 0x33, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x42, 0x2f, 0x6a, 0x43, 0x43, 0x41, 0x59, 0x57, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x49, 0x64, 0x4a, 0x63, 0x6c, 0x69, + 0x73, 0x63, 0x2f, 0x65, 0x6c, 0x51, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, + 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x4d, 0x77, 0x52, + 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x68, 0x4d, 0x43, 0x0a, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x44, 0x41, 0x53, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x43, 0x30, 0x46, 0x6d, + 0x5a, 0x6d, 0x6c, 0x79, 0x62, 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, + 0x4d, 0x53, 0x41, 0x77, 0x48, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, + 0x44, 0x42, 0x64, 0x42, 0x5a, 0x6d, 0x5a, 0x70, 0x63, 0x6d, 0x31, 0x55, + 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x51, 0x0a, 0x63, 0x6d, 0x56, + 0x74, 0x61, 0x58, 0x56, 0x74, 0x49, 0x45, 0x56, 0x44, 0x51, 0x7a, 0x41, + 0x65, 0x46, 0x77, 0x30, 0x78, 0x4d, 0x44, 0x41, 0x78, 0x4d, 0x6a, 0x6b, + 0x78, 0x4e, 0x44, 0x49, 0x77, 0x4d, 0x6a, 0x52, 0x61, 0x46, 0x77, 0x30, + 0x30, 0x4d, 0x44, 0x45, 0x79, 0x4d, 0x7a, 0x45, 0x78, 0x4e, 0x44, 0x49, + 0x77, 0x4d, 0x6a, 0x52, 0x61, 0x4d, 0x45, 0x55, 0x78, 0x43, 0x7a, 0x41, + 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, + 0x56, 0x54, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4b, 0x44, 0x41, 0x74, 0x42, 0x5a, 0x6d, 0x5a, 0x70, 0x63, 0x6d, + 0x31, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x44, 0x45, 0x67, 0x4d, 0x42, + 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x58, 0x51, 0x57, + 0x5a, 0x6d, 0x61, 0x58, 0x4a, 0x74, 0x0a, 0x56, 0x48, 0x4a, 0x31, 0x63, + 0x33, 0x51, 0x67, 0x55, 0x48, 0x4a, 0x6c, 0x62, 0x57, 0x6c, 0x31, 0x62, + 0x53, 0x42, 0x46, 0x51, 0x30, 0x4d, 0x77, 0x64, 0x6a, 0x41, 0x51, 0x42, + 0x67, 0x63, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x49, 0x42, 0x42, + 0x67, 0x55, 0x72, 0x67, 0x51, 0x51, 0x41, 0x49, 0x67, 0x4e, 0x69, 0x41, + 0x41, 0x51, 0x4e, 0x4d, 0x46, 0x34, 0x62, 0x46, 0x5a, 0x30, 0x44, 0x0a, + 0x30, 0x4b, 0x46, 0x35, 0x4e, 0x62, 0x63, 0x36, 0x50, 0x4a, 0x4a, 0x36, + 0x79, 0x68, 0x55, 0x63, 0x7a, 0x57, 0x4c, 0x7a, 0x6e, 0x43, 0x5a, 0x63, + 0x42, 0x7a, 0x33, 0x6c, 0x56, 0x50, 0x71, 0x6a, 0x31, 0x73, 0x77, 0x53, + 0x36, 0x76, 0x51, 0x55, 0x58, 0x2b, 0x69, 0x4f, 0x47, 0x61, 0x73, 0x76, + 0x4c, 0x6b, 0x6a, 0x6d, 0x72, 0x42, 0x68, 0x44, 0x65, 0x4b, 0x7a, 0x51, + 0x4e, 0x38, 0x4f, 0x39, 0x0a, 0x73, 0x73, 0x30, 0x73, 0x35, 0x6b, 0x66, + 0x69, 0x47, 0x75, 0x5a, 0x6a, 0x75, 0x44, 0x30, 0x75, 0x4c, 0x33, 0x6a, + 0x45, 0x54, 0x39, 0x76, 0x30, 0x44, 0x36, 0x52, 0x6f, 0x54, 0x46, 0x56, + 0x79, 0x61, 0x35, 0x55, 0x64, 0x54, 0x68, 0x68, 0x43, 0x6c, 0x58, 0x6a, + 0x4d, 0x4e, 0x7a, 0x79, 0x52, 0x34, 0x70, 0x74, 0x6c, 0x4b, 0x79, 0x6d, + 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x42, 0x30, 0x47, 0x0a, 0x41, 0x31, + 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x53, 0x61, 0x72, 0x79, + 0x6c, 0x36, 0x77, 0x42, 0x45, 0x31, 0x4e, 0x53, 0x5a, 0x52, 0x4d, 0x41, + 0x44, 0x44, 0x61, 0x76, 0x35, 0x41, 0x31, 0x61, 0x37, 0x57, 0x50, 0x44, + 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, + 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, + 0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, + 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x4b, 0x42, + 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, + 0x77, 0x4e, 0x6e, 0x41, 0x44, 0x42, 0x6b, 0x41, 0x6a, 0x41, 0x58, 0x43, + 0x66, 0x4f, 0x48, 0x69, 0x46, 0x42, 0x61, 0x72, 0x38, 0x6a, 0x41, 0x51, + 0x72, 0x39, 0x48, 0x58, 0x2f, 0x56, 0x73, 0x0a, 0x61, 0x6f, 0x62, 0x67, + 0x78, 0x43, 0x64, 0x30, 0x35, 0x44, 0x68, 0x54, 0x31, 0x77, 0x56, 0x2f, + 0x47, 0x7a, 0x54, 0x6a, 0x78, 0x69, 0x2b, 0x7a, 0x79, 0x67, 0x6b, 0x38, + 0x4e, 0x35, 0x33, 0x58, 0x35, 0x37, 0x68, 0x47, 0x38, 0x66, 0x32, 0x68, + 0x34, 0x6e, 0x45, 0x43, 0x4d, 0x45, 0x4a, 0x5a, 0x68, 0x30, 0x50, 0x55, + 0x55, 0x64, 0x2b, 0x36, 0x30, 0x77, 0x6b, 0x79, 0x57, 0x73, 0x36, 0x49, + 0x0a, 0x66, 0x6c, 0x63, 0x39, 0x6e, 0x46, 0x39, 0x43, 0x61, 0x2f, 0x55, + 0x48, 0x4c, 0x62, 0x58, 0x77, 0x67, 0x70, 0x50, 0x35, 0x57, 0x57, 0x2b, + 0x75, 0x5a, 0x50, 0x70, 0x59, 0x35, 0x59, 0x73, 0x65, 0x34, 0x32, 0x4f, + 0x2b, 0x74, 0x59, 0x48, 0x4e, 0x62, 0x77, 0x4b, 0x4d, 0x65, 0x51, 0x3d, + 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x55, 0x6e, + 0x69, 0x7a, 0x65, 0x74, 0x6f, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, + 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x20, + 0x4f, 0x55, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x65, 0x64, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x43, + 0x41, 0x20, 0x4f, 0x3d, 0x55, 0x6e, 0x69, 0x7a, 0x65, 0x74, 0x6f, 0x20, + 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, + 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x65, 0x72, + 0x74, 0x75, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x65, 0x64, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x32, 0x37, 0x39, 0x37, 0x34, 0x34, 0x0a, 0x23, 0x20, + 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x35, 0x3a, 0x65, 0x39, 0x3a, 0x38, + 0x31, 0x3a, 0x34, 0x30, 0x3a, 0x63, 0x35, 0x3a, 0x31, 0x38, 0x3a, 0x36, + 0x39, 0x3a, 0x66, 0x63, 0x3a, 0x34, 0x36, 0x3a, 0x32, 0x63, 0x3a, 0x38, + 0x39, 0x3a, 0x37, 0x35, 0x3a, 0x36, 0x32, 0x3a, 0x30, 0x66, 0x3a, 0x61, + 0x61, 0x3a, 0x37, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x30, 0x37, 0x3a, 0x65, 0x30, 0x3a, 0x33, 0x32, 0x3a, 0x65, 0x30, + 0x3a, 0x32, 0x30, 0x3a, 0x62, 0x37, 0x3a, 0x32, 0x63, 0x3a, 0x33, 0x66, + 0x3a, 0x31, 0x39, 0x3a, 0x32, 0x66, 0x3a, 0x30, 0x36, 0x3a, 0x32, 0x38, + 0x3a, 0x61, 0x32, 0x3a, 0x35, 0x39, 0x3a, 0x33, 0x61, 0x3a, 0x31, 0x39, + 0x3a, 0x61, 0x37, 0x3a, 0x30, 0x66, 0x3a, 0x30, 0x36, 0x3a, 0x39, 0x65, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, + 0x63, 0x3a, 0x35, 0x38, 0x3a, 0x34, 0x36, 0x3a, 0x38, 0x64, 0x3a, 0x35, + 0x35, 0x3a, 0x66, 0x35, 0x3a, 0x38, 0x65, 0x3a, 0x34, 0x39, 0x3a, 0x37, + 0x65, 0x3a, 0x37, 0x34, 0x3a, 0x33, 0x39, 0x3a, 0x38, 0x32, 0x3a, 0x64, + 0x32, 0x3a, 0x62, 0x35, 0x3a, 0x30, 0x30, 0x3a, 0x31, 0x30, 0x3a, 0x62, + 0x36, 0x3a, 0x64, 0x31, 0x3a, 0x36, 0x35, 0x3a, 0x33, 0x37, 0x3a, 0x34, + 0x61, 0x3a, 0x63, 0x66, 0x3a, 0x38, 0x33, 0x3a, 0x61, 0x37, 0x3a, 0x64, + 0x34, 0x3a, 0x61, 0x33, 0x3a, 0x32, 0x64, 0x3a, 0x62, 0x37, 0x3a, 0x36, + 0x38, 0x3a, 0x63, 0x34, 0x3a, 0x34, 0x30, 0x3a, 0x38, 0x65, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x75, 0x7a, 0x43, 0x43, 0x41, + 0x71, 0x4f, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x44, 0x42, + 0x45, 0x54, 0x41, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, + 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x4d, + 0x48, 0x34, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x59, 0x54, 0x41, 0x6c, 0x42, 0x4d, 0x0a, 0x4d, 0x53, 0x49, 0x77, + 0x49, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x6c, 0x56, + 0x62, 0x6d, 0x6c, 0x36, 0x5a, 0x58, 0x52, 0x76, 0x49, 0x46, 0x52, 0x6c, + 0x59, 0x32, 0x68, 0x75, 0x62, 0x32, 0x78, 0x76, 0x5a, 0x32, 0x6c, 0x6c, + 0x63, 0x79, 0x42, 0x54, 0x4c, 0x6b, 0x45, 0x75, 0x4d, 0x53, 0x63, 0x77, + 0x4a, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x35, 0x44, + 0x0a, 0x5a, 0x58, 0x4a, 0x30, 0x64, 0x57, 0x30, 0x67, 0x51, 0x32, 0x56, + 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, + 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, + 0x70, 0x64, 0x48, 0x6b, 0x78, 0x49, 0x6a, 0x41, 0x67, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x4d, 0x54, 0x47, 0x55, 0x4e, 0x6c, 0x63, 0x6e, 0x52, + 0x31, 0x62, 0x53, 0x42, 0x55, 0x0a, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, + 0x56, 0x6b, 0x49, 0x45, 0x35, 0x6c, 0x64, 0x48, 0x64, 0x76, 0x63, 0x6d, + 0x73, 0x67, 0x51, 0x30, 0x45, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, + 0x67, 0x78, 0x4d, 0x44, 0x49, 0x79, 0x4d, 0x54, 0x49, 0x77, 0x4e, 0x7a, + 0x4d, 0x33, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x6b, 0x78, 0x4d, 0x6a, + 0x4d, 0x78, 0x4d, 0x54, 0x49, 0x77, 0x4e, 0x7a, 0x4d, 0x33, 0x0a, 0x57, + 0x6a, 0x42, 0x2b, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x51, 0x54, 0x44, 0x45, 0x69, 0x4d, + 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x5a, 0x56, + 0x57, 0x35, 0x70, 0x65, 0x6d, 0x56, 0x30, 0x62, 0x79, 0x42, 0x55, 0x5a, + 0x57, 0x4e, 0x6f, 0x62, 0x6d, 0x39, 0x73, 0x62, 0x32, 0x64, 0x70, 0x5a, + 0x58, 0x4d, 0x67, 0x0a, 0x55, 0x79, 0x35, 0x42, 0x4c, 0x6a, 0x45, 0x6e, + 0x4d, 0x43, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x65, + 0x51, 0x32, 0x56, 0x79, 0x64, 0x48, 0x56, 0x74, 0x49, 0x45, 0x4e, 0x6c, + 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, + 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, + 0x61, 0x58, 0x52, 0x35, 0x4d, 0x53, 0x49, 0x77, 0x0a, 0x49, 0x41, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x6c, 0x44, 0x5a, 0x58, 0x4a, + 0x30, 0x64, 0x57, 0x30, 0x67, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, + 0x6c, 0x5a, 0x43, 0x42, 0x4f, 0x5a, 0x58, 0x52, 0x33, 0x62, 0x33, 0x4a, + 0x72, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, + 0x42, 0x0a, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, + 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, + 0x45, 0x41, 0x34, 0x2f, 0x74, 0x39, 0x6f, 0x33, 0x4b, 0x36, 0x77, 0x76, + 0x44, 0x4a, 0x46, 0x49, 0x66, 0x31, 0x61, 0x77, 0x46, 0x4f, 0x34, 0x57, + 0x35, 0x41, 0x42, 0x37, 0x70, 0x74, 0x4a, 0x31, 0x31, 0x2f, 0x39, 0x31, + 0x73, 0x74, 0x73, 0x31, 0x72, 0x48, 0x0a, 0x55, 0x56, 0x2b, 0x72, 0x70, + 0x44, 0x4b, 0x6d, 0x59, 0x59, 0x65, 0x32, 0x62, 0x67, 0x2b, 0x47, 0x30, + 0x6a, 0x41, 0x43, 0x6c, 0x2f, 0x6a, 0x58, 0x61, 0x56, 0x65, 0x68, 0x47, + 0x44, 0x6c, 0x64, 0x61, 0x6d, 0x52, 0x35, 0x78, 0x67, 0x46, 0x5a, 0x72, + 0x44, 0x77, 0x78, 0x53, 0x6a, 0x68, 0x38, 0x30, 0x67, 0x54, 0x53, 0x53, + 0x79, 0x6a, 0x6f, 0x49, 0x46, 0x38, 0x37, 0x42, 0x36, 0x4c, 0x4d, 0x0a, + 0x54, 0x58, 0x50, 0x62, 0x38, 0x36, 0x35, 0x50, 0x78, 0x31, 0x62, 0x56, + 0x57, 0x71, 0x65, 0x57, 0x69, 0x66, 0x72, 0x7a, 0x71, 0x32, 0x6a, 0x55, + 0x49, 0x34, 0x5a, 0x5a, 0x4a, 0x38, 0x38, 0x4a, 0x4a, 0x37, 0x79, 0x73, + 0x62, 0x6e, 0x4b, 0x44, 0x48, 0x44, 0x42, 0x79, 0x33, 0x2b, 0x43, 0x69, + 0x36, 0x64, 0x4c, 0x68, 0x64, 0x48, 0x55, 0x5a, 0x76, 0x53, 0x71, 0x65, + 0x65, 0x78, 0x56, 0x55, 0x0a, 0x42, 0x42, 0x76, 0x58, 0x51, 0x7a, 0x6d, + 0x74, 0x56, 0x53, 0x6a, 0x46, 0x34, 0x68, 0x71, 0x37, 0x39, 0x4d, 0x44, + 0x6b, 0x72, 0x6a, 0x68, 0x4a, 0x4d, 0x38, 0x78, 0x32, 0x68, 0x5a, 0x38, + 0x35, 0x52, 0x64, 0x4b, 0x6b, 0x6e, 0x76, 0x49, 0x53, 0x6a, 0x46, 0x48, + 0x34, 0x66, 0x4f, 0x51, 0x74, 0x66, 0x2f, 0x57, 0x73, 0x58, 0x2b, 0x73, + 0x57, 0x6e, 0x37, 0x45, 0x74, 0x30, 0x62, 0x72, 0x4d, 0x0a, 0x6b, 0x55, + 0x4a, 0x33, 0x54, 0x43, 0x58, 0x4a, 0x6b, 0x44, 0x68, 0x76, 0x32, 0x2f, + 0x44, 0x4d, 0x2b, 0x34, 0x34, 0x65, 0x6c, 0x31, 0x6b, 0x2b, 0x31, 0x57, + 0x42, 0x4f, 0x35, 0x67, 0x55, 0x6f, 0x37, 0x55, 0x6c, 0x35, 0x45, 0x30, + 0x75, 0x36, 0x53, 0x4e, 0x73, 0x76, 0x2b, 0x58, 0x4c, 0x54, 0x4f, 0x63, + 0x72, 0x2b, 0x48, 0x39, 0x67, 0x30, 0x63, 0x76, 0x57, 0x30, 0x51, 0x4d, + 0x38, 0x78, 0x0a, 0x41, 0x63, 0x50, 0x73, 0x33, 0x68, 0x45, 0x74, 0x46, + 0x31, 0x30, 0x66, 0x75, 0x46, 0x44, 0x52, 0x58, 0x68, 0x6d, 0x6e, 0x61, + 0x64, 0x34, 0x48, 0x4d, 0x79, 0x6a, 0x4b, 0x55, 0x4a, 0x58, 0x35, 0x70, + 0x31, 0x54, 0x4c, 0x56, 0x49, 0x5a, 0x51, 0x52, 0x61, 0x6e, 0x35, 0x53, + 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, + 0x44, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x52, 0x4d, 0x42, + 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, + 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, + 0x42, 0x42, 0x51, 0x49, 0x64, 0x73, 0x33, 0x4c, 0x42, 0x2f, 0x38, 0x6b, + 0x39, 0x73, 0x58, 0x4e, 0x37, 0x62, 0x75, 0x51, 0x76, 0x4f, 0x4b, 0x45, + 0x4e, 0x30, 0x5a, 0x31, 0x39, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, + 0x0a, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, + 0x43, 0x41, 0x51, 0x59, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, + 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4b, 0x61, 0x6f, 0x72, 0x53, 0x4c, + 0x4f, 0x41, 0x54, 0x32, 0x6d, 0x6f, 0x2f, 0x39, 0x69, 0x30, 0x45, 0x69, + 0x64, 0x69, 0x31, 0x35, 0x79, 0x0a, 0x73, 0x48, 0x68, 0x45, 0x34, 0x39, + 0x77, 0x63, 0x72, 0x77, 0x6e, 0x39, 0x49, 0x30, 0x6a, 0x36, 0x76, 0x53, + 0x72, 0x45, 0x75, 0x56, 0x55, 0x45, 0x74, 0x52, 0x43, 0x6a, 0x6a, 0x53, + 0x66, 0x65, 0x43, 0x34, 0x4a, 0x6a, 0x30, 0x4f, 0x37, 0x65, 0x44, 0x44, + 0x64, 0x35, 0x51, 0x56, 0x73, 0x69, 0x73, 0x72, 0x43, 0x61, 0x51, 0x56, + 0x79, 0x6d, 0x63, 0x4f, 0x44, 0x55, 0x30, 0x48, 0x66, 0x4c, 0x0a, 0x49, + 0x39, 0x4d, 0x41, 0x34, 0x47, 0x78, 0x57, 0x4c, 0x2b, 0x46, 0x70, 0x44, + 0x51, 0x33, 0x5a, 0x71, 0x72, 0x38, 0x68, 0x67, 0x56, 0x44, 0x5a, 0x42, + 0x71, 0x57, 0x6f, 0x2f, 0x35, 0x55, 0x33, 0x30, 0x4b, 0x72, 0x2b, 0x34, + 0x72, 0x50, 0x31, 0x6d, 0x53, 0x31, 0x46, 0x68, 0x49, 0x72, 0x6c, 0x51, + 0x67, 0x6e, 0x58, 0x64, 0x41, 0x49, 0x76, 0x39, 0x34, 0x6e, 0x59, 0x6d, + 0x65, 0x6d, 0x38, 0x0a, 0x4a, 0x39, 0x52, 0x48, 0x6a, 0x62, 0x6f, 0x4e, + 0x52, 0x68, 0x78, 0x33, 0x7a, 0x78, 0x53, 0x6b, 0x48, 0x4c, 0x6d, 0x6b, + 0x4d, 0x63, 0x53, 0x63, 0x4b, 0x48, 0x51, 0x44, 0x4e, 0x50, 0x38, 0x7a, + 0x47, 0x53, 0x61, 0x6c, 0x36, 0x51, 0x31, 0x30, 0x74, 0x7a, 0x36, 0x58, + 0x78, 0x6e, 0x62, 0x6f, 0x4a, 0x35, 0x61, 0x6a, 0x5a, 0x74, 0x33, 0x68, + 0x72, 0x76, 0x4a, 0x42, 0x57, 0x38, 0x71, 0x59, 0x0a, 0x56, 0x6f, 0x4e, + 0x7a, 0x63, 0x4f, 0x53, 0x47, 0x47, 0x74, 0x49, 0x78, 0x51, 0x62, 0x6f, + 0x76, 0x76, 0x69, 0x30, 0x54, 0x57, 0x6e, 0x5a, 0x76, 0x54, 0x75, 0x68, + 0x4f, 0x67, 0x51, 0x34, 0x2f, 0x57, 0x77, 0x4d, 0x69, 0x6f, 0x42, 0x4b, + 0x2b, 0x5a, 0x6c, 0x67, 0x52, 0x53, 0x73, 0x73, 0x44, 0x78, 0x4c, 0x51, + 0x71, 0x4b, 0x69, 0x32, 0x57, 0x46, 0x2b, 0x41, 0x35, 0x56, 0x4c, 0x78, + 0x49, 0x0a, 0x30, 0x33, 0x59, 0x6e, 0x6e, 0x5a, 0x6f, 0x74, 0x42, 0x71, + 0x62, 0x4a, 0x37, 0x44, 0x6e, 0x53, 0x71, 0x39, 0x75, 0x66, 0x6d, 0x67, + 0x73, 0x6e, 0x41, 0x6a, 0x55, 0x70, 0x73, 0x55, 0x43, 0x56, 0x35, 0x2f, + 0x6e, 0x6f, 0x6e, 0x46, 0x57, 0x49, 0x47, 0x55, 0x62, 0x57, 0x74, 0x7a, + 0x54, 0x31, 0x66, 0x73, 0x34, 0x35, 0x6d, 0x74, 0x6b, 0x34, 0x38, 0x56, + 0x48, 0x33, 0x54, 0x79, 0x77, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, + 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x54, + 0x57, 0x43, 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x54, + 0x41, 0x49, 0x57, 0x41, 0x4e, 0x2d, 0x43, 0x41, 0x20, 0x4f, 0x55, 0x3d, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x0a, 0x23, 0x20, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x54, 0x57, + 0x43, 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x54, 0x41, + 0x49, 0x57, 0x41, 0x4e, 0x2d, 0x43, 0x41, 0x20, 0x4f, 0x55, 0x3d, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x54, 0x57, 0x43, 0x41, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x3a, 0x20, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, + 0x61, 0x3a, 0x30, 0x38, 0x3a, 0x38, 0x66, 0x3a, 0x66, 0x36, 0x3a, 0x66, + 0x39, 0x3a, 0x37, 0x62, 0x3a, 0x62, 0x37, 0x3a, 0x66, 0x32, 0x3a, 0x62, + 0x31, 0x3a, 0x61, 0x37, 0x3a, 0x31, 0x65, 0x3a, 0x39, 0x62, 0x3a, 0x65, + 0x61, 0x3a, 0x65, 0x61, 0x3a, 0x62, 0x64, 0x3a, 0x37, 0x39, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x66, 0x3a, 0x39, 0x65, + 0x3a, 0x38, 0x37, 0x3a, 0x36, 0x64, 0x3a, 0x64, 0x33, 0x3a, 0x65, 0x62, + 0x3a, 0x66, 0x63, 0x3a, 0x34, 0x32, 0x3a, 0x32, 0x36, 0x3a, 0x39, 0x37, + 0x3a, 0x61, 0x33, 0x3a, 0x62, 0x35, 0x3a, 0x61, 0x33, 0x3a, 0x37, 0x61, + 0x3a, 0x61, 0x30, 0x3a, 0x37, 0x36, 0x3a, 0x61, 0x39, 0x3a, 0x30, 0x36, + 0x3a, 0x32, 0x33, 0x3a, 0x34, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x66, 0x3a, 0x64, 0x38, 0x3a, 0x38, + 0x66, 0x3a, 0x65, 0x31, 0x3a, 0x31, 0x30, 0x3a, 0x31, 0x63, 0x3a, 0x34, + 0x31, 0x3a, 0x61, 0x65, 0x3a, 0x33, 0x65, 0x3a, 0x38, 0x30, 0x3a, 0x31, + 0x62, 0x3a, 0x66, 0x38, 0x3a, 0x62, 0x65, 0x3a, 0x35, 0x36, 0x3a, 0x33, + 0x35, 0x3a, 0x30, 0x65, 0x3a, 0x65, 0x39, 0x3a, 0x62, 0x61, 0x3a, 0x64, + 0x31, 0x3a, 0x61, 0x36, 0x3a, 0x62, 0x39, 0x3a, 0x62, 0x64, 0x3a, 0x35, + 0x31, 0x3a, 0x35, 0x65, 0x3a, 0x64, 0x63, 0x3a, 0x35, 0x63, 0x3a, 0x36, + 0x64, 0x3a, 0x35, 0x62, 0x3a, 0x38, 0x37, 0x3a, 0x31, 0x31, 0x3a, 0x61, + 0x63, 0x3a, 0x34, 0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x44, 0x65, 0x7a, 0x43, 0x43, 0x41, 0x6d, 0x4f, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, + 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, + 0x46, 0x41, 0x44, 0x42, 0x66, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x55, 0x56, 0x7a, 0x45, + 0x53, 0x0a, 0x4d, 0x42, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, + 0x77, 0x4a, 0x56, 0x45, 0x46, 0x4a, 0x56, 0x30, 0x46, 0x4f, 0x4c, 0x55, + 0x4e, 0x42, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4c, 0x44, 0x41, 0x64, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, + 0x4e, 0x42, 0x4d, 0x53, 0x6f, 0x77, 0x4b, 0x41, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x44, 0x44, 0x43, 0x46, 0x55, 0x0a, 0x56, 0x30, 0x4e, 0x42, 0x49, + 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, + 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, + 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, + 0x48, 0x6b, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x67, 0x77, 0x4f, + 0x44, 0x49, 0x34, 0x4d, 0x44, 0x63, 0x79, 0x4e, 0x44, 0x4d, 0x7a, 0x0a, + 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x41, 0x78, 0x4d, 0x6a, 0x4d, 0x78, + 0x4d, 0x54, 0x55, 0x31, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, 0x42, 0x66, + 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, + 0x45, 0x77, 0x4a, 0x55, 0x56, 0x7a, 0x45, 0x53, 0x4d, 0x42, 0x41, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x4a, 0x56, 0x45, 0x46, 0x4a, + 0x56, 0x30, 0x46, 0x4f, 0x0a, 0x4c, 0x55, 0x4e, 0x42, 0x4d, 0x52, 0x41, + 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x44, 0x41, 0x64, + 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x53, 0x6f, + 0x77, 0x4b, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x43, 0x46, + 0x55, 0x56, 0x30, 0x4e, 0x42, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, + 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x0a, 0x61, 0x57, + 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, + 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, 0x67, 0x67, + 0x45, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, + 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, + 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, + 0x49, 0x42, 0x0a, 0x41, 0x51, 0x43, 0x77, 0x66, 0x6e, 0x4b, 0x34, 0x70, + 0x41, 0x4f, 0x55, 0x35, 0x71, 0x66, 0x65, 0x43, 0x54, 0x69, 0x52, 0x53, + 0x68, 0x46, 0x41, 0x68, 0x36, 0x64, 0x38, 0x57, 0x57, 0x51, 0x55, 0x65, + 0x37, 0x55, 0x52, 0x45, 0x4e, 0x33, 0x2b, 0x76, 0x39, 0x58, 0x41, 0x75, + 0x31, 0x62, 0x69, 0x68, 0x53, 0x58, 0x30, 0x4e, 0x58, 0x49, 0x50, 0x2b, + 0x46, 0x50, 0x51, 0x51, 0x65, 0x46, 0x45, 0x0a, 0x41, 0x63, 0x4b, 0x30, + 0x48, 0x4d, 0x4d, 0x78, 0x51, 0x68, 0x5a, 0x48, 0x68, 0x54, 0x4d, 0x69, + 0x64, 0x72, 0x49, 0x4b, 0x62, 0x77, 0x2f, 0x6c, 0x4a, 0x56, 0x42, 0x50, + 0x68, 0x59, 0x61, 0x2b, 0x76, 0x35, 0x67, 0x75, 0x45, 0x47, 0x63, 0x65, + 0x76, 0x68, 0x45, 0x46, 0x68, 0x67, 0x57, 0x51, 0x78, 0x46, 0x6e, 0x51, + 0x66, 0x48, 0x67, 0x51, 0x73, 0x49, 0x42, 0x63, 0x74, 0x2b, 0x48, 0x48, + 0x0a, 0x4b, 0x33, 0x58, 0x4c, 0x66, 0x4a, 0x2b, 0x75, 0x74, 0x64, 0x47, + 0x64, 0x49, 0x7a, 0x64, 0x6a, 0x70, 0x39, 0x78, 0x43, 0x6f, 0x69, 0x32, + 0x53, 0x42, 0x42, 0x74, 0x51, 0x77, 0x58, 0x75, 0x34, 0x50, 0x68, 0x76, + 0x4a, 0x56, 0x67, 0x53, 0x4c, 0x4c, 0x31, 0x4b, 0x62, 0x72, 0x61, 0x6c, + 0x57, 0x36, 0x63, 0x48, 0x2f, 0x72, 0x61, 0x6c, 0x59, 0x68, 0x7a, 0x43, + 0x32, 0x67, 0x66, 0x65, 0x58, 0x0a, 0x52, 0x66, 0x77, 0x5a, 0x56, 0x7a, + 0x73, 0x72, 0x62, 0x2b, 0x52, 0x48, 0x39, 0x4a, 0x6c, 0x46, 0x2f, 0x68, + 0x33, 0x78, 0x2b, 0x4a, 0x65, 0x6a, 0x69, 0x42, 0x30, 0x33, 0x48, 0x46, + 0x79, 0x50, 0x34, 0x48, 0x59, 0x6c, 0x6d, 0x6c, 0x44, 0x34, 0x6f, 0x46, + 0x54, 0x2f, 0x52, 0x4a, 0x42, 0x32, 0x49, 0x39, 0x49, 0x79, 0x78, 0x73, + 0x4f, 0x72, 0x42, 0x72, 0x2f, 0x38, 0x2b, 0x37, 0x2f, 0x7a, 0x0a, 0x72, + 0x58, 0x32, 0x53, 0x59, 0x67, 0x4a, 0x62, 0x4b, 0x64, 0x4d, 0x31, 0x6f, + 0x35, 0x4f, 0x61, 0x51, 0x32, 0x52, 0x67, 0x58, 0x62, 0x4c, 0x36, 0x4d, + 0x76, 0x38, 0x37, 0x42, 0x4b, 0x39, 0x4e, 0x51, 0x47, 0x72, 0x35, 0x78, + 0x2b, 0x50, 0x76, 0x49, 0x2f, 0x31, 0x72, 0x79, 0x2b, 0x55, 0x50, 0x69, + 0x7a, 0x67, 0x4e, 0x37, 0x67, 0x72, 0x38, 0x2f, 0x67, 0x2b, 0x59, 0x6e, + 0x7a, 0x41, 0x78, 0x0a, 0x33, 0x57, 0x78, 0x53, 0x5a, 0x66, 0x6d, 0x4c, + 0x67, 0x62, 0x34, 0x69, 0x34, 0x52, 0x78, 0x59, 0x41, 0x37, 0x71, 0x52, + 0x47, 0x34, 0x6b, 0x48, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, + 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, + 0x42, 0x6a, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x52, 0x4d, + 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, + 0x2f, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, + 0x57, 0x42, 0x42, 0x52, 0x71, 0x4f, 0x46, 0x73, 0x6d, 0x6a, 0x64, 0x36, + 0x4c, 0x57, 0x76, 0x4a, 0x50, 0x65, 0x6c, 0x53, 0x44, 0x47, 0x52, 0x6a, + 0x6a, 0x43, 0x44, 0x57, 0x6d, 0x75, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, + 0x71, 0x0a, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x50, 0x4e, + 0x56, 0x33, 0x50, 0x64, 0x72, 0x66, 0x69, 0x62, 0x71, 0x48, 0x44, 0x41, + 0x68, 0x55, 0x61, 0x69, 0x42, 0x51, 0x6b, 0x72, 0x36, 0x77, 0x51, 0x54, + 0x32, 0x35, 0x4a, 0x6d, 0x53, 0x44, 0x43, 0x69, 0x2f, 0x6f, 0x51, 0x4d, + 0x43, 0x58, 0x4b, 0x43, 0x65, 0x43, 0x0a, 0x4d, 0x45, 0x72, 0x4a, 0x6b, + 0x2f, 0x39, 0x71, 0x35, 0x36, 0x59, 0x41, 0x66, 0x34, 0x6c, 0x43, 0x6d, + 0x74, 0x59, 0x52, 0x35, 0x56, 0x50, 0x4f, 0x4c, 0x38, 0x7a, 0x79, 0x32, + 0x67, 0x58, 0x45, 0x2f, 0x75, 0x4a, 0x51, 0x78, 0x44, 0x71, 0x47, 0x66, + 0x63, 0x7a, 0x61, 0x66, 0x68, 0x41, 0x4a, 0x4f, 0x35, 0x49, 0x31, 0x4b, + 0x6c, 0x4f, 0x79, 0x2f, 0x75, 0x73, 0x72, 0x42, 0x64, 0x6c, 0x73, 0x0a, + 0x58, 0x65, 0x62, 0x51, 0x37, 0x39, 0x4e, 0x71, 0x5a, 0x70, 0x34, 0x56, + 0x4b, 0x49, 0x56, 0x36, 0x36, 0x49, 0x49, 0x41, 0x72, 0x42, 0x36, 0x6e, + 0x43, 0x57, 0x6c, 0x57, 0x51, 0x74, 0x4e, 0x6f, 0x55, 0x52, 0x69, 0x2b, + 0x56, 0x4a, 0x71, 0x2f, 0x52, 0x45, 0x47, 0x36, 0x53, 0x62, 0x34, 0x67, + 0x75, 0x6d, 0x6c, 0x63, 0x37, 0x72, 0x68, 0x33, 0x7a, 0x63, 0x35, 0x73, + 0x48, 0x36, 0x32, 0x44, 0x0a, 0x6c, 0x68, 0x68, 0x39, 0x44, 0x72, 0x55, + 0x55, 0x4f, 0x59, 0x54, 0x78, 0x4b, 0x4f, 0x6b, 0x74, 0x6f, 0x35, 0x35, + 0x37, 0x48, 0x6e, 0x70, 0x79, 0x57, 0x6f, 0x4f, 0x7a, 0x65, 0x57, 0x2f, + 0x76, 0x74, 0x50, 0x7a, 0x51, 0x43, 0x71, 0x56, 0x59, 0x54, 0x30, 0x62, + 0x66, 0x2b, 0x32, 0x31, 0x35, 0x57, 0x66, 0x4b, 0x45, 0x49, 0x6c, 0x4b, + 0x75, 0x44, 0x38, 0x7a, 0x37, 0x66, 0x44, 0x76, 0x6e, 0x0a, 0x61, 0x73, + 0x70, 0x48, 0x59, 0x63, 0x4e, 0x36, 0x2b, 0x4e, 0x4f, 0x53, 0x42, 0x42, + 0x2b, 0x34, 0x49, 0x49, 0x54, 0x68, 0x4e, 0x6c, 0x51, 0x57, 0x78, 0x30, + 0x44, 0x65, 0x4f, 0x34, 0x70, 0x7a, 0x33, 0x4e, 0x2f, 0x47, 0x43, 0x55, + 0x7a, 0x66, 0x37, 0x4e, 0x72, 0x2f, 0x31, 0x46, 0x4e, 0x43, 0x6f, 0x63, + 0x6e, 0x79, 0x59, 0x68, 0x30, 0x69, 0x67, 0x7a, 0x79, 0x58, 0x78, 0x66, + 0x6b, 0x5a, 0x0a, 0x59, 0x69, 0x65, 0x73, 0x5a, 0x53, 0x4c, 0x58, 0x30, + 0x7a, 0x7a, 0x47, 0x35, 0x59, 0x36, 0x79, 0x55, 0x38, 0x78, 0x4a, 0x7a, + 0x72, 0x77, 0x77, 0x2f, 0x6e, 0x73, 0x4f, 0x4d, 0x35, 0x44, 0x37, 0x37, + 0x64, 0x49, 0x55, 0x6b, 0x52, 0x38, 0x48, 0x72, 0x77, 0x3d, 0x3d, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, + 0x20, 0x4f, 0x3d, 0x53, 0x45, 0x43, 0x4f, 0x4d, 0x20, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x43, + 0x4f, 0x2e, 0x2c, 0x4c, 0x54, 0x44, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x53, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x43, 0x6f, 0x6d, 0x6d, + 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x43, 0x41, 0x32, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x3a, 0x20, 0x4f, 0x3d, 0x53, 0x45, 0x43, 0x4f, 0x4d, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x73, 0x20, 0x43, 0x4f, 0x2e, 0x2c, 0x4c, 0x54, 0x44, 0x2e, 0x20, + 0x4f, 0x55, 0x3d, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, + 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x32, 0x0a, 0x23, 0x20, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x53, 0x65, 0x63, 0x75, + 0x72, 0x69, 0x74, 0x79, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, + 0x41, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x3a, 0x20, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, + 0x63, 0x3a, 0x33, 0x39, 0x3a, 0x37, 0x64, 0x3a, 0x61, 0x34, 0x3a, 0x30, + 0x65, 0x3a, 0x35, 0x35, 0x3a, 0x35, 0x39, 0x3a, 0x62, 0x32, 0x3a, 0x33, + 0x66, 0x3a, 0x64, 0x36, 0x3a, 0x34, 0x31, 0x3a, 0x62, 0x31, 0x3a, 0x31, + 0x32, 0x3a, 0x35, 0x30, 0x3a, 0x64, 0x65, 0x3a, 0x34, 0x33, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x66, 0x3a, 0x33, 0x62, + 0x3a, 0x38, 0x63, 0x3a, 0x66, 0x32, 0x3a, 0x66, 0x38, 0x3a, 0x31, 0x30, + 0x3a, 0x62, 0x33, 0x3a, 0x37, 0x64, 0x3a, 0x37, 0x38, 0x3a, 0x62, 0x34, + 0x3a, 0x63, 0x65, 0x3a, 0x65, 0x63, 0x3a, 0x31, 0x39, 0x3a, 0x31, 0x39, + 0x3a, 0x63, 0x33, 0x3a, 0x37, 0x33, 0x3a, 0x33, 0x34, 0x3a, 0x62, 0x39, + 0x3a, 0x63, 0x37, 0x3a, 0x37, 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x31, 0x3a, 0x33, 0x62, 0x3a, 0x32, + 0x63, 0x3a, 0x65, 0x63, 0x3a, 0x62, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x64, + 0x34, 0x3a, 0x63, 0x64, 0x3a, 0x65, 0x35, 0x3a, 0x64, 0x64, 0x3a, 0x38, + 0x35, 0x3a, 0x33, 0x39, 0x3a, 0x31, 0x61, 0x3a, 0x64, 0x66, 0x3a, 0x63, + 0x36, 0x3a, 0x63, 0x32, 0x3a, 0x64, 0x64, 0x3a, 0x36, 0x30, 0x3a, 0x64, + 0x38, 0x3a, 0x37, 0x62, 0x3a, 0x62, 0x37, 0x3a, 0x33, 0x36, 0x3a, 0x64, + 0x32, 0x3a, 0x62, 0x35, 0x3a, 0x32, 0x31, 0x3a, 0x34, 0x38, 0x3a, 0x34, + 0x61, 0x3a, 0x61, 0x34, 0x3a, 0x37, 0x61, 0x3a, 0x30, 0x65, 0x3a, 0x62, + 0x65, 0x3a, 0x66, 0x36, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x44, 0x64, 0x7a, 0x43, 0x43, 0x41, 0x6c, 0x2b, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, + 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, + 0x46, 0x41, 0x44, 0x42, 0x64, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x4b, 0x55, 0x44, 0x45, + 0x6c, 0x0a, 0x4d, 0x43, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, + 0x4d, 0x63, 0x55, 0x30, 0x56, 0x44, 0x54, 0x30, 0x30, 0x67, 0x56, 0x48, + 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x55, 0x33, 0x6c, 0x7a, 0x64, 0x47, + 0x56, 0x74, 0x63, 0x79, 0x42, 0x44, 0x54, 0x79, 0x34, 0x73, 0x54, 0x46, + 0x52, 0x45, 0x4c, 0x6a, 0x45, 0x6e, 0x4d, 0x43, 0x55, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x78, 0x4d, 0x65, 0x0a, 0x55, 0x32, 0x56, 0x6a, 0x64, + 0x58, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x51, 0x32, 0x39, 0x74, 0x62, + 0x58, 0x56, 0x75, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, + 0x69, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x51, 0x30, 0x45, 0x79, 0x4d, + 0x42, 0x34, 0x58, 0x44, 0x54, 0x41, 0x35, 0x4d, 0x44, 0x55, 0x79, 0x4f, + 0x54, 0x41, 0x31, 0x4d, 0x44, 0x41, 0x7a, 0x4f, 0x56, 0x6f, 0x58, 0x0a, + 0x44, 0x54, 0x49, 0x35, 0x4d, 0x44, 0x55, 0x79, 0x4f, 0x54, 0x41, 0x31, + 0x4d, 0x44, 0x41, 0x7a, 0x4f, 0x56, 0x6f, 0x77, 0x58, 0x54, 0x45, 0x4c, + 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, + 0x53, 0x6c, 0x41, 0x78, 0x4a, 0x54, 0x41, 0x6a, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x6f, 0x54, 0x48, 0x46, 0x4e, 0x46, 0x51, 0x30, 0x39, 0x4e, + 0x49, 0x46, 0x52, 0x79, 0x0a, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x46, 0x4e, + 0x35, 0x63, 0x33, 0x52, 0x6c, 0x62, 0x58, 0x4d, 0x67, 0x51, 0x30, 0x38, + 0x75, 0x4c, 0x45, 0x78, 0x55, 0x52, 0x43, 0x34, 0x78, 0x4a, 0x7a, 0x41, + 0x6c, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x48, 0x6c, 0x4e, + 0x6c, 0x59, 0x33, 0x56, 0x79, 0x61, 0x58, 0x52, 0x35, 0x49, 0x45, 0x4e, + 0x76, 0x62, 0x57, 0x31, 0x31, 0x62, 0x6d, 0x6c, 0x6a, 0x0a, 0x59, 0x58, + 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x45, + 0x4e, 0x42, 0x4d, 0x6a, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, + 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, + 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, + 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4e, + 0x41, 0x56, 0x0a, 0x4f, 0x56, 0x4b, 0x78, 0x55, 0x72, 0x4f, 0x36, 0x78, + 0x56, 0x6d, 0x43, 0x78, 0x46, 0x31, 0x53, 0x72, 0x6a, 0x70, 0x44, 0x5a, + 0x59, 0x42, 0x4c, 0x78, 0x2f, 0x4b, 0x57, 0x76, 0x4e, 0x73, 0x32, 0x6c, + 0x39, 0x61, 0x6d, 0x5a, 0x49, 0x79, 0x6f, 0x58, 0x76, 0x44, 0x6a, 0x43, + 0x68, 0x7a, 0x33, 0x33, 0x35, 0x63, 0x39, 0x53, 0x36, 0x37, 0x32, 0x58, + 0x65, 0x77, 0x68, 0x74, 0x55, 0x47, 0x72, 0x0a, 0x7a, 0x62, 0x6c, 0x2b, + 0x64, 0x70, 0x2b, 0x2b, 0x2b, 0x54, 0x34, 0x32, 0x4e, 0x4b, 0x41, 0x37, + 0x77, 0x66, 0x59, 0x78, 0x45, 0x55, 0x56, 0x30, 0x6b, 0x7a, 0x31, 0x58, + 0x67, 0x4d, 0x58, 0x35, 0x69, 0x5a, 0x6e, 0x4b, 0x35, 0x61, 0x74, 0x71, + 0x31, 0x4c, 0x58, 0x61, 0x51, 0x5a, 0x41, 0x51, 0x77, 0x64, 0x62, 0x57, + 0x51, 0x6f, 0x6e, 0x43, 0x76, 0x2f, 0x51, 0x34, 0x45, 0x70, 0x56, 0x4d, + 0x0a, 0x56, 0x41, 0x58, 0x33, 0x4e, 0x75, 0x52, 0x46, 0x67, 0x33, 0x73, + 0x55, 0x5a, 0x64, 0x62, 0x63, 0x44, 0x45, 0x33, 0x52, 0x33, 0x6e, 0x34, + 0x4d, 0x71, 0x7a, 0x76, 0x45, 0x46, 0x62, 0x34, 0x36, 0x56, 0x71, 0x5a, + 0x61, 0x62, 0x33, 0x5a, 0x70, 0x55, 0x71, 0x6c, 0x36, 0x75, 0x63, 0x6a, + 0x72, 0x61, 0x70, 0x70, 0x64, 0x55, 0x74, 0x41, 0x74, 0x43, 0x6d, 0x73, + 0x31, 0x46, 0x67, 0x6b, 0x51, 0x0a, 0x68, 0x4e, 0x42, 0x71, 0x79, 0x6a, + 0x6f, 0x47, 0x41, 0x44, 0x64, 0x48, 0x35, 0x48, 0x35, 0x58, 0x54, 0x7a, + 0x2b, 0x4c, 0x36, 0x32, 0x65, 0x34, 0x69, 0x4b, 0x72, 0x46, 0x76, 0x6c, + 0x4e, 0x56, 0x73, 0x70, 0x48, 0x45, 0x66, 0x62, 0x6d, 0x77, 0x68, 0x52, + 0x6b, 0x47, 0x65, 0x43, 0x37, 0x62, 0x59, 0x52, 0x72, 0x36, 0x68, 0x66, + 0x56, 0x4b, 0x6b, 0x61, 0x48, 0x6e, 0x46, 0x74, 0x57, 0x4f, 0x0a, 0x6f, + 0x6a, 0x6e, 0x66, 0x6c, 0x4c, 0x68, 0x77, 0x48, 0x79, 0x67, 0x2f, 0x69, + 0x2f, 0x78, 0x41, 0x58, 0x6d, 0x4f, 0x44, 0x50, 0x49, 0x4d, 0x71, 0x47, + 0x70, 0x6c, 0x72, 0x7a, 0x39, 0x35, 0x5a, 0x61, 0x6a, 0x76, 0x38, 0x62, + 0x78, 0x62, 0x58, 0x48, 0x2f, 0x31, 0x4b, 0x45, 0x4f, 0x74, 0x4f, 0x67, + 0x68, 0x59, 0x36, 0x72, 0x43, 0x63, 0x4d, 0x55, 0x2f, 0x47, 0x74, 0x31, + 0x53, 0x53, 0x77, 0x0a, 0x61, 0x77, 0x4e, 0x51, 0x77, 0x53, 0x30, 0x38, + 0x46, 0x74, 0x31, 0x45, 0x4e, 0x43, 0x63, 0x61, 0x64, 0x66, 0x73, 0x43, + 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77, + 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, + 0x46, 0x41, 0x71, 0x46, 0x71, 0x58, 0x64, 0x6c, 0x42, 0x5a, 0x68, 0x38, + 0x51, 0x49, 0x48, 0x34, 0x44, 0x35, 0x63, 0x73, 0x0a, 0x4f, 0x50, 0x45, + 0x4b, 0x37, 0x44, 0x7a, 0x50, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, + 0x42, 0x42, 0x6a, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, + 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, + 0x2f, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x33, 0x0a, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, 0x34, + 0x49, 0x42, 0x41, 0x51, 0x42, 0x4d, 0x4f, 0x71, 0x4e, 0x45, 0x72, 0x4c, + 0x6c, 0x46, 0x73, 0x63, 0x65, 0x54, 0x66, 0x73, 0x67, 0x4c, 0x43, 0x6b, + 0x4c, 0x66, 0x5a, 0x4f, 0x6f, 0x63, 0x37, 0x6c, 0x6c, 0x73, 0x43, 0x4c, + 0x71, 0x4a, 0x58, 0x32, 0x72, 0x4b, 0x53, 0x70, 0x57, 0x65, 0x65, 0x6f, + 0x38, 0x48, 0x78, 0x64, 0x70, 0x46, 0x0a, 0x63, 0x6f, 0x4a, 0x78, 0x44, + 0x6a, 0x72, 0x53, 0x7a, 0x47, 0x2b, 0x6e, 0x74, 0x4b, 0x45, 0x6a, 0x75, + 0x2f, 0x59, 0x6b, 0x6e, 0x38, 0x73, 0x58, 0x2f, 0x6f, 0x79, 0x6d, 0x7a, + 0x73, 0x4c, 0x53, 0x32, 0x38, 0x79, 0x4e, 0x2f, 0x48, 0x48, 0x38, 0x41, + 0x79, 0x6e, 0x42, 0x62, 0x46, 0x30, 0x7a, 0x58, 0x32, 0x53, 0x32, 0x5a, + 0x54, 0x75, 0x4a, 0x62, 0x78, 0x68, 0x32, 0x65, 0x50, 0x58, 0x63, 0x0a, + 0x6f, 0x6b, 0x67, 0x66, 0x47, 0x54, 0x2b, 0x4f, 0x6b, 0x2b, 0x76, 0x78, + 0x2b, 0x68, 0x66, 0x75, 0x7a, 0x55, 0x37, 0x6a, 0x42, 0x42, 0x4a, 0x56, + 0x31, 0x75, 0x58, 0x6b, 0x33, 0x66, 0x73, 0x2b, 0x42, 0x58, 0x7a, 0x69, + 0x48, 0x56, 0x37, 0x47, 0x70, 0x37, 0x79, 0x58, 0x54, 0x32, 0x67, 0x36, + 0x39, 0x65, 0x6b, 0x75, 0x43, 0x6b, 0x4f, 0x32, 0x72, 0x31, 0x64, 0x63, + 0x59, 0x6d, 0x68, 0x38, 0x0a, 0x74, 0x2f, 0x32, 0x6a, 0x69, 0x6f, 0x53, + 0x67, 0x72, 0x47, 0x4b, 0x2b, 0x4b, 0x77, 0x6d, 0x48, 0x4e, 0x50, 0x42, + 0x71, 0x41, 0x62, 0x75, 0x62, 0x4b, 0x56, 0x59, 0x38, 0x2f, 0x67, 0x41, + 0x33, 0x7a, 0x79, 0x4e, 0x73, 0x38, 0x55, 0x36, 0x71, 0x74, 0x6e, 0x52, + 0x47, 0x45, 0x6d, 0x79, 0x52, 0x37, 0x6a, 0x54, 0x56, 0x37, 0x4a, 0x71, + 0x52, 0x35, 0x30, 0x53, 0x2b, 0x6b, 0x44, 0x46, 0x79, 0x0a, 0x31, 0x55, + 0x6b, 0x43, 0x39, 0x67, 0x4c, 0x6c, 0x39, 0x42, 0x2f, 0x72, 0x66, 0x4e, + 0x6d, 0x57, 0x56, 0x61, 0x6e, 0x2f, 0x37, 0x49, 0x72, 0x35, 0x6d, 0x55, + 0x66, 0x2f, 0x4e, 0x56, 0x6f, 0x43, 0x71, 0x67, 0x54, 0x4c, 0x69, 0x6c, + 0x75, 0x48, 0x63, 0x53, 0x6d, 0x52, 0x76, 0x61, 0x53, 0x30, 0x65, 0x67, + 0x32, 0x39, 0x6d, 0x76, 0x56, 0x58, 0x49, 0x77, 0x41, 0x48, 0x49, 0x52, + 0x63, 0x2f, 0x0a, 0x53, 0x6a, 0x6e, 0x52, 0x42, 0x55, 0x6b, 0x4c, 0x70, + 0x37, 0x59, 0x33, 0x67, 0x61, 0x56, 0x64, 0x6a, 0x4b, 0x6f, 0x7a, 0x58, + 0x6f, 0x45, 0x6f, 0x66, 0x4b, 0x64, 0x39, 0x4a, 0x2b, 0x73, 0x41, 0x72, + 0x6f, 0x30, 0x33, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45, 0x43, 0x2d, 0x41, + 0x43, 0x43, 0x20, 0x4f, 0x3d, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x61, + 0x20, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x61, 0x6e, 0x61, 0x20, 0x64, 0x65, + 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x63, 0x69, + 0x6f, 0x20, 0x28, 0x4e, 0x49, 0x46, 0x20, 0x51, 0x2d, 0x30, 0x38, 0x30, + 0x31, 0x31, 0x37, 0x36, 0x2d, 0x49, 0x29, 0x20, 0x4f, 0x55, 0x3d, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x69, 0x73, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x73, 0x20, 0x64, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x63, 0x69, 0x6f, 0x2f, 0x56, 0x65, 0x67, 0x65, 0x75, + 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, + 0x2e, 0x63, 0x61, 0x74, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6e, 0x65, 0x74, + 0x2f, 0x76, 0x65, 0x72, 0x61, 0x72, 0x72, 0x65, 0x6c, 0x20, 0x28, 0x63, + 0x29, 0x30, 0x33, 0x2f, 0x4a, 0x65, 0x72, 0x61, 0x72, 0x71, 0x75, 0x69, + 0x61, 0x20, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x61, 0x74, 0x73, 0x20, 0x64, + 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x63, + 0x69, 0x6f, 0x20, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x61, 0x6e, 0x65, 0x73, + 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x45, 0x43, 0x2d, 0x41, 0x43, 0x43, 0x20, 0x4f, 0x3d, + 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x61, 0x20, 0x43, 0x61, 0x74, 0x61, + 0x6c, 0x61, 0x6e, 0x61, 0x20, 0x64, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x63, 0x69, 0x6f, 0x20, 0x28, 0x4e, 0x49, + 0x46, 0x20, 0x51, 0x2d, 0x30, 0x38, 0x30, 0x31, 0x31, 0x37, 0x36, 0x2d, + 0x49, 0x29, 0x20, 0x4f, 0x55, 0x3d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x69, + 0x73, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x73, 0x20, 0x64, 0x65, + 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x63, 0x69, + 0x6f, 0x2f, 0x56, 0x65, 0x67, 0x65, 0x75, 0x20, 0x68, 0x74, 0x74, 0x70, + 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x61, 0x74, 0x63, + 0x65, 0x72, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x65, 0x72, 0x61, + 0x72, 0x72, 0x65, 0x6c, 0x20, 0x28, 0x63, 0x29, 0x30, 0x33, 0x2f, 0x4a, + 0x65, 0x72, 0x61, 0x72, 0x71, 0x75, 0x69, 0x61, 0x20, 0x45, 0x6e, 0x74, + 0x69, 0x74, 0x61, 0x74, 0x73, 0x20, 0x64, 0x65, 0x20, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x63, 0x69, 0x6f, 0x20, 0x43, 0x61, + 0x74, 0x61, 0x6c, 0x61, 0x6e, 0x65, 0x73, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, 0x43, 0x2d, 0x41, 0x43, 0x43, + 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, + 0x2d, 0x32, 0x33, 0x37, 0x30, 0x31, 0x35, 0x37, 0x39, 0x32, 0x34, 0x37, + 0x39, 0x35, 0x35, 0x37, 0x30, 0x39, 0x31, 0x33, 0x39, 0x36, 0x32, 0x36, + 0x35, 0x35, 0x35, 0x31, 0x32, 0x36, 0x35, 0x32, 0x34, 0x38, 0x32, 0x30, + 0x34, 0x37, 0x39, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, + 0x62, 0x3a, 0x66, 0x35, 0x3a, 0x39, 0x64, 0x3a, 0x32, 0x39, 0x3a, 0x30, + 0x64, 0x3a, 0x36, 0x31, 0x3a, 0x66, 0x39, 0x3a, 0x34, 0x32, 0x3a, 0x31, + 0x66, 0x3a, 0x37, 0x63, 0x3a, 0x63, 0x32, 0x3a, 0x62, 0x61, 0x3a, 0x36, + 0x64, 0x3a, 0x65, 0x33, 0x3a, 0x31, 0x35, 0x3a, 0x30, 0x39, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x38, 0x3a, 0x39, 0x30, + 0x3a, 0x33, 0x61, 0x3a, 0x36, 0x33, 0x3a, 0x35, 0x62, 0x3a, 0x35, 0x32, + 0x3a, 0x38, 0x30, 0x3a, 0x66, 0x61, 0x3a, 0x65, 0x36, 0x3a, 0x37, 0x37, + 0x3a, 0x34, 0x63, 0x3a, 0x30, 0x62, 0x3a, 0x36, 0x64, 0x3a, 0x61, 0x37, + 0x3a, 0x64, 0x36, 0x3a, 0x62, 0x61, 0x3a, 0x61, 0x36, 0x3a, 0x34, 0x61, + 0x3a, 0x66, 0x32, 0x3a, 0x65, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x38, 0x3a, 0x34, 0x39, 0x3a, 0x37, + 0x66, 0x3a, 0x30, 0x31, 0x3a, 0x36, 0x30, 0x3a, 0x32, 0x66, 0x3a, 0x33, + 0x31, 0x3a, 0x35, 0x34, 0x3a, 0x32, 0x34, 0x3a, 0x36, 0x61, 0x3a, 0x65, + 0x32, 0x3a, 0x38, 0x63, 0x3a, 0x34, 0x64, 0x3a, 0x35, 0x61, 0x3a, 0x65, + 0x66, 0x3a, 0x31, 0x30, 0x3a, 0x66, 0x31, 0x3a, 0x64, 0x38, 0x3a, 0x37, + 0x65, 0x3a, 0x62, 0x62, 0x3a, 0x37, 0x36, 0x3a, 0x36, 0x32, 0x3a, 0x36, + 0x66, 0x3a, 0x34, 0x61, 0x3a, 0x65, 0x30, 0x3a, 0x62, 0x37, 0x3a, 0x66, + 0x39, 0x3a, 0x35, 0x62, 0x3a, 0x61, 0x37, 0x3a, 0x39, 0x36, 0x3a, 0x38, + 0x37, 0x3a, 0x39, 0x39, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x46, 0x56, 0x6a, 0x43, 0x43, 0x42, 0x44, 0x36, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x51, 0x37, 0x69, 0x73, 0x39, 0x36, 0x39, 0x51, + 0x68, 0x33, 0x68, 0x53, 0x6f, 0x59, 0x71, 0x77, 0x45, 0x38, 0x39, 0x33, + 0x45, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x43, + 0x42, 0x0a, 0x38, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x56, 0x4d, 0x78, 0x4f, 0x7a, + 0x41, 0x35, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x4d, 0x6b, + 0x46, 0x6e, 0x5a, 0x57, 0x35, 0x6a, 0x61, 0x57, 0x45, 0x67, 0x51, 0x32, + 0x46, 0x30, 0x59, 0x57, 0x78, 0x68, 0x62, 0x6d, 0x45, 0x67, 0x5a, 0x47, + 0x55, 0x67, 0x51, 0x32, 0x56, 0x79, 0x0a, 0x64, 0x47, 0x6c, 0x6d, 0x61, + 0x57, 0x4e, 0x68, 0x59, 0x32, 0x6c, 0x76, 0x49, 0x43, 0x68, 0x4f, 0x53, + 0x55, 0x59, 0x67, 0x55, 0x53, 0x30, 0x77, 0x4f, 0x44, 0x41, 0x78, 0x4d, + 0x54, 0x63, 0x32, 0x4c, 0x55, 0x6b, 0x70, 0x4d, 0x53, 0x67, 0x77, 0x4a, + 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x39, 0x54, 0x5a, + 0x58, 0x4a, 0x32, 0x5a, 0x57, 0x6c, 0x7a, 0x49, 0x46, 0x42, 0x31, 0x0a, + 0x59, 0x6d, 0x78, 0x70, 0x59, 0x33, 0x4d, 0x67, 0x5a, 0x47, 0x55, 0x67, + 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, + 0x59, 0x32, 0x6c, 0x76, 0x4d, 0x54, 0x55, 0x77, 0x4d, 0x77, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4c, 0x45, 0x79, 0x78, 0x57, 0x5a, 0x57, 0x64, 0x6c, + 0x64, 0x53, 0x42, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, 0x76, + 0x4c, 0x33, 0x64, 0x33, 0x0a, 0x64, 0x79, 0x35, 0x6a, 0x59, 0x58, 0x52, + 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x4c, 0x6d, 0x35, 0x6c, 0x64, 0x43, 0x39, + 0x32, 0x5a, 0x58, 0x4a, 0x68, 0x63, 0x6e, 0x4a, 0x6c, 0x62, 0x43, 0x41, + 0x6f, 0x59, 0x79, 0x6b, 0x77, 0x4d, 0x7a, 0x45, 0x31, 0x4d, 0x44, 0x4d, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x73, 0x53, 0x6d, 0x56, + 0x79, 0x59, 0x58, 0x4a, 0x78, 0x64, 0x57, 0x6c, 0x68, 0x0a, 0x49, 0x45, + 0x56, 0x75, 0x64, 0x47, 0x6c, 0x30, 0x59, 0x58, 0x52, 0x7a, 0x49, 0x47, + 0x52, 0x6c, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, + 0x6c, 0x6a, 0x59, 0x57, 0x4e, 0x70, 0x62, 0x79, 0x42, 0x44, 0x59, 0x58, + 0x52, 0x68, 0x62, 0x47, 0x46, 0x75, 0x5a, 0x58, 0x4d, 0x78, 0x44, 0x7a, + 0x41, 0x4e, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x42, 0x6b, + 0x56, 0x44, 0x0a, 0x4c, 0x55, 0x46, 0x44, 0x51, 0x7a, 0x41, 0x65, 0x46, + 0x77, 0x30, 0x77, 0x4d, 0x7a, 0x41, 0x78, 0x4d, 0x44, 0x63, 0x79, 0x4d, + 0x7a, 0x41, 0x77, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4d, + 0x54, 0x41, 0x78, 0x4d, 0x44, 0x63, 0x79, 0x4d, 0x6a, 0x55, 0x35, 0x4e, + 0x54, 0x6c, 0x61, 0x4d, 0x49, 0x48, 0x7a, 0x4d, 0x51, 0x73, 0x77, 0x43, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x0a, 0x45, 0x77, 0x4a, 0x46, + 0x55, 0x7a, 0x45, 0x37, 0x4d, 0x44, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x68, 0x4d, 0x79, 0x51, 0x57, 0x64, 0x6c, 0x62, 0x6d, 0x4e, 0x70, + 0x59, 0x53, 0x42, 0x44, 0x59, 0x58, 0x52, 0x68, 0x62, 0x47, 0x46, 0x75, + 0x59, 0x53, 0x42, 0x6b, 0x5a, 0x53, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, + 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x6a, 0x61, 0x57, 0x38, 0x67, + 0x0a, 0x4b, 0x45, 0x35, 0x4a, 0x52, 0x69, 0x42, 0x52, 0x4c, 0x54, 0x41, + 0x34, 0x4d, 0x44, 0x45, 0x78, 0x4e, 0x7a, 0x59, 0x74, 0x53, 0x53, 0x6b, + 0x78, 0x4b, 0x44, 0x41, 0x6d, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, + 0x54, 0x48, 0x31, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x6c, 0x61, 0x58, 0x4d, + 0x67, 0x55, 0x48, 0x56, 0x69, 0x62, 0x47, 0x6c, 0x6a, 0x63, 0x79, 0x42, + 0x6b, 0x5a, 0x53, 0x42, 0x44, 0x0a, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, + 0x5a, 0x70, 0x59, 0x32, 0x46, 0x6a, 0x61, 0x57, 0x38, 0x78, 0x4e, 0x54, + 0x41, 0x7a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x4c, 0x46, + 0x5a, 0x6c, 0x5a, 0x32, 0x56, 0x31, 0x49, 0x47, 0x68, 0x30, 0x64, 0x48, + 0x42, 0x7a, 0x4f, 0x69, 0x38, 0x76, 0x64, 0x33, 0x64, 0x33, 0x4c, 0x6d, + 0x4e, 0x68, 0x64, 0x47, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x75, 0x0a, 0x62, + 0x6d, 0x56, 0x30, 0x4c, 0x33, 0x5a, 0x6c, 0x63, 0x6d, 0x46, 0x79, 0x63, + 0x6d, 0x56, 0x73, 0x49, 0x43, 0x68, 0x6a, 0x4b, 0x54, 0x41, 0x7a, 0x4d, + 0x54, 0x55, 0x77, 0x4d, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, + 0x79, 0x78, 0x4b, 0x5a, 0x58, 0x4a, 0x68, 0x63, 0x6e, 0x46, 0x31, 0x61, + 0x57, 0x45, 0x67, 0x52, 0x57, 0x35, 0x30, 0x61, 0x58, 0x52, 0x68, 0x64, + 0x48, 0x4d, 0x67, 0x0a, 0x5a, 0x47, 0x55, 0x67, 0x51, 0x32, 0x56, 0x79, + 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x59, 0x32, 0x6c, 0x76, + 0x49, 0x45, 0x4e, 0x68, 0x64, 0x47, 0x46, 0x73, 0x59, 0x57, 0x35, 0x6c, + 0x63, 0x7a, 0x45, 0x50, 0x4d, 0x41, 0x30, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x41, 0x78, 0x4d, 0x47, 0x52, 0x55, 0x4d, 0x74, 0x51, 0x55, 0x4e, 0x44, + 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x0a, 0x42, 0x67, 0x6b, + 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, + 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, + 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x73, 0x79, 0x4c, + 0x48, 0x54, 0x2b, 0x4b, 0x58, 0x51, 0x70, 0x57, 0x49, 0x52, 0x34, 0x4e, + 0x41, 0x39, 0x68, 0x30, 0x58, 0x38, 0x34, 0x4e, 0x7a, 0x4a, 0x42, 0x35, + 0x52, 0x0a, 0x38, 0x35, 0x69, 0x4b, 0x77, 0x35, 0x4b, 0x34, 0x2f, 0x30, + 0x43, 0x51, 0x42, 0x58, 0x43, 0x48, 0x59, 0x4d, 0x6b, 0x41, 0x71, 0x62, + 0x57, 0x55, 0x5a, 0x52, 0x6b, 0x69, 0x46, 0x52, 0x66, 0x43, 0x51, 0x32, + 0x78, 0x6d, 0x52, 0x4a, 0x6f, 0x4e, 0x42, 0x44, 0x34, 0x35, 0x62, 0x36, + 0x56, 0x4c, 0x65, 0x71, 0x70, 0x6a, 0x74, 0x34, 0x70, 0x45, 0x6e, 0x64, + 0x6c, 0x6a, 0x6b, 0x59, 0x52, 0x6d, 0x0a, 0x34, 0x43, 0x67, 0x50, 0x75, + 0x6b, 0x4c, 0x6a, 0x62, 0x6f, 0x37, 0x33, 0x46, 0x43, 0x65, 0x54, 0x61, + 0x65, 0x36, 0x52, 0x44, 0x71, 0x4e, 0x66, 0x44, 0x72, 0x48, 0x72, 0x5a, + 0x71, 0x4a, 0x79, 0x54, 0x78, 0x49, 0x54, 0x68, 0x6d, 0x56, 0x36, 0x50, + 0x74, 0x74, 0x50, 0x42, 0x2f, 0x53, 0x6e, 0x43, 0x57, 0x44, 0x61, 0x4f, + 0x6b, 0x4b, 0x5a, 0x78, 0x37, 0x4a, 0x2f, 0x73, 0x78, 0x61, 0x56, 0x0a, + 0x48, 0x4d, 0x66, 0x35, 0x4e, 0x4c, 0x57, 0x55, 0x68, 0x64, 0x57, 0x5a, + 0x58, 0x71, 0x42, 0x49, 0x6f, 0x48, 0x37, 0x6e, 0x46, 0x32, 0x57, 0x34, + 0x6f, 0x6e, 0x57, 0x34, 0x48, 0x76, 0x50, 0x6c, 0x51, 0x6e, 0x32, 0x76, + 0x37, 0x66, 0x4f, 0x4b, 0x53, 0x47, 0x52, 0x64, 0x67, 0x68, 0x53, 0x54, + 0x32, 0x4d, 0x44, 0x6b, 0x2f, 0x37, 0x4e, 0x51, 0x63, 0x76, 0x4a, 0x32, + 0x39, 0x72, 0x4e, 0x64, 0x0a, 0x51, 0x6c, 0x42, 0x35, 0x30, 0x4a, 0x51, + 0x2b, 0x61, 0x77, 0x77, 0x41, 0x76, 0x74, 0x68, 0x72, 0x44, 0x6b, 0x34, + 0x71, 0x37, 0x44, 0x37, 0x53, 0x7a, 0x49, 0x4b, 0x69, 0x47, 0x47, 0x55, + 0x7a, 0x45, 0x33, 0x65, 0x65, 0x6d, 0x6c, 0x30, 0x61, 0x45, 0x39, 0x6a, + 0x44, 0x32, 0x7a, 0x33, 0x49, 0x6c, 0x33, 0x72, 0x75, 0x63, 0x4f, 0x32, + 0x6e, 0x35, 0x6e, 0x7a, 0x62, 0x63, 0x63, 0x38, 0x74, 0x0a, 0x6c, 0x47, + 0x4c, 0x66, 0x62, 0x64, 0x62, 0x31, 0x4f, 0x4c, 0x34, 0x2f, 0x70, 0x59, + 0x55, 0x4b, 0x47, 0x62, 0x69, 0x6f, 0x32, 0x41, 0x6c, 0x31, 0x51, 0x6e, + 0x44, 0x45, 0x36, 0x75, 0x2f, 0x4c, 0x44, 0x73, 0x67, 0x30, 0x71, 0x42, + 0x49, 0x69, 0x6d, 0x41, 0x79, 0x34, 0x45, 0x35, 0x53, 0x32, 0x53, 0x2b, + 0x7a, 0x77, 0x30, 0x4a, 0x44, 0x6e, 0x4a, 0x77, 0x49, 0x44, 0x41, 0x51, + 0x41, 0x42, 0x0a, 0x6f, 0x34, 0x48, 0x6a, 0x4d, 0x49, 0x48, 0x67, 0x4d, + 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x51, 0x51, 0x57, 0x4d, + 0x42, 0x53, 0x42, 0x45, 0x6d, 0x56, 0x6a, 0x58, 0x32, 0x46, 0x6a, 0x59, + 0x30, 0x42, 0x6a, 0x59, 0x58, 0x52, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x4c, + 0x6d, 0x35, 0x6c, 0x64, 0x44, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x0a, 0x42, 0x54, 0x41, 0x44, + 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, + 0x42, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, + 0x46, 0x67, 0x51, 0x55, 0x6f, 0x4d, 0x4f, 0x4c, 0x52, 0x4b, 0x6f, 0x33, + 0x70, 0x55, 0x57, 0x2f, 0x6c, 0x34, 0x42, 0x61, 0x30, 0x66, 0x46, 0x34, + 0x0a, 0x6f, 0x70, 0x76, 0x70, 0x58, 0x59, 0x30, 0x77, 0x66, 0x77, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x67, 0x42, 0x48, 0x67, 0x77, 0x64, 0x6a, 0x42, + 0x30, 0x42, 0x67, 0x73, 0x72, 0x42, 0x67, 0x45, 0x45, 0x41, 0x66, 0x56, + 0x34, 0x41, 0x51, 0x4d, 0x42, 0x43, 0x6a, 0x42, 0x6c, 0x4d, 0x43, 0x77, + 0x47, 0x43, 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x77, 0x49, + 0x42, 0x46, 0x69, 0x42, 0x6f, 0x0a, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, + 0x6f, 0x76, 0x4c, 0x33, 0x64, 0x33, 0x64, 0x79, 0x35, 0x6a, 0x59, 0x58, + 0x52, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x4c, 0x6d, 0x35, 0x6c, 0x64, 0x43, + 0x39, 0x32, 0x5a, 0x58, 0x4a, 0x68, 0x63, 0x6e, 0x4a, 0x6c, 0x62, 0x44, + 0x41, 0x31, 0x42, 0x67, 0x67, 0x72, 0x42, 0x67, 0x45, 0x46, 0x42, 0x51, + 0x63, 0x43, 0x41, 0x6a, 0x41, 0x70, 0x47, 0x69, 0x64, 0x57, 0x0a, 0x5a, + 0x57, 0x64, 0x6c, 0x64, 0x53, 0x42, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, + 0x7a, 0x6f, 0x76, 0x4c, 0x33, 0x64, 0x33, 0x64, 0x79, 0x35, 0x6a, 0x59, + 0x58, 0x52, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x4c, 0x6d, 0x35, 0x6c, 0x64, + 0x43, 0x39, 0x32, 0x5a, 0x58, 0x4a, 0x68, 0x63, 0x6e, 0x4a, 0x6c, 0x62, + 0x43, 0x41, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x63, 0x4e, 0x0a, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, + 0x67, 0x67, 0x45, 0x42, 0x41, 0x4b, 0x42, 0x49, 0x57, 0x34, 0x49, 0x42, + 0x39, 0x6b, 0x31, 0x49, 0x75, 0x44, 0x6c, 0x56, 0x4e, 0x5a, 0x79, 0x41, + 0x65, 0x6c, 0x4f, 0x5a, 0x31, 0x56, 0x72, 0x2f, 0x73, 0x58, 0x45, 0x37, + 0x7a, 0x44, 0x6b, 0x4a, 0x6c, 0x46, 0x37, 0x57, 0x32, 0x75, 0x2b, 0x2b, + 0x41, 0x56, 0x74, 0x64, 0x30, 0x78, 0x37, 0x59, 0x0a, 0x2f, 0x58, 0x31, + 0x50, 0x7a, 0x61, 0x42, 0x42, 0x34, 0x44, 0x53, 0x54, 0x76, 0x38, 0x76, + 0x69, 0x68, 0x70, 0x77, 0x33, 0x6b, 0x70, 0x42, 0x57, 0x48, 0x4e, 0x7a, + 0x72, 0x4b, 0x51, 0x58, 0x6c, 0x78, 0x4a, 0x37, 0x48, 0x4e, 0x64, 0x2b, + 0x4b, 0x44, 0x4d, 0x33, 0x46, 0x49, 0x55, 0x50, 0x70, 0x71, 0x6f, 0x6a, + 0x6c, 0x4e, 0x63, 0x41, 0x5a, 0x51, 0x6d, 0x4e, 0x61, 0x41, 0x6c, 0x36, + 0x6b, 0x0a, 0x53, 0x42, 0x67, 0x36, 0x68, 0x57, 0x2f, 0x63, 0x6e, 0x62, + 0x77, 0x2f, 0x6e, 0x5a, 0x7a, 0x42, 0x68, 0x37, 0x68, 0x36, 0x59, 0x51, + 0x6a, 0x70, 0x64, 0x77, 0x74, 0x2f, 0x63, 0x4b, 0x74, 0x36, 0x33, 0x64, + 0x6d, 0x58, 0x4c, 0x47, 0x51, 0x65, 0x68, 0x62, 0x2b, 0x38, 0x64, 0x4a, + 0x61, 0x68, 0x77, 0x33, 0x6f, 0x53, 0x37, 0x41, 0x77, 0x61, 0x62, 0x6f, + 0x4d, 0x4d, 0x50, 0x4f, 0x68, 0x79, 0x0a, 0x52, 0x70, 0x2f, 0x37, 0x53, + 0x4e, 0x56, 0x65, 0x6c, 0x2b, 0x61, 0x78, 0x6f, 0x66, 0x6a, 0x6b, 0x37, + 0x30, 0x59, 0x6c, 0x6c, 0x4a, 0x79, 0x4a, 0x32, 0x32, 0x6b, 0x34, 0x76, + 0x75, 0x78, 0x63, 0x44, 0x6c, 0x62, 0x48, 0x5a, 0x56, 0x48, 0x6c, 0x55, + 0x49, 0x69, 0x49, 0x76, 0x30, 0x4c, 0x56, 0x4b, 0x7a, 0x33, 0x6c, 0x2b, + 0x62, 0x71, 0x65, 0x4c, 0x72, 0x50, 0x4b, 0x39, 0x48, 0x4f, 0x53, 0x0a, + 0x41, 0x67, 0x75, 0x2b, 0x54, 0x47, 0x62, 0x72, 0x49, 0x50, 0x36, 0x35, + 0x79, 0x37, 0x57, 0x5a, 0x66, 0x2b, 0x61, 0x32, 0x45, 0x2f, 0x72, 0x4b, + 0x53, 0x30, 0x33, 0x5a, 0x37, 0x6c, 0x4e, 0x47, 0x42, 0x6a, 0x76, 0x47, + 0x54, 0x71, 0x32, 0x54, 0x57, 0x6f, 0x46, 0x2b, 0x62, 0x43, 0x70, 0x4c, + 0x61, 0x67, 0x56, 0x46, 0x6a, 0x50, 0x49, 0x68, 0x70, 0x44, 0x47, 0x51, + 0x68, 0x32, 0x78, 0x6c, 0x0a, 0x6e, 0x4a, 0x32, 0x6c, 0x59, 0x4a, 0x55, + 0x36, 0x55, 0x6e, 0x2f, 0x31, 0x30, 0x61, 0x73, 0x49, 0x62, 0x76, 0x50, + 0x75, 0x57, 0x2f, 0x6d, 0x49, 0x50, 0x58, 0x36, 0x34, 0x62, 0x32, 0x34, + 0x44, 0x35, 0x45, 0x49, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x48, 0x65, + 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, + 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, + 0x20, 0x32, 0x30, 0x31, 0x31, 0x20, 0x4f, 0x3d, 0x48, 0x65, 0x6c, 0x6c, + 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, + 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65, 0x72, 0x74, 0x2e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x48, 0x65, + 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, + 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, + 0x20, 0x32, 0x30, 0x31, 0x31, 0x20, 0x4f, 0x3d, 0x48, 0x65, 0x6c, 0x6c, + 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, + 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65, 0x72, 0x74, 0x2e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, + 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, + 0x31, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x33, + 0x3a, 0x39, 0x66, 0x3a, 0x34, 0x63, 0x3a, 0x34, 0x62, 0x3a, 0x37, 0x33, + 0x3a, 0x35, 0x62, 0x3a, 0x37, 0x39, 0x3a, 0x65, 0x39, 0x3a, 0x66, 0x61, + 0x3a, 0x62, 0x61, 0x3a, 0x31, 0x63, 0x3a, 0x65, 0x66, 0x3a, 0x36, 0x65, + 0x3a, 0x63, 0x62, 0x3a, 0x64, 0x35, 0x3a, 0x63, 0x39, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x66, 0x65, 0x3a, 0x34, 0x35, 0x3a, + 0x36, 0x35, 0x3a, 0x39, 0x62, 0x3a, 0x37, 0x39, 0x3a, 0x30, 0x33, 0x3a, + 0x35, 0x62, 0x3a, 0x39, 0x38, 0x3a, 0x61, 0x31, 0x3a, 0x36, 0x31, 0x3a, + 0x62, 0x35, 0x3a, 0x35, 0x31, 0x3a, 0x32, 0x65, 0x3a, 0x61, 0x63, 0x3a, + 0x64, 0x61, 0x3a, 0x35, 0x38, 0x3a, 0x30, 0x39, 0x3a, 0x34, 0x38, 0x3a, + 0x32, 0x32, 0x3a, 0x34, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x63, 0x3a, 0x31, 0x30, 0x3a, 0x34, 0x66, + 0x3a, 0x31, 0x35, 0x3a, 0x61, 0x34, 0x3a, 0x38, 0x62, 0x3a, 0x65, 0x37, + 0x3a, 0x30, 0x39, 0x3a, 0x64, 0x63, 0x3a, 0x61, 0x35, 0x3a, 0x34, 0x32, + 0x3a, 0x61, 0x37, 0x3a, 0x65, 0x31, 0x3a, 0x64, 0x34, 0x3a, 0x62, 0x39, + 0x3a, 0x64, 0x66, 0x3a, 0x36, 0x66, 0x3a, 0x30, 0x35, 0x3a, 0x34, 0x35, + 0x3a, 0x32, 0x37, 0x3a, 0x65, 0x38, 0x3a, 0x30, 0x32, 0x3a, 0x65, 0x61, + 0x3a, 0x61, 0x39, 0x3a, 0x32, 0x64, 0x3a, 0x35, 0x39, 0x3a, 0x35, 0x34, + 0x3a, 0x34, 0x34, 0x3a, 0x32, 0x35, 0x3a, 0x38, 0x61, 0x3a, 0x66, 0x65, + 0x3a, 0x37, 0x31, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, + 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, + 0x4d, 0x54, 0x43, 0x43, 0x41, 0x78, 0x6d, 0x67, 0x41, 0x77, 0x49, 0x42, + 0x41, 0x67, 0x49, 0x42, 0x41, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, + 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, + 0x41, 0x44, 0x43, 0x42, 0x6c, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x31, 0x49, 0x78, + 0x0a, 0x52, 0x44, 0x42, 0x43, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, + 0x54, 0x4f, 0x30, 0x68, 0x6c, 0x62, 0x47, 0x78, 0x6c, 0x62, 0x6d, 0x6c, + 0x6a, 0x49, 0x45, 0x46, 0x6a, 0x59, 0x57, 0x52, 0x6c, 0x62, 0x57, 0x6c, + 0x6a, 0x49, 0x47, 0x46, 0x75, 0x5a, 0x43, 0x42, 0x53, 0x5a, 0x58, 0x4e, + 0x6c, 0x59, 0x58, 0x4a, 0x6a, 0x61, 0x43, 0x42, 0x4a, 0x62, 0x6e, 0x4e, + 0x30, 0x61, 0x58, 0x52, 0x31, 0x0a, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6e, + 0x4d, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x34, 0x67, 0x51, 0x58, + 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x55, + 0x41, 0x77, 0x50, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x7a, + 0x64, 0x49, 0x5a, 0x57, 0x78, 0x73, 0x5a, 0x57, 0x35, 0x70, 0x59, 0x79, + 0x42, 0x42, 0x59, 0x32, 0x46, 0x6b, 0x5a, 0x57, 0x31, 0x70, 0x0a, 0x59, + 0x79, 0x42, 0x68, 0x62, 0x6d, 0x51, 0x67, 0x55, 0x6d, 0x56, 0x7a, 0x5a, + 0x57, 0x46, 0x79, 0x59, 0x32, 0x67, 0x67, 0x53, 0x57, 0x35, 0x7a, 0x64, + 0x47, 0x6c, 0x30, 0x64, 0x58, 0x52, 0x70, 0x62, 0x32, 0x35, 0x7a, 0x49, + 0x46, 0x4a, 0x76, 0x62, 0x33, 0x52, 0x44, 0x51, 0x53, 0x41, 0x79, 0x4d, + 0x44, 0x45, 0x78, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x78, 0x4d, + 0x54, 0x49, 0x77, 0x0a, 0x4e, 0x6a, 0x45, 0x7a, 0x4e, 0x44, 0x6b, 0x31, + 0x4d, 0x6c, 0x6f, 0x58, 0x44, 0x54, 0x4d, 0x78, 0x4d, 0x54, 0x49, 0x77, + 0x4d, 0x54, 0x45, 0x7a, 0x4e, 0x44, 0x6b, 0x31, 0x4d, 0x6c, 0x6f, 0x77, + 0x67, 0x5a, 0x55, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x64, 0x53, 0x4d, 0x55, 0x51, 0x77, + 0x51, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x0a, 0x45, 0x7a, 0x74, + 0x49, 0x5a, 0x57, 0x78, 0x73, 0x5a, 0x57, 0x35, 0x70, 0x59, 0x79, 0x42, + 0x42, 0x59, 0x32, 0x46, 0x6b, 0x5a, 0x57, 0x31, 0x70, 0x59, 0x79, 0x42, + 0x68, 0x62, 0x6d, 0x51, 0x67, 0x55, 0x6d, 0x56, 0x7a, 0x5a, 0x57, 0x46, + 0x79, 0x59, 0x32, 0x67, 0x67, 0x53, 0x57, 0x35, 0x7a, 0x64, 0x47, 0x6c, + 0x30, 0x64, 0x58, 0x52, 0x70, 0x62, 0x32, 0x35, 0x7a, 0x49, 0x45, 0x4e, + 0x6c, 0x0a, 0x63, 0x6e, 0x51, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, + 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, 0x46, 0x41, 0x4d, 0x44, + 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x33, 0x53, 0x47, + 0x56, 0x73, 0x62, 0x47, 0x56, 0x75, 0x61, 0x57, 0x4d, 0x67, 0x51, 0x57, + 0x4e, 0x68, 0x5a, 0x47, 0x56, 0x74, 0x61, 0x57, 0x4d, 0x67, 0x59, 0x57, + 0x35, 0x6b, 0x49, 0x46, 0x4a, 0x6c, 0x0a, 0x63, 0x32, 0x56, 0x68, 0x63, + 0x6d, 0x4e, 0x6f, 0x49, 0x45, 0x6c, 0x75, 0x63, 0x33, 0x52, 0x70, 0x64, + 0x48, 0x56, 0x30, 0x61, 0x57, 0x39, 0x75, 0x63, 0x79, 0x42, 0x53, 0x62, + 0x32, 0x39, 0x30, 0x51, 0x30, 0x45, 0x67, 0x4d, 0x6a, 0x41, 0x78, 0x4d, + 0x54, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x0a, + 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, + 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4b, 0x6c, 0x54, + 0x41, 0x4f, 0x4d, 0x75, 0x70, 0x76, 0x61, 0x4f, 0x2b, 0x6d, 0x44, 0x59, + 0x4c, 0x5a, 0x55, 0x2b, 0x2b, 0x43, 0x77, 0x71, 0x56, 0x45, 0x37, 0x4e, + 0x75, 0x59, 0x52, 0x68, 0x6c, 0x46, 0x68, 0x50, 0x6a, 0x7a, 0x32, 0x4c, + 0x35, 0x45, 0x50, 0x7a, 0x0a, 0x64, 0x59, 0x6d, 0x4e, 0x55, 0x65, 0x54, + 0x44, 0x4e, 0x39, 0x4b, 0x4b, 0x69, 0x45, 0x31, 0x35, 0x48, 0x72, 0x63, + 0x53, 0x33, 0x55, 0x4e, 0x34, 0x53, 0x6f, 0x71, 0x53, 0x35, 0x74, 0x64, + 0x49, 0x31, 0x51, 0x2b, 0x6b, 0x4f, 0x69, 0x6c, 0x45, 0x4e, 0x62, 0x67, + 0x48, 0x39, 0x6d, 0x67, 0x64, 0x56, 0x63, 0x30, 0x34, 0x55, 0x66, 0x43, + 0x4d, 0x4a, 0x44, 0x47, 0x46, 0x72, 0x34, 0x50, 0x4a, 0x0a, 0x66, 0x65, + 0x6c, 0x33, 0x72, 0x2b, 0x30, 0x61, 0x65, 0x35, 0x30, 0x58, 0x2b, 0x62, + 0x4f, 0x64, 0x4f, 0x46, 0x41, 0x50, 0x70, 0x6c, 0x70, 0x35, 0x6b, 0x59, + 0x43, 0x76, 0x4e, 0x36, 0x36, 0x6d, 0x30, 0x7a, 0x48, 0x37, 0x74, 0x53, + 0x59, 0x4a, 0x6e, 0x54, 0x78, 0x61, 0x37, 0x31, 0x48, 0x46, 0x4b, 0x39, + 0x2b, 0x57, 0x58, 0x65, 0x73, 0x79, 0x48, 0x67, 0x4c, 0x61, 0x63, 0x45, + 0x6e, 0x73, 0x0a, 0x62, 0x67, 0x7a, 0x49, 0x6d, 0x6a, 0x65, 0x4e, 0x39, + 0x2f, 0x45, 0x32, 0x59, 0x45, 0x73, 0x6d, 0x4c, 0x49, 0x4b, 0x65, 0x30, + 0x48, 0x6a, 0x7a, 0x44, 0x51, 0x39, 0x6a, 0x70, 0x46, 0x45, 0x77, 0x34, + 0x66, 0x6b, 0x72, 0x4a, 0x78, 0x49, 0x48, 0x32, 0x4f, 0x71, 0x39, 0x47, + 0x47, 0x4b, 0x59, 0x73, 0x46, 0x6b, 0x33, 0x66, 0x62, 0x37, 0x75, 0x38, + 0x79, 0x42, 0x52, 0x51, 0x6c, 0x71, 0x44, 0x0a, 0x37, 0x35, 0x4f, 0x36, + 0x61, 0x52, 0x58, 0x78, 0x59, 0x70, 0x32, 0x66, 0x6d, 0x54, 0x6d, 0x43, + 0x6f, 0x62, 0x64, 0x30, 0x4c, 0x6f, 0x76, 0x55, 0x78, 0x51, 0x74, 0x37, + 0x4c, 0x2f, 0x44, 0x49, 0x43, 0x74, 0x6f, 0x39, 0x65, 0x51, 0x71, 0x61, + 0x6b, 0x78, 0x79, 0x6c, 0x4b, 0x48, 0x4a, 0x7a, 0x6b, 0x55, 0x4f, 0x61, + 0x70, 0x39, 0x46, 0x4e, 0x68, 0x59, 0x53, 0x35, 0x71, 0x58, 0x53, 0x50, + 0x0a, 0x46, 0x45, 0x44, 0x48, 0x33, 0x4e, 0x36, 0x73, 0x51, 0x57, 0x52, + 0x73, 0x74, 0x42, 0x6d, 0x62, 0x41, 0x6d, 0x4e, 0x74, 0x4a, 0x47, 0x53, + 0x50, 0x52, 0x4c, 0x49, 0x6c, 0x36, 0x73, 0x35, 0x64, 0x64, 0x41, 0x78, + 0x6a, 0x4d, 0x6c, 0x79, 0x4e, 0x68, 0x2b, 0x55, 0x43, 0x41, 0x77, 0x45, + 0x41, 0x41, 0x61, 0x4f, 0x42, 0x69, 0x54, 0x43, 0x42, 0x68, 0x6a, 0x41, + 0x50, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, + 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, + 0x73, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x51, 0x45, 0x41, 0x77, + 0x49, 0x42, 0x42, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, + 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x70, 0x70, 0x46, 0x43, 0x2f, 0x52, + 0x4e, 0x68, 0x53, 0x69, 0x4f, 0x65, 0x43, 0x4b, 0x51, 0x70, 0x0a, 0x35, + 0x64, 0x67, 0x54, 0x42, 0x43, 0x50, 0x75, 0x51, 0x53, 0x55, 0x77, 0x52, + 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x65, 0x42, 0x45, 0x41, 0x77, 0x50, + 0x71, 0x41, 0x38, 0x4d, 0x41, 0x57, 0x43, 0x41, 0x79, 0x35, 0x6e, 0x63, + 0x6a, 0x41, 0x46, 0x67, 0x67, 0x4d, 0x75, 0x5a, 0x58, 0x55, 0x77, 0x42, + 0x6f, 0x49, 0x45, 0x4c, 0x6d, 0x56, 0x6b, 0x64, 0x54, 0x41, 0x47, 0x67, + 0x67, 0x51, 0x75, 0x0a, 0x62, 0x33, 0x4a, 0x6e, 0x4d, 0x41, 0x57, 0x42, + 0x41, 0x79, 0x35, 0x6e, 0x63, 0x6a, 0x41, 0x46, 0x67, 0x51, 0x4d, 0x75, + 0x5a, 0x58, 0x55, 0x77, 0x42, 0x6f, 0x45, 0x45, 0x4c, 0x6d, 0x56, 0x6b, + 0x64, 0x54, 0x41, 0x47, 0x67, 0x51, 0x51, 0x75, 0x62, 0x33, 0x4a, 0x6e, + 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, + 0x44, 0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x0a, 0x41, 0x34, 0x49, + 0x42, 0x41, 0x51, 0x41, 0x66, 0x37, 0x33, 0x6c, 0x42, 0x34, 0x58, 0x74, + 0x75, 0x50, 0x37, 0x4b, 0x4d, 0x68, 0x6a, 0x64, 0x43, 0x53, 0x6b, 0x34, + 0x63, 0x4e, 0x78, 0x36, 0x4e, 0x5a, 0x72, 0x6f, 0x6b, 0x67, 0x63, 0x6c, + 0x50, 0x45, 0x67, 0x38, 0x68, 0x77, 0x41, 0x4f, 0x58, 0x68, 0x69, 0x56, + 0x74, 0x58, 0x64, 0x4d, 0x69, 0x4b, 0x61, 0x68, 0x73, 0x6f, 0x67, 0x32, + 0x70, 0x0a, 0x36, 0x7a, 0x30, 0x47, 0x57, 0x35, 0x6b, 0x36, 0x78, 0x38, + 0x7a, 0x44, 0x6d, 0x6a, 0x52, 0x2f, 0x71, 0x77, 0x37, 0x49, 0x54, 0x68, + 0x7a, 0x68, 0x2b, 0x75, 0x54, 0x63, 0x7a, 0x51, 0x32, 0x2b, 0x76, 0x79, + 0x54, 0x2b, 0x62, 0x4f, 0x64, 0x72, 0x77, 0x67, 0x33, 0x49, 0x42, 0x70, + 0x35, 0x4f, 0x6a, 0x57, 0x45, 0x6f, 0x70, 0x6d, 0x72, 0x39, 0x35, 0x66, + 0x5a, 0x69, 0x36, 0x68, 0x67, 0x38, 0x0a, 0x54, 0x71, 0x42, 0x54, 0x6e, + 0x62, 0x49, 0x36, 0x6e, 0x4f, 0x75, 0x6c, 0x6e, 0x4a, 0x45, 0x57, 0x74, + 0x6b, 0x32, 0x43, 0x34, 0x41, 0x77, 0x46, 0x53, 0x4b, 0x6c, 0x73, 0x39, + 0x63, 0x7a, 0x34, 0x79, 0x35, 0x31, 0x4a, 0x74, 0x50, 0x41, 0x43, 0x70, + 0x66, 0x31, 0x77, 0x41, 0x2b, 0x32, 0x4b, 0x49, 0x61, 0x57, 0x75, 0x45, + 0x34, 0x5a, 0x4a, 0x77, 0x7a, 0x4e, 0x7a, 0x76, 0x6f, 0x63, 0x37, 0x0a, + 0x64, 0x49, 0x73, 0x58, 0x52, 0x53, 0x5a, 0x4d, 0x46, 0x70, 0x47, 0x44, + 0x2f, 0x6d, 0x64, 0x39, 0x7a, 0x55, 0x31, 0x6a, 0x5a, 0x2f, 0x72, 0x7a, + 0x41, 0x78, 0x4b, 0x57, 0x65, 0x41, 0x61, 0x4e, 0x73, 0x57, 0x66, 0x74, + 0x6a, 0x6a, 0x2b, 0x2b, 0x6e, 0x30, 0x38, 0x43, 0x39, 0x62, 0x4d, 0x4a, + 0x4c, 0x2f, 0x4e, 0x4d, 0x68, 0x39, 0x38, 0x71, 0x79, 0x35, 0x56, 0x38, + 0x41, 0x63, 0x79, 0x73, 0x0a, 0x4e, 0x6e, 0x71, 0x2f, 0x6f, 0x6e, 0x4e, + 0x36, 0x39, 0x34, 0x2f, 0x42, 0x74, 0x5a, 0x71, 0x68, 0x46, 0x4c, 0x4b, + 0x50, 0x4d, 0x35, 0x38, 0x4e, 0x37, 0x79, 0x4c, 0x63, 0x5a, 0x6e, 0x75, + 0x45, 0x76, 0x55, 0x55, 0x58, 0x42, 0x6a, 0x30, 0x38, 0x79, 0x72, 0x6c, + 0x33, 0x4e, 0x49, 0x2f, 0x4b, 0x36, 0x73, 0x38, 0x2f, 0x4d, 0x54, 0x37, + 0x6a, 0x69, 0x4f, 0x4f, 0x41, 0x53, 0x53, 0x58, 0x49, 0x0a, 0x6c, 0x37, + 0x57, 0x64, 0x6d, 0x70, 0x6c, 0x4e, 0x73, 0x44, 0x7a, 0x34, 0x53, 0x67, + 0x43, 0x62, 0x5a, 0x4e, 0x32, 0x66, 0x4f, 0x55, 0x76, 0x52, 0x4a, 0x39, + 0x65, 0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x63, 0x74, 0x61, 0x6c, + 0x69, 0x73, 0x20, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x20, 0x4f, 0x3d, 0x41, 0x63, 0x74, 0x61, 0x6c, 0x69, 0x73, 0x20, + 0x53, 0x2e, 0x70, 0x2e, 0x41, 0x2e, 0x2f, 0x30, 0x33, 0x33, 0x35, 0x38, + 0x35, 0x32, 0x30, 0x39, 0x36, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x63, 0x74, + 0x61, 0x6c, 0x69, 0x73, 0x20, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x41, 0x63, 0x74, 0x61, 0x6c, 0x69, + 0x73, 0x20, 0x53, 0x2e, 0x70, 0x2e, 0x41, 0x2e, 0x2f, 0x30, 0x33, 0x33, + 0x35, 0x38, 0x35, 0x32, 0x30, 0x39, 0x36, 0x37, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, 0x63, 0x74, 0x61, 0x6c, + 0x69, 0x73, 0x20, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x36, 0x32, 0x37, 0x31, 0x38, 0x34, 0x34, 0x37, 0x37, 0x32, 0x34, + 0x32, 0x34, 0x37, 0x37, 0x30, 0x35, 0x30, 0x38, 0x0a, 0x23, 0x20, 0x4d, + 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x39, 0x3a, 0x63, 0x31, 0x3a, 0x30, 0x64, + 0x3a, 0x34, 0x66, 0x3a, 0x30, 0x37, 0x3a, 0x61, 0x33, 0x3a, 0x31, 0x62, + 0x3a, 0x63, 0x33, 0x3a, 0x66, 0x65, 0x3a, 0x35, 0x36, 0x3a, 0x33, 0x64, + 0x3a, 0x30, 0x34, 0x3a, 0x62, 0x63, 0x3a, 0x31, 0x31, 0x3a, 0x66, 0x36, + 0x3a, 0x61, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x66, 0x33, 0x3a, 0x37, 0x33, 0x3a, 0x62, 0x33, 0x3a, 0x38, 0x37, 0x3a, + 0x30, 0x36, 0x3a, 0x35, 0x61, 0x3a, 0x32, 0x38, 0x3a, 0x38, 0x34, 0x3a, + 0x38, 0x61, 0x3a, 0x66, 0x32, 0x3a, 0x66, 0x33, 0x3a, 0x34, 0x61, 0x3a, + 0x63, 0x65, 0x3a, 0x31, 0x39, 0x3a, 0x32, 0x62, 0x3a, 0x64, 0x64, 0x3a, + 0x63, 0x37, 0x3a, 0x38, 0x65, 0x3a, 0x39, 0x63, 0x3a, 0x61, 0x63, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x35, + 0x3a, 0x39, 0x32, 0x3a, 0x36, 0x30, 0x3a, 0x38, 0x34, 0x3a, 0x65, 0x63, + 0x3a, 0x39, 0x36, 0x3a, 0x33, 0x61, 0x3a, 0x36, 0x34, 0x3a, 0x62, 0x39, + 0x3a, 0x36, 0x65, 0x3a, 0x32, 0x61, 0x3a, 0x62, 0x65, 0x3a, 0x30, 0x31, + 0x3a, 0x63, 0x65, 0x3a, 0x30, 0x62, 0x3a, 0x61, 0x38, 0x3a, 0x36, 0x61, + 0x3a, 0x36, 0x34, 0x3a, 0x66, 0x62, 0x3a, 0x66, 0x65, 0x3a, 0x62, 0x63, + 0x3a, 0x63, 0x37, 0x3a, 0x61, 0x61, 0x3a, 0x62, 0x35, 0x3a, 0x61, 0x66, + 0x3a, 0x63, 0x31, 0x3a, 0x35, 0x35, 0x3a, 0x62, 0x33, 0x3a, 0x37, 0x66, + 0x3a, 0x64, 0x37, 0x3a, 0x36, 0x30, 0x3a, 0x36, 0x36, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x75, 0x7a, 0x43, 0x43, 0x41, 0x36, + 0x4f, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x49, 0x56, 0x77, + 0x6f, 0x52, 0x6c, 0x30, 0x4c, 0x45, 0x34, 0x38, 0x77, 0x77, 0x44, 0x51, + 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, + 0x45, 0x4c, 0x42, 0x51, 0x41, 0x77, 0x61, 0x7a, 0x45, 0x4c, 0x4d, 0x41, + 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x42, 0x68, 0x4d, 0x43, 0x53, + 0x56, 0x51, 0x78, 0x44, 0x6a, 0x41, 0x4d, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x63, 0x4d, 0x42, 0x55, 0x31, 0x70, 0x62, 0x47, 0x46, 0x75, 0x4d, + 0x53, 0x4d, 0x77, 0x49, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, + 0x42, 0x70, 0x42, 0x59, 0x33, 0x52, 0x68, 0x62, 0x47, 0x6c, 0x7a, 0x49, + 0x46, 0x4d, 0x75, 0x63, 0x43, 0x35, 0x42, 0x4c, 0x69, 0x38, 0x77, 0x0a, + 0x4d, 0x7a, 0x4d, 0x31, 0x4f, 0x44, 0x55, 0x79, 0x4d, 0x44, 0x6b, 0x32, + 0x4e, 0x7a, 0x45, 0x6e, 0x4d, 0x43, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x41, 0x77, 0x77, 0x65, 0x51, 0x57, 0x4e, 0x30, 0x59, 0x57, 0x78, 0x70, + 0x63, 0x79, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x5a, 0x57, 0x35, 0x30, + 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x53, + 0x62, 0x32, 0x39, 0x30, 0x0a, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x42, 0x34, + 0x58, 0x44, 0x54, 0x45, 0x78, 0x4d, 0x44, 0x6b, 0x79, 0x4d, 0x6a, 0x45, + 0x78, 0x4d, 0x6a, 0x49, 0x77, 0x4d, 0x6c, 0x6f, 0x58, 0x44, 0x54, 0x4d, + 0x77, 0x4d, 0x44, 0x6b, 0x79, 0x4d, 0x6a, 0x45, 0x78, 0x4d, 0x6a, 0x49, + 0x77, 0x4d, 0x6c, 0x6f, 0x77, 0x61, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x0a, 0x53, 0x56, + 0x51, 0x78, 0x44, 0x6a, 0x41, 0x4d, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x63, 0x4d, 0x42, 0x55, 0x31, 0x70, 0x62, 0x47, 0x46, 0x75, 0x4d, 0x53, + 0x4d, 0x77, 0x49, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, + 0x70, 0x42, 0x59, 0x33, 0x52, 0x68, 0x62, 0x47, 0x6c, 0x7a, 0x49, 0x46, + 0x4d, 0x75, 0x63, 0x43, 0x35, 0x42, 0x4c, 0x69, 0x38, 0x77, 0x4d, 0x7a, + 0x4d, 0x31, 0x0a, 0x4f, 0x44, 0x55, 0x79, 0x4d, 0x44, 0x6b, 0x32, 0x4e, + 0x7a, 0x45, 0x6e, 0x4d, 0x43, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, + 0x77, 0x77, 0x65, 0x51, 0x57, 0x4e, 0x30, 0x59, 0x57, 0x78, 0x70, 0x63, + 0x79, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x5a, 0x57, 0x35, 0x30, 0x61, + 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x53, 0x62, + 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x0a, 0x4d, 0x49, 0x49, 0x43, + 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, + 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, + 0x41, 0x67, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x43, 0x43, 0x67, 0x4b, 0x43, + 0x41, 0x67, 0x45, 0x41, 0x70, 0x38, 0x62, 0x45, 0x70, 0x53, 0x6d, 0x6b, + 0x4c, 0x4f, 0x2f, 0x6c, 0x47, 0x4d, 0x57, 0x77, 0x55, 0x4b, 0x4e, 0x76, + 0x0a, 0x55, 0x54, 0x75, 0x66, 0x43, 0x6c, 0x72, 0x4a, 0x77, 0x6b, 0x67, + 0x34, 0x43, 0x73, 0x49, 0x63, 0x6f, 0x42, 0x68, 0x2f, 0x6b, 0x62, 0x57, + 0x48, 0x75, 0x55, 0x41, 0x2f, 0x33, 0x52, 0x31, 0x6f, 0x48, 0x77, 0x69, + 0x44, 0x31, 0x53, 0x30, 0x65, 0x69, 0x4b, 0x44, 0x34, 0x6a, 0x31, 0x61, + 0x50, 0x62, 0x5a, 0x6b, 0x43, 0x6b, 0x70, 0x41, 0x57, 0x31, 0x56, 0x38, + 0x49, 0x62, 0x49, 0x6e, 0x58, 0x0a, 0x34, 0x61, 0x79, 0x38, 0x49, 0x4d, + 0x4b, 0x78, 0x34, 0x49, 0x4e, 0x52, 0x69, 0x6d, 0x6c, 0x4e, 0x41, 0x4a, + 0x5a, 0x61, 0x62, 0x79, 0x2f, 0x41, 0x52, 0x48, 0x36, 0x6a, 0x44, 0x75, + 0x53, 0x52, 0x7a, 0x56, 0x6a, 0x75, 0x33, 0x50, 0x76, 0x48, 0x48, 0x6b, + 0x56, 0x48, 0x33, 0x53, 0x65, 0x35, 0x43, 0x41, 0x47, 0x66, 0x70, 0x69, + 0x45, 0x64, 0x39, 0x55, 0x45, 0x74, 0x4c, 0x30, 0x7a, 0x39, 0x0a, 0x4b, + 0x4b, 0x33, 0x67, 0x69, 0x71, 0x30, 0x69, 0x74, 0x46, 0x5a, 0x6c, 0x6a, + 0x6f, 0x5a, 0x55, 0x6a, 0x35, 0x4e, 0x44, 0x4b, 0x64, 0x34, 0x35, 0x52, + 0x6e, 0x69, 0x6a, 0x4d, 0x43, 0x4f, 0x36, 0x7a, 0x66, 0x42, 0x39, 0x45, + 0x31, 0x66, 0x41, 0x58, 0x64, 0x4b, 0x44, 0x61, 0x30, 0x68, 0x4d, 0x78, + 0x4b, 0x75, 0x66, 0x67, 0x46, 0x70, 0x62, 0x4f, 0x72, 0x33, 0x4a, 0x70, + 0x79, 0x49, 0x2f, 0x0a, 0x67, 0x43, 0x63, 0x7a, 0x57, 0x77, 0x36, 0x33, + 0x69, 0x67, 0x78, 0x64, 0x42, 0x7a, 0x63, 0x49, 0x79, 0x32, 0x7a, 0x53, + 0x65, 0x6b, 0x63, 0x69, 0x52, 0x44, 0x58, 0x46, 0x7a, 0x4d, 0x77, 0x75, + 0x6a, 0x74, 0x30, 0x71, 0x37, 0x62, 0x64, 0x39, 0x5a, 0x67, 0x31, 0x66, + 0x59, 0x56, 0x45, 0x69, 0x56, 0x52, 0x76, 0x6a, 0x52, 0x75, 0x50, 0x6a, + 0x50, 0x64, 0x41, 0x31, 0x59, 0x70, 0x72, 0x62, 0x0a, 0x72, 0x78, 0x54, + 0x49, 0x57, 0x36, 0x48, 0x4d, 0x69, 0x52, 0x76, 0x68, 0x4d, 0x43, 0x62, + 0x38, 0x6f, 0x4a, 0x73, 0x66, 0x67, 0x61, 0x64, 0x48, 0x48, 0x77, 0x54, + 0x72, 0x6f, 0x7a, 0x6d, 0x53, 0x42, 0x70, 0x2b, 0x5a, 0x30, 0x37, 0x2f, + 0x54, 0x36, 0x6b, 0x39, 0x51, 0x6e, 0x42, 0x6e, 0x2b, 0x6c, 0x6f, 0x63, + 0x65, 0x50, 0x47, 0x58, 0x32, 0x6f, 0x78, 0x67, 0x6b, 0x67, 0x34, 0x59, + 0x51, 0x0a, 0x35, 0x31, 0x51, 0x2b, 0x71, 0x44, 0x70, 0x32, 0x4a, 0x45, + 0x2b, 0x42, 0x49, 0x63, 0x58, 0x6a, 0x44, 0x77, 0x4c, 0x34, 0x6b, 0x35, + 0x52, 0x48, 0x49, 0x4c, 0x76, 0x2b, 0x31, 0x41, 0x37, 0x54, 0x61, 0x4c, + 0x6e, 0x64, 0x78, 0x48, 0x71, 0x45, 0x67, 0x75, 0x4e, 0x54, 0x56, 0x48, + 0x6e, 0x64, 0x32, 0x35, 0x7a, 0x53, 0x38, 0x67, 0x65, 0x62, 0x4c, 0x72, + 0x61, 0x38, 0x50, 0x75, 0x32, 0x46, 0x0a, 0x62, 0x65, 0x38, 0x6c, 0x45, + 0x66, 0x4b, 0x58, 0x47, 0x6b, 0x4a, 0x68, 0x39, 0x30, 0x71, 0x58, 0x36, + 0x49, 0x75, 0x78, 0x45, 0x41, 0x66, 0x36, 0x5a, 0x59, 0x47, 0x79, 0x6f, + 0x6a, 0x6e, 0x50, 0x39, 0x7a, 0x7a, 0x2f, 0x47, 0x50, 0x76, 0x47, 0x38, + 0x56, 0x71, 0x4c, 0x57, 0x65, 0x49, 0x43, 0x72, 0x48, 0x75, 0x53, 0x30, + 0x45, 0x34, 0x55, 0x54, 0x31, 0x6c, 0x46, 0x39, 0x67, 0x78, 0x65, 0x0a, + 0x4b, 0x46, 0x2b, 0x77, 0x36, 0x44, 0x39, 0x46, 0x7a, 0x38, 0x2b, 0x76, + 0x6d, 0x32, 0x2f, 0x37, 0x68, 0x4e, 0x4e, 0x33, 0x57, 0x70, 0x56, 0x76, + 0x72, 0x4a, 0x53, 0x45, 0x6e, 0x75, 0x36, 0x38, 0x77, 0x45, 0x71, 0x50, + 0x53, 0x70, 0x50, 0x34, 0x52, 0x43, 0x48, 0x69, 0x4d, 0x55, 0x56, 0x68, + 0x55, 0x45, 0x34, 0x51, 0x32, 0x4f, 0x4d, 0x31, 0x66, 0x45, 0x77, 0x5a, + 0x74, 0x4e, 0x34, 0x46, 0x0a, 0x76, 0x36, 0x4d, 0x47, 0x6e, 0x38, 0x69, + 0x31, 0x7a, 0x65, 0x51, 0x66, 0x31, 0x78, 0x63, 0x47, 0x44, 0x58, 0x71, + 0x56, 0x64, 0x46, 0x55, 0x4e, 0x61, 0x42, 0x72, 0x38, 0x45, 0x42, 0x74, + 0x69, 0x5a, 0x4a, 0x31, 0x74, 0x34, 0x4a, 0x57, 0x67, 0x77, 0x35, 0x51, + 0x48, 0x56, 0x77, 0x30, 0x55, 0x35, 0x72, 0x30, 0x46, 0x2b, 0x37, 0x69, + 0x66, 0x35, 0x74, 0x2b, 0x4c, 0x34, 0x73, 0x62, 0x6e, 0x0a, 0x66, 0x70, + 0x62, 0x32, 0x55, 0x38, 0x57, 0x41, 0x4e, 0x46, 0x41, 0x6f, 0x57, 0x50, + 0x41, 0x53, 0x55, 0x48, 0x45, 0x58, 0x4d, 0x4c, 0x72, 0x6d, 0x65, 0x47, + 0x4f, 0x38, 0x39, 0x4c, 0x4b, 0x74, 0x6d, 0x79, 0x75, 0x79, 0x2f, 0x75, + 0x45, 0x35, 0x6a, 0x46, 0x36, 0x36, 0x43, 0x79, 0x43, 0x55, 0x33, 0x6e, + 0x75, 0x44, 0x75, 0x50, 0x2f, 0x6a, 0x56, 0x6f, 0x32, 0x33, 0x45, 0x65, + 0x6b, 0x37, 0x0a, 0x6a, 0x50, 0x4b, 0x78, 0x77, 0x56, 0x32, 0x64, 0x70, + 0x41, 0x74, 0x4d, 0x4b, 0x39, 0x6d, 0x79, 0x47, 0x50, 0x57, 0x31, 0x6e, + 0x30, 0x73, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, 0x6a, 0x4d, + 0x47, 0x45, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, + 0x42, 0x59, 0x45, 0x46, 0x46, 0x4c, 0x59, 0x69, 0x44, 0x72, 0x49, 0x6e, + 0x33, 0x68, 0x6d, 0x37, 0x59, 0x6e, 0x7a, 0x0a, 0x65, 0x7a, 0x68, 0x77, + 0x6c, 0x4d, 0x6b, 0x43, 0x41, 0x6a, 0x62, 0x51, 0x4d, 0x41, 0x38, 0x47, + 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, + 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x48, 0x77, 0x59, 0x44, + 0x56, 0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, + 0x55, 0x74, 0x69, 0x49, 0x4f, 0x73, 0x69, 0x66, 0x65, 0x47, 0x62, 0x74, + 0x0a, 0x69, 0x66, 0x4e, 0x37, 0x4f, 0x48, 0x43, 0x55, 0x79, 0x51, 0x49, + 0x43, 0x4e, 0x74, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, + 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, + 0x47, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, 0x34, 0x49, + 0x43, 0x41, 0x51, 0x41, 0x4c, 0x0a, 0x65, 0x33, 0x4b, 0x48, 0x77, 0x47, + 0x43, 0x6d, 0x53, 0x55, 0x79, 0x49, 0x57, 0x4f, 0x59, 0x64, 0x69, 0x50, + 0x63, 0x55, 0x5a, 0x45, 0x69, 0x6d, 0x32, 0x46, 0x67, 0x4b, 0x44, 0x6b, + 0x38, 0x54, 0x4e, 0x64, 0x38, 0x31, 0x48, 0x64, 0x54, 0x74, 0x42, 0x6a, + 0x48, 0x49, 0x67, 0x54, 0x35, 0x71, 0x31, 0x64, 0x30, 0x37, 0x47, 0x6a, + 0x4c, 0x75, 0x6b, 0x44, 0x30, 0x52, 0x30, 0x69, 0x37, 0x30, 0x0a, 0x6a, + 0x73, 0x4e, 0x6a, 0x4c, 0x69, 0x4e, 0x6d, 0x73, 0x47, 0x65, 0x2b, 0x62, + 0x37, 0x62, 0x41, 0x45, 0x7a, 0x6c, 0x67, 0x71, 0x71, 0x49, 0x30, 0x4a, + 0x5a, 0x4e, 0x31, 0x55, 0x74, 0x36, 0x6e, 0x6e, 0x61, 0x30, 0x4f, 0x68, + 0x34, 0x6c, 0x53, 0x63, 0x57, 0x6f, 0x57, 0x50, 0x42, 0x6b, 0x64, 0x67, + 0x2f, 0x69, 0x61, 0x4b, 0x57, 0x57, 0x2b, 0x39, 0x44, 0x2b, 0x61, 0x32, + 0x66, 0x44, 0x7a, 0x0a, 0x57, 0x6f, 0x63, 0x68, 0x63, 0x59, 0x42, 0x4e, + 0x79, 0x2b, 0x41, 0x34, 0x6d, 0x7a, 0x2b, 0x37, 0x2b, 0x75, 0x41, 0x77, + 0x54, 0x63, 0x2b, 0x47, 0x30, 0x32, 0x55, 0x51, 0x47, 0x52, 0x6a, 0x52, + 0x6c, 0x77, 0x4b, 0x78, 0x4b, 0x33, 0x4a, 0x43, 0x61, 0x4b, 0x79, 0x67, + 0x76, 0x55, 0x35, 0x61, 0x32, 0x68, 0x69, 0x2f, 0x61, 0x35, 0x69, 0x42, + 0x30, 0x50, 0x32, 0x61, 0x76, 0x6c, 0x34, 0x56, 0x0a, 0x53, 0x4d, 0x30, + 0x52, 0x46, 0x62, 0x6e, 0x41, 0x4b, 0x56, 0x79, 0x30, 0x36, 0x49, 0x6a, + 0x33, 0x50, 0x6a, 0x61, 0x75, 0x74, 0x32, 0x4c, 0x39, 0x48, 0x6d, 0x4c, + 0x65, 0x63, 0x48, 0x67, 0x51, 0x48, 0x45, 0x68, 0x62, 0x32, 0x72, 0x79, + 0x6b, 0x4f, 0x4c, 0x70, 0x6e, 0x37, 0x56, 0x55, 0x2b, 0x58, 0x6c, 0x66, + 0x66, 0x31, 0x41, 0x4e, 0x41, 0x54, 0x49, 0x47, 0x6b, 0x30, 0x6b, 0x39, + 0x6a, 0x0a, 0x70, 0x77, 0x6c, 0x43, 0x43, 0x52, 0x54, 0x38, 0x41, 0x4b, + 0x6e, 0x43, 0x67, 0x48, 0x4e, 0x50, 0x4c, 0x73, 0x42, 0x41, 0x32, 0x52, + 0x46, 0x37, 0x53, 0x4f, 0x70, 0x36, 0x41, 0x73, 0x44, 0x54, 0x36, 0x79, + 0x67, 0x42, 0x4a, 0x6c, 0x68, 0x30, 0x77, 0x63, 0x42, 0x7a, 0x49, 0x6d, + 0x32, 0x54, 0x6c, 0x66, 0x30, 0x35, 0x66, 0x62, 0x73, 0x71, 0x34, 0x2f, + 0x61, 0x43, 0x34, 0x79, 0x79, 0x58, 0x0a, 0x58, 0x30, 0x34, 0x66, 0x6b, + 0x5a, 0x54, 0x36, 0x2f, 0x69, 0x79, 0x6a, 0x32, 0x48, 0x59, 0x61, 0x75, + 0x45, 0x32, 0x79, 0x4f, 0x45, 0x2b, 0x62, 0x2b, 0x68, 0x31, 0x49, 0x59, + 0x48, 0x6b, 0x6d, 0x34, 0x76, 0x50, 0x39, 0x71, 0x64, 0x43, 0x61, 0x36, + 0x48, 0x43, 0x50, 0x53, 0x58, 0x72, 0x57, 0x35, 0x62, 0x30, 0x4b, 0x44, + 0x74, 0x73, 0x74, 0x38, 0x34, 0x32, 0x2f, 0x36, 0x2b, 0x4f, 0x6b, 0x0a, + 0x66, 0x63, 0x76, 0x48, 0x6c, 0x58, 0x48, 0x6f, 0x32, 0x71, 0x4e, 0x38, + 0x78, 0x63, 0x4c, 0x34, 0x64, 0x4a, 0x49, 0x45, 0x47, 0x34, 0x61, 0x73, + 0x70, 0x43, 0x4a, 0x54, 0x51, 0x4c, 0x61, 0x73, 0x2f, 0x6b, 0x78, 0x32, + 0x7a, 0x2f, 0x75, 0x55, 0x4d, 0x73, 0x41, 0x31, 0x6e, 0x33, 0x59, 0x2f, + 0x62, 0x75, 0x57, 0x51, 0x62, 0x71, 0x43, 0x6d, 0x4a, 0x71, 0x4b, 0x34, + 0x4c, 0x4c, 0x37, 0x52, 0x0a, 0x4b, 0x34, 0x58, 0x39, 0x70, 0x32, 0x6a, + 0x49, 0x75, 0x67, 0x45, 0x72, 0x73, 0x57, 0x78, 0x30, 0x48, 0x62, 0x68, + 0x7a, 0x6c, 0x65, 0x66, 0x75, 0x74, 0x38, 0x63, 0x6c, 0x38, 0x41, 0x42, + 0x4d, 0x41, 0x4c, 0x4a, 0x2b, 0x74, 0x67, 0x75, 0x4c, 0x48, 0x50, 0x50, + 0x41, 0x55, 0x4a, 0x34, 0x6c, 0x75, 0x65, 0x41, 0x49, 0x33, 0x6a, 0x5a, + 0x6d, 0x2f, 0x7a, 0x65, 0x6c, 0x30, 0x62, 0x74, 0x55, 0x0a, 0x5a, 0x43, + 0x7a, 0x4a, 0x4a, 0x37, 0x56, 0x4c, 0x6b, 0x6e, 0x35, 0x6c, 0x2f, 0x39, + 0x4d, 0x74, 0x34, 0x62, 0x6c, 0x4f, 0x76, 0x48, 0x2b, 0x6b, 0x51, 0x53, + 0x47, 0x51, 0x51, 0x58, 0x65, 0x6d, 0x4f, 0x52, 0x2f, 0x71, 0x6e, 0x75, + 0x4f, 0x66, 0x30, 0x47, 0x5a, 0x76, 0x42, 0x65, 0x79, 0x71, 0x64, 0x6e, + 0x36, 0x2f, 0x61, 0x78, 0x61, 0x67, 0x36, 0x37, 0x58, 0x48, 0x2f, 0x4a, + 0x4a, 0x55, 0x0a, 0x4c, 0x79, 0x73, 0x52, 0x4a, 0x79, 0x55, 0x33, 0x65, + 0x45, 0x78, 0x52, 0x61, 0x72, 0x44, 0x7a, 0x7a, 0x46, 0x68, 0x64, 0x46, + 0x50, 0x46, 0x71, 0x53, 0x42, 0x58, 0x2f, 0x77, 0x67, 0x65, 0x32, 0x73, + 0x59, 0x30, 0x50, 0x6a, 0x6c, 0x78, 0x51, 0x52, 0x72, 0x4d, 0x39, 0x76, + 0x77, 0x47, 0x59, 0x54, 0x37, 0x4a, 0x5a, 0x56, 0x45, 0x63, 0x2b, 0x4e, + 0x48, 0x74, 0x34, 0x62, 0x56, 0x61, 0x54, 0x0a, 0x4c, 0x6e, 0x50, 0x71, + 0x5a, 0x69, 0x68, 0x34, 0x7a, 0x52, 0x30, 0x55, 0x76, 0x36, 0x43, 0x50, + 0x4c, 0x79, 0x36, 0x34, 0x4c, 0x6f, 0x37, 0x79, 0x46, 0x49, 0x72, 0x4d, + 0x36, 0x62, 0x56, 0x38, 0x2b, 0x32, 0x79, 0x64, 0x44, 0x4b, 0x58, 0x68, + 0x6c, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x4f, 0x3d, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x20, + 0x4f, 0x55, 0x3d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x69, 0x73, 0x20, 0x46, + 0x50, 0x53, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x0a, 0x23, + 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x4f, 0x3d, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, + 0x74, 0x65, 0x64, 0x20, 0x4f, 0x55, 0x3d, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x69, 0x73, 0x20, 0x46, 0x50, 0x53, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x54, 0x72, 0x75, 0x73, 0x74, 0x69, 0x73, 0x20, 0x46, 0x50, 0x53, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, + 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x33, 0x36, 0x30, 0x35, + 0x33, 0x36, 0x34, 0x30, 0x33, 0x37, 0x35, 0x33, 0x39, 0x39, 0x30, 0x33, + 0x34, 0x33, 0x30, 0x34, 0x37, 0x32, 0x34, 0x39, 0x38, 0x38, 0x39, 0x37, + 0x35, 0x35, 0x36, 0x33, 0x37, 0x31, 0x30, 0x35, 0x35, 0x33, 0x0a, 0x23, + 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x30, 0x3a, 0x63, 0x39, 0x3a, + 0x65, 0x37, 0x3a, 0x31, 0x65, 0x3a, 0x36, 0x62, 0x3a, 0x65, 0x36, 0x3a, + 0x31, 0x34, 0x3a, 0x65, 0x62, 0x3a, 0x36, 0x35, 0x3a, 0x62, 0x32, 0x3a, + 0x31, 0x36, 0x3a, 0x36, 0x39, 0x3a, 0x32, 0x30, 0x3a, 0x33, 0x31, 0x3a, + 0x36, 0x37, 0x3a, 0x34, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x33, 0x62, 0x3a, 0x63, 0x30, 0x3a, 0x33, 0x38, 0x3a, 0x30, + 0x62, 0x3a, 0x33, 0x33, 0x3a, 0x63, 0x33, 0x3a, 0x66, 0x36, 0x3a, 0x61, + 0x36, 0x3a, 0x30, 0x63, 0x3a, 0x38, 0x36, 0x3a, 0x31, 0x35, 0x3a, 0x32, + 0x32, 0x3a, 0x39, 0x33, 0x3a, 0x64, 0x39, 0x3a, 0x64, 0x66, 0x3a, 0x66, + 0x35, 0x3a, 0x34, 0x62, 0x3a, 0x38, 0x31, 0x3a, 0x63, 0x30, 0x3a, 0x30, + 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x63, 0x31, 0x3a, 0x62, 0x34, 0x3a, 0x38, 0x32, 0x3a, 0x39, 0x39, 0x3a, + 0x61, 0x62, 0x3a, 0x61, 0x35, 0x3a, 0x32, 0x30, 0x3a, 0x38, 0x66, 0x3a, + 0x65, 0x39, 0x3a, 0x36, 0x33, 0x3a, 0x30, 0x61, 0x3a, 0x63, 0x65, 0x3a, + 0x35, 0x35, 0x3a, 0x63, 0x61, 0x3a, 0x36, 0x38, 0x3a, 0x61, 0x30, 0x3a, + 0x33, 0x65, 0x3a, 0x64, 0x61, 0x3a, 0x35, 0x61, 0x3a, 0x35, 0x31, 0x3a, + 0x39, 0x63, 0x3a, 0x38, 0x38, 0x3a, 0x30, 0x32, 0x3a, 0x61, 0x30, 0x3a, + 0x64, 0x33, 0x3a, 0x61, 0x36, 0x3a, 0x37, 0x33, 0x3a, 0x62, 0x65, 0x3a, + 0x38, 0x66, 0x3a, 0x38, 0x65, 0x3a, 0x35, 0x35, 0x3a, 0x37, 0x64, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x5a, 0x7a, 0x43, 0x43, + 0x41, 0x6b, 0x2b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, + 0x47, 0x78, 0x2b, 0x74, 0x74, 0x69, 0x44, 0x35, 0x4a, 0x4e, 0x4d, 0x32, + 0x61, 0x2f, 0x66, 0x48, 0x38, 0x59, 0x79, 0x67, 0x57, 0x54, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x46, 0x0a, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, + 0x48, 0x51, 0x6a, 0x45, 0x59, 0x4d, 0x42, 0x59, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x68, 0x4d, 0x50, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, + 0x70, 0x63, 0x79, 0x42, 0x4d, 0x61, 0x57, 0x31, 0x70, 0x64, 0x47, 0x56, + 0x6b, 0x4d, 0x52, 0x77, 0x77, 0x47, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x4c, 0x0a, 0x45, 0x78, 0x4e, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, + 0x6c, 0x7a, 0x49, 0x45, 0x5a, 0x51, 0x55, 0x79, 0x42, 0x53, 0x62, 0x32, + 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, + 0x41, 0x7a, 0x4d, 0x54, 0x49, 0x79, 0x4d, 0x7a, 0x45, 0x79, 0x4d, 0x54, + 0x51, 0x77, 0x4e, 0x6c, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x30, 0x4d, 0x44, + 0x45, 0x79, 0x4d, 0x54, 0x45, 0x78, 0x0a, 0x4d, 0x7a, 0x59, 0x31, 0x4e, + 0x46, 0x6f, 0x77, 0x52, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x30, 0x49, 0x78, 0x47, + 0x44, 0x41, 0x57, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, + 0x31, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x61, 0x58, 0x4d, 0x67, 0x54, + 0x47, 0x6c, 0x74, 0x61, 0x58, 0x52, 0x6c, 0x5a, 0x44, 0x45, 0x63, 0x0a, + 0x4d, 0x42, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x54, + 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x70, 0x63, 0x79, 0x42, 0x47, + 0x55, 0x46, 0x4d, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, + 0x51, 0x54, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, + 0x42, 0x51, 0x41, 0x44, 0x0a, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, + 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4d, 0x56, + 0x51, 0x65, 0x35, 0x34, 0x37, 0x4e, 0x64, 0x44, 0x66, 0x78, 0x49, 0x7a, + 0x4e, 0x6a, 0x70, 0x76, 0x74, 0x6f, 0x38, 0x41, 0x32, 0x6d, 0x66, 0x52, + 0x43, 0x36, 0x71, 0x63, 0x2b, 0x67, 0x49, 0x4d, 0x50, 0x70, 0x71, 0x64, + 0x5a, 0x68, 0x38, 0x6d, 0x51, 0x52, 0x55, 0x4e, 0x2b, 0x0a, 0x41, 0x4f, + 0x71, 0x47, 0x65, 0x53, 0x6f, 0x44, 0x76, 0x54, 0x30, 0x33, 0x6d, 0x59, + 0x6c, 0x6d, 0x74, 0x2b, 0x57, 0x4b, 0x56, 0x6f, 0x61, 0x54, 0x6e, 0x47, + 0x68, 0x4c, 0x61, 0x41, 0x53, 0x4d, 0x6b, 0x35, 0x4d, 0x43, 0x50, 0x6a, + 0x44, 0x53, 0x4e, 0x7a, 0x6f, 0x69, 0x59, 0x59, 0x6b, 0x63, 0x68, 0x55, + 0x35, 0x39, 0x6a, 0x39, 0x57, 0x76, 0x65, 0x7a, 0x58, 0x32, 0x66, 0x69, + 0x68, 0x48, 0x0a, 0x69, 0x54, 0x48, 0x63, 0x44, 0x6e, 0x6c, 0x6b, 0x48, + 0x35, 0x6e, 0x53, 0x57, 0x37, 0x72, 0x2b, 0x66, 0x32, 0x43, 0x2f, 0x72, + 0x65, 0x76, 0x6e, 0x50, 0x44, 0x67, 0x70, 0x61, 0x69, 0x2f, 0x6c, 0x6b, + 0x51, 0x74, 0x56, 0x2f, 0x2b, 0x78, 0x76, 0x57, 0x4e, 0x55, 0x74, 0x79, + 0x64, 0x35, 0x4d, 0x5a, 0x6e, 0x47, 0x50, 0x44, 0x4e, 0x63, 0x45, 0x32, + 0x67, 0x66, 0x6d, 0x48, 0x68, 0x6a, 0x6a, 0x0a, 0x76, 0x53, 0x6b, 0x43, + 0x71, 0x50, 0x6f, 0x63, 0x34, 0x56, 0x75, 0x35, 0x67, 0x36, 0x68, 0x42, + 0x53, 0x4c, 0x77, 0x61, 0x63, 0x59, 0x33, 0x6e, 0x59, 0x75, 0x55, 0x74, + 0x73, 0x75, 0x76, 0x66, 0x66, 0x4d, 0x2f, 0x62, 0x71, 0x31, 0x72, 0x4b, + 0x4d, 0x66, 0x46, 0x4d, 0x49, 0x76, 0x4d, 0x46, 0x45, 0x2f, 0x65, 0x43, + 0x2b, 0x58, 0x4e, 0x35, 0x44, 0x4c, 0x37, 0x58, 0x53, 0x78, 0x7a, 0x41, + 0x0a, 0x30, 0x52, 0x55, 0x38, 0x6b, 0x30, 0x46, 0x6b, 0x30, 0x65, 0x61, + 0x2b, 0x49, 0x78, 0x63, 0x69, 0x41, 0x49, 0x6c, 0x65, 0x48, 0x32, 0x75, + 0x6c, 0x72, 0x47, 0x36, 0x6e, 0x53, 0x34, 0x7a, 0x74, 0x6f, 0x33, 0x4c, + 0x6d, 0x72, 0x32, 0x4e, 0x4e, 0x4c, 0x34, 0x58, 0x53, 0x46, 0x44, 0x57, + 0x61, 0x4c, 0x6b, 0x36, 0x4d, 0x36, 0x6a, 0x4b, 0x59, 0x4b, 0x49, 0x61, + 0x68, 0x6b, 0x51, 0x6c, 0x42, 0x0a, 0x4f, 0x72, 0x54, 0x68, 0x34, 0x2f, + 0x4c, 0x36, 0x38, 0x4d, 0x6b, 0x4b, 0x6f, 0x6b, 0x48, 0x64, 0x71, 0x65, + 0x4d, 0x44, 0x78, 0x34, 0x67, 0x56, 0x4f, 0x78, 0x7a, 0x55, 0x47, 0x70, + 0x54, 0x58, 0x6e, 0x32, 0x52, 0x5a, 0x45, 0x6d, 0x30, 0x43, 0x41, 0x77, + 0x45, 0x41, 0x41, 0x61, 0x4e, 0x54, 0x4d, 0x46, 0x45, 0x77, 0x44, 0x77, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x0a, 0x42, + 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x66, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, + 0x42, 0x53, 0x36, 0x2b, 0x6e, 0x45, 0x6c, 0x65, 0x59, 0x74, 0x58, 0x51, + 0x53, 0x55, 0x68, 0x68, 0x67, 0x74, 0x78, 0x36, 0x37, 0x4a, 0x6b, 0x44, + 0x6f, 0x73, 0x68, 0x5a, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x51, 0x34, 0x45, 0x0a, 0x46, 0x67, 0x51, 0x55, 0x75, 0x76, 0x70, 0x78, + 0x4a, 0x58, 0x6d, 0x4c, 0x56, 0x30, 0x45, 0x6c, 0x49, 0x59, 0x59, 0x4c, + 0x63, 0x65, 0x75, 0x79, 0x5a, 0x41, 0x36, 0x4c, 0x49, 0x57, 0x63, 0x77, + 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, + 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, + 0x41, 0x48, 0x35, 0x59, 0x2f, 0x2f, 0x30, 0x31, 0x0a, 0x47, 0x58, 0x32, + 0x63, 0x47, 0x45, 0x2b, 0x65, 0x73, 0x43, 0x75, 0x38, 0x6a, 0x6f, 0x77, + 0x55, 0x2f, 0x79, 0x79, 0x67, 0x32, 0x6b, 0x64, 0x62, 0x77, 0x2b, 0x2b, + 0x42, 0x4c, 0x61, 0x38, 0x46, 0x36, 0x6e, 0x52, 0x49, 0x57, 0x2f, 0x4d, + 0x2b, 0x54, 0x67, 0x66, 0x48, 0x62, 0x63, 0x57, 0x7a, 0x6b, 0x38, 0x38, + 0x69, 0x4e, 0x56, 0x79, 0x32, 0x50, 0x33, 0x55, 0x6e, 0x58, 0x77, 0x6d, + 0x57, 0x0a, 0x7a, 0x61, 0x44, 0x2b, 0x76, 0x6b, 0x41, 0x4d, 0x58, 0x42, + 0x4a, 0x56, 0x2b, 0x4a, 0x4f, 0x43, 0x79, 0x69, 0x6e, 0x70, 0x58, 0x6a, + 0x39, 0x57, 0x56, 0x34, 0x73, 0x34, 0x4e, 0x76, 0x64, 0x46, 0x47, 0x6b, + 0x77, 0x6f, 0x7a, 0x5a, 0x35, 0x42, 0x75, 0x4f, 0x31, 0x57, 0x54, 0x49, + 0x53, 0x6b, 0x51, 0x4d, 0x69, 0x34, 0x73, 0x4b, 0x55, 0x72, 0x61, 0x58, + 0x41, 0x45, 0x61, 0x73, 0x50, 0x34, 0x0a, 0x31, 0x42, 0x49, 0x79, 0x2b, + 0x51, 0x37, 0x44, 0x73, 0x64, 0x77, 0x79, 0x68, 0x45, 0x51, 0x73, 0x62, + 0x38, 0x74, 0x47, 0x44, 0x2b, 0x70, 0x6d, 0x51, 0x51, 0x39, 0x50, 0x38, + 0x56, 0x69, 0x6c, 0x70, 0x67, 0x30, 0x4e, 0x44, 0x32, 0x48, 0x65, 0x70, + 0x5a, 0x35, 0x64, 0x66, 0x57, 0x57, 0x68, 0x50, 0x42, 0x66, 0x6e, 0x71, + 0x46, 0x56, 0x4f, 0x37, 0x36, 0x44, 0x48, 0x37, 0x63, 0x5a, 0x45, 0x0a, + 0x66, 0x31, 0x54, 0x31, 0x6f, 0x2b, 0x43, 0x50, 0x38, 0x48, 0x78, 0x56, + 0x49, 0x6f, 0x38, 0x70, 0x74, 0x6f, 0x47, 0x6a, 0x34, 0x57, 0x31, 0x4f, + 0x4c, 0x42, 0x75, 0x41, 0x5a, 0x2b, 0x79, 0x74, 0x49, 0x4a, 0x38, 0x4d, + 0x59, 0x6d, 0x48, 0x56, 0x6c, 0x2f, 0x39, 0x44, 0x37, 0x53, 0x33, 0x42, + 0x32, 0x6c, 0x30, 0x70, 0x4b, 0x6f, 0x55, 0x2f, 0x72, 0x47, 0x58, 0x75, + 0x68, 0x67, 0x38, 0x46, 0x0a, 0x6a, 0x5a, 0x42, 0x66, 0x33, 0x2b, 0x36, + 0x66, 0x39, 0x4c, 0x2f, 0x75, 0x48, 0x66, 0x75, 0x59, 0x35, 0x48, 0x2b, + 0x51, 0x4b, 0x34, 0x52, 0x34, 0x45, 0x41, 0x35, 0x73, 0x53, 0x56, 0x50, + 0x76, 0x46, 0x56, 0x74, 0x6c, 0x52, 0x6b, 0x70, 0x64, 0x72, 0x37, 0x72, + 0x37, 0x4f, 0x6e, 0x49, 0x64, 0x7a, 0x66, 0x59, 0x6c, 0x69, 0x42, 0x36, + 0x58, 0x7a, 0x43, 0x47, 0x63, 0x4b, 0x51, 0x45, 0x4e, 0x0a, 0x5a, 0x65, + 0x74, 0x58, 0x32, 0x66, 0x4e, 0x58, 0x6c, 0x72, 0x74, 0x49, 0x7a, 0x59, + 0x45, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x42, 0x75, 0x79, 0x70, 0x61, + 0x73, 0x73, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x42, 0x75, 0x79, + 0x70, 0x61, 0x73, 0x73, 0x20, 0x41, 0x53, 0x2d, 0x39, 0x38, 0x33, 0x31, + 0x36, 0x33, 0x33, 0x32, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x42, 0x75, 0x79, 0x70, + 0x61, 0x73, 0x73, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x42, 0x75, + 0x79, 0x70, 0x61, 0x73, 0x73, 0x20, 0x41, 0x53, 0x2d, 0x39, 0x38, 0x33, + 0x31, 0x36, 0x33, 0x33, 0x32, 0x37, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x42, 0x75, 0x79, 0x70, 0x61, 0x73, 0x73, + 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x32, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x34, 0x36, 0x3a, 0x61, 0x37, 0x3a, 0x64, 0x32, 0x3a, 0x66, 0x65, + 0x3a, 0x34, 0x35, 0x3a, 0x66, 0x62, 0x3a, 0x36, 0x34, 0x3a, 0x35, 0x61, + 0x3a, 0x61, 0x38, 0x3a, 0x35, 0x39, 0x3a, 0x39, 0x30, 0x3a, 0x39, 0x62, + 0x3a, 0x37, 0x38, 0x3a, 0x34, 0x34, 0x3a, 0x39, 0x62, 0x3a, 0x32, 0x39, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x39, 0x3a, + 0x30, 0x61, 0x3a, 0x37, 0x35, 0x3a, 0x37, 0x34, 0x3a, 0x64, 0x65, 0x3a, + 0x38, 0x37, 0x3a, 0x30, 0x61, 0x3a, 0x34, 0x37, 0x3a, 0x66, 0x65, 0x3a, + 0x35, 0x38, 0x3a, 0x65, 0x65, 0x3a, 0x66, 0x36, 0x3a, 0x63, 0x37, 0x3a, + 0x36, 0x62, 0x3a, 0x65, 0x62, 0x3a, 0x63, 0x36, 0x3a, 0x30, 0x62, 0x3a, + 0x31, 0x32, 0x3a, 0x34, 0x30, 0x3a, 0x39, 0x39, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x61, 0x3a, 0x31, 0x31, + 0x3a, 0x34, 0x30, 0x3a, 0x32, 0x35, 0x3a, 0x31, 0x39, 0x3a, 0x37, 0x63, + 0x3a, 0x35, 0x62, 0x3a, 0x62, 0x39, 0x3a, 0x35, 0x64, 0x3a, 0x39, 0x34, + 0x3a, 0x65, 0x36, 0x3a, 0x33, 0x64, 0x3a, 0x35, 0x35, 0x3a, 0x63, 0x64, + 0x3a, 0x34, 0x33, 0x3a, 0x37, 0x39, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x37, + 0x3a, 0x62, 0x36, 0x3a, 0x34, 0x36, 0x3a, 0x62, 0x32, 0x3a, 0x33, 0x63, + 0x3a, 0x64, 0x66, 0x3a, 0x31, 0x31, 0x3a, 0x61, 0x64, 0x3a, 0x61, 0x34, + 0x3a, 0x61, 0x30, 0x3a, 0x30, 0x65, 0x3a, 0x66, 0x66, 0x3a, 0x31, 0x35, + 0x3a, 0x66, 0x62, 0x3a, 0x34, 0x38, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x46, 0x57, 0x54, 0x43, 0x43, 0x41, 0x30, 0x47, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x6a, 0x41, 0x4e, 0x42, + 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, + 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x4f, 0x4d, 0x51, 0x73, 0x77, 0x43, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x4f, 0x54, + 0x7a, 0x45, 0x64, 0x0a, 0x4d, 0x42, 0x73, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x67, 0x77, 0x55, 0x51, 0x6e, 0x56, 0x35, 0x63, 0x47, 0x46, 0x7a, + 0x63, 0x79, 0x42, 0x42, 0x55, 0x79, 0x30, 0x35, 0x4f, 0x44, 0x4d, 0x78, + 0x4e, 0x6a, 0x4d, 0x7a, 0x4d, 0x6a, 0x63, 0x78, 0x49, 0x44, 0x41, 0x65, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x46, 0x30, 0x4a, 0x31, + 0x65, 0x58, 0x42, 0x68, 0x63, 0x33, 0x4d, 0x67, 0x0a, 0x51, 0x32, 0x78, + 0x68, 0x63, 0x33, 0x4d, 0x67, 0x4d, 0x69, 0x42, 0x53, 0x62, 0x32, 0x39, + 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, + 0x77, 0x4d, 0x54, 0x41, 0x79, 0x4e, 0x6a, 0x41, 0x34, 0x4d, 0x7a, 0x67, + 0x77, 0x4d, 0x31, 0x6f, 0x58, 0x44, 0x54, 0x51, 0x77, 0x4d, 0x54, 0x41, + 0x79, 0x4e, 0x6a, 0x41, 0x34, 0x4d, 0x7a, 0x67, 0x77, 0x4d, 0x31, 0x6f, + 0x77, 0x0a, 0x54, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x54, 0x6b, 0x38, 0x78, 0x48, 0x54, + 0x41, 0x62, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x46, 0x45, + 0x4a, 0x31, 0x65, 0x58, 0x42, 0x68, 0x63, 0x33, 0x4d, 0x67, 0x51, 0x56, + 0x4d, 0x74, 0x4f, 0x54, 0x67, 0x7a, 0x4d, 0x54, 0x59, 0x7a, 0x4d, 0x7a, + 0x49, 0x33, 0x4d, 0x53, 0x41, 0x77, 0x0a, 0x48, 0x67, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x44, 0x44, 0x42, 0x64, 0x43, 0x64, 0x58, 0x6c, 0x77, 0x59, + 0x58, 0x4e, 0x7a, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x49, + 0x44, 0x49, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, + 0x54, 0x43, 0x43, 0x41, 0x69, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x0a, + 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x50, 0x41, 0x44, 0x43, 0x43, + 0x41, 0x67, 0x6f, 0x43, 0x67, 0x67, 0x49, 0x42, 0x41, 0x4e, 0x66, 0x48, + 0x58, 0x76, 0x66, 0x42, 0x42, 0x39, 0x52, 0x33, 0x2b, 0x30, 0x4d, 0x68, + 0x39, 0x50, 0x54, 0x31, 0x61, 0x65, 0x54, 0x75, 0x4d, 0x67, 0x48, 0x62, + 0x6f, 0x34, 0x59, 0x66, 0x35, 0x46, 0x6b, 0x4e, 0x75, 0x75, 0x64, 0x31, + 0x67, 0x31, 0x4c, 0x72, 0x0a, 0x36, 0x68, 0x78, 0x68, 0x46, 0x55, 0x69, + 0x37, 0x48, 0x51, 0x66, 0x4b, 0x6a, 0x4b, 0x36, 0x77, 0x33, 0x4a, 0x61, + 0x64, 0x36, 0x73, 0x4e, 0x67, 0x6b, 0x6f, 0x61, 0x43, 0x4b, 0x48, 0x4f, + 0x63, 0x56, 0x67, 0x62, 0x2f, 0x53, 0x32, 0x54, 0x77, 0x44, 0x43, 0x6f, + 0x33, 0x53, 0x62, 0x58, 0x6c, 0x7a, 0x77, 0x78, 0x38, 0x37, 0x76, 0x46, + 0x4b, 0x75, 0x33, 0x4d, 0x77, 0x5a, 0x66, 0x50, 0x56, 0x0a, 0x4c, 0x34, + 0x4f, 0x32, 0x66, 0x75, 0x50, 0x6e, 0x39, 0x5a, 0x36, 0x72, 0x59, 0x50, + 0x6e, 0x54, 0x38, 0x5a, 0x32, 0x53, 0x64, 0x49, 0x72, 0x6b, 0x48, 0x4a, + 0x61, 0x73, 0x57, 0x34, 0x44, 0x70, 0x74, 0x66, 0x51, 0x78, 0x68, 0x36, + 0x4e, 0x52, 0x2f, 0x4d, 0x64, 0x2b, 0x6f, 0x57, 0x2b, 0x4f, 0x55, 0x33, + 0x66, 0x55, 0x6c, 0x38, 0x46, 0x56, 0x4d, 0x35, 0x49, 0x2b, 0x47, 0x43, + 0x39, 0x31, 0x0a, 0x31, 0x4b, 0x32, 0x47, 0x53, 0x63, 0x75, 0x56, 0x72, + 0x31, 0x51, 0x47, 0x62, 0x4e, 0x67, 0x47, 0x45, 0x34, 0x31, 0x62, 0x2f, + 0x2b, 0x45, 0x6d, 0x47, 0x56, 0x6e, 0x41, 0x4a, 0x4c, 0x71, 0x42, 0x63, + 0x58, 0x6d, 0x51, 0x52, 0x46, 0x42, 0x6f, 0x4a, 0x4a, 0x52, 0x66, 0x75, + 0x4c, 0x4d, 0x52, 0x38, 0x53, 0x6c, 0x42, 0x59, 0x61, 0x4e, 0x42, 0x79, + 0x79, 0x4d, 0x32, 0x31, 0x63, 0x48, 0x78, 0x0a, 0x4d, 0x6c, 0x41, 0x51, + 0x54, 0x6e, 0x2f, 0x30, 0x68, 0x70, 0x50, 0x73, 0x68, 0x4e, 0x4f, 0x4f, + 0x76, 0x45, 0x75, 0x2f, 0x58, 0x41, 0x46, 0x4f, 0x42, 0x7a, 0x33, 0x63, + 0x46, 0x49, 0x71, 0x55, 0x43, 0x71, 0x54, 0x71, 0x63, 0x2f, 0x73, 0x4c, + 0x55, 0x65, 0x67, 0x54, 0x42, 0x78, 0x6a, 0x36, 0x44, 0x76, 0x45, 0x72, + 0x30, 0x56, 0x51, 0x56, 0x66, 0x54, 0x7a, 0x68, 0x39, 0x37, 0x51, 0x5a, + 0x0a, 0x51, 0x6d, 0x64, 0x69, 0x58, 0x6e, 0x66, 0x67, 0x6f, 0x6c, 0x58, + 0x73, 0x74, 0x74, 0x6c, 0x70, 0x46, 0x39, 0x55, 0x36, 0x72, 0x30, 0x54, + 0x74, 0x53, 0x73, 0x57, 0x65, 0x35, 0x48, 0x6f, 0x6e, 0x66, 0x4f, 0x56, + 0x31, 0x31, 0x36, 0x72, 0x4c, 0x4a, 0x65, 0x66, 0x66, 0x61, 0x77, 0x72, + 0x62, 0x44, 0x30, 0x32, 0x54, 0x54, 0x71, 0x69, 0x67, 0x7a, 0x58, 0x73, + 0x75, 0x38, 0x6c, 0x6b, 0x42, 0x0a, 0x61, 0x72, 0x63, 0x4e, 0x75, 0x41, + 0x65, 0x42, 0x66, 0x6f, 0x73, 0x34, 0x47, 0x7a, 0x6a, 0x6d, 0x43, 0x6c, + 0x65, 0x5a, 0x50, 0x65, 0x34, 0x68, 0x36, 0x4b, 0x50, 0x31, 0x44, 0x42, + 0x62, 0x64, 0x69, 0x2b, 0x77, 0x30, 0x6a, 0x70, 0x77, 0x71, 0x48, 0x41, + 0x41, 0x56, 0x46, 0x34, 0x31, 0x6f, 0x67, 0x39, 0x4a, 0x77, 0x6e, 0x78, + 0x67, 0x49, 0x7a, 0x52, 0x46, 0x6f, 0x31, 0x63, 0x6c, 0x72, 0x0a, 0x55, + 0x73, 0x33, 0x45, 0x52, 0x6f, 0x2f, 0x63, 0x74, 0x66, 0x50, 0x59, 0x56, + 0x33, 0x4d, 0x65, 0x36, 0x5a, 0x51, 0x35, 0x42, 0x4c, 0x2f, 0x54, 0x33, + 0x6a, 0x6a, 0x65, 0x74, 0x46, 0x50, 0x73, 0x61, 0x52, 0x79, 0x69, 0x66, + 0x73, 0x53, 0x50, 0x35, 0x42, 0x74, 0x77, 0x72, 0x66, 0x4b, 0x69, 0x2b, + 0x66, 0x76, 0x33, 0x46, 0x6d, 0x52, 0x6d, 0x61, 0x5a, 0x39, 0x4a, 0x55, + 0x61, 0x4c, 0x69, 0x0a, 0x46, 0x52, 0x68, 0x6e, 0x42, 0x6b, 0x70, 0x2f, + 0x31, 0x57, 0x79, 0x31, 0x54, 0x62, 0x4d, 0x7a, 0x34, 0x47, 0x48, 0x72, + 0x58, 0x62, 0x37, 0x70, 0x6d, 0x41, 0x38, 0x79, 0x31, 0x78, 0x31, 0x4c, + 0x50, 0x43, 0x35, 0x61, 0x41, 0x56, 0x4b, 0x52, 0x43, 0x66, 0x4c, 0x66, + 0x36, 0x6f, 0x33, 0x59, 0x42, 0x6b, 0x42, 0x6a, 0x71, 0x68, 0x48, 0x6b, + 0x2f, 0x73, 0x4d, 0x33, 0x6e, 0x68, 0x52, 0x53, 0x0a, 0x50, 0x2f, 0x54, + 0x69, 0x7a, 0x50, 0x4a, 0x68, 0x6b, 0x39, 0x48, 0x39, 0x5a, 0x32, 0x76, + 0x58, 0x55, 0x71, 0x36, 0x2f, 0x61, 0x4b, 0x74, 0x41, 0x51, 0x36, 0x42, + 0x58, 0x4e, 0x56, 0x4e, 0x34, 0x38, 0x46, 0x50, 0x34, 0x59, 0x55, 0x49, + 0x48, 0x5a, 0x4d, 0x62, 0x58, 0x62, 0x35, 0x74, 0x4d, 0x4f, 0x41, 0x31, + 0x6a, 0x72, 0x47, 0x4b, 0x76, 0x4e, 0x6f, 0x75, 0x69, 0x63, 0x77, 0x6f, + 0x4e, 0x0a, 0x39, 0x53, 0x47, 0x39, 0x64, 0x4b, 0x70, 0x4e, 0x36, 0x6e, + 0x49, 0x44, 0x53, 0x64, 0x76, 0x48, 0x58, 0x78, 0x31, 0x69, 0x59, 0x38, + 0x66, 0x39, 0x33, 0x5a, 0x48, 0x73, 0x4d, 0x2b, 0x37, 0x31, 0x62, 0x62, + 0x52, 0x75, 0x4d, 0x47, 0x6a, 0x65, 0x79, 0x4e, 0x59, 0x6d, 0x73, 0x48, + 0x56, 0x65, 0x65, 0x37, 0x51, 0x48, 0x49, 0x4a, 0x69, 0x68, 0x64, 0x6a, + 0x4b, 0x34, 0x54, 0x57, 0x78, 0x50, 0x0a, 0x41, 0x67, 0x4d, 0x42, 0x41, + 0x41, 0x47, 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x41, 0x38, 0x47, 0x41, + 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, + 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4d, 0x6d, 0x41, 0x64, + 0x2b, 0x42, 0x69, 0x6b, 0x6f, 0x4c, 0x31, 0x52, 0x70, 0x7a, 0x7a, 0x0a, + 0x75, 0x76, 0x64, 0x4d, 0x77, 0x39, 0x36, 0x34, 0x6f, 0x36, 0x30, 0x35, + 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, + 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x73, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, + 0x55, 0x31, 0x38, 0x68, 0x0a, 0x39, 0x62, 0x71, 0x77, 0x4f, 0x6c, 0x49, + 0x35, 0x4c, 0x4a, 0x4b, 0x77, 0x62, 0x41, 0x44, 0x4a, 0x37, 0x38, 0x34, + 0x67, 0x37, 0x77, 0x62, 0x79, 0x6c, 0x70, 0x37, 0x70, 0x70, 0x48, 0x52, + 0x2f, 0x65, 0x68, 0x62, 0x38, 0x74, 0x2f, 0x57, 0x32, 0x2b, 0x78, 0x55, + 0x62, 0x50, 0x36, 0x75, 0x6d, 0x77, 0x48, 0x4a, 0x64, 0x45, 0x4c, 0x46, + 0x78, 0x37, 0x72, 0x78, 0x50, 0x34, 0x36, 0x32, 0x73, 0x0a, 0x41, 0x32, + 0x30, 0x75, 0x63, 0x53, 0x36, 0x76, 0x78, 0x4f, 0x4f, 0x74, 0x6f, 0x37, + 0x30, 0x4d, 0x45, 0x61, 0x65, 0x30, 0x2f, 0x30, 0x71, 0x79, 0x65, 0x78, + 0x41, 0x51, 0x48, 0x36, 0x64, 0x58, 0x51, 0x62, 0x4c, 0x41, 0x72, 0x76, + 0x51, 0x73, 0x57, 0x64, 0x5a, 0x48, 0x45, 0x49, 0x6a, 0x7a, 0x49, 0x56, + 0x45, 0x70, 0x4d, 0x4d, 0x70, 0x67, 0x68, 0x71, 0x39, 0x47, 0x71, 0x78, + 0x33, 0x74, 0x0a, 0x4f, 0x6c, 0x75, 0x77, 0x6c, 0x4e, 0x35, 0x45, 0x34, + 0x30, 0x45, 0x49, 0x6f, 0x73, 0x48, 0x73, 0x48, 0x64, 0x62, 0x39, 0x54, + 0x37, 0x62, 0x57, 0x52, 0x39, 0x41, 0x55, 0x43, 0x38, 0x72, 0x6d, 0x79, + 0x72, 0x56, 0x37, 0x64, 0x33, 0x35, 0x42, 0x48, 0x31, 0x36, 0x44, 0x78, + 0x37, 0x61, 0x4d, 0x4f, 0x5a, 0x61, 0x77, 0x50, 0x35, 0x61, 0x42, 0x51, + 0x57, 0x39, 0x67, 0x6b, 0x4f, 0x4c, 0x6f, 0x0a, 0x2b, 0x66, 0x73, 0x69, + 0x63, 0x64, 0x6c, 0x39, 0x73, 0x7a, 0x31, 0x47, 0x76, 0x37, 0x53, 0x45, + 0x72, 0x35, 0x41, 0x63, 0x44, 0x34, 0x38, 0x53, 0x61, 0x71, 0x2f, 0x76, + 0x37, 0x68, 0x35, 0x36, 0x72, 0x67, 0x4a, 0x4b, 0x69, 0x68, 0x63, 0x72, + 0x64, 0x76, 0x36, 0x73, 0x56, 0x49, 0x6b, 0x6b, 0x4c, 0x45, 0x38, 0x2f, + 0x74, 0x72, 0x4b, 0x6e, 0x54, 0x6f, 0x79, 0x6f, 0x6b, 0x5a, 0x66, 0x37, + 0x0a, 0x4b, 0x63, 0x5a, 0x37, 0x58, 0x43, 0x32, 0x35, 0x79, 0x32, 0x61, + 0x32, 0x74, 0x36, 0x68, 0x62, 0x45, 0x6c, 0x47, 0x46, 0x74, 0x51, 0x6c, + 0x2b, 0x59, 0x6e, 0x68, 0x77, 0x2f, 0x71, 0x6c, 0x71, 0x59, 0x4c, 0x59, + 0x64, 0x44, 0x6e, 0x6b, 0x4d, 0x2f, 0x63, 0x72, 0x71, 0x4a, 0x49, 0x42, + 0x79, 0x77, 0x35, 0x63, 0x2f, 0x38, 0x6e, 0x65, 0x72, 0x51, 0x79, 0x49, + 0x4b, 0x78, 0x2b, 0x75, 0x32, 0x0a, 0x44, 0x49, 0x53, 0x43, 0x4c, 0x49, + 0x42, 0x72, 0x51, 0x59, 0x6f, 0x49, 0x77, 0x4f, 0x75, 0x6c, 0x61, 0x39, + 0x2b, 0x5a, 0x45, 0x73, 0x75, 0x4b, 0x31, 0x56, 0x36, 0x41, 0x44, 0x4a, + 0x48, 0x67, 0x4a, 0x67, 0x67, 0x32, 0x53, 0x4d, 0x58, 0x36, 0x4f, 0x42, + 0x45, 0x31, 0x2f, 0x79, 0x57, 0x44, 0x4c, 0x66, 0x4a, 0x36, 0x76, 0x39, + 0x72, 0x39, 0x6a, 0x76, 0x36, 0x6c, 0x79, 0x30, 0x55, 0x73, 0x0a, 0x48, + 0x38, 0x53, 0x49, 0x55, 0x36, 0x35, 0x33, 0x44, 0x74, 0x6d, 0x61, 0x64, + 0x73, 0x57, 0x4f, 0x4c, 0x42, 0x32, 0x6a, 0x75, 0x74, 0x58, 0x73, 0x4d, + 0x71, 0x37, 0x41, 0x71, 0x71, 0x7a, 0x33, 0x30, 0x58, 0x70, 0x4e, 0x36, + 0x39, 0x51, 0x48, 0x34, 0x6b, 0x6a, 0x33, 0x49, 0x6f, 0x36, 0x77, 0x70, + 0x4a, 0x39, 0x71, 0x7a, 0x6f, 0x36, 0x79, 0x73, 0x6d, 0x44, 0x30, 0x6f, + 0x79, 0x4c, 0x51, 0x0a, 0x49, 0x2b, 0x75, 0x55, 0x57, 0x6e, 0x70, 0x70, + 0x33, 0x51, 0x2b, 0x2f, 0x51, 0x46, 0x65, 0x73, 0x61, 0x31, 0x6c, 0x51, + 0x32, 0x61, 0x4f, 0x5a, 0x34, 0x57, 0x37, 0x2b, 0x6a, 0x51, 0x46, 0x35, + 0x4a, 0x79, 0x4d, 0x56, 0x33, 0x70, 0x4b, 0x64, 0x65, 0x77, 0x6c, 0x4e, + 0x57, 0x75, 0x64, 0x4c, 0x53, 0x44, 0x42, 0x61, 0x47, 0x4f, 0x59, 0x4b, + 0x62, 0x65, 0x61, 0x50, 0x34, 0x4e, 0x4b, 0x37, 0x0a, 0x35, 0x74, 0x39, + 0x38, 0x62, 0x69, 0x47, 0x43, 0x77, 0x57, 0x67, 0x35, 0x54, 0x62, 0x53, + 0x59, 0x57, 0x47, 0x5a, 0x69, 0x7a, 0x45, 0x71, 0x51, 0x58, 0x73, 0x50, + 0x36, 0x4a, 0x77, 0x53, 0x78, 0x65, 0x52, 0x56, 0x30, 0x6d, 0x63, 0x79, + 0x2b, 0x72, 0x53, 0x44, 0x65, 0x4a, 0x6d, 0x41, 0x63, 0x36, 0x31, 0x5a, + 0x52, 0x70, 0x71, 0x50, 0x71, 0x35, 0x4b, 0x4d, 0x2f, 0x70, 0x2f, 0x39, + 0x68, 0x0a, 0x33, 0x50, 0x46, 0x61, 0x54, 0x57, 0x77, 0x79, 0x49, 0x30, + 0x50, 0x75, 0x72, 0x4b, 0x6a, 0x75, 0x37, 0x6b, 0x6f, 0x53, 0x43, 0x54, + 0x78, 0x64, 0x63, 0x63, 0x4b, 0x2b, 0x65, 0x66, 0x72, 0x43, 0x68, 0x32, + 0x67, 0x64, 0x43, 0x2f, 0x31, 0x63, 0x61, 0x63, 0x77, 0x47, 0x30, 0x4a, + 0x70, 0x39, 0x56, 0x4a, 0x6b, 0x71, 0x79, 0x54, 0x6b, 0x61, 0x47, 0x61, + 0x39, 0x4c, 0x4b, 0x6b, 0x50, 0x7a, 0x0a, 0x59, 0x31, 0x31, 0x61, 0x57, + 0x4f, 0x49, 0x76, 0x34, 0x78, 0x33, 0x6b, 0x71, 0x64, 0x62, 0x51, 0x43, + 0x74, 0x43, 0x65, 0x76, 0x39, 0x65, 0x42, 0x43, 0x66, 0x48, 0x4a, 0x78, + 0x79, 0x59, 0x4e, 0x72, 0x4a, 0x67, 0x57, 0x56, 0x71, 0x41, 0x3d, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x42, 0x75, 0x79, 0x70, 0x61, 0x73, 0x73, 0x20, + 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x42, 0x75, 0x79, 0x70, 0x61, 0x73, + 0x73, 0x20, 0x41, 0x53, 0x2d, 0x39, 0x38, 0x33, 0x31, 0x36, 0x33, 0x33, + 0x32, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x42, 0x75, 0x79, 0x70, 0x61, 0x73, 0x73, + 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x42, 0x75, 0x79, 0x70, 0x61, + 0x73, 0x73, 0x20, 0x41, 0x53, 0x2d, 0x39, 0x38, 0x33, 0x31, 0x36, 0x33, + 0x33, 0x32, 0x37, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x42, 0x75, 0x79, 0x70, 0x61, 0x73, 0x73, 0x20, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x32, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x64, + 0x3a, 0x33, 0x62, 0x3a, 0x31, 0x38, 0x3a, 0x39, 0x65, 0x3a, 0x32, 0x63, + 0x3a, 0x36, 0x34, 0x3a, 0x35, 0x61, 0x3a, 0x65, 0x38, 0x3a, 0x64, 0x35, + 0x3a, 0x38, 0x38, 0x3a, 0x63, 0x65, 0x3a, 0x30, 0x65, 0x3a, 0x66, 0x39, + 0x3a, 0x33, 0x37, 0x3a, 0x63, 0x32, 0x3a, 0x65, 0x63, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x61, 0x3a, 0x66, 0x61, 0x3a, + 0x66, 0x37, 0x3a, 0x66, 0x61, 0x3a, 0x36, 0x36, 0x3a, 0x38, 0x34, 0x3a, + 0x65, 0x63, 0x3a, 0x30, 0x36, 0x3a, 0x38, 0x66, 0x3a, 0x31, 0x34, 0x3a, + 0x35, 0x30, 0x3a, 0x62, 0x64, 0x3a, 0x63, 0x37, 0x3a, 0x63, 0x32, 0x3a, + 0x38, 0x31, 0x3a, 0x61, 0x35, 0x3a, 0x62, 0x63, 0x3a, 0x61, 0x39, 0x3a, + 0x36, 0x34, 0x3a, 0x35, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x64, 0x3a, 0x66, 0x37, 0x3a, 0x65, 0x62, + 0x3a, 0x62, 0x63, 0x3a, 0x61, 0x32, 0x3a, 0x37, 0x61, 0x3a, 0x32, 0x61, + 0x3a, 0x33, 0x38, 0x3a, 0x34, 0x64, 0x3a, 0x33, 0x38, 0x3a, 0x37, 0x62, + 0x3a, 0x37, 0x64, 0x3a, 0x34, 0x30, 0x3a, 0x31, 0x30, 0x3a, 0x63, 0x36, + 0x3a, 0x36, 0x36, 0x3a, 0x65, 0x32, 0x3a, 0x65, 0x64, 0x3a, 0x62, 0x34, + 0x3a, 0x38, 0x34, 0x3a, 0x33, 0x65, 0x3a, 0x34, 0x63, 0x3a, 0x32, 0x39, + 0x3a, 0x62, 0x34, 0x3a, 0x61, 0x65, 0x3a, 0x31, 0x64, 0x3a, 0x35, 0x62, + 0x3a, 0x39, 0x33, 0x3a, 0x33, 0x32, 0x3a, 0x65, 0x36, 0x3a, 0x62, 0x32, + 0x3a, 0x34, 0x64, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, + 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, + 0x57, 0x54, 0x43, 0x43, 0x41, 0x30, 0x47, 0x67, 0x41, 0x77, 0x49, 0x42, + 0x41, 0x67, 0x49, 0x42, 0x41, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, + 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, + 0x41, 0x44, 0x42, 0x4f, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x4f, 0x54, 0x7a, 0x45, 0x64, + 0x0a, 0x4d, 0x42, 0x73, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, + 0x55, 0x51, 0x6e, 0x56, 0x35, 0x63, 0x47, 0x46, 0x7a, 0x63, 0x79, 0x42, + 0x42, 0x55, 0x79, 0x30, 0x35, 0x4f, 0x44, 0x4d, 0x78, 0x4e, 0x6a, 0x4d, + 0x7a, 0x4d, 0x6a, 0x63, 0x78, 0x49, 0x44, 0x41, 0x65, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x46, 0x30, 0x4a, 0x31, 0x65, 0x58, 0x42, + 0x68, 0x63, 0x33, 0x4d, 0x67, 0x0a, 0x51, 0x32, 0x78, 0x68, 0x63, 0x33, + 0x4d, 0x67, 0x4d, 0x79, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, + 0x4e, 0x42, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x77, 0x4d, 0x54, + 0x41, 0x79, 0x4e, 0x6a, 0x41, 0x34, 0x4d, 0x6a, 0x67, 0x31, 0x4f, 0x46, + 0x6f, 0x58, 0x44, 0x54, 0x51, 0x77, 0x4d, 0x54, 0x41, 0x79, 0x4e, 0x6a, + 0x41, 0x34, 0x4d, 0x6a, 0x67, 0x31, 0x4f, 0x46, 0x6f, 0x77, 0x0a, 0x54, + 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x68, 0x4d, 0x43, 0x54, 0x6b, 0x38, 0x78, 0x48, 0x54, 0x41, 0x62, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x46, 0x45, 0x4a, 0x31, 0x65, + 0x58, 0x42, 0x68, 0x63, 0x33, 0x4d, 0x67, 0x51, 0x56, 0x4d, 0x74, 0x4f, + 0x54, 0x67, 0x7a, 0x4d, 0x54, 0x59, 0x7a, 0x4d, 0x7a, 0x49, 0x33, 0x4d, + 0x53, 0x41, 0x77, 0x0a, 0x48, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, + 0x44, 0x42, 0x64, 0x43, 0x64, 0x58, 0x6c, 0x77, 0x59, 0x58, 0x4e, 0x7a, + 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44, 0x4d, 0x67, + 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x54, 0x43, 0x43, + 0x41, 0x69, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x0a, 0x42, 0x51, 0x41, + 0x44, 0x67, 0x67, 0x49, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x67, 0x6f, + 0x43, 0x67, 0x67, 0x49, 0x42, 0x41, 0x4b, 0x58, 0x61, 0x43, 0x70, 0x55, + 0x57, 0x55, 0x4f, 0x4f, 0x56, 0x38, 0x6c, 0x36, 0x64, 0x64, 0x6a, 0x45, + 0x47, 0x4d, 0x6e, 0x71, 0x62, 0x38, 0x52, 0x42, 0x32, 0x75, 0x41, 0x43, + 0x61, 0x74, 0x56, 0x49, 0x32, 0x7a, 0x53, 0x52, 0x48, 0x73, 0x4a, 0x38, + 0x59, 0x0a, 0x5a, 0x4c, 0x79, 0x61, 0x39, 0x76, 0x72, 0x56, 0x65, 0x64, + 0x69, 0x51, 0x59, 0x6b, 0x77, 0x69, 0x4c, 0x39, 0x34, 0x34, 0x50, 0x64, + 0x62, 0x67, 0x71, 0x4f, 0x6b, 0x63, 0x4c, 0x4e, 0x74, 0x34, 0x45, 0x65, + 0x6d, 0x4f, 0x61, 0x46, 0x45, 0x56, 0x63, 0x73, 0x66, 0x7a, 0x4d, 0x34, + 0x66, 0x6b, 0x6f, 0x46, 0x30, 0x4c, 0x58, 0x4f, 0x42, 0x58, 0x42, 0x79, + 0x6f, 0x77, 0x39, 0x63, 0x33, 0x45, 0x0a, 0x4e, 0x33, 0x63, 0x6f, 0x54, + 0x52, 0x69, 0x52, 0x35, 0x72, 0x2f, 0x56, 0x55, 0x76, 0x31, 0x78, 0x4c, + 0x58, 0x41, 0x2b, 0x35, 0x38, 0x62, 0x45, 0x69, 0x75, 0x50, 0x77, 0x4b, + 0x41, 0x76, 0x30, 0x64, 0x70, 0x69, 0x68, 0x69, 0x34, 0x64, 0x56, 0x73, + 0x6a, 0x6f, 0x54, 0x2f, 0x4c, 0x63, 0x2b, 0x4a, 0x7a, 0x65, 0x4f, 0x49, + 0x75, 0x4f, 0x6f, 0x54, 0x79, 0x72, 0x76, 0x59, 0x4c, 0x73, 0x39, 0x0a, + 0x74, 0x7a, 0x6e, 0x44, 0x44, 0x67, 0x46, 0x48, 0x6d, 0x56, 0x30, 0x53, + 0x54, 0x39, 0x74, 0x44, 0x2b, 0x6c, 0x65, 0x68, 0x37, 0x66, 0x6d, 0x64, + 0x76, 0x68, 0x46, 0x48, 0x4a, 0x6c, 0x73, 0x54, 0x6d, 0x4b, 0x74, 0x64, + 0x46, 0x6f, 0x71, 0x77, 0x4e, 0x78, 0x78, 0x58, 0x6e, 0x55, 0x58, 0x2f, + 0x69, 0x4a, 0x59, 0x32, 0x76, 0x37, 0x76, 0x4b, 0x42, 0x33, 0x74, 0x76, + 0x68, 0x32, 0x50, 0x58, 0x0a, 0x30, 0x44, 0x4a, 0x71, 0x31, 0x6c, 0x31, + 0x73, 0x44, 0x50, 0x47, 0x7a, 0x62, 0x6a, 0x6e, 0x69, 0x61, 0x7a, 0x45, + 0x75, 0x4f, 0x51, 0x41, 0x6e, 0x46, 0x4e, 0x34, 0x34, 0x77, 0x4f, 0x77, + 0x5a, 0x5a, 0x6f, 0x59, 0x53, 0x36, 0x4a, 0x31, 0x79, 0x46, 0x68, 0x4e, + 0x6b, 0x55, 0x73, 0x65, 0x70, 0x4e, 0x78, 0x7a, 0x39, 0x67, 0x6a, 0x44, + 0x74, 0x68, 0x42, 0x67, 0x64, 0x39, 0x4b, 0x35, 0x63, 0x0a, 0x2f, 0x33, + 0x41, 0x54, 0x41, 0x4f, 0x75, 0x78, 0x39, 0x54, 0x4e, 0x36, 0x53, 0x39, + 0x5a, 0x56, 0x2b, 0x41, 0x57, 0x4e, 0x53, 0x32, 0x6d, 0x77, 0x39, 0x62, + 0x4d, 0x6f, 0x4e, 0x6c, 0x77, 0x55, 0x78, 0x46, 0x46, 0x7a, 0x54, 0x57, + 0x73, 0x4c, 0x38, 0x54, 0x51, 0x48, 0x32, 0x78, 0x63, 0x35, 0x31, 0x39, + 0x77, 0x6f, 0x65, 0x32, 0x76, 0x31, 0x6e, 0x2f, 0x4d, 0x75, 0x77, 0x55, + 0x38, 0x58, 0x0a, 0x4b, 0x68, 0x44, 0x7a, 0x7a, 0x4d, 0x72, 0x6f, 0x36, + 0x2f, 0x31, 0x72, 0x71, 0x79, 0x36, 0x61, 0x6e, 0x79, 0x32, 0x43, 0x62, + 0x67, 0x54, 0x55, 0x55, 0x67, 0x47, 0x54, 0x4c, 0x54, 0x32, 0x47, 0x2f, + 0x48, 0x37, 0x38, 0x33, 0x2b, 0x39, 0x43, 0x48, 0x61, 0x5a, 0x72, 0x37, + 0x37, 0x6b, 0x67, 0x78, 0x76, 0x65, 0x39, 0x6f, 0x4b, 0x65, 0x56, 0x2f, + 0x61, 0x66, 0x6d, 0x69, 0x53, 0x54, 0x59, 0x0a, 0x7a, 0x49, 0x77, 0x30, + 0x62, 0x4f, 0x49, 0x6a, 0x4c, 0x39, 0x6b, 0x53, 0x47, 0x69, 0x47, 0x35, + 0x56, 0x5a, 0x46, 0x76, 0x43, 0x35, 0x46, 0x35, 0x47, 0x51, 0x79, 0x74, + 0x51, 0x49, 0x67, 0x4c, 0x63, 0x4f, 0x4a, 0x36, 0x30, 0x67, 0x37, 0x59, + 0x61, 0x45, 0x69, 0x37, 0x67, 0x68, 0x4d, 0x35, 0x45, 0x46, 0x6a, 0x70, + 0x32, 0x43, 0x6f, 0x48, 0x78, 0x68, 0x4c, 0x62, 0x57, 0x4e, 0x76, 0x53, + 0x0a, 0x4f, 0x31, 0x55, 0x51, 0x52, 0x77, 0x55, 0x56, 0x5a, 0x32, 0x4a, + 0x2b, 0x47, 0x47, 0x4f, 0x6d, 0x52, 0x6a, 0x38, 0x4a, 0x44, 0x6c, 0x51, + 0x79, 0x58, 0x72, 0x38, 0x4e, 0x59, 0x6e, 0x6f, 0x6e, 0x37, 0x34, 0x44, + 0x6f, 0x32, 0x39, 0x6c, 0x4c, 0x42, 0x6c, 0x6f, 0x33, 0x57, 0x69, 0x58, + 0x51, 0x43, 0x42, 0x4a, 0x33, 0x31, 0x47, 0x38, 0x4a, 0x55, 0x4a, 0x63, + 0x39, 0x79, 0x42, 0x33, 0x44, 0x0a, 0x33, 0x34, 0x78, 0x46, 0x4d, 0x46, + 0x62, 0x47, 0x30, 0x32, 0x53, 0x72, 0x5a, 0x76, 0x50, 0x41, 0x58, 0x70, + 0x61, 0x63, 0x77, 0x38, 0x54, 0x76, 0x77, 0x33, 0x78, 0x72, 0x69, 0x7a, + 0x70, 0x35, 0x66, 0x37, 0x4e, 0x4a, 0x7a, 0x7a, 0x33, 0x69, 0x69, 0x5a, + 0x2b, 0x67, 0x4d, 0x45, 0x75, 0x46, 0x75, 0x5a, 0x79, 0x55, 0x4a, 0x48, + 0x6d, 0x50, 0x66, 0x57, 0x75, 0x70, 0x52, 0x57, 0x67, 0x50, 0x0a, 0x4b, + 0x39, 0x44, 0x78, 0x32, 0x68, 0x7a, 0x4c, 0x61, 0x62, 0x6a, 0x4b, 0x53, + 0x57, 0x4a, 0x74, 0x79, 0x4e, 0x42, 0x6a, 0x59, 0x74, 0x31, 0x67, 0x44, + 0x31, 0x69, 0x71, 0x6a, 0x36, 0x47, 0x38, 0x42, 0x61, 0x56, 0x6d, 0x6f, + 0x73, 0x38, 0x62, 0x64, 0x72, 0x4b, 0x45, 0x5a, 0x4c, 0x46, 0x4d, 0x4f, + 0x56, 0x4c, 0x41, 0x4d, 0x4c, 0x72, 0x77, 0x6a, 0x45, 0x73, 0x43, 0x73, + 0x4c, 0x61, 0x33, 0x0a, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, + 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, + 0x41, 0x66, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, + 0x42, 0x42, 0x59, 0x45, 0x46, 0x45, 0x65, 0x34, 0x7a, 0x66, 0x2f, 0x6c, + 0x62, 0x2b, 0x37, 0x34, 0x73, 0x75, 0x77, 0x76, 0x0a, 0x54, 0x67, 0x37, + 0x35, 0x4a, 0x62, 0x43, 0x4f, 0x50, 0x47, 0x76, 0x44, 0x4d, 0x41, 0x34, + 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, + 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, + 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, + 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, 0x41, 0x43, 0x41, + 0x6a, 0x0a, 0x51, 0x54, 0x55, 0x45, 0x6b, 0x4d, 0x4a, 0x41, 0x59, 0x6d, + 0x44, 0x76, 0x34, 0x6a, 0x56, 0x4d, 0x31, 0x7a, 0x2b, 0x73, 0x34, 0x6a, + 0x53, 0x51, 0x75, 0x4b, 0x46, 0x76, 0x64, 0x76, 0x6f, 0x57, 0x46, 0x71, + 0x52, 0x49, 0x4e, 0x79, 0x7a, 0x70, 0x6b, 0x4d, 0x4c, 0x79, 0x50, 0x50, + 0x67, 0x4b, 0x6e, 0x39, 0x69, 0x42, 0x35, 0x62, 0x74, 0x62, 0x32, 0x69, + 0x55, 0x73, 0x70, 0x4b, 0x64, 0x56, 0x0a, 0x63, 0x53, 0x51, 0x79, 0x39, + 0x73, 0x67, 0x4c, 0x38, 0x72, 0x78, 0x71, 0x2b, 0x4a, 0x4f, 0x73, 0x73, + 0x67, 0x66, 0x43, 0x58, 0x35, 0x2f, 0x62, 0x7a, 0x4d, 0x69, 0x4b, 0x71, + 0x72, 0x35, 0x71, 0x62, 0x2b, 0x46, 0x4a, 0x45, 0x4d, 0x77, 0x78, 0x31, + 0x34, 0x43, 0x37, 0x75, 0x38, 0x6a, 0x59, 0x6f, 0x67, 0x35, 0x6b, 0x56, + 0x2b, 0x71, 0x69, 0x39, 0x63, 0x4b, 0x70, 0x4d, 0x52, 0x58, 0x53, 0x0a, + 0x49, 0x47, 0x72, 0x73, 0x2f, 0x43, 0x49, 0x42, 0x4b, 0x4d, 0x2b, 0x47, + 0x75, 0x49, 0x41, 0x65, 0x71, 0x63, 0x77, 0x52, 0x70, 0x54, 0x7a, 0x79, + 0x46, 0x72, 0x4e, 0x48, 0x6e, 0x66, 0x7a, 0x53, 0x67, 0x43, 0x48, 0x45, + 0x79, 0x39, 0x42, 0x48, 0x63, 0x45, 0x47, 0x68, 0x79, 0x6f, 0x4d, 0x5a, + 0x43, 0x43, 0x78, 0x74, 0x38, 0x6c, 0x31, 0x33, 0x6e, 0x49, 0x6f, 0x55, + 0x45, 0x39, 0x51, 0x32, 0x0a, 0x48, 0x4a, 0x4c, 0x77, 0x35, 0x51, 0x59, + 0x33, 0x33, 0x4b, 0x62, 0x6d, 0x6b, 0x4a, 0x73, 0x34, 0x6a, 0x31, 0x78, + 0x72, 0x47, 0x30, 0x61, 0x47, 0x51, 0x30, 0x4a, 0x66, 0x50, 0x67, 0x45, + 0x48, 0x55, 0x31, 0x52, 0x64, 0x5a, 0x58, 0x33, 0x33, 0x69, 0x6e, 0x4f, + 0x68, 0x6d, 0x6c, 0x52, 0x61, 0x48, 0x79, 0x6c, 0x44, 0x46, 0x43, 0x66, + 0x43, 0x68, 0x51, 0x2b, 0x31, 0x69, 0x48, 0x73, 0x61, 0x0a, 0x4f, 0x35, + 0x53, 0x33, 0x48, 0x57, 0x43, 0x6e, 0x74, 0x5a, 0x7a, 0x6e, 0x4b, 0x57, + 0x6c, 0x58, 0x57, 0x70, 0x75, 0x54, 0x65, 0x6b, 0x4d, 0x77, 0x47, 0x77, + 0x50, 0x58, 0x59, 0x73, 0x68, 0x41, 0x70, 0x71, 0x72, 0x38, 0x5a, 0x4f, + 0x52, 0x4b, 0x31, 0x35, 0x46, 0x54, 0x41, 0x61, 0x67, 0x67, 0x69, 0x47, + 0x36, 0x63, 0x58, 0x30, 0x53, 0x35, 0x79, 0x32, 0x43, 0x42, 0x4e, 0x4f, + 0x78, 0x76, 0x0a, 0x30, 0x33, 0x33, 0x61, 0x53, 0x46, 0x2f, 0x72, 0x74, + 0x4a, 0x43, 0x38, 0x4c, 0x61, 0x6b, 0x63, 0x43, 0x36, 0x77, 0x63, 0x31, + 0x61, 0x4a, 0x6f, 0x49, 0x49, 0x41, 0x45, 0x31, 0x76, 0x79, 0x78, 0x6a, + 0x79, 0x2b, 0x37, 0x53, 0x6a, 0x45, 0x4e, 0x53, 0x6f, 0x59, 0x63, 0x36, + 0x2b, 0x49, 0x32, 0x4b, 0x53, 0x62, 0x31, 0x32, 0x74, 0x6a, 0x45, 0x38, + 0x6e, 0x56, 0x68, 0x7a, 0x33, 0x36, 0x75, 0x0a, 0x64, 0x6d, 0x4e, 0x4b, + 0x65, 0x6b, 0x42, 0x6c, 0x6b, 0x34, 0x66, 0x34, 0x48, 0x6f, 0x43, 0x4d, + 0x68, 0x75, 0x57, 0x47, 0x31, 0x6f, 0x38, 0x4f, 0x2f, 0x46, 0x4d, 0x73, + 0x59, 0x4f, 0x67, 0x57, 0x59, 0x52, 0x71, 0x69, 0x50, 0x6b, 0x4e, 0x37, + 0x7a, 0x54, 0x6c, 0x67, 0x56, 0x47, 0x72, 0x31, 0x38, 0x6f, 0x6b, 0x6d, + 0x41, 0x57, 0x69, 0x44, 0x53, 0x4b, 0x49, 0x7a, 0x36, 0x4d, 0x6b, 0x45, + 0x0a, 0x6b, 0x62, 0x49, 0x52, 0x4e, 0x42, 0x45, 0x2b, 0x36, 0x74, 0x42, + 0x44, 0x47, 0x52, 0x38, 0x44, 0x6b, 0x35, 0x41, 0x4d, 0x2f, 0x31, 0x45, + 0x39, 0x56, 0x2f, 0x52, 0x42, 0x62, 0x75, 0x48, 0x4c, 0x6f, 0x4c, 0x37, + 0x72, 0x79, 0x57, 0x50, 0x4e, 0x62, 0x63, 0x7a, 0x6b, 0x2b, 0x44, 0x61, + 0x71, 0x61, 0x4a, 0x33, 0x74, 0x76, 0x56, 0x32, 0x58, 0x63, 0x45, 0x51, + 0x4e, 0x74, 0x67, 0x34, 0x31, 0x0a, 0x33, 0x4f, 0x45, 0x4d, 0x58, 0x62, + 0x75, 0x67, 0x55, 0x5a, 0x54, 0x4c, 0x66, 0x68, 0x62, 0x72, 0x45, 0x53, + 0x2b, 0x6a, 0x6b, 0x6b, 0x58, 0x49, 0x54, 0x48, 0x48, 0x5a, 0x76, 0x4d, + 0x6d, 0x5a, 0x55, 0x6c, 0x64, 0x47, 0x4c, 0x31, 0x44, 0x50, 0x76, 0x54, + 0x56, 0x70, 0x39, 0x44, 0x30, 0x56, 0x7a, 0x67, 0x61, 0x6c, 0x4c, 0x41, + 0x38, 0x2b, 0x39, 0x6f, 0x47, 0x36, 0x6c, 0x4c, 0x76, 0x44, 0x0a, 0x75, + 0x37, 0x39, 0x6c, 0x65, 0x4e, 0x4b, 0x47, 0x65, 0x66, 0x39, 0x4a, 0x4f, + 0x78, 0x71, 0x44, 0x44, 0x50, 0x44, 0x65, 0x65, 0x4f, 0x7a, 0x49, 0x38, + 0x6b, 0x31, 0x4d, 0x47, 0x74, 0x36, 0x43, 0x4b, 0x66, 0x6a, 0x42, 0x57, + 0x74, 0x72, 0x74, 0x37, 0x75, 0x59, 0x6e, 0x58, 0x75, 0x68, 0x46, 0x30, + 0x4a, 0x30, 0x63, 0x55, 0x61, 0x68, 0x6f, 0x71, 0x30, 0x54, 0x6a, 0x30, + 0x49, 0x74, 0x71, 0x0a, 0x34, 0x2f, 0x67, 0x37, 0x75, 0x39, 0x78, 0x4e, + 0x31, 0x32, 0x54, 0x79, 0x55, 0x62, 0x37, 0x6d, 0x71, 0x71, 0x74, 0x61, + 0x36, 0x54, 0x48, 0x75, 0x42, 0x72, 0x78, 0x7a, 0x76, 0x78, 0x4e, 0x69, + 0x43, 0x70, 0x2f, 0x48, 0x75, 0x5a, 0x63, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, + 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x54, 0x2d, 0x54, 0x65, 0x6c, 0x65, 0x53, 0x65, 0x63, 0x20, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x4f, 0x3d, 0x54, 0x2d, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x73, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x20, 0x4f, 0x55, 0x3d, 0x54, 0x2d, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x0a, 0x23, 0x20, 0x53, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x54, + 0x2d, 0x54, 0x65, 0x6c, 0x65, 0x53, 0x65, 0x63, 0x20, 0x47, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x33, 0x20, 0x4f, 0x3d, 0x54, 0x2d, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x73, 0x20, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x73, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, + 0x47, 0x6d, 0x62, 0x48, 0x20, 0x4f, 0x55, 0x3d, 0x54, 0x2d, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x54, 0x2d, 0x54, 0x65, 0x6c, 0x65, 0x53, + 0x65, 0x63, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x22, 0x0a, 0x23, + 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23, + 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x61, 0x3a, 0x66, 0x62, 0x3a, + 0x34, 0x30, 0x3a, 0x61, 0x38, 0x3a, 0x34, 0x65, 0x3a, 0x33, 0x39, 0x3a, + 0x39, 0x32, 0x3a, 0x38, 0x61, 0x3a, 0x31, 0x64, 0x3a, 0x66, 0x65, 0x3a, + 0x38, 0x65, 0x3a, 0x32, 0x66, 0x3a, 0x63, 0x34, 0x3a, 0x32, 0x37, 0x3a, + 0x65, 0x61, 0x3a, 0x65, 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x35, 0x35, 0x3a, 0x61, 0x36, 0x3a, 0x37, 0x32, 0x3a, 0x33, + 0x65, 0x3a, 0x63, 0x62, 0x3a, 0x66, 0x32, 0x3a, 0x65, 0x63, 0x3a, 0x63, + 0x64, 0x3a, 0x63, 0x33, 0x3a, 0x32, 0x33, 0x3a, 0x37, 0x34, 0x3a, 0x37, + 0x30, 0x3a, 0x31, 0x39, 0x3a, 0x39, 0x64, 0x3a, 0x32, 0x61, 0x3a, 0x62, + 0x65, 0x3a, 0x31, 0x31, 0x3a, 0x65, 0x33, 0x3a, 0x38, 0x31, 0x3a, 0x64, + 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x66, 0x64, 0x3a, 0x37, 0x33, 0x3a, 0x64, 0x61, 0x3a, 0x64, 0x33, 0x3a, + 0x31, 0x63, 0x3a, 0x36, 0x34, 0x3a, 0x34, 0x66, 0x3a, 0x66, 0x31, 0x3a, + 0x62, 0x34, 0x3a, 0x33, 0x62, 0x3a, 0x65, 0x66, 0x3a, 0x30, 0x63, 0x3a, + 0x63, 0x64, 0x3a, 0x64, 0x61, 0x3a, 0x39, 0x36, 0x3a, 0x37, 0x31, 0x3a, + 0x30, 0x62, 0x3a, 0x39, 0x63, 0x3a, 0x64, 0x39, 0x3a, 0x38, 0x37, 0x3a, + 0x35, 0x65, 0x3a, 0x63, 0x61, 0x3a, 0x37, 0x65, 0x3a, 0x33, 0x31, 0x3a, + 0x37, 0x30, 0x3a, 0x37, 0x61, 0x3a, 0x66, 0x33, 0x3a, 0x65, 0x39, 0x3a, + 0x36, 0x64, 0x3a, 0x35, 0x32, 0x3a, 0x32, 0x62, 0x3a, 0x62, 0x64, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x77, 0x7a, 0x43, 0x43, + 0x41, 0x71, 0x75, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, + 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, + 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x43, 0x42, + 0x67, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x42, 0x68, 0x4d, 0x43, 0x52, 0x45, 0x55, 0x78, 0x0a, 0x4b, 0x7a, 0x41, + 0x70, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x49, 0x6c, 0x51, + 0x74, 0x55, 0x33, 0x6c, 0x7a, 0x64, 0x47, 0x56, 0x74, 0x63, 0x79, 0x42, + 0x46, 0x62, 0x6e, 0x52, 0x6c, 0x63, 0x6e, 0x42, 0x79, 0x61, 0x58, 0x4e, + 0x6c, 0x49, 0x46, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, + 0x7a, 0x49, 0x45, 0x64, 0x74, 0x59, 0x6b, 0x67, 0x78, 0x48, 0x7a, 0x41, + 0x64, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x4d, 0x46, 0x6c, + 0x51, 0x74, 0x55, 0x33, 0x6c, 0x7a, 0x64, 0x47, 0x56, 0x74, 0x63, 0x79, + 0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x44, 0x5a, 0x57, + 0x35, 0x30, 0x5a, 0x58, 0x49, 0x78, 0x4a, 0x54, 0x41, 0x6a, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x48, 0x46, 0x51, 0x74, 0x56, 0x47, + 0x56, 0x73, 0x5a, 0x56, 0x4e, 0x6c, 0x0a, 0x59, 0x79, 0x42, 0x48, 0x62, + 0x47, 0x39, 0x69, 0x59, 0x57, 0x78, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, + 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44, 0x4d, 0x77, 0x48, + 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x67, 0x78, 0x4d, 0x44, 0x41, 0x78, 0x4d, + 0x54, 0x41, 0x79, 0x4f, 0x54, 0x55, 0x32, 0x57, 0x68, 0x63, 0x4e, 0x4d, + 0x7a, 0x4d, 0x78, 0x4d, 0x44, 0x41, 0x78, 0x4d, 0x6a, 0x4d, 0x31, 0x0a, + 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, 0x43, 0x42, 0x67, 0x6a, 0x45, 0x4c, + 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, + 0x52, 0x45, 0x55, 0x78, 0x4b, 0x7a, 0x41, 0x70, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x6f, 0x4d, 0x49, 0x6c, 0x51, 0x74, 0x55, 0x33, 0x6c, 0x7a, + 0x64, 0x47, 0x56, 0x74, 0x63, 0x79, 0x42, 0x46, 0x62, 0x6e, 0x52, 0x6c, + 0x63, 0x6e, 0x42, 0x79, 0x0a, 0x61, 0x58, 0x4e, 0x6c, 0x49, 0x46, 0x4e, + 0x6c, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, 0x7a, 0x49, 0x45, 0x64, + 0x74, 0x59, 0x6b, 0x67, 0x78, 0x48, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x73, 0x4d, 0x46, 0x6c, 0x51, 0x74, 0x55, 0x33, 0x6c, + 0x7a, 0x64, 0x47, 0x56, 0x74, 0x63, 0x79, 0x42, 0x55, 0x63, 0x6e, 0x56, + 0x7a, 0x64, 0x43, 0x42, 0x44, 0x5a, 0x57, 0x35, 0x30, 0x0a, 0x5a, 0x58, + 0x49, 0x78, 0x4a, 0x54, 0x41, 0x6a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x4d, 0x4d, 0x48, 0x46, 0x51, 0x74, 0x56, 0x47, 0x56, 0x73, 0x5a, 0x56, + 0x4e, 0x6c, 0x59, 0x79, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, + 0x78, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, + 0x4e, 0x7a, 0x49, 0x44, 0x4d, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4d, 0x41, + 0x30, 0x47, 0x0a, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, + 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, 0x44, + 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, 0x41, + 0x51, 0x43, 0x39, 0x64, 0x5a, 0x50, 0x77, 0x59, 0x69, 0x4a, 0x76, 0x4a, + 0x4b, 0x37, 0x67, 0x65, 0x6e, 0x61, 0x73, 0x66, 0x62, 0x33, 0x5a, 0x4a, + 0x4e, 0x57, 0x34, 0x74, 0x2f, 0x7a, 0x4e, 0x0a, 0x38, 0x45, 0x4c, 0x67, + 0x36, 0x33, 0x69, 0x49, 0x56, 0x6c, 0x36, 0x62, 0x6d, 0x6c, 0x51, 0x64, + 0x54, 0x51, 0x79, 0x4b, 0x39, 0x74, 0x50, 0x50, 0x63, 0x50, 0x52, 0x53, + 0x74, 0x64, 0x69, 0x54, 0x42, 0x4f, 0x4e, 0x47, 0x68, 0x6e, 0x46, 0x42, + 0x53, 0x69, 0x76, 0x77, 0x4b, 0x69, 0x78, 0x56, 0x41, 0x39, 0x5a, 0x49, + 0x77, 0x2b, 0x41, 0x35, 0x4f, 0x4f, 0x33, 0x79, 0x58, 0x44, 0x77, 0x2f, + 0x0a, 0x52, 0x4c, 0x79, 0x54, 0x50, 0x57, 0x47, 0x72, 0x54, 0x73, 0x30, + 0x4e, 0x76, 0x76, 0x41, 0x67, 0x4a, 0x31, 0x67, 0x4f, 0x52, 0x48, 0x38, + 0x45, 0x47, 0x6f, 0x65, 0x6c, 0x31, 0x35, 0x59, 0x55, 0x4e, 0x70, 0x44, + 0x51, 0x53, 0x58, 0x75, 0x68, 0x64, 0x66, 0x73, 0x61, 0x61, 0x33, 0x4f, + 0x78, 0x2b, 0x4d, 0x36, 0x70, 0x43, 0x53, 0x7a, 0x79, 0x55, 0x39, 0x58, + 0x44, 0x46, 0x45, 0x53, 0x34, 0x0a, 0x68, 0x71, 0x58, 0x32, 0x69, 0x79, + 0x73, 0x35, 0x32, 0x71, 0x4d, 0x7a, 0x56, 0x4e, 0x6e, 0x36, 0x63, 0x68, + 0x72, 0x33, 0x49, 0x68, 0x55, 0x63, 0x69, 0x4a, 0x46, 0x72, 0x66, 0x32, + 0x62, 0x6c, 0x77, 0x32, 0x71, 0x41, 0x73, 0x43, 0x54, 0x7a, 0x33, 0x34, + 0x5a, 0x46, 0x69, 0x50, 0x30, 0x5a, 0x66, 0x33, 0x57, 0x48, 0x48, 0x78, + 0x2b, 0x78, 0x47, 0x77, 0x70, 0x7a, 0x4a, 0x46, 0x75, 0x35, 0x0a, 0x5a, + 0x65, 0x41, 0x73, 0x56, 0x4d, 0x68, 0x67, 0x30, 0x32, 0x59, 0x58, 0x50, + 0x2b, 0x48, 0x4d, 0x56, 0x44, 0x4e, 0x7a, 0x6b, 0x51, 0x49, 0x36, 0x70, + 0x6e, 0x39, 0x37, 0x64, 0x6a, 0x6d, 0x69, 0x48, 0x35, 0x61, 0x32, 0x4f, + 0x4b, 0x36, 0x31, 0x79, 0x4a, 0x4e, 0x30, 0x48, 0x5a, 0x36, 0x35, 0x74, + 0x4f, 0x56, 0x67, 0x6e, 0x53, 0x39, 0x57, 0x30, 0x65, 0x44, 0x72, 0x58, + 0x6c, 0x74, 0x4d, 0x0a, 0x45, 0x6e, 0x41, 0x4d, 0x62, 0x45, 0x51, 0x67, + 0x71, 0x78, 0x48, 0x59, 0x39, 0x42, 0x6e, 0x32, 0x30, 0x70, 0x78, 0x53, + 0x4e, 0x2b, 0x66, 0x36, 0x74, 0x73, 0x49, 0x78, 0x4f, 0x30, 0x72, 0x55, + 0x46, 0x4a, 0x6d, 0x74, 0x78, 0x78, 0x72, 0x31, 0x58, 0x56, 0x2f, 0x36, + 0x42, 0x37, 0x68, 0x38, 0x44, 0x52, 0x2f, 0x57, 0x67, 0x78, 0x36, 0x7a, + 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x0a, 0x51, 0x6a, 0x42, + 0x41, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, + 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, + 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, + 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x30, + 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x53, + 0x31, 0x0a, 0x41, 0x2f, 0x64, 0x32, 0x4f, 0x32, 0x47, 0x43, 0x61, 0x68, + 0x4b, 0x71, 0x47, 0x46, 0x50, 0x72, 0x41, 0x79, 0x47, 0x55, 0x76, 0x2f, + 0x37, 0x4f, 0x79, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, + 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x41, + 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x56, 0x6a, 0x33, 0x76, 0x6c, 0x4e, + 0x57, 0x39, 0x32, 0x6e, 0x4f, 0x79, 0x0a, 0x57, 0x4c, 0x36, 0x75, 0x6b, + 0x4b, 0x32, 0x59, 0x4a, 0x35, 0x66, 0x2b, 0x41, 0x62, 0x47, 0x77, 0x55, + 0x67, 0x43, 0x34, 0x54, 0x65, 0x51, 0x62, 0x49, 0x58, 0x51, 0x62, 0x66, + 0x73, 0x44, 0x75, 0x58, 0x6d, 0x6b, 0x71, 0x4a, 0x61, 0x39, 0x63, 0x31, + 0x68, 0x33, 0x61, 0x30, 0x6e, 0x6e, 0x4a, 0x38, 0x35, 0x63, 0x70, 0x34, + 0x49, 0x61, 0x48, 0x33, 0x67, 0x52, 0x5a, 0x44, 0x2f, 0x46, 0x5a, 0x0a, + 0x31, 0x47, 0x53, 0x46, 0x53, 0x35, 0x6d, 0x76, 0x4a, 0x51, 0x51, 0x65, + 0x79, 0x55, 0x61, 0x70, 0x6c, 0x39, 0x36, 0x43, 0x73, 0x68, 0x74, 0x77, + 0x6e, 0x35, 0x7a, 0x32, 0x72, 0x33, 0x45, 0x78, 0x33, 0x58, 0x73, 0x46, + 0x70, 0x53, 0x7a, 0x54, 0x75, 0x63, 0x70, 0x48, 0x39, 0x73, 0x72, 0x79, + 0x39, 0x75, 0x65, 0x74, 0x75, 0x55, 0x67, 0x2f, 0x76, 0x42, 0x61, 0x33, + 0x77, 0x57, 0x33, 0x30, 0x0a, 0x36, 0x67, 0x6d, 0x76, 0x37, 0x50, 0x4f, + 0x31, 0x35, 0x77, 0x57, 0x65, 0x70, 0x68, 0x36, 0x4b, 0x55, 0x31, 0x48, + 0x57, 0x6b, 0x34, 0x48, 0x4d, 0x64, 0x4a, 0x50, 0x32, 0x75, 0x64, 0x71, + 0x6d, 0x4a, 0x51, 0x56, 0x30, 0x65, 0x56, 0x70, 0x2b, 0x51, 0x44, 0x36, + 0x43, 0x53, 0x79, 0x59, 0x52, 0x4d, 0x47, 0x37, 0x68, 0x50, 0x30, 0x48, + 0x48, 0x52, 0x77, 0x41, 0x31, 0x31, 0x66, 0x58, 0x54, 0x0a, 0x39, 0x31, + 0x51, 0x2b, 0x67, 0x54, 0x33, 0x61, 0x53, 0x57, 0x71, 0x61, 0x73, 0x2b, + 0x38, 0x51, 0x50, 0x65, 0x62, 0x72, 0x62, 0x39, 0x48, 0x49, 0x49, 0x6b, + 0x66, 0x4c, 0x7a, 0x4d, 0x38, 0x42, 0x4d, 0x5a, 0x4c, 0x5a, 0x47, 0x4f, + 0x4d, 0x69, 0x76, 0x67, 0x6b, 0x65, 0x47, 0x6a, 0x35, 0x61, 0x73, 0x75, + 0x52, 0x72, 0x44, 0x46, 0x52, 0x36, 0x66, 0x55, 0x4e, 0x4f, 0x75, 0x49, + 0x6d, 0x6c, 0x0a, 0x65, 0x39, 0x65, 0x69, 0x50, 0x5a, 0x61, 0x47, 0x7a, + 0x50, 0x49, 0x6d, 0x4e, 0x43, 0x31, 0x71, 0x6b, 0x70, 0x32, 0x61, 0x47, + 0x74, 0x41, 0x77, 0x34, 0x6c, 0x31, 0x4f, 0x42, 0x4c, 0x42, 0x66, 0x69, + 0x79, 0x42, 0x2b, 0x64, 0x38, 0x45, 0x39, 0x6c, 0x59, 0x4c, 0x52, 0x52, + 0x70, 0x6f, 0x37, 0x50, 0x48, 0x69, 0x34, 0x62, 0x36, 0x48, 0x51, 0x44, + 0x57, 0x53, 0x69, 0x65, 0x42, 0x34, 0x70, 0x0a, 0x54, 0x70, 0x50, 0x44, + 0x70, 0x46, 0x51, 0x55, 0x57, 0x77, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, + 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x45, 0x45, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x65, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x41, + 0x53, 0x20, 0x53, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x74, 0x73, 0x65, + 0x65, 0x72, 0x69, 0x6d, 0x69, 0x73, 0x6b, 0x65, 0x73, 0x6b, 0x75, 0x73, + 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x45, 0x45, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x43, 0x65, 0x6e, 0x74, + 0x72, 0x65, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, + 0x3d, 0x41, 0x53, 0x20, 0x53, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x74, + 0x73, 0x65, 0x65, 0x72, 0x69, 0x6d, 0x69, 0x73, 0x6b, 0x65, 0x73, 0x6b, + 0x75, 0x73, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x45, 0x45, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x65, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, + 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x31, 0x32, 0x33, + 0x32, 0x34, 0x38, 0x32, 0x38, 0x36, 0x37, 0x36, 0x32, 0x30, 0x30, 0x32, + 0x39, 0x31, 0x38, 0x37, 0x31, 0x39, 0x32, 0x36, 0x34, 0x33, 0x31, 0x38, + 0x38, 0x38, 0x34, 0x39, 0x34, 0x39, 0x34, 0x35, 0x38, 0x36, 0x36, 0x0a, + 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x33, 0x3a, 0x35, 0x65, + 0x3a, 0x38, 0x38, 0x3a, 0x64, 0x34, 0x3a, 0x37, 0x64, 0x3a, 0x31, 0x61, + 0x3a, 0x34, 0x61, 0x3a, 0x37, 0x65, 0x3a, 0x66, 0x64, 0x3a, 0x38, 0x34, + 0x3a, 0x32, 0x65, 0x3a, 0x35, 0x32, 0x3a, 0x65, 0x62, 0x3a, 0x30, 0x31, + 0x3a, 0x64, 0x34, 0x3a, 0x36, 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x63, 0x39, 0x3a, 0x61, 0x38, 0x3a, 0x62, 0x39, 0x3a, + 0x65, 0x37, 0x3a, 0x35, 0x35, 0x3a, 0x38, 0x30, 0x3a, 0x35, 0x65, 0x3a, + 0x35, 0x38, 0x3a, 0x65, 0x33, 0x3a, 0x35, 0x33, 0x3a, 0x37, 0x37, 0x3a, + 0x61, 0x37, 0x3a, 0x32, 0x35, 0x3a, 0x65, 0x62, 0x3a, 0x61, 0x66, 0x3a, + 0x63, 0x33, 0x3a, 0x37, 0x62, 0x3a, 0x32, 0x37, 0x3a, 0x63, 0x63, 0x3a, + 0x64, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x33, 0x65, 0x3a, 0x38, 0x34, 0x3a, 0x62, 0x61, 0x3a, 0x34, 0x33, + 0x3a, 0x34, 0x32, 0x3a, 0x39, 0x30, 0x3a, 0x38, 0x35, 0x3a, 0x31, 0x36, + 0x3a, 0x65, 0x37, 0x3a, 0x37, 0x35, 0x3a, 0x37, 0x33, 0x3a, 0x63, 0x30, + 0x3a, 0x39, 0x39, 0x3a, 0x32, 0x66, 0x3a, 0x30, 0x39, 0x3a, 0x37, 0x39, + 0x3a, 0x63, 0x61, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x65, 0x3a, 0x34, 0x36, + 0x3a, 0x38, 0x35, 0x3a, 0x36, 0x38, 0x3a, 0x31, 0x66, 0x3a, 0x66, 0x31, + 0x3a, 0x39, 0x35, 0x3a, 0x63, 0x63, 0x3a, 0x62, 0x61, 0x3a, 0x38, 0x61, + 0x3a, 0x32, 0x32, 0x3a, 0x39, 0x62, 0x3a, 0x38, 0x61, 0x3a, 0x37, 0x36, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x41, 0x7a, 0x43, + 0x43, 0x41, 0x75, 0x75, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x51, 0x56, 0x49, 0x44, 0x35, 0x6f, 0x48, 0x50, 0x74, 0x50, 0x77, 0x42, + 0x4d, 0x79, 0x6f, 0x6e, 0x59, 0x34, 0x33, 0x48, 0x6d, 0x53, 0x6a, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, + 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x31, 0x0a, 0x4d, 0x51, + 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, + 0x4a, 0x46, 0x52, 0x54, 0x45, 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x67, 0x77, 0x5a, 0x51, 0x56, 0x4d, 0x67, 0x55, 0x32, + 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x58, 0x52, 0x7a, 0x5a, 0x57, + 0x56, 0x79, 0x61, 0x57, 0x31, 0x70, 0x63, 0x32, 0x74, 0x6c, 0x63, 0x32, + 0x74, 0x31, 0x0a, 0x63, 0x7a, 0x45, 0x6f, 0x4d, 0x43, 0x59, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x66, 0x52, 0x55, 0x55, 0x67, 0x51, + 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, + 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x44, 0x5a, 0x57, 0x35, 0x30, 0x63, + 0x6d, 0x55, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, + 0x54, 0x45, 0x59, 0x4d, 0x42, 0x59, 0x47, 0x0a, 0x43, 0x53, 0x71, 0x47, + 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x4a, 0x41, 0x52, 0x59, 0x4a, + 0x63, 0x47, 0x74, 0x70, 0x51, 0x48, 0x4e, 0x72, 0x4c, 0x6d, 0x56, 0x6c, + 0x4d, 0x43, 0x49, 0x59, 0x44, 0x7a, 0x49, 0x77, 0x4d, 0x54, 0x41, 0x78, + 0x4d, 0x44, 0x4d, 0x77, 0x4d, 0x54, 0x41, 0x78, 0x4d, 0x44, 0x4d, 0x77, + 0x57, 0x68, 0x67, 0x50, 0x4d, 0x6a, 0x41, 0x7a, 0x4d, 0x44, 0x45, 0x79, + 0x0a, 0x4d, 0x54, 0x63, 0x79, 0x4d, 0x7a, 0x55, 0x35, 0x4e, 0x54, 0x6c, + 0x61, 0x4d, 0x48, 0x55, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x56, 0x46, 0x4d, 0x53, 0x49, + 0x77, 0x49, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x6c, + 0x42, 0x55, 0x79, 0x42, 0x54, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, + 0x70, 0x64, 0x48, 0x4e, 0x6c, 0x0a, 0x5a, 0x58, 0x4a, 0x70, 0x62, 0x57, + 0x6c, 0x7a, 0x61, 0x32, 0x56, 0x7a, 0x61, 0x33, 0x56, 0x7a, 0x4d, 0x53, + 0x67, 0x77, 0x4a, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, + 0x39, 0x46, 0x52, 0x53, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, + 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, + 0x4e, 0x6c, 0x62, 0x6e, 0x52, 0x79, 0x5a, 0x53, 0x42, 0x53, 0x0a, 0x62, + 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x52, 0x67, 0x77, 0x46, + 0x67, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, + 0x51, 0x6b, 0x42, 0x46, 0x67, 0x6c, 0x77, 0x61, 0x32, 0x6c, 0x41, 0x63, + 0x32, 0x73, 0x75, 0x5a, 0x57, 0x55, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4d, + 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, + 0x51, 0x45, 0x42, 0x0a, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, + 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, + 0x41, 0x51, 0x44, 0x49, 0x49, 0x4d, 0x44, 0x73, 0x34, 0x4d, 0x56, 0x4c, + 0x71, 0x77, 0x64, 0x34, 0x6c, 0x66, 0x4e, 0x45, 0x37, 0x76, 0x73, 0x4c, + 0x44, 0x50, 0x39, 0x30, 0x6a, 0x6d, 0x47, 0x37, 0x73, 0x57, 0x4c, 0x71, + 0x49, 0x39, 0x69, 0x72, 0x6f, 0x57, 0x55, 0x79, 0x0a, 0x65, 0x75, 0x75, + 0x4f, 0x46, 0x30, 0x2b, 0x57, 0x32, 0x41, 0x70, 0x37, 0x6b, 0x61, 0x4a, + 0x6a, 0x62, 0x4d, 0x65, 0x4d, 0x54, 0x43, 0x35, 0x35, 0x76, 0x36, 0x6b, + 0x46, 0x2f, 0x47, 0x6c, 0x63, 0x6c, 0x59, 0x31, 0x69, 0x2b, 0x62, 0x6c, + 0x77, 0x37, 0x63, 0x4e, 0x52, 0x66, 0x64, 0x43, 0x54, 0x35, 0x6d, 0x7a, + 0x72, 0x4d, 0x45, 0x76, 0x68, 0x76, 0x48, 0x32, 0x2f, 0x55, 0x70, 0x76, + 0x4f, 0x0a, 0x62, 0x6e, 0x74, 0x6c, 0x38, 0x6a, 0x69, 0x78, 0x77, 0x4b, + 0x49, 0x79, 0x37, 0x32, 0x4b, 0x79, 0x61, 0x4f, 0x42, 0x68, 0x55, 0x38, + 0x45, 0x32, 0x6c, 0x66, 0x2f, 0x73, 0x6c, 0x4c, 0x6f, 0x32, 0x72, 0x70, + 0x77, 0x63, 0x70, 0x7a, 0x49, 0x50, 0x35, 0x58, 0x79, 0x30, 0x78, 0x6d, + 0x39, 0x30, 0x2f, 0x58, 0x73, 0x59, 0x36, 0x4b, 0x78, 0x58, 0x37, 0x51, + 0x59, 0x67, 0x53, 0x7a, 0x49, 0x77, 0x0a, 0x57, 0x46, 0x76, 0x39, 0x7a, + 0x61, 0x6a, 0x6d, 0x6f, 0x66, 0x78, 0x77, 0x76, 0x49, 0x36, 0x53, 0x63, + 0x39, 0x75, 0x58, 0x70, 0x33, 0x77, 0x68, 0x72, 0x6a, 0x33, 0x42, 0x39, + 0x55, 0x69, 0x48, 0x62, 0x43, 0x65, 0x39, 0x6e, 0x79, 0x56, 0x30, 0x67, + 0x56, 0x57, 0x77, 0x39, 0x33, 0x58, 0x32, 0x50, 0x61, 0x52, 0x6b, 0x61, + 0x39, 0x5a, 0x50, 0x35, 0x38, 0x35, 0x41, 0x72, 0x51, 0x2f, 0x64, 0x0a, + 0x4d, 0x74, 0x4f, 0x38, 0x69, 0x68, 0x4a, 0x54, 0x6d, 0x4d, 0x6d, 0x4a, + 0x2b, 0x78, 0x41, 0x64, 0x54, 0x58, 0x37, 0x4e, 0x66, 0x68, 0x39, 0x57, + 0x44, 0x53, 0x46, 0x77, 0x68, 0x66, 0x59, 0x67, 0x67, 0x78, 0x2f, 0x32, + 0x75, 0x68, 0x38, 0x45, 0x6a, 0x2b, 0x70, 0x33, 0x69, 0x44, 0x58, 0x45, + 0x2f, 0x2b, 0x70, 0x4f, 0x6f, 0x59, 0x74, 0x4e, 0x50, 0x32, 0x4d, 0x62, + 0x52, 0x4d, 0x4e, 0x45, 0x0a, 0x31, 0x43, 0x56, 0x32, 0x79, 0x72, 0x65, + 0x4e, 0x31, 0x78, 0x35, 0x4b, 0x5a, 0x6d, 0x54, 0x4e, 0x58, 0x4d, 0x57, + 0x63, 0x67, 0x2b, 0x48, 0x43, 0x43, 0x49, 0x69, 0x61, 0x37, 0x45, 0x36, + 0x6a, 0x38, 0x54, 0x34, 0x63, 0x4c, 0x4e, 0x6c, 0x73, 0x48, 0x61, 0x46, + 0x4c, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x67, 0x59, 0x6f, + 0x77, 0x67, 0x59, 0x63, 0x77, 0x44, 0x77, 0x59, 0x44, 0x0a, 0x56, 0x52, + 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, + 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, + 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, + 0x59, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, + 0x59, 0x45, 0x46, 0x42, 0x4c, 0x79, 0x57, 0x6a, 0x37, 0x71, 0x56, 0x68, + 0x79, 0x2f, 0x0a, 0x7a, 0x51, 0x61, 0x73, 0x38, 0x66, 0x45, 0x6c, 0x79, + 0x61, 0x6c, 0x4c, 0x31, 0x42, 0x53, 0x5a, 0x4d, 0x45, 0x55, 0x47, 0x41, + 0x31, 0x55, 0x64, 0x4a, 0x51, 0x51, 0x2b, 0x4d, 0x44, 0x77, 0x47, 0x43, + 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x77, 0x4d, 0x43, 0x42, + 0x67, 0x67, 0x72, 0x42, 0x67, 0x45, 0x46, 0x42, 0x51, 0x63, 0x44, 0x41, + 0x51, 0x59, 0x49, 0x4b, 0x77, 0x59, 0x42, 0x0a, 0x42, 0x51, 0x55, 0x48, + 0x41, 0x77, 0x4d, 0x47, 0x43, 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, + 0x42, 0x77, 0x4d, 0x45, 0x42, 0x67, 0x67, 0x72, 0x42, 0x67, 0x45, 0x46, + 0x42, 0x51, 0x63, 0x44, 0x43, 0x41, 0x59, 0x49, 0x4b, 0x77, 0x59, 0x42, + 0x42, 0x51, 0x55, 0x48, 0x41, 0x77, 0x6b, 0x77, 0x44, 0x51, 0x59, 0x4a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, + 0x0a, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x48, 0x76, + 0x32, 0x35, 0x4d, 0x41, 0x4e, 0x71, 0x68, 0x6c, 0x48, 0x74, 0x30, 0x31, + 0x58, 0x6f, 0x2f, 0x36, 0x74, 0x75, 0x37, 0x46, 0x71, 0x31, 0x51, 0x2b, + 0x65, 0x32, 0x2b, 0x52, 0x6a, 0x78, 0x59, 0x36, 0x68, 0x55, 0x46, 0x61, + 0x54, 0x6c, 0x72, 0x67, 0x34, 0x77, 0x43, 0x51, 0x69, 0x5a, 0x72, 0x78, + 0x54, 0x46, 0x47, 0x47, 0x56, 0x0a, 0x76, 0x39, 0x44, 0x48, 0x4b, 0x70, + 0x59, 0x35, 0x50, 0x33, 0x30, 0x6f, 0x73, 0x78, 0x42, 0x41, 0x49, 0x57, + 0x72, 0x45, 0x72, 0x37, 0x42, 0x53, 0x64, 0x78, 0x6a, 0x68, 0x6c, 0x74, + 0x68, 0x57, 0x58, 0x65, 0x50, 0x64, 0x4e, 0x6c, 0x34, 0x64, 0x70, 0x31, + 0x42, 0x55, 0x6f, 0x4d, 0x55, 0x71, 0x35, 0x4b, 0x71, 0x4d, 0x6c, 0x49, + 0x70, 0x50, 0x6e, 0x54, 0x58, 0x2f, 0x64, 0x71, 0x51, 0x47, 0x0a, 0x45, + 0x35, 0x47, 0x69, 0x6f, 0x6e, 0x30, 0x41, 0x52, 0x44, 0x39, 0x56, 0x30, + 0x34, 0x49, 0x38, 0x47, 0x74, 0x56, 0x62, 0x76, 0x46, 0x5a, 0x4d, 0x49, + 0x69, 0x35, 0x47, 0x51, 0x34, 0x6f, 0x6b, 0x51, 0x43, 0x33, 0x7a, 0x45, + 0x72, 0x67, 0x37, 0x63, 0x42, 0x71, 0x6b, 0x6c, 0x72, 0x6b, 0x61, 0x72, + 0x34, 0x64, 0x42, 0x47, 0x6d, 0x6f, 0x59, 0x44, 0x51, 0x5a, 0x50, 0x78, + 0x7a, 0x35, 0x75, 0x0a, 0x75, 0x53, 0x6c, 0x4e, 0x44, 0x55, 0x6d, 0x4a, + 0x45, 0x59, 0x63, 0x79, 0x57, 0x2b, 0x5a, 0x4c, 0x42, 0x4d, 0x6a, 0x6b, + 0x58, 0x4f, 0x5a, 0x30, 0x63, 0x35, 0x52, 0x64, 0x46, 0x70, 0x67, 0x54, + 0x6c, 0x66, 0x37, 0x37, 0x32, 0x37, 0x46, 0x45, 0x35, 0x54, 0x70, 0x77, + 0x72, 0x44, 0x64, 0x72, 0x35, 0x72, 0x4d, 0x7a, 0x63, 0x69, 0x6a, 0x4a, + 0x73, 0x31, 0x65, 0x67, 0x39, 0x67, 0x49, 0x57, 0x0a, 0x69, 0x41, 0x59, + 0x4c, 0x74, 0x71, 0x5a, 0x4c, 0x49, 0x43, 0x6a, 0x55, 0x33, 0x6a, 0x32, + 0x4c, 0x72, 0x54, 0x63, 0x46, 0x55, 0x33, 0x54, 0x2b, 0x62, 0x73, 0x79, + 0x38, 0x51, 0x78, 0x64, 0x78, 0x58, 0x76, 0x6e, 0x46, 0x7a, 0x42, 0x71, + 0x70, 0x59, 0x65, 0x37, 0x33, 0x64, 0x67, 0x7a, 0x7a, 0x63, 0x76, 0x52, + 0x79, 0x72, 0x63, 0x39, 0x79, 0x41, 0x6a, 0x59, 0x48, 0x52, 0x38, 0x2f, + 0x76, 0x0a, 0x47, 0x56, 0x43, 0x4a, 0x59, 0x4d, 0x7a, 0x70, 0x4a, 0x4a, + 0x55, 0x50, 0x77, 0x73, 0x73, 0x64, 0x38, 0x6d, 0x39, 0x32, 0x6b, 0x4d, + 0x66, 0x4d, 0x64, 0x63, 0x47, 0x57, 0x78, 0x5a, 0x30, 0x3d, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x44, 0x2d, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, + 0x43, 0x41, 0x20, 0x32, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x4f, 0x3d, + 0x44, 0x2d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6d, 0x62, 0x48, + 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x44, 0x2d, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, + 0x43, 0x41, 0x20, 0x32, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x4f, 0x3d, + 0x44, 0x2d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6d, 0x62, 0x48, + 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x44, + 0x2d, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x43, 0x41, 0x20, 0x32, + 0x20, 0x32, 0x30, 0x30, 0x39, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x36, 0x32, 0x33, 0x36, 0x30, 0x33, 0x0a, + 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x64, 0x3a, 0x65, 0x30, + 0x3a, 0x32, 0x35, 0x3a, 0x36, 0x39, 0x3a, 0x38, 0x64, 0x3a, 0x34, 0x37, + 0x3a, 0x61, 0x63, 0x3a, 0x39, 0x63, 0x3a, 0x38, 0x39, 0x3a, 0x33, 0x35, + 0x3a, 0x39, 0x30, 0x3a, 0x66, 0x37, 0x3a, 0x66, 0x64, 0x3a, 0x35, 0x31, + 0x3a, 0x33, 0x64, 0x3a, 0x32, 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x35, 0x38, 0x3a, 0x65, 0x38, 0x3a, 0x61, 0x62, 0x3a, + 0x62, 0x30, 0x3a, 0x33, 0x36, 0x3a, 0x31, 0x35, 0x3a, 0x33, 0x33, 0x3a, + 0x66, 0x62, 0x3a, 0x38, 0x30, 0x3a, 0x66, 0x37, 0x3a, 0x39, 0x62, 0x3a, + 0x31, 0x62, 0x3a, 0x36, 0x64, 0x3a, 0x32, 0x39, 0x3a, 0x64, 0x33, 0x3a, + 0x66, 0x66, 0x3a, 0x38, 0x64, 0x3a, 0x35, 0x66, 0x3a, 0x30, 0x30, 0x3a, + 0x66, 0x30, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x34, 0x39, 0x3a, 0x65, 0x37, 0x3a, 0x61, 0x34, 0x3a, 0x34, 0x32, + 0x3a, 0x61, 0x63, 0x3a, 0x66, 0x30, 0x3a, 0x65, 0x61, 0x3a, 0x36, 0x32, + 0x3a, 0x38, 0x37, 0x3a, 0x30, 0x35, 0x3a, 0x30, 0x30, 0x3a, 0x35, 0x34, + 0x3a, 0x62, 0x35, 0x3a, 0x32, 0x35, 0x3a, 0x36, 0x34, 0x3a, 0x62, 0x36, + 0x3a, 0x35, 0x30, 0x3a, 0x65, 0x34, 0x3a, 0x66, 0x34, 0x3a, 0x39, 0x65, + 0x3a, 0x34, 0x32, 0x3a, 0x65, 0x33, 0x3a, 0x34, 0x38, 0x3a, 0x64, 0x36, + 0x3a, 0x61, 0x61, 0x3a, 0x33, 0x38, 0x3a, 0x65, 0x30, 0x3a, 0x33, 0x39, + 0x3a, 0x65, 0x39, 0x3a, 0x35, 0x37, 0x3a, 0x62, 0x31, 0x3a, 0x63, 0x31, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x4d, 0x7a, 0x43, + 0x43, 0x41, 0x78, 0x75, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x44, 0x43, 0x59, 0x50, 0x7a, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, + 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, + 0x41, 0x4d, 0x45, 0x30, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x52, 0x46, 0x0a, 0x4d, 0x52, + 0x55, 0x77, 0x45, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, + 0x78, 0x45, 0x4c, 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, + 0x64, 0x74, 0x59, 0x6b, 0x67, 0x78, 0x4a, 0x7a, 0x41, 0x6c, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x48, 0x6b, 0x51, 0x74, 0x56, 0x46, + 0x4a, 0x56, 0x55, 0x31, 0x51, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, + 0x42, 0x44, 0x0a, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, 0x41, 0x7a, 0x49, + 0x45, 0x4e, 0x42, 0x49, 0x44, 0x49, 0x67, 0x4d, 0x6a, 0x41, 0x77, 0x4f, + 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, 0x77, 0x4f, 0x54, 0x45, 0x78, 0x4d, + 0x44, 0x55, 0x77, 0x4f, 0x44, 0x4d, 0x31, 0x4e, 0x54, 0x68, 0x61, 0x46, + 0x77, 0x30, 0x79, 0x4f, 0x54, 0x45, 0x78, 0x4d, 0x44, 0x55, 0x77, 0x4f, + 0x44, 0x4d, 0x31, 0x4e, 0x54, 0x68, 0x61, 0x0a, 0x4d, 0x45, 0x30, 0x78, + 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, + 0x41, 0x6b, 0x52, 0x46, 0x4d, 0x52, 0x55, 0x77, 0x45, 0x77, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, 0x78, 0x45, 0x4c, 0x56, 0x52, 0x79, + 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, 0x64, 0x74, 0x59, 0x6b, 0x67, 0x78, + 0x4a, 0x7a, 0x41, 0x6c, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, + 0x0a, 0x48, 0x6b, 0x51, 0x74, 0x56, 0x46, 0x4a, 0x56, 0x55, 0x31, 0x51, + 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x62, 0x47, 0x46, + 0x7a, 0x63, 0x79, 0x41, 0x7a, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x44, 0x49, + 0x67, 0x4d, 0x6a, 0x41, 0x77, 0x4f, 0x54, 0x43, 0x43, 0x41, 0x53, 0x49, + 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, + 0x4e, 0x41, 0x51, 0x45, 0x42, 0x0a, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, + 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, + 0x45, 0x42, 0x41, 0x4e, 0x4f, 0x79, 0x53, 0x73, 0x39, 0x36, 0x52, 0x2b, + 0x39, 0x31, 0x6d, 0x79, 0x50, 0x36, 0x4f, 0x69, 0x2f, 0x57, 0x55, 0x45, + 0x57, 0x4a, 0x4e, 0x54, 0x72, 0x47, 0x61, 0x39, 0x76, 0x2b, 0x32, 0x77, + 0x42, 0x6f, 0x71, 0x4f, 0x41, 0x44, 0x45, 0x52, 0x30, 0x33, 0x0a, 0x55, + 0x41, 0x69, 0x66, 0x54, 0x55, 0x70, 0x6f, 0x6c, 0x44, 0x57, 0x7a, 0x55, + 0x39, 0x47, 0x55, 0x59, 0x36, 0x63, 0x67, 0x56, 0x71, 0x2f, 0x65, 0x55, + 0x58, 0x6a, 0x73, 0x4b, 0x6a, 0x33, 0x7a, 0x53, 0x45, 0x68, 0x51, 0x50, + 0x67, 0x72, 0x66, 0x52, 0x6c, 0x57, 0x4c, 0x4a, 0x32, 0x33, 0x44, 0x45, + 0x45, 0x30, 0x4e, 0x6b, 0x56, 0x4a, 0x44, 0x32, 0x49, 0x66, 0x67, 0x58, + 0x55, 0x34, 0x32, 0x0a, 0x74, 0x53, 0x48, 0x4b, 0x58, 0x7a, 0x6c, 0x41, + 0x42, 0x46, 0x39, 0x62, 0x66, 0x73, 0x79, 0x6a, 0x78, 0x69, 0x75, 0x70, + 0x51, 0x42, 0x37, 0x5a, 0x4e, 0x6f, 0x54, 0x57, 0x53, 0x50, 0x4f, 0x53, + 0x48, 0x6a, 0x52, 0x47, 0x49, 0x43, 0x54, 0x42, 0x70, 0x46, 0x47, 0x4f, + 0x53, 0x68, 0x72, 0x76, 0x55, 0x44, 0x39, 0x70, 0x58, 0x52, 0x6c, 0x2f, + 0x52, 0x63, 0x50, 0x48, 0x41, 0x59, 0x39, 0x52, 0x0a, 0x79, 0x53, 0x50, + 0x6f, 0x63, 0x71, 0x36, 0x30, 0x76, 0x46, 0x59, 0x4a, 0x66, 0x78, 0x4c, + 0x4c, 0x48, 0x4c, 0x47, 0x76, 0x4b, 0x5a, 0x41, 0x4b, 0x79, 0x56, 0x58, + 0x4d, 0x44, 0x39, 0x4f, 0x30, 0x47, 0x75, 0x31, 0x48, 0x4e, 0x56, 0x70, + 0x4b, 0x37, 0x5a, 0x78, 0x7a, 0x42, 0x43, 0x48, 0x51, 0x71, 0x72, 0x30, + 0x4d, 0x45, 0x37, 0x55, 0x41, 0x79, 0x69, 0x5a, 0x73, 0x78, 0x47, 0x73, + 0x4d, 0x0a, 0x6c, 0x46, 0x71, 0x56, 0x6c, 0x4e, 0x70, 0x51, 0x6d, 0x76, + 0x48, 0x2f, 0x70, 0x53, 0x74, 0x6d, 0x4d, 0x61, 0x54, 0x4a, 0x4f, 0x4b, + 0x44, 0x66, 0x48, 0x52, 0x2b, 0x34, 0x43, 0x53, 0x37, 0x7a, 0x70, 0x2b, + 0x68, 0x6e, 0x55, 0x71, 0x75, 0x56, 0x48, 0x2b, 0x42, 0x47, 0x50, 0x74, + 0x69, 0x6b, 0x77, 0x38, 0x70, 0x61, 0x78, 0x54, 0x47, 0x41, 0x36, 0x45, + 0x69, 0x61, 0x6e, 0x35, 0x52, 0x70, 0x0a, 0x2f, 0x68, 0x6e, 0x64, 0x32, + 0x48, 0x4e, 0x38, 0x67, 0x63, 0x71, 0x57, 0x33, 0x6f, 0x37, 0x74, 0x73, + 0x7a, 0x49, 0x46, 0x5a, 0x59, 0x51, 0x30, 0x35, 0x75, 0x62, 0x39, 0x56, + 0x78, 0x43, 0x31, 0x58, 0x33, 0x61, 0x2f, 0x4c, 0x37, 0x41, 0x51, 0x44, + 0x63, 0x55, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4f, 0x43, 0x41, + 0x52, 0x6f, 0x77, 0x67, 0x67, 0x45, 0x57, 0x4d, 0x41, 0x38, 0x47, 0x0a, + 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, + 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, + 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x50, 0x33, 0x61, + 0x46, 0x4d, 0x53, 0x66, 0x4d, 0x4e, 0x34, 0x68, 0x76, 0x52, 0x35, 0x43, + 0x4f, 0x66, 0x79, 0x72, 0x59, 0x79, 0x4e, 0x4a, 0x34, 0x50, 0x47, 0x45, + 0x4d, 0x41, 0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, + 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x43, + 0x42, 0x30, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x66, 0x42, 0x49, 0x48, + 0x4c, 0x4d, 0x49, 0x48, 0x49, 0x4d, 0x49, 0x47, 0x41, 0x6f, 0x48, 0x36, + 0x67, 0x66, 0x49, 0x5a, 0x36, 0x62, 0x47, 0x52, 0x68, 0x63, 0x44, 0x6f, + 0x76, 0x4c, 0x32, 0x52, 0x70, 0x63, 0x6d, 0x56, 0x6a, 0x0a, 0x64, 0x47, + 0x39, 0x79, 0x65, 0x53, 0x35, 0x6b, 0x4c, 0x58, 0x52, 0x79, 0x64, 0x58, + 0x4e, 0x30, 0x4c, 0x6d, 0x35, 0x6c, 0x64, 0x43, 0x39, 0x44, 0x54, 0x6a, + 0x31, 0x45, 0x4c, 0x56, 0x52, 0x53, 0x56, 0x56, 0x4e, 0x55, 0x4a, 0x54, + 0x49, 0x77, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x55, 0x79, 0x4d, 0x45, + 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x4a, 0x54, 0x49, 0x77, 0x4d, 0x79, + 0x55, 0x79, 0x0a, 0x4d, 0x45, 0x4e, 0x42, 0x4a, 0x54, 0x49, 0x77, 0x4d, + 0x69, 0x55, 0x79, 0x4d, 0x44, 0x49, 0x77, 0x4d, 0x44, 0x6b, 0x73, 0x54, + 0x7a, 0x31, 0x45, 0x4c, 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4a, + 0x54, 0x49, 0x77, 0x52, 0x32, 0x31, 0x69, 0x53, 0x43, 0x78, 0x44, 0x50, + 0x55, 0x52, 0x46, 0x50, 0x32, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, + 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x0a, 0x63, 0x6d, 0x56, 0x32, + 0x62, 0x32, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6d, 0x78, 0x70, + 0x63, 0x33, 0x51, 0x77, 0x51, 0x36, 0x42, 0x42, 0x6f, 0x44, 0x2b, 0x47, + 0x50, 0x57, 0x68, 0x30, 0x64, 0x48, 0x41, 0x36, 0x4c, 0x79, 0x39, 0x33, + 0x64, 0x33, 0x63, 0x75, 0x5a, 0x43, 0x31, 0x30, 0x63, 0x6e, 0x56, 0x7a, + 0x64, 0x43, 0x35, 0x75, 0x5a, 0x58, 0x51, 0x76, 0x59, 0x33, 0x4a, 0x73, + 0x0a, 0x4c, 0x32, 0x51, 0x74, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, + 0x66, 0x63, 0x6d, 0x39, 0x76, 0x64, 0x46, 0x39, 0x6a, 0x62, 0x47, 0x46, + 0x7a, 0x63, 0x31, 0x38, 0x7a, 0x58, 0x32, 0x4e, 0x68, 0x58, 0x7a, 0x4a, + 0x66, 0x4d, 0x6a, 0x41, 0x77, 0x4f, 0x53, 0x35, 0x6a, 0x63, 0x6d, 0x77, + 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, + 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x0a, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, + 0x45, 0x42, 0x41, 0x48, 0x2b, 0x58, 0x32, 0x7a, 0x44, 0x49, 0x33, 0x36, + 0x53, 0x63, 0x66, 0x53, 0x46, 0x36, 0x67, 0x48, 0x44, 0x4f, 0x46, 0x42, + 0x4a, 0x70, 0x69, 0x42, 0x53, 0x56, 0x59, 0x45, 0x51, 0x42, 0x72, 0x4c, + 0x4c, 0x70, 0x4d, 0x45, 0x2b, 0x62, 0x55, 0x4d, 0x4a, 0x6d, 0x32, 0x48, + 0x36, 0x4e, 0x4d, 0x4c, 0x56, 0x77, 0x4d, 0x65, 0x6e, 0x69, 0x0a, 0x61, + 0x63, 0x66, 0x7a, 0x63, 0x4e, 0x73, 0x67, 0x46, 0x59, 0x62, 0x51, 0x44, + 0x66, 0x43, 0x2b, 0x72, 0x41, 0x46, 0x31, 0x68, 0x4d, 0x35, 0x2b, 0x6e, + 0x30, 0x32, 0x2f, 0x74, 0x32, 0x41, 0x37, 0x6e, 0x50, 0x50, 0x4b, 0x48, + 0x65, 0x4a, 0x65, 0x61, 0x4e, 0x69, 0x6a, 0x6e, 0x5a, 0x66, 0x6c, 0x51, + 0x47, 0x44, 0x53, 0x4e, 0x69, 0x48, 0x2b, 0x30, 0x4c, 0x53, 0x34, 0x46, + 0x39, 0x70, 0x30, 0x0a, 0x6f, 0x33, 0x2f, 0x55, 0x33, 0x37, 0x43, 0x59, + 0x41, 0x71, 0x78, 0x76, 0x61, 0x32, 0x73, 0x73, 0x4a, 0x53, 0x52, 0x79, + 0x6f, 0x57, 0x58, 0x75, 0x4a, 0x56, 0x72, 0x6c, 0x35, 0x6a, 0x4c, 0x6e, + 0x38, 0x74, 0x2b, 0x72, 0x53, 0x66, 0x72, 0x7a, 0x6b, 0x47, 0x6b, 0x6a, + 0x32, 0x77, 0x54, 0x5a, 0x35, 0x31, 0x78, 0x59, 0x2f, 0x47, 0x58, 0x55, + 0x6c, 0x37, 0x37, 0x4d, 0x2f, 0x43, 0x34, 0x4b, 0x0a, 0x7a, 0x43, 0x55, + 0x71, 0x4e, 0x51, 0x54, 0x34, 0x59, 0x4a, 0x45, 0x56, 0x64, 0x54, 0x31, + 0x42, 0x2f, 0x79, 0x4d, 0x66, 0x47, 0x63, 0x68, 0x73, 0x36, 0x34, 0x4a, + 0x54, 0x42, 0x4b, 0x62, 0x6b, 0x54, 0x43, 0x4a, 0x4e, 0x6a, 0x59, 0x79, + 0x36, 0x7a, 0x6c, 0x74, 0x7a, 0x37, 0x47, 0x52, 0x55, 0x55, 0x47, 0x33, + 0x52, 0x6e, 0x46, 0x58, 0x37, 0x61, 0x63, 0x4d, 0x32, 0x77, 0x34, 0x79, + 0x38, 0x0a, 0x50, 0x49, 0x57, 0x6d, 0x61, 0x77, 0x6f, 0x6d, 0x44, 0x65, + 0x43, 0x54, 0x6d, 0x47, 0x43, 0x75, 0x66, 0x73, 0x59, 0x6b, 0x6c, 0x34, + 0x70, 0x68, 0x58, 0x35, 0x47, 0x4f, 0x5a, 0x70, 0x49, 0x4a, 0x68, 0x7a, + 0x62, 0x4e, 0x69, 0x35, 0x73, 0x74, 0x50, 0x76, 0x5a, 0x52, 0x31, 0x46, + 0x44, 0x55, 0x57, 0x53, 0x69, 0x39, 0x67, 0x2f, 0x4c, 0x4d, 0x4b, 0x48, + 0x74, 0x54, 0x68, 0x6d, 0x33, 0x59, 0x0a, 0x4a, 0x6f, 0x68, 0x77, 0x31, + 0x2b, 0x71, 0x52, 0x7a, 0x54, 0x36, 0x35, 0x79, 0x73, 0x43, 0x51, 0x62, + 0x6c, 0x72, 0x47, 0x58, 0x6e, 0x52, 0x6c, 0x31, 0x31, 0x7a, 0x2b, 0x6f, + 0x2b, 0x49, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x2d, 0x54, 0x52, + 0x55, 0x53, 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x6c, 0x61, + 0x73, 0x73, 0x20, 0x33, 0x20, 0x43, 0x41, 0x20, 0x32, 0x20, 0x45, 0x56, + 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x4f, 0x3d, 0x44, 0x2d, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x0a, 0x23, 0x20, 0x53, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, + 0x2d, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x43, 0x41, 0x20, 0x32, + 0x20, 0x45, 0x56, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x4f, 0x3d, 0x44, + 0x2d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x0a, + 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x44, 0x2d, + 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x43, 0x41, 0x20, 0x32, 0x20, + 0x45, 0x56, 0x20, 0x32, 0x30, 0x30, 0x39, 0x22, 0x0a, 0x23, 0x20, 0x53, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x36, 0x32, 0x33, 0x36, 0x30, + 0x34, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x61, 0x3a, + 0x63, 0x36, 0x3a, 0x34, 0x33, 0x3a, 0x32, 0x63, 0x3a, 0x35, 0x65, 0x3a, + 0x32, 0x64, 0x3a, 0x63, 0x64, 0x3a, 0x63, 0x34, 0x3a, 0x33, 0x34, 0x3a, + 0x63, 0x30, 0x3a, 0x35, 0x30, 0x3a, 0x34, 0x66, 0x3a, 0x31, 0x31, 0x3a, + 0x30, 0x32, 0x3a, 0x34, 0x66, 0x3a, 0x62, 0x36, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x36, 0x3a, 0x63, 0x39, 0x3a, 0x31, + 0x62, 0x3a, 0x30, 0x62, 0x3a, 0x39, 0x35, 0x3a, 0x62, 0x34, 0x3a, 0x31, + 0x30, 0x3a, 0x39, 0x38, 0x3a, 0x34, 0x32, 0x3a, 0x66, 0x61, 0x3a, 0x64, + 0x30, 0x3a, 0x64, 0x38, 0x3a, 0x32, 0x32, 0x3a, 0x37, 0x39, 0x3a, 0x66, + 0x65, 0x3a, 0x36, 0x30, 0x3a, 0x66, 0x61, 0x3a, 0x62, 0x39, 0x3a, 0x31, + 0x36, 0x3a, 0x38, 0x33, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, + 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x65, 0x65, 0x3a, 0x63, 0x35, 0x3a, 0x34, 0x39, 0x3a, + 0x36, 0x62, 0x3a, 0x39, 0x38, 0x3a, 0x38, 0x63, 0x3a, 0x65, 0x39, 0x3a, + 0x38, 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x62, 0x39, 0x3a, 0x33, 0x34, 0x3a, + 0x30, 0x39, 0x3a, 0x32, 0x65, 0x3a, 0x65, 0x63, 0x3a, 0x32, 0x39, 0x3a, + 0x30, 0x38, 0x3a, 0x62, 0x65, 0x3a, 0x64, 0x30, 0x3a, 0x62, 0x30, 0x3a, + 0x66, 0x33, 0x3a, 0x31, 0x36, 0x3a, 0x63, 0x32, 0x3a, 0x64, 0x34, 0x3a, + 0x37, 0x33, 0x3a, 0x30, 0x63, 0x3a, 0x38, 0x34, 0x3a, 0x65, 0x61, 0x3a, + 0x66, 0x31, 0x3a, 0x66, 0x33, 0x3a, 0x64, 0x33, 0x3a, 0x34, 0x38, 0x3a, + 0x38, 0x31, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, + 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x51, + 0x7a, 0x43, 0x43, 0x41, 0x79, 0x75, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, + 0x67, 0x49, 0x44, 0x43, 0x59, 0x50, 0x30, 0x4d, 0x41, 0x30, 0x47, 0x43, + 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, + 0x77, 0x55, 0x41, 0x4d, 0x46, 0x41, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x52, 0x46, 0x0a, + 0x4d, 0x52, 0x55, 0x77, 0x45, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, + 0x44, 0x41, 0x78, 0x45, 0x4c, 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, + 0x49, 0x45, 0x64, 0x74, 0x59, 0x6b, 0x67, 0x78, 0x4b, 0x6a, 0x41, 0x6f, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x49, 0x55, 0x51, 0x74, + 0x56, 0x46, 0x4a, 0x56, 0x55, 0x31, 0x51, 0x67, 0x55, 0x6d, 0x39, 0x76, + 0x64, 0x43, 0x42, 0x44, 0x0a, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, 0x41, + 0x7a, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x44, 0x49, 0x67, 0x52, 0x56, 0x59, + 0x67, 0x4d, 0x6a, 0x41, 0x77, 0x4f, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, + 0x77, 0x4f, 0x54, 0x45, 0x78, 0x4d, 0x44, 0x55, 0x77, 0x4f, 0x44, 0x55, + 0x77, 0x4e, 0x44, 0x5a, 0x61, 0x46, 0x77, 0x30, 0x79, 0x4f, 0x54, 0x45, + 0x78, 0x4d, 0x44, 0x55, 0x77, 0x4f, 0x44, 0x55, 0x77, 0x0a, 0x4e, 0x44, + 0x5a, 0x61, 0x4d, 0x46, 0x41, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x52, 0x46, 0x4d, 0x52, + 0x55, 0x77, 0x45, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, + 0x78, 0x45, 0x4c, 0x56, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, + 0x64, 0x74, 0x59, 0x6b, 0x67, 0x78, 0x4b, 0x6a, 0x41, 0x6f, 0x42, 0x67, + 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x4d, 0x4d, 0x49, 0x55, 0x51, 0x74, 0x56, + 0x46, 0x4a, 0x56, 0x55, 0x31, 0x51, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, + 0x43, 0x42, 0x44, 0x62, 0x47, 0x46, 0x7a, 0x63, 0x79, 0x41, 0x7a, 0x49, + 0x45, 0x4e, 0x42, 0x49, 0x44, 0x49, 0x67, 0x52, 0x56, 0x59, 0x67, 0x4d, + 0x6a, 0x41, 0x77, 0x4f, 0x54, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, + 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x0a, 0x68, 0x76, 0x63, 0x4e, + 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, + 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, + 0x41, 0x4a, 0x6e, 0x78, 0x68, 0x44, 0x52, 0x77, 0x75, 0x69, 0x2b, 0x33, + 0x4d, 0x4b, 0x43, 0x4f, 0x76, 0x58, 0x77, 0x45, 0x7a, 0x37, 0x35, 0x69, + 0x76, 0x4a, 0x6e, 0x39, 0x67, 0x70, 0x66, 0x53, 0x65, 0x67, 0x70, 0x6e, + 0x0a, 0x6c, 0x6a, 0x67, 0x4a, 0x39, 0x68, 0x42, 0x4f, 0x6c, 0x53, 0x4a, + 0x7a, 0x6d, 0x59, 0x33, 0x61, 0x46, 0x53, 0x33, 0x6e, 0x42, 0x66, 0x77, + 0x5a, 0x63, 0x79, 0x4b, 0x33, 0x6a, 0x70, 0x67, 0x41, 0x76, 0x44, 0x77, + 0x39, 0x72, 0x4b, 0x46, 0x73, 0x2b, 0x39, 0x5a, 0x35, 0x4a, 0x55, 0x75, + 0x74, 0x38, 0x4d, 0x78, 0x6b, 0x32, 0x6f, 0x67, 0x2b, 0x4b, 0x62, 0x67, + 0x50, 0x43, 0x64, 0x4d, 0x30, 0x0a, 0x33, 0x54, 0x50, 0x31, 0x59, 0x74, + 0x48, 0x68, 0x7a, 0x52, 0x6e, 0x70, 0x37, 0x68, 0x68, 0x50, 0x54, 0x46, + 0x69, 0x75, 0x34, 0x68, 0x37, 0x57, 0x44, 0x46, 0x73, 0x56, 0x57, 0x74, + 0x67, 0x36, 0x75, 0x4d, 0x51, 0x59, 0x5a, 0x42, 0x37, 0x6a, 0x4d, 0x37, + 0x4b, 0x31, 0x69, 0x58, 0x64, 0x4f, 0x44, 0x4c, 0x2f, 0x5a, 0x6c, 0x47, + 0x73, 0x54, 0x6c, 0x32, 0x38, 0x53, 0x6f, 0x2f, 0x36, 0x5a, 0x0a, 0x71, + 0x51, 0x54, 0x4d, 0x46, 0x65, 0x78, 0x67, 0x61, 0x44, 0x62, 0x74, 0x43, + 0x48, 0x75, 0x33, 0x39, 0x62, 0x2b, 0x54, 0x37, 0x57, 0x59, 0x78, 0x67, + 0x34, 0x7a, 0x47, 0x63, 0x54, 0x53, 0x48, 0x54, 0x68, 0x66, 0x71, 0x72, + 0x34, 0x75, 0x52, 0x6a, 0x52, 0x78, 0x57, 0x51, 0x61, 0x34, 0x69, 0x4e, + 0x31, 0x34, 0x33, 0x38, 0x68, 0x33, 0x5a, 0x30, 0x53, 0x30, 0x4e, 0x4c, + 0x32, 0x6c, 0x52, 0x0a, 0x70, 0x37, 0x35, 0x6d, 0x70, 0x6f, 0x6f, 0x36, + 0x4b, 0x72, 0x33, 0x48, 0x47, 0x72, 0x48, 0x68, 0x46, 0x50, 0x43, 0x2b, + 0x4f, 0x68, 0x32, 0x35, 0x7a, 0x31, 0x75, 0x78, 0x61, 0x76, 0x36, 0x30, + 0x73, 0x55, 0x59, 0x67, 0x6f, 0x76, 0x73, 0x65, 0x4f, 0x33, 0x44, 0x76, + 0x6b, 0x35, 0x68, 0x39, 0x6a, 0x48, 0x4f, 0x57, 0x38, 0x73, 0x58, 0x76, + 0x68, 0x58, 0x43, 0x74, 0x4b, 0x53, 0x62, 0x38, 0x0a, 0x48, 0x67, 0x51, + 0x2b, 0x48, 0x4b, 0x44, 0x59, 0x44, 0x38, 0x74, 0x53, 0x67, 0x32, 0x4a, + 0x38, 0x37, 0x6f, 0x74, 0x54, 0x6c, 0x5a, 0x43, 0x70, 0x56, 0x36, 0x4c, + 0x71, 0x59, 0x51, 0x58, 0x59, 0x2b, 0x55, 0x33, 0x45, 0x4a, 0x2f, 0x70, + 0x75, 0x72, 0x65, 0x33, 0x35, 0x31, 0x31, 0x48, 0x33, 0x61, 0x36, 0x55, + 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4f, 0x43, 0x41, 0x53, 0x51, + 0x77, 0x0a, 0x67, 0x67, 0x45, 0x67, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, + 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, + 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4e, 0x4f, 0x55, 0x69, 0x6b, + 0x78, 0x69, 0x45, 0x79, 0x6f, 0x5a, 0x4c, 0x73, 0x79, 0x76, 0x63, 0x6f, + 0x70, 0x39, 0x4e, 0x74, 0x65, 0x61, 0x0a, 0x48, 0x4e, 0x78, 0x6e, 0x4d, + 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, + 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x43, 0x42, 0x33, + 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x66, 0x42, 0x49, 0x48, 0x56, 0x4d, + 0x49, 0x48, 0x53, 0x4d, 0x49, 0x47, 0x48, 0x6f, 0x49, 0x47, 0x45, 0x6f, + 0x49, 0x47, 0x42, 0x68, 0x6e, 0x39, 0x73, 0x5a, 0x47, 0x46, 0x77, 0x0a, + 0x4f, 0x69, 0x38, 0x76, 0x5a, 0x47, 0x6c, 0x79, 0x5a, 0x57, 0x4e, 0x30, + 0x62, 0x33, 0x4a, 0x35, 0x4c, 0x6d, 0x51, 0x74, 0x64, 0x48, 0x4a, 0x31, + 0x63, 0x33, 0x51, 0x75, 0x62, 0x6d, 0x56, 0x30, 0x4c, 0x30, 0x4e, 0x4f, + 0x50, 0x55, 0x51, 0x74, 0x56, 0x46, 0x4a, 0x56, 0x55, 0x31, 0x51, 0x6c, + 0x4d, 0x6a, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x4a, 0x54, 0x49, 0x77, + 0x51, 0x32, 0x78, 0x68, 0x0a, 0x63, 0x33, 0x4d, 0x6c, 0x4d, 0x6a, 0x41, + 0x7a, 0x4a, 0x54, 0x49, 0x77, 0x51, 0x30, 0x45, 0x6c, 0x4d, 0x6a, 0x41, + 0x79, 0x4a, 0x54, 0x49, 0x77, 0x52, 0x56, 0x59, 0x6c, 0x4d, 0x6a, 0x41, + 0x79, 0x4d, 0x44, 0x41, 0x35, 0x4c, 0x45, 0x38, 0x39, 0x52, 0x43, 0x31, + 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x55, 0x79, 0x4d, 0x45, 0x64, + 0x74, 0x59, 0x6b, 0x67, 0x73, 0x51, 0x7a, 0x31, 0x45, 0x0a, 0x52, 0x54, + 0x39, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, + 0x46, 0x30, 0x5a, 0x58, 0x4a, 0x6c, 0x64, 0x6d, 0x39, 0x6a, 0x59, 0x58, + 0x52, 0x70, 0x62, 0x32, 0x35, 0x73, 0x61, 0x58, 0x4e, 0x30, 0x4d, 0x45, + 0x61, 0x67, 0x52, 0x4b, 0x42, 0x43, 0x68, 0x6b, 0x42, 0x6f, 0x64, 0x48, + 0x52, 0x77, 0x4f, 0x69, 0x38, 0x76, 0x64, 0x33, 0x64, 0x33, 0x4c, 0x6d, + 0x51, 0x74, 0x0a, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x75, 0x62, + 0x6d, 0x56, 0x30, 0x4c, 0x32, 0x4e, 0x79, 0x62, 0x43, 0x39, 0x6b, 0x4c, + 0x58, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x58, 0x33, 0x4a, 0x76, 0x62, + 0x33, 0x52, 0x66, 0x59, 0x32, 0x78, 0x68, 0x63, 0x33, 0x4e, 0x66, 0x4d, + 0x31, 0x39, 0x6a, 0x59, 0x56, 0x38, 0x79, 0x58, 0x32, 0x56, 0x32, 0x58, + 0x7a, 0x49, 0x77, 0x4d, 0x44, 0x6b, 0x75, 0x0a, 0x59, 0x33, 0x4a, 0x73, + 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, + 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, + 0x41, 0x51, 0x41, 0x30, 0x37, 0x58, 0x74, 0x61, 0x50, 0x4b, 0x53, 0x55, + 0x69, 0x4f, 0x38, 0x61, 0x45, 0x58, 0x55, 0x48, 0x4c, 0x37, 0x50, 0x2b, + 0x50, 0x50, 0x6f, 0x65, 0x55, 0x53, 0x62, 0x72, 0x68, 0x2f, 0x59, 0x70, + 0x0a, 0x33, 0x75, 0x44, 0x78, 0x31, 0x4d, 0x59, 0x6b, 0x43, 0x65, 0x6e, + 0x42, 0x7a, 0x31, 0x55, 0x62, 0x74, 0x44, 0x44, 0x5a, 0x7a, 0x68, 0x72, + 0x2b, 0x42, 0x6c, 0x47, 0x6d, 0x46, 0x61, 0x51, 0x74, 0x37, 0x37, 0x4a, + 0x4c, 0x76, 0x79, 0x41, 0x6f, 0x4a, 0x55, 0x6e, 0x52, 0x70, 0x6a, 0x5a, + 0x33, 0x4e, 0x4f, 0x68, 0x6b, 0x33, 0x31, 0x4b, 0x78, 0x45, 0x63, 0x64, + 0x7a, 0x65, 0x73, 0x30, 0x35, 0x0a, 0x6e, 0x73, 0x4b, 0x74, 0x6a, 0x48, + 0x45, 0x68, 0x38, 0x6c, 0x70, 0x72, 0x72, 0x39, 0x38, 0x38, 0x54, 0x6c, + 0x57, 0x76, 0x73, 0x6f, 0x52, 0x6c, 0x46, 0x49, 0x6d, 0x35, 0x64, 0x38, + 0x73, 0x71, 0x4d, 0x62, 0x37, 0x50, 0x6f, 0x32, 0x33, 0x50, 0x62, 0x30, + 0x69, 0x55, 0x4d, 0x6b, 0x5a, 0x76, 0x35, 0x33, 0x47, 0x4d, 0x6f, 0x4b, + 0x61, 0x45, 0x47, 0x54, 0x63, 0x48, 0x38, 0x67, 0x4e, 0x46, 0x0a, 0x43, + 0x53, 0x75, 0x47, 0x64, 0x58, 0x7a, 0x66, 0x58, 0x32, 0x6c, 0x58, 0x41, + 0x4e, 0x74, 0x75, 0x32, 0x4b, 0x5a, 0x79, 0x49, 0x6b, 0x74, 0x51, 0x31, + 0x48, 0x57, 0x59, 0x56, 0x74, 0x2b, 0x33, 0x47, 0x50, 0x39, 0x44, 0x51, + 0x31, 0x43, 0x75, 0x65, 0x6b, 0x52, 0x37, 0x38, 0x48, 0x6c, 0x52, 0x31, + 0x30, 0x4d, 0x39, 0x70, 0x39, 0x4f, 0x42, 0x30, 0x2f, 0x44, 0x4a, 0x54, + 0x37, 0x6e, 0x61, 0x0a, 0x78, 0x70, 0x65, 0x47, 0x30, 0x49, 0x4c, 0x44, + 0x35, 0x45, 0x4a, 0x74, 0x2f, 0x72, 0x44, 0x69, 0x5a, 0x45, 0x34, 0x4f, + 0x4a, 0x75, 0x64, 0x41, 0x4e, 0x43, 0x61, 0x31, 0x43, 0x49, 0x6e, 0x58, + 0x43, 0x47, 0x4e, 0x6a, 0x4f, 0x43, 0x64, 0x31, 0x48, 0x6a, 0x50, 0x71, + 0x62, 0x71, 0x6a, 0x64, 0x6e, 0x35, 0x6c, 0x50, 0x64, 0x45, 0x32, 0x42, + 0x69, 0x59, 0x42, 0x4c, 0x33, 0x5a, 0x71, 0x58, 0x0a, 0x4b, 0x56, 0x77, + 0x76, 0x76, 0x6f, 0x46, 0x42, 0x75, 0x59, 0x7a, 0x2f, 0x36, 0x6e, 0x31, + 0x67, 0x42, 0x70, 0x37, 0x4e, 0x31, 0x7a, 0x33, 0x54, 0x4c, 0x71, 0x4d, + 0x56, 0x76, 0x4b, 0x6a, 0x6d, 0x4a, 0x75, 0x56, 0x76, 0x77, 0x39, 0x79, + 0x34, 0x41, 0x79, 0x48, 0x71, 0x6e, 0x78, 0x62, 0x78, 0x4c, 0x46, 0x53, + 0x31, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x41, 0x20, 0x44, 0x69, 0x73, + 0x69, 0x67, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x32, 0x20, 0x4f, + 0x3d, 0x44, 0x69, 0x73, 0x69, 0x67, 0x20, 0x61, 0x2e, 0x73, 0x2e, 0x0a, + 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x43, 0x41, 0x20, 0x44, 0x69, 0x73, 0x69, 0x67, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x32, 0x20, 0x4f, 0x3d, 0x44, 0x69, 0x73, + 0x69, 0x67, 0x20, 0x61, 0x2e, 0x73, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x41, 0x20, 0x44, 0x69, 0x73, + 0x69, 0x67, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x32, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x30, + 0x35, 0x37, 0x32, 0x33, 0x35, 0x30, 0x36, 0x30, 0x32, 0x33, 0x39, 0x33, + 0x33, 0x33, 0x38, 0x32, 0x31, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x32, 0x36, 0x3a, 0x30, 0x31, 0x3a, 0x66, 0x62, 0x3a, 0x64, + 0x38, 0x3a, 0x32, 0x37, 0x3a, 0x61, 0x37, 0x3a, 0x31, 0x37, 0x3a, 0x39, + 0x61, 0x3a, 0x34, 0x35, 0x3a, 0x35, 0x34, 0x3a, 0x33, 0x38, 0x3a, 0x31, + 0x61, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x31, 0x3a, 0x33, 0x62, 0x3a, 0x30, + 0x33, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x35, + 0x3a, 0x36, 0x31, 0x3a, 0x65, 0x62, 0x3a, 0x65, 0x61, 0x3a, 0x61, 0x34, + 0x3a, 0x64, 0x65, 0x3a, 0x65, 0x34, 0x3a, 0x32, 0x35, 0x3a, 0x34, 0x62, + 0x3a, 0x36, 0x39, 0x3a, 0x31, 0x61, 0x3a, 0x39, 0x38, 0x3a, 0x61, 0x35, + 0x3a, 0x35, 0x37, 0x3a, 0x34, 0x37, 0x3a, 0x63, 0x32, 0x3a, 0x33, 0x34, + 0x3a, 0x63, 0x37, 0x3a, 0x64, 0x39, 0x3a, 0x37, 0x31, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x32, 0x3a, 0x33, + 0x64, 0x3a, 0x34, 0x61, 0x3a, 0x30, 0x33, 0x3a, 0x36, 0x64, 0x3a, 0x37, + 0x62, 0x3a, 0x37, 0x30, 0x3a, 0x65, 0x39, 0x3a, 0x66, 0x35, 0x3a, 0x39, + 0x35, 0x3a, 0x62, 0x31, 0x3a, 0x34, 0x32, 0x3a, 0x32, 0x30, 0x3a, 0x37, + 0x39, 0x3a, 0x64, 0x32, 0x3a, 0x62, 0x39, 0x3a, 0x31, 0x65, 0x3a, 0x64, + 0x66, 0x3a, 0x62, 0x62, 0x3a, 0x31, 0x66, 0x3a, 0x62, 0x36, 0x3a, 0x35, + 0x31, 0x3a, 0x61, 0x30, 0x3a, 0x36, 0x33, 0x3a, 0x33, 0x65, 0x3a, 0x61, + 0x61, 0x3a, 0x38, 0x61, 0x3a, 0x39, 0x64, 0x3a, 0x63, 0x35, 0x3a, 0x66, + 0x38, 0x3a, 0x30, 0x37, 0x3a, 0x30, 0x33, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x46, 0x61, 0x54, 0x43, 0x43, 0x41, 0x31, 0x47, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x4a, 0x41, 0x4a, 0x4b, 0x34, + 0x69, 0x4e, 0x75, 0x77, 0x69, 0x73, 0x46, 0x6a, 0x4d, 0x41, 0x30, 0x47, + 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, + 0x43, 0x77, 0x55, 0x41, 0x4d, 0x46, 0x49, 0x78, 0x43, 0x7a, 0x41, 0x4a, + 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x4e, + 0x4c, 0x4d, 0x52, 0x4d, 0x77, 0x45, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x48, 0x45, 0x77, 0x70, 0x43, 0x63, 0x6d, 0x46, 0x30, 0x61, 0x58, 0x4e, + 0x73, 0x59, 0x58, 0x5a, 0x68, 0x4d, 0x52, 0x4d, 0x77, 0x45, 0x51, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x70, 0x45, 0x61, 0x58, 0x4e, + 0x70, 0x5a, 0x79, 0x42, 0x68, 0x4c, 0x6e, 0x4d, 0x75, 0x0a, 0x4d, 0x52, + 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, + 0x42, 0x44, 0x51, 0x53, 0x42, 0x45, 0x61, 0x58, 0x4e, 0x70, 0x5a, 0x79, + 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x46, 0x49, 0x79, 0x4d, 0x42, + 0x34, 0x58, 0x44, 0x54, 0x45, 0x79, 0x4d, 0x44, 0x63, 0x78, 0x4f, 0x54, + 0x41, 0x35, 0x4d, 0x54, 0x55, 0x7a, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, + 0x51, 0x79, 0x0a, 0x4d, 0x44, 0x63, 0x78, 0x4f, 0x54, 0x41, 0x35, 0x4d, + 0x54, 0x55, 0x7a, 0x4d, 0x46, 0x6f, 0x77, 0x55, 0x6a, 0x45, 0x4c, 0x4d, + 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x55, + 0x30, 0x73, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x63, 0x54, 0x43, 0x6b, 0x4a, 0x79, 0x59, 0x58, 0x52, 0x70, 0x63, + 0x32, 0x78, 0x68, 0x64, 0x6d, 0x45, 0x78, 0x0a, 0x45, 0x7a, 0x41, 0x52, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x43, 0x6b, 0x52, 0x70, + 0x63, 0x32, 0x6c, 0x6e, 0x49, 0x47, 0x45, 0x75, 0x63, 0x79, 0x34, 0x78, + 0x47, 0x54, 0x41, 0x58, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, + 0x45, 0x45, 0x4e, 0x42, 0x49, 0x45, 0x52, 0x70, 0x63, 0x32, 0x6c, 0x6e, + 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x55, 0x6a, 0x49, 0x77, + 0x0a, 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, + 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, + 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, + 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51, 0x43, 0x69, 0x6f, 0x38, 0x51, + 0x41, 0x43, 0x64, 0x61, 0x46, 0x58, 0x53, 0x31, 0x74, 0x46, 0x50, 0x62, + 0x43, 0x77, 0x33, 0x4f, 0x65, 0x0a, 0x4e, 0x63, 0x4a, 0x78, 0x56, 0x58, + 0x36, 0x42, 0x2b, 0x36, 0x74, 0x47, 0x55, 0x4f, 0x44, 0x42, 0x66, 0x45, + 0x6c, 0x34, 0x35, 0x71, 0x74, 0x35, 0x57, 0x44, 0x7a, 0x61, 0x2f, 0x33, + 0x77, 0x63, 0x6e, 0x39, 0x69, 0x58, 0x41, 0x6e, 0x67, 0x2b, 0x61, 0x30, + 0x45, 0x45, 0x36, 0x55, 0x47, 0x39, 0x76, 0x67, 0x4d, 0x73, 0x52, 0x66, + 0x59, 0x76, 0x5a, 0x4e, 0x53, 0x72, 0x58, 0x61, 0x4e, 0x48, 0x0a, 0x50, + 0x57, 0x53, 0x62, 0x36, 0x57, 0x69, 0x61, 0x78, 0x73, 0x77, 0x62, 0x50, + 0x37, 0x71, 0x2b, 0x73, 0x6f, 0x73, 0x30, 0x41, 0x69, 0x36, 0x59, 0x56, + 0x52, 0x6e, 0x38, 0x6a, 0x47, 0x2b, 0x71, 0x58, 0x39, 0x70, 0x4d, 0x7a, + 0x6b, 0x30, 0x44, 0x49, 0x61, 0x50, 0x59, 0x30, 0x6a, 0x53, 0x54, 0x56, + 0x70, 0x62, 0x4c, 0x54, 0x41, 0x77, 0x41, 0x46, 0x6a, 0x78, 0x66, 0x47, + 0x73, 0x33, 0x49, 0x0a, 0x78, 0x32, 0x79, 0x6d, 0x72, 0x64, 0x4d, 0x78, + 0x70, 0x37, 0x7a, 0x6f, 0x35, 0x65, 0x46, 0x6d, 0x31, 0x74, 0x4c, 0x37, + 0x41, 0x37, 0x52, 0x42, 0x5a, 0x63, 0x6b, 0x51, 0x72, 0x67, 0x34, 0x46, + 0x59, 0x38, 0x61, 0x41, 0x61, 0x6d, 0x6b, 0x77, 0x2f, 0x64, 0x4c, 0x75, + 0x6b, 0x4f, 0x38, 0x4e, 0x4a, 0x39, 0x2b, 0x66, 0x6c, 0x58, 0x50, 0x30, + 0x34, 0x53, 0x58, 0x61, 0x62, 0x42, 0x62, 0x65, 0x0a, 0x51, 0x54, 0x67, + 0x30, 0x36, 0x6f, 0x76, 0x38, 0x30, 0x65, 0x67, 0x45, 0x46, 0x47, 0x45, + 0x74, 0x51, 0x58, 0x36, 0x73, 0x78, 0x33, 0x64, 0x4f, 0x79, 0x31, 0x46, + 0x55, 0x2b, 0x31, 0x36, 0x53, 0x47, 0x42, 0x73, 0x45, 0x57, 0x6d, 0x6a, + 0x47, 0x79, 0x63, 0x54, 0x36, 0x74, 0x78, 0x4f, 0x67, 0x6d, 0x4c, 0x63, + 0x52, 0x4b, 0x37, 0x66, 0x57, 0x56, 0x38, 0x78, 0x38, 0x6e, 0x68, 0x66, + 0x52, 0x0a, 0x79, 0x79, 0x58, 0x2b, 0x68, 0x6b, 0x34, 0x6b, 0x4c, 0x6c, + 0x59, 0x4d, 0x65, 0x45, 0x32, 0x65, 0x41, 0x52, 0x4b, 0x6d, 0x4b, 0x36, + 0x63, 0x42, 0x5a, 0x57, 0x35, 0x38, 0x59, 0x68, 0x32, 0x45, 0x68, 0x4e, + 0x2f, 0x71, 0x77, 0x47, 0x75, 0x31, 0x70, 0x53, 0x71, 0x56, 0x67, 0x38, + 0x4e, 0x54, 0x45, 0x51, 0x78, 0x7a, 0x48, 0x51, 0x75, 0x79, 0x52, 0x70, + 0x44, 0x52, 0x51, 0x6a, 0x72, 0x4f, 0x0a, 0x51, 0x47, 0x36, 0x56, 0x72, + 0x66, 0x2f, 0x47, 0x6c, 0x4b, 0x31, 0x75, 0x6c, 0x34, 0x53, 0x4f, 0x66, + 0x57, 0x2b, 0x65, 0x69, 0x6f, 0x41, 0x4e, 0x53, 0x57, 0x31, 0x7a, 0x34, + 0x6e, 0x75, 0x53, 0x48, 0x73, 0x50, 0x7a, 0x77, 0x66, 0x50, 0x72, 0x4c, + 0x67, 0x56, 0x76, 0x32, 0x52, 0x76, 0x50, 0x4e, 0x33, 0x59, 0x45, 0x79, + 0x4c, 0x52, 0x61, 0x35, 0x42, 0x65, 0x6e, 0x79, 0x39, 0x31, 0x32, 0x0a, + 0x48, 0x39, 0x41, 0x5a, 0x64, 0x75, 0x67, 0x73, 0x42, 0x62, 0x50, 0x57, + 0x6e, 0x44, 0x54, 0x59, 0x6c, 0x74, 0x78, 0x68, 0x68, 0x35, 0x45, 0x46, + 0x35, 0x45, 0x51, 0x49, 0x4d, 0x38, 0x48, 0x61, 0x75, 0x51, 0x68, 0x6c, + 0x31, 0x4b, 0x36, 0x79, 0x4e, 0x67, 0x33, 0x72, 0x75, 0x6a, 0x69, 0x36, + 0x44, 0x4f, 0x57, 0x62, 0x6e, 0x75, 0x75, 0x4e, 0x5a, 0x74, 0x32, 0x5a, + 0x7a, 0x39, 0x61, 0x4a, 0x0a, 0x51, 0x66, 0x59, 0x45, 0x6b, 0x6f, 0x6f, + 0x70, 0x4b, 0x57, 0x31, 0x72, 0x4f, 0x68, 0x7a, 0x6e, 0x64, 0x58, 0x30, + 0x43, 0x63, 0x51, 0x37, 0x7a, 0x77, 0x4f, 0x65, 0x39, 0x79, 0x78, 0x6e, + 0x64, 0x6e, 0x57, 0x43, 0x79, 0x77, 0x6d, 0x5a, 0x67, 0x74, 0x72, 0x45, + 0x45, 0x37, 0x73, 0x6e, 0x6d, 0x68, 0x72, 0x6d, 0x61, 0x5a, 0x6b, 0x43, + 0x6f, 0x35, 0x78, 0x48, 0x74, 0x67, 0x55, 0x55, 0x44, 0x0a, 0x69, 0x2f, + 0x5a, 0x6e, 0x57, 0x65, 0x6a, 0x42, 0x42, 0x68, 0x47, 0x39, 0x33, 0x63, + 0x2b, 0x41, 0x41, 0x6b, 0x39, 0x6c, 0x51, 0x48, 0x68, 0x63, 0x52, 0x31, + 0x44, 0x49, 0x6d, 0x2b, 0x59, 0x66, 0x67, 0x58, 0x76, 0x6b, 0x52, 0x4b, + 0x68, 0x62, 0x68, 0x5a, 0x72, 0x69, 0x33, 0x6c, 0x72, 0x56, 0x78, 0x2f, + 0x6b, 0x36, 0x52, 0x47, 0x5a, 0x4c, 0x35, 0x44, 0x4a, 0x55, 0x66, 0x4f, + 0x52, 0x73, 0x0a, 0x6e, 0x4c, 0x4d, 0x4f, 0x50, 0x52, 0x65, 0x69, 0x73, + 0x6a, 0x51, 0x53, 0x31, 0x6e, 0x36, 0x79, 0x71, 0x45, 0x6d, 0x37, 0x30, + 0x58, 0x6f, 0x6f, 0x51, 0x4c, 0x36, 0x69, 0x46, 0x68, 0x2f, 0x66, 0x35, + 0x44, 0x63, 0x66, 0x45, 0x58, 0x50, 0x37, 0x6b, 0x41, 0x70, 0x6c, 0x51, + 0x36, 0x49, 0x4e, 0x66, 0x50, 0x67, 0x47, 0x41, 0x56, 0x55, 0x7a, 0x66, + 0x62, 0x41, 0x4e, 0x75, 0x50, 0x54, 0x31, 0x0a, 0x72, 0x71, 0x56, 0x43, + 0x56, 0x33, 0x77, 0x32, 0x45, 0x59, 0x78, 0x37, 0x58, 0x73, 0x51, 0x44, + 0x6e, 0x59, 0x78, 0x35, 0x6e, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, + 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, + 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x0a, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, + 0x42, 0x42, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, + 0x45, 0x46, 0x67, 0x51, 0x55, 0x74, 0x5a, 0x6e, 0x34, 0x72, 0x37, 0x43, + 0x55, 0x39, 0x65, 0x4d, 0x67, 0x31, 0x67, 0x71, 0x74, 0x7a, 0x6b, 0x35, + 0x57, 0x70, 0x43, 0x35, 0x75, 0x51, 0x75, 0x30, 0x77, 0x44, 0x51, 0x59, + 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x0a, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, + 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x42, 0x41, 0x43, + 0x59, 0x47, 0x58, 0x6e, 0x44, 0x6e, 0x5a, 0x54, 0x50, 0x49, 0x67, 0x6d, + 0x37, 0x5a, 0x6e, 0x42, 0x63, 0x36, 0x47, 0x33, 0x70, 0x6d, 0x73, 0x67, + 0x48, 0x32, 0x65, 0x44, 0x74, 0x70, 0x58, 0x69, 0x2f, 0x71, 0x2f, 0x30, + 0x37, 0x35, 0x4b, 0x4d, 0x4f, 0x59, 0x4b, 0x6d, 0x46, 0x4d, 0x0a, 0x74, + 0x43, 0x51, 0x53, 0x69, 0x6e, 0x31, 0x74, 0x45, 0x52, 0x54, 0x33, 0x6e, + 0x4c, 0x58, 0x4b, 0x35, 0x72, 0x79, 0x65, 0x4a, 0x34, 0x35, 0x4d, 0x47, + 0x63, 0x69, 0x70, 0x76, 0x58, 0x72, 0x41, 0x31, 0x7a, 0x59, 0x4f, 0x62, + 0x59, 0x56, 0x79, 0x62, 0x71, 0x6a, 0x47, 0x6f, 0x6d, 0x33, 0x32, 0x2b, + 0x6e, 0x4e, 0x6a, 0x66, 0x37, 0x78, 0x75, 0x65, 0x51, 0x67, 0x63, 0x6e, + 0x59, 0x71, 0x66, 0x0a, 0x47, 0x6f, 0x70, 0x54, 0x70, 0x74, 0x69, 0x37, + 0x32, 0x54, 0x56, 0x56, 0x73, 0x52, 0x48, 0x46, 0x71, 0x51, 0x4f, 0x7a, + 0x56, 0x6a, 0x75, 0x35, 0x68, 0x4a, 0x4d, 0x69, 0x58, 0x6e, 0x37, 0x42, + 0x39, 0x68, 0x4a, 0x53, 0x69, 0x2b, 0x6f, 0x73, 0x5a, 0x37, 0x7a, 0x2b, + 0x4e, 0x6b, 0x7a, 0x31, 0x75, 0x4d, 0x2f, 0x52, 0x73, 0x30, 0x6d, 0x53, + 0x4f, 0x39, 0x4d, 0x70, 0x44, 0x70, 0x6b, 0x62, 0x0a, 0x6c, 0x76, 0x64, + 0x68, 0x75, 0x44, 0x76, 0x45, 0x4b, 0x37, 0x5a, 0x34, 0x62, 0x4c, 0x51, + 0x6a, 0x62, 0x2f, 0x44, 0x39, 0x30, 0x37, 0x4a, 0x65, 0x64, 0x52, 0x2b, + 0x5a, 0x6c, 0x61, 0x69, 0x73, 0x39, 0x74, 0x72, 0x68, 0x78, 0x54, 0x46, + 0x37, 0x2b, 0x39, 0x46, 0x47, 0x73, 0x39, 0x4b, 0x38, 0x5a, 0x37, 0x52, + 0x69, 0x56, 0x4c, 0x6f, 0x4a, 0x39, 0x32, 0x4f, 0x77, 0x6b, 0x36, 0x4b, + 0x61, 0x0a, 0x2b, 0x65, 0x6c, 0x53, 0x4c, 0x6f, 0x74, 0x67, 0x45, 0x71, + 0x76, 0x38, 0x39, 0x57, 0x42, 0x57, 0x37, 0x78, 0x42, 0x63, 0x69, 0x38, + 0x51, 0x61, 0x51, 0x74, 0x79, 0x44, 0x57, 0x32, 0x51, 0x4f, 0x79, 0x37, + 0x57, 0x38, 0x31, 0x6b, 0x2f, 0x42, 0x66, 0x44, 0x78, 0x75, 0x6a, 0x52, + 0x4e, 0x74, 0x2b, 0x33, 0x76, 0x72, 0x4d, 0x4e, 0x44, 0x63, 0x54, 0x61, + 0x2f, 0x46, 0x31, 0x62, 0x61, 0x6c, 0x0a, 0x54, 0x46, 0x74, 0x78, 0x79, + 0x65, 0x67, 0x78, 0x76, 0x75, 0x67, 0x34, 0x42, 0x6b, 0x69, 0x68, 0x47, + 0x75, 0x4c, 0x71, 0x30, 0x74, 0x34, 0x53, 0x4f, 0x56, 0x67, 0x61, 0x2f, + 0x34, 0x41, 0x4f, 0x67, 0x6e, 0x58, 0x6d, 0x74, 0x38, 0x6b, 0x48, 0x62, + 0x41, 0x37, 0x76, 0x2f, 0x7a, 0x6a, 0x78, 0x6d, 0x48, 0x48, 0x45, 0x74, + 0x33, 0x38, 0x4f, 0x46, 0x64, 0x41, 0x6c, 0x61, 0x62, 0x30, 0x69, 0x0a, + 0x6e, 0x53, 0x76, 0x74, 0x42, 0x66, 0x5a, 0x47, 0x52, 0x36, 0x7a, 0x74, + 0x77, 0x50, 0x44, 0x55, 0x4f, 0x2b, 0x4c, 0x73, 0x37, 0x70, 0x5a, 0x62, + 0x6b, 0x42, 0x4e, 0x4f, 0x48, 0x6c, 0x59, 0x36, 0x36, 0x37, 0x44, 0x76, + 0x6c, 0x72, 0x75, 0x57, 0x49, 0x78, 0x47, 0x36, 0x38, 0x6b, 0x4f, 0x47, + 0x64, 0x47, 0x53, 0x56, 0x79, 0x43, 0x68, 0x31, 0x33, 0x78, 0x30, 0x31, + 0x75, 0x74, 0x49, 0x33, 0x0a, 0x67, 0x7a, 0x68, 0x54, 0x4f, 0x44, 0x59, + 0x37, 0x7a, 0x32, 0x7a, 0x70, 0x2b, 0x57, 0x73, 0x4f, 0x30, 0x50, 0x73, + 0x45, 0x36, 0x45, 0x39, 0x33, 0x31, 0x32, 0x55, 0x42, 0x65, 0x49, 0x59, + 0x4d, 0x65, 0x6a, 0x34, 0x68, 0x59, 0x76, 0x46, 0x2f, 0x59, 0x33, 0x45, + 0x4d, 0x79, 0x5a, 0x39, 0x45, 0x32, 0x36, 0x67, 0x6e, 0x6f, 0x6e, 0x57, + 0x2b, 0x62, 0x6f, 0x45, 0x2b, 0x31, 0x38, 0x44, 0x72, 0x0a, 0x47, 0x35, + 0x67, 0x50, 0x63, 0x46, 0x77, 0x30, 0x73, 0x6f, 0x72, 0x4d, 0x77, 0x49, + 0x55, 0x59, 0x36, 0x32, 0x35, 0x36, 0x73, 0x2f, 0x64, 0x61, 0x6f, 0x51, + 0x65, 0x2f, 0x71, 0x55, 0x4b, 0x53, 0x38, 0x32, 0x41, 0x69, 0x6c, 0x2b, + 0x51, 0x55, 0x6f, 0x51, 0x65, 0x62, 0x54, 0x6e, 0x62, 0x41, 0x6a, 0x6e, + 0x33, 0x39, 0x70, 0x43, 0x58, 0x48, 0x52, 0x2b, 0x33, 0x2f, 0x48, 0x33, + 0x4f, 0x73, 0x0a, 0x7a, 0x4d, 0x4f, 0x6c, 0x36, 0x57, 0x38, 0x4b, 0x6a, + 0x70, 0x74, 0x6c, 0x77, 0x6c, 0x43, 0x46, 0x74, 0x61, 0x4f, 0x67, 0x55, + 0x78, 0x4c, 0x4d, 0x56, 0x59, 0x64, 0x68, 0x38, 0x34, 0x47, 0x75, 0x45, + 0x45, 0x5a, 0x68, 0x76, 0x55, 0x51, 0x68, 0x75, 0x4d, 0x49, 0x39, 0x64, + 0x4d, 0x39, 0x2b, 0x4a, 0x44, 0x58, 0x36, 0x48, 0x41, 0x63, 0x4f, 0x6d, + 0x7a, 0x30, 0x69, 0x79, 0x75, 0x38, 0x78, 0x0a, 0x4c, 0x34, 0x79, 0x73, + 0x45, 0x72, 0x33, 0x76, 0x51, 0x43, 0x6a, 0x38, 0x4b, 0x57, 0x65, 0x66, + 0x73, 0x68, 0x4e, 0x50, 0x5a, 0x69, 0x54, 0x45, 0x55, 0x78, 0x6e, 0x70, + 0x48, 0x69, 0x6b, 0x56, 0x37, 0x2b, 0x5a, 0x74, 0x73, 0x48, 0x38, 0x74, + 0x5a, 0x2f, 0x33, 0x7a, 0x62, 0x42, 0x74, 0x31, 0x52, 0x71, 0x50, 0x6c, + 0x53, 0x68, 0x66, 0x70, 0x70, 0x4e, 0x63, 0x4c, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, + 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x41, 0x43, 0x43, 0x56, 0x52, 0x41, 0x49, 0x5a, 0x31, 0x20, 0x4f, + 0x3d, 0x41, 0x43, 0x43, 0x56, 0x20, 0x4f, 0x55, 0x3d, 0x50, 0x4b, 0x49, + 0x41, 0x43, 0x43, 0x56, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x43, 0x43, 0x56, 0x52, + 0x41, 0x49, 0x5a, 0x31, 0x20, 0x4f, 0x3d, 0x41, 0x43, 0x43, 0x56, 0x20, + 0x4f, 0x55, 0x3d, 0x50, 0x4b, 0x49, 0x41, 0x43, 0x43, 0x56, 0x0a, 0x23, + 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, 0x43, 0x43, + 0x56, 0x52, 0x41, 0x49, 0x5a, 0x31, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x36, 0x38, 0x32, 0x38, 0x35, 0x30, + 0x33, 0x33, 0x38, 0x34, 0x37, 0x34, 0x38, 0x36, 0x39, 0x36, 0x38, 0x30, + 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x30, 0x3a, + 0x61, 0x30, 0x3a, 0x35, 0x61, 0x3a, 0x65, 0x65, 0x3a, 0x30, 0x35, 0x3a, + 0x62, 0x36, 0x3a, 0x30, 0x39, 0x3a, 0x39, 0x34, 0x3a, 0x32, 0x31, 0x3a, + 0x61, 0x31, 0x3a, 0x37, 0x64, 0x3a, 0x66, 0x31, 0x3a, 0x62, 0x32, 0x3a, + 0x32, 0x39, 0x3a, 0x38, 0x32, 0x3a, 0x30, 0x32, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x33, 0x3a, 0x30, 0x35, 0x3a, 0x37, + 0x61, 0x3a, 0x38, 0x38, 0x3a, 0x31, 0x35, 0x3a, 0x63, 0x36, 0x3a, 0x34, + 0x66, 0x3a, 0x63, 0x65, 0x3a, 0x38, 0x38, 0x3a, 0x32, 0x66, 0x3a, 0x66, + 0x61, 0x3a, 0x39, 0x31, 0x3a, 0x31, 0x36, 0x3a, 0x35, 0x32, 0x3a, 0x32, + 0x38, 0x3a, 0x37, 0x38, 0x3a, 0x62, 0x63, 0x3a, 0x35, 0x33, 0x3a, 0x36, + 0x34, 0x3a, 0x31, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, + 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x39, 0x61, 0x3a, 0x36, 0x65, 0x3a, 0x63, 0x30, 0x3a, + 0x31, 0x32, 0x3a, 0x65, 0x31, 0x3a, 0x61, 0x37, 0x3a, 0x64, 0x61, 0x3a, + 0x39, 0x64, 0x3a, 0x62, 0x65, 0x3a, 0x33, 0x34, 0x3a, 0x31, 0x39, 0x3a, + 0x34, 0x64, 0x3a, 0x34, 0x37, 0x3a, 0x38, 0x61, 0x3a, 0x64, 0x37, 0x3a, + 0x63, 0x30, 0x3a, 0x64, 0x62, 0x3a, 0x31, 0x38, 0x3a, 0x32, 0x32, 0x3a, + 0x66, 0x62, 0x3a, 0x30, 0x37, 0x3a, 0x31, 0x64, 0x3a, 0x66, 0x31, 0x3a, + 0x32, 0x39, 0x3a, 0x38, 0x31, 0x3a, 0x34, 0x39, 0x3a, 0x36, 0x65, 0x3a, + 0x64, 0x31, 0x3a, 0x30, 0x34, 0x3a, 0x33, 0x38, 0x3a, 0x34, 0x31, 0x3a, + 0x31, 0x33, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, + 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x48, 0x30, + 0x7a, 0x43, 0x43, 0x42, 0x62, 0x75, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, + 0x67, 0x49, 0x49, 0x58, 0x73, 0x4f, 0x33, 0x70, 0x6b, 0x4e, 0x2f, 0x70, + 0x4f, 0x41, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x51, + 0x6a, 0x45, 0x53, 0x4d, 0x42, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, + 0x41, 0x77, 0x77, 0x4a, 0x51, 0x55, 0x4e, 0x44, 0x56, 0x6c, 0x4a, 0x42, + 0x53, 0x56, 0x6f, 0x78, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4c, 0x44, 0x41, 0x64, 0x51, 0x53, 0x30, 0x6c, 0x42, + 0x51, 0x30, 0x4e, 0x57, 0x4d, 0x51, 0x30, 0x77, 0x43, 0x77, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, 0x52, 0x42, 0x51, 0x30, 0x4e, 0x57, + 0x4d, 0x51, 0x73, 0x77, 0x0a, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x47, 0x45, 0x77, 0x4a, 0x46, 0x55, 0x7a, 0x41, 0x65, 0x46, 0x77, 0x30, + 0x78, 0x4d, 0x54, 0x41, 0x31, 0x4d, 0x44, 0x55, 0x77, 0x4f, 0x54, 0x4d, + 0x33, 0x4d, 0x7a, 0x64, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4d, 0x44, 0x45, + 0x79, 0x4d, 0x7a, 0x45, 0x77, 0x4f, 0x54, 0x4d, 0x33, 0x4d, 0x7a, 0x64, + 0x61, 0x4d, 0x45, 0x49, 0x78, 0x45, 0x6a, 0x41, 0x51, 0x0a, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x43, 0x55, 0x46, 0x44, 0x51, 0x31, + 0x5a, 0x53, 0x51, 0x55, 0x6c, 0x61, 0x4d, 0x54, 0x45, 0x51, 0x4d, 0x41, + 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x77, 0x77, 0x48, 0x55, 0x45, + 0x74, 0x4a, 0x51, 0x55, 0x4e, 0x44, 0x56, 0x6a, 0x45, 0x4e, 0x4d, 0x41, + 0x73, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x45, 0x51, 0x55, + 0x4e, 0x44, 0x0a, 0x56, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x56, 0x4d, 0x77, 0x67, + 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, + 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, + 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, + 0x6f, 0x49, 0x43, 0x41, 0x51, 0x43, 0x62, 0x0a, 0x71, 0x61, 0x75, 0x2f, + 0x59, 0x55, 0x71, 0x58, 0x72, 0x79, 0x2b, 0x58, 0x5a, 0x70, 0x70, 0x30, + 0x58, 0x39, 0x44, 0x5a, 0x6c, 0x76, 0x33, 0x50, 0x34, 0x75, 0x52, 0x6d, + 0x37, 0x78, 0x38, 0x66, 0x52, 0x7a, 0x50, 0x43, 0x52, 0x4b, 0x50, 0x66, + 0x6d, 0x74, 0x34, 0x66, 0x74, 0x56, 0x54, 0x64, 0x46, 0x58, 0x78, 0x70, + 0x4e, 0x52, 0x46, 0x76, 0x75, 0x38, 0x67, 0x4d, 0x6a, 0x6d, 0x6f, 0x59, + 0x0a, 0x48, 0x74, 0x69, 0x50, 0x32, 0x52, 0x61, 0x38, 0x45, 0x45, 0x67, + 0x32, 0x58, 0x50, 0x42, 0x6a, 0x73, 0x35, 0x42, 0x61, 0x58, 0x43, 0x51, + 0x33, 0x31, 0x36, 0x50, 0x57, 0x79, 0x77, 0x6c, 0x78, 0x75, 0x66, 0x45, + 0x42, 0x63, 0x6f, 0x53, 0x77, 0x66, 0x64, 0x74, 0x4e, 0x67, 0x4d, 0x33, + 0x38, 0x30, 0x32, 0x2f, 0x4a, 0x2b, 0x4e, 0x71, 0x32, 0x44, 0x6f, 0x4c, + 0x53, 0x52, 0x59, 0x57, 0x6f, 0x0a, 0x47, 0x32, 0x69, 0x6f, 0x50, 0x65, + 0x6a, 0x30, 0x52, 0x47, 0x79, 0x39, 0x6f, 0x63, 0x4c, 0x4c, 0x41, 0x37, + 0x36, 0x4d, 0x50, 0x68, 0x4d, 0x41, 0x68, 0x4e, 0x39, 0x4b, 0x53, 0x4d, + 0x44, 0x6a, 0x49, 0x67, 0x72, 0x6f, 0x36, 0x54, 0x65, 0x6e, 0x47, 0x45, + 0x79, 0x78, 0x43, 0x51, 0x30, 0x6a, 0x56, 0x6e, 0x38, 0x45, 0x54, 0x64, + 0x6b, 0x58, 0x68, 0x42, 0x69, 0x6c, 0x79, 0x4e, 0x70, 0x41, 0x0a, 0x6c, + 0x48, 0x50, 0x72, 0x7a, 0x67, 0x35, 0x58, 0x50, 0x41, 0x4f, 0x42, 0x4f, + 0x70, 0x30, 0x4b, 0x6f, 0x56, 0x64, 0x44, 0x61, 0x61, 0x78, 0x58, 0x62, + 0x58, 0x6d, 0x51, 0x65, 0x4f, 0x57, 0x31, 0x74, 0x44, 0x76, 0x59, 0x76, + 0x45, 0x79, 0x4e, 0x4b, 0x4b, 0x47, 0x6e, 0x6f, 0x36, 0x65, 0x36, 0x41, + 0x6b, 0x34, 0x6c, 0x30, 0x53, 0x71, 0x75, 0x37, 0x61, 0x34, 0x44, 0x49, + 0x72, 0x68, 0x72, 0x0a, 0x49, 0x41, 0x38, 0x77, 0x4b, 0x46, 0x53, 0x56, + 0x66, 0x2b, 0x44, 0x75, 0x7a, 0x67, 0x70, 0x6d, 0x6e, 0x64, 0x46, 0x41, + 0x4c, 0x57, 0x34, 0x69, 0x72, 0x35, 0x30, 0x61, 0x77, 0x51, 0x55, 0x5a, + 0x30, 0x6d, 0x2f, 0x41, 0x38, 0x70, 0x2f, 0x34, 0x65, 0x37, 0x4d, 0x43, + 0x51, 0x76, 0x74, 0x51, 0x71, 0x52, 0x30, 0x74, 0x6b, 0x77, 0x38, 0x6a, + 0x71, 0x38, 0x62, 0x42, 0x44, 0x35, 0x4c, 0x2f, 0x0a, 0x30, 0x4b, 0x49, + 0x56, 0x39, 0x56, 0x4d, 0x4a, 0x63, 0x52, 0x7a, 0x2f, 0x52, 0x52, 0x4f, + 0x45, 0x35, 0x69, 0x5a, 0x65, 0x2b, 0x4f, 0x43, 0x49, 0x48, 0x41, 0x72, + 0x38, 0x46, 0x72, 0x61, 0x6f, 0x63, 0x77, 0x61, 0x34, 0x38, 0x47, 0x4f, + 0x45, 0x41, 0x71, 0x44, 0x47, 0x57, 0x75, 0x7a, 0x6e, 0x64, 0x4e, 0x39, + 0x77, 0x72, 0x71, 0x4f, 0x44, 0x4a, 0x65, 0x72, 0x57, 0x78, 0x35, 0x65, + 0x48, 0x0a, 0x6b, 0x36, 0x66, 0x47, 0x69, 0x6f, 0x6f, 0x7a, 0x6c, 0x32, + 0x41, 0x33, 0x45, 0x44, 0x36, 0x58, 0x50, 0x6d, 0x34, 0x70, 0x46, 0x64, + 0x61, 0x68, 0x44, 0x39, 0x47, 0x49, 0x4c, 0x42, 0x4b, 0x66, 0x62, 0x36, + 0x71, 0x6b, 0x78, 0x6b, 0x4c, 0x72, 0x51, 0x61, 0x4c, 0x6a, 0x6c, 0x55, + 0x50, 0x54, 0x41, 0x59, 0x56, 0x74, 0x6a, 0x72, 0x73, 0x37, 0x38, 0x79, + 0x4d, 0x32, 0x78, 0x2f, 0x34, 0x37, 0x0a, 0x34, 0x4b, 0x45, 0x6c, 0x42, + 0x30, 0x69, 0x72, 0x79, 0x59, 0x6c, 0x30, 0x2f, 0x77, 0x69, 0x50, 0x67, + 0x4c, 0x2f, 0x41, 0x6c, 0x6d, 0x58, 0x7a, 0x37, 0x75, 0x78, 0x4c, 0x61, + 0x4c, 0x32, 0x64, 0x69, 0x4d, 0x4d, 0x78, 0x73, 0x30, 0x44, 0x78, 0x36, + 0x4d, 0x2f, 0x32, 0x4f, 0x4c, 0x75, 0x63, 0x35, 0x4e, 0x46, 0x2f, 0x31, + 0x4f, 0x56, 0x59, 0x6d, 0x33, 0x7a, 0x36, 0x31, 0x50, 0x4d, 0x4f, 0x0a, + 0x6d, 0x33, 0x57, 0x52, 0x35, 0x4c, 0x70, 0x53, 0x4c, 0x68, 0x6c, 0x2b, + 0x30, 0x66, 0x58, 0x4e, 0x57, 0x68, 0x6e, 0x38, 0x75, 0x67, 0x62, 0x32, + 0x2b, 0x31, 0x4b, 0x6f, 0x53, 0x35, 0x6b, 0x45, 0x33, 0x66, 0x6a, 0x35, + 0x74, 0x49, 0x74, 0x51, 0x6f, 0x30, 0x35, 0x69, 0x69, 0x66, 0x43, 0x48, + 0x4a, 0x50, 0x71, 0x44, 0x51, 0x73, 0x47, 0x48, 0x2b, 0x74, 0x55, 0x74, + 0x4b, 0x53, 0x70, 0x61, 0x0a, 0x63, 0x58, 0x70, 0x6b, 0x61, 0x74, 0x63, + 0x6e, 0x59, 0x47, 0x4d, 0x4e, 0x32, 0x38, 0x35, 0x4a, 0x39, 0x59, 0x30, + 0x66, 0x6b, 0x49, 0x6b, 0x79, 0x46, 0x2f, 0x68, 0x7a, 0x51, 0x37, 0x6a, + 0x53, 0x57, 0x70, 0x4f, 0x47, 0x59, 0x64, 0x62, 0x68, 0x64, 0x51, 0x72, + 0x71, 0x65, 0x57, 0x5a, 0x32, 0x69, 0x45, 0x39, 0x78, 0x36, 0x77, 0x51, + 0x6c, 0x31, 0x67, 0x70, 0x61, 0x65, 0x70, 0x50, 0x6c, 0x0a, 0x75, 0x55, + 0x73, 0x58, 0x51, 0x41, 0x2b, 0x78, 0x74, 0x72, 0x6e, 0x31, 0x33, 0x6b, + 0x2f, 0x63, 0x34, 0x4c, 0x4f, 0x73, 0x4f, 0x78, 0x46, 0x77, 0x59, 0x49, + 0x52, 0x4b, 0x51, 0x32, 0x36, 0x5a, 0x49, 0x4d, 0x41, 0x70, 0x63, 0x51, + 0x72, 0x41, 0x5a, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x34, + 0x49, 0x43, 0x79, 0x7a, 0x43, 0x43, 0x41, 0x73, 0x63, 0x77, 0x66, 0x51, + 0x59, 0x49, 0x0a, 0x4b, 0x77, 0x59, 0x42, 0x42, 0x51, 0x55, 0x48, 0x41, + 0x51, 0x45, 0x45, 0x63, 0x54, 0x42, 0x76, 0x4d, 0x45, 0x77, 0x47, 0x43, + 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x7a, 0x41, 0x43, 0x68, + 0x6b, 0x42, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69, 0x38, 0x76, 0x64, + 0x33, 0x64, 0x33, 0x4c, 0x6d, 0x46, 0x6a, 0x59, 0x33, 0x59, 0x75, 0x5a, + 0x58, 0x4d, 0x76, 0x5a, 0x6d, 0x6c, 0x73, 0x0a, 0x5a, 0x57, 0x46, 0x6b, + 0x62, 0x57, 0x6c, 0x75, 0x4c, 0x30, 0x46, 0x79, 0x59, 0x32, 0x68, 0x70, + 0x64, 0x6d, 0x39, 0x7a, 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, + 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x57, 0x52, 0x76, 0x63, 0x79, 0x39, 0x79, + 0x59, 0x57, 0x6c, 0x36, 0x59, 0x57, 0x4e, 0x6a, 0x64, 0x6a, 0x45, 0x75, + 0x59, 0x33, 0x4a, 0x30, 0x4d, 0x42, 0x38, 0x47, 0x43, 0x43, 0x73, 0x47, + 0x0a, 0x41, 0x51, 0x55, 0x46, 0x42, 0x7a, 0x41, 0x42, 0x68, 0x68, 0x4e, + 0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69, 0x38, 0x76, 0x62, 0x32, 0x4e, + 0x7a, 0x63, 0x43, 0x35, 0x68, 0x59, 0x32, 0x4e, 0x32, 0x4c, 0x6d, 0x56, + 0x7a, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, + 0x57, 0x42, 0x42, 0x54, 0x53, 0x68, 0x37, 0x54, 0x6a, 0x33, 0x7a, 0x63, + 0x6e, 0x6b, 0x31, 0x58, 0x32, 0x0a, 0x56, 0x75, 0x71, 0x42, 0x35, 0x54, + 0x62, 0x4d, 0x6a, 0x42, 0x34, 0x2f, 0x76, 0x54, 0x41, 0x50, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, + 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, 0x61, 0x41, 0x46, 0x4e, + 0x4b, 0x48, 0x74, 0x4f, 0x50, 0x66, 0x4e, 0x79, 0x65, 0x54, 0x0a, 0x56, + 0x66, 0x5a, 0x57, 0x36, 0x6f, 0x48, 0x6c, 0x4e, 0x73, 0x79, 0x4d, 0x48, + 0x6a, 0x2b, 0x39, 0x4d, 0x49, 0x49, 0x42, 0x63, 0x77, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x67, 0x42, 0x49, 0x49, 0x42, 0x61, 0x6a, 0x43, 0x43, 0x41, + 0x57, 0x59, 0x77, 0x67, 0x67, 0x46, 0x69, 0x42, 0x67, 0x52, 0x56, 0x48, + 0x53, 0x41, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x57, 0x44, 0x43, 0x43, 0x41, + 0x53, 0x49, 0x47, 0x0a, 0x43, 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, + 0x42, 0x77, 0x49, 0x43, 0x4d, 0x49, 0x49, 0x42, 0x46, 0x42, 0x36, 0x43, + 0x41, 0x52, 0x41, 0x41, 0x51, 0x51, 0x42, 0x31, 0x41, 0x48, 0x51, 0x41, + 0x62, 0x77, 0x42, 0x79, 0x41, 0x47, 0x6b, 0x41, 0x5a, 0x41, 0x42, 0x68, + 0x41, 0x47, 0x51, 0x41, 0x49, 0x41, 0x42, 0x6b, 0x41, 0x47, 0x55, 0x41, + 0x49, 0x41, 0x42, 0x44, 0x41, 0x47, 0x55, 0x41, 0x0a, 0x63, 0x67, 0x42, + 0x30, 0x41, 0x47, 0x6b, 0x41, 0x5a, 0x67, 0x42, 0x70, 0x41, 0x47, 0x4d, + 0x41, 0x59, 0x51, 0x42, 0x6a, 0x41, 0x47, 0x6b, 0x41, 0x38, 0x77, 0x42, + 0x75, 0x41, 0x43, 0x41, 0x41, 0x55, 0x67, 0x42, 0x68, 0x41, 0x4f, 0x30, + 0x41, 0x65, 0x67, 0x41, 0x67, 0x41, 0x47, 0x51, 0x41, 0x5a, 0x51, 0x41, + 0x67, 0x41, 0x47, 0x77, 0x41, 0x59, 0x51, 0x41, 0x67, 0x41, 0x45, 0x45, + 0x41, 0x0a, 0x51, 0x77, 0x42, 0x44, 0x41, 0x46, 0x59, 0x41, 0x49, 0x41, + 0x41, 0x6f, 0x41, 0x45, 0x45, 0x41, 0x5a, 0x77, 0x42, 0x6c, 0x41, 0x47, + 0x34, 0x41, 0x59, 0x77, 0x42, 0x70, 0x41, 0x47, 0x45, 0x41, 0x49, 0x41, + 0x42, 0x6b, 0x41, 0x47, 0x55, 0x41, 0x49, 0x41, 0x42, 0x55, 0x41, 0x47, + 0x55, 0x41, 0x59, 0x77, 0x42, 0x75, 0x41, 0x47, 0x38, 0x41, 0x62, 0x41, + 0x42, 0x76, 0x41, 0x47, 0x63, 0x41, 0x0a, 0x37, 0x51, 0x42, 0x68, 0x41, + 0x43, 0x41, 0x41, 0x65, 0x51, 0x41, 0x67, 0x41, 0x45, 0x4d, 0x41, 0x5a, + 0x51, 0x42, 0x79, 0x41, 0x48, 0x51, 0x41, 0x61, 0x51, 0x42, 0x6d, 0x41, + 0x47, 0x6b, 0x41, 0x59, 0x77, 0x42, 0x68, 0x41, 0x47, 0x4d, 0x41, 0x61, + 0x51, 0x44, 0x7a, 0x41, 0x47, 0x34, 0x41, 0x49, 0x41, 0x42, 0x46, 0x41, + 0x47, 0x77, 0x41, 0x5a, 0x51, 0x42, 0x6a, 0x41, 0x48, 0x51, 0x41, 0x0a, + 0x63, 0x67, 0x44, 0x7a, 0x41, 0x47, 0x34, 0x41, 0x61, 0x51, 0x42, 0x6a, + 0x41, 0x47, 0x45, 0x41, 0x4c, 0x41, 0x41, 0x67, 0x41, 0x45, 0x4d, 0x41, + 0x53, 0x51, 0x42, 0x47, 0x41, 0x43, 0x41, 0x41, 0x55, 0x51, 0x41, 0x30, + 0x41, 0x44, 0x59, 0x41, 0x4d, 0x41, 0x41, 0x78, 0x41, 0x44, 0x45, 0x41, + 0x4e, 0x51, 0x41, 0x32, 0x41, 0x45, 0x55, 0x41, 0x4b, 0x51, 0x41, 0x75, + 0x41, 0x43, 0x41, 0x41, 0x0a, 0x51, 0x77, 0x42, 0x51, 0x41, 0x46, 0x4d, + 0x41, 0x49, 0x41, 0x42, 0x6c, 0x41, 0x47, 0x34, 0x41, 0x49, 0x41, 0x42, + 0x6f, 0x41, 0x48, 0x51, 0x41, 0x64, 0x41, 0x42, 0x77, 0x41, 0x44, 0x6f, + 0x41, 0x4c, 0x77, 0x41, 0x76, 0x41, 0x48, 0x63, 0x41, 0x64, 0x77, 0x42, + 0x33, 0x41, 0x43, 0x34, 0x41, 0x59, 0x51, 0x42, 0x6a, 0x41, 0x47, 0x4d, + 0x41, 0x64, 0x67, 0x41, 0x75, 0x41, 0x47, 0x55, 0x41, 0x0a, 0x63, 0x7a, + 0x41, 0x77, 0x42, 0x67, 0x67, 0x72, 0x42, 0x67, 0x45, 0x46, 0x42, 0x51, + 0x63, 0x43, 0x41, 0x52, 0x59, 0x6b, 0x61, 0x48, 0x52, 0x30, 0x63, 0x44, + 0x6f, 0x76, 0x4c, 0x33, 0x64, 0x33, 0x64, 0x79, 0x35, 0x68, 0x59, 0x32, + 0x4e, 0x32, 0x4c, 0x6d, 0x56, 0x7a, 0x4c, 0x32, 0x78, 0x6c, 0x5a, 0x32, + 0x6c, 0x7a, 0x62, 0x47, 0x46, 0x6a, 0x61, 0x57, 0x39, 0x75, 0x58, 0x32, + 0x4d, 0x75, 0x0a, 0x61, 0x48, 0x52, 0x74, 0x4d, 0x46, 0x55, 0x47, 0x41, + 0x31, 0x55, 0x64, 0x48, 0x77, 0x52, 0x4f, 0x4d, 0x45, 0x77, 0x77, 0x53, + 0x71, 0x42, 0x49, 0x6f, 0x45, 0x61, 0x47, 0x52, 0x47, 0x68, 0x30, 0x64, + 0x48, 0x41, 0x36, 0x4c, 0x79, 0x39, 0x33, 0x64, 0x33, 0x63, 0x75, 0x59, + 0x57, 0x4e, 0x6a, 0x64, 0x69, 0x35, 0x6c, 0x63, 0x79, 0x39, 0x6d, 0x61, + 0x57, 0x78, 0x6c, 0x59, 0x57, 0x52, 0x74, 0x0a, 0x61, 0x57, 0x34, 0x76, + 0x51, 0x58, 0x4a, 0x6a, 0x61, 0x47, 0x6c, 0x32, 0x62, 0x33, 0x4d, 0x76, + 0x59, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, + 0x5a, 0x47, 0x39, 0x7a, 0x4c, 0x33, 0x4a, 0x68, 0x61, 0x58, 0x70, 0x68, + 0x59, 0x32, 0x4e, 0x32, 0x4d, 0x56, 0x39, 0x6b, 0x5a, 0x58, 0x49, 0x75, + 0x59, 0x33, 0x4a, 0x73, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x0a, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, + 0x42, 0x42, 0x6a, 0x41, 0x58, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x45, + 0x45, 0x45, 0x44, 0x41, 0x4f, 0x67, 0x51, 0x78, 0x68, 0x59, 0x32, 0x4e, + 0x32, 0x51, 0x47, 0x46, 0x6a, 0x59, 0x33, 0x59, 0x75, 0x5a, 0x58, 0x4d, + 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, + 0x4e, 0x41, 0x51, 0x45, 0x46, 0x0a, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, + 0x49, 0x42, 0x41, 0x4a, 0x63, 0x78, 0x41, 0x70, 0x2f, 0x6e, 0x2f, 0x55, + 0x4e, 0x6e, 0x53, 0x45, 0x51, 0x55, 0x35, 0x43, 0x6d, 0x48, 0x37, 0x55, + 0x77, 0x6f, 0x5a, 0x74, 0x43, 0x50, 0x4e, 0x64, 0x70, 0x4e, 0x59, 0x62, + 0x64, 0x4b, 0x6c, 0x30, 0x32, 0x31, 0x32, 0x35, 0x44, 0x67, 0x42, 0x53, + 0x34, 0x4f, 0x78, 0x6e, 0x6e, 0x51, 0x38, 0x70, 0x64, 0x70, 0x0a, 0x44, + 0x37, 0x30, 0x45, 0x52, 0x39, 0x6d, 0x2b, 0x32, 0x37, 0x55, 0x70, 0x32, + 0x70, 0x76, 0x5a, 0x72, 0x71, 0x6d, 0x5a, 0x31, 0x64, 0x4d, 0x38, 0x4d, + 0x4a, 0x50, 0x31, 0x6a, 0x61, 0x47, 0x6f, 0x2f, 0x41, 0x61, 0x4e, 0x52, + 0x50, 0x54, 0x4b, 0x46, 0x70, 0x56, 0x38, 0x4d, 0x39, 0x78, 0x69, 0x69, + 0x36, 0x67, 0x33, 0x2b, 0x43, 0x66, 0x59, 0x43, 0x53, 0x30, 0x62, 0x37, + 0x38, 0x67, 0x55, 0x0a, 0x4a, 0x79, 0x43, 0x70, 0x5a, 0x45, 0x54, 0x2f, + 0x4c, 0x74, 0x5a, 0x31, 0x71, 0x6d, 0x78, 0x4e, 0x59, 0x45, 0x41, 0x5a, + 0x53, 0x55, 0x4e, 0x55, 0x59, 0x39, 0x72, 0x69, 0x7a, 0x4c, 0x70, 0x6d, + 0x35, 0x55, 0x39, 0x45, 0x65, 0x6c, 0x76, 0x5a, 0x61, 0x6f, 0x45, 0x72, + 0x51, 0x4e, 0x56, 0x2f, 0x2b, 0x51, 0x45, 0x6e, 0x57, 0x43, 0x7a, 0x49, + 0x37, 0x55, 0x69, 0x52, 0x66, 0x44, 0x2b, 0x6d, 0x0a, 0x41, 0x4d, 0x2f, + 0x45, 0x4b, 0x58, 0x4d, 0x52, 0x4e, 0x74, 0x36, 0x47, 0x47, 0x54, 0x36, + 0x64, 0x37, 0x68, 0x6d, 0x4b, 0x47, 0x39, 0x57, 0x77, 0x37, 0x59, 0x34, + 0x39, 0x6e, 0x43, 0x72, 0x41, 0x44, 0x64, 0x67, 0x39, 0x5a, 0x75, 0x4d, + 0x38, 0x44, 0x62, 0x33, 0x56, 0x6c, 0x46, 0x7a, 0x69, 0x34, 0x71, 0x63, + 0x31, 0x47, 0x77, 0x51, 0x41, 0x39, 0x6a, 0x39, 0x61, 0x6a, 0x65, 0x70, + 0x44, 0x0a, 0x76, 0x56, 0x2b, 0x4a, 0x48, 0x61, 0x6e, 0x42, 0x73, 0x4d, + 0x79, 0x5a, 0x34, 0x6b, 0x30, 0x41, 0x43, 0x74, 0x72, 0x4a, 0x4a, 0x31, + 0x76, 0x6e, 0x45, 0x35, 0x42, 0x63, 0x35, 0x50, 0x55, 0x7a, 0x6f, 0x6c, + 0x56, 0x74, 0x33, 0x4f, 0x41, 0x4a, 0x54, 0x53, 0x2b, 0x78, 0x4a, 0x6c, + 0x73, 0x6e, 0x64, 0x51, 0x41, 0x4a, 0x78, 0x47, 0x4a, 0x33, 0x4b, 0x51, + 0x68, 0x66, 0x6e, 0x6c, 0x6d, 0x73, 0x0a, 0x74, 0x6e, 0x36, 0x74, 0x6e, + 0x31, 0x51, 0x77, 0x49, 0x67, 0x50, 0x42, 0x48, 0x6e, 0x46, 0x6b, 0x2f, + 0x76, 0x6b, 0x34, 0x43, 0x70, 0x59, 0x59, 0x33, 0x51, 0x49, 0x55, 0x72, + 0x43, 0x50, 0x4c, 0x42, 0x68, 0x77, 0x65, 0x70, 0x48, 0x32, 0x4e, 0x44, + 0x64, 0x34, 0x6e, 0x51, 0x65, 0x69, 0x74, 0x32, 0x68, 0x57, 0x33, 0x73, + 0x43, 0x50, 0x64, 0x4b, 0x36, 0x6a, 0x54, 0x32, 0x69, 0x57, 0x48, 0x0a, + 0x37, 0x65, 0x68, 0x56, 0x52, 0x45, 0x32, 0x49, 0x39, 0x44, 0x5a, 0x2b, + 0x68, 0x4a, 0x70, 0x34, 0x72, 0x50, 0x63, 0x4f, 0x56, 0x6b, 0x6b, 0x4f, + 0x31, 0x6a, 0x4d, 0x6c, 0x31, 0x6f, 0x52, 0x51, 0x51, 0x6d, 0x77, 0x67, + 0x45, 0x68, 0x30, 0x71, 0x31, 0x62, 0x36, 0x38, 0x38, 0x6e, 0x43, 0x42, + 0x70, 0x48, 0x42, 0x67, 0x76, 0x67, 0x57, 0x31, 0x6d, 0x35, 0x34, 0x45, + 0x52, 0x4c, 0x35, 0x68, 0x0a, 0x49, 0x36, 0x7a, 0x70, 0x70, 0x53, 0x53, + 0x4d, 0x45, 0x59, 0x43, 0x55, 0x57, 0x71, 0x4b, 0x69, 0x75, 0x55, 0x6e, + 0x53, 0x77, 0x64, 0x7a, 0x52, 0x70, 0x2b, 0x30, 0x78, 0x45, 0x53, 0x79, + 0x65, 0x47, 0x61, 0x62, 0x75, 0x34, 0x56, 0x58, 0x68, 0x77, 0x4f, 0x72, + 0x50, 0x44, 0x59, 0x54, 0x6b, 0x46, 0x37, 0x65, 0x69, 0x66, 0x4b, 0x58, + 0x65, 0x56, 0x53, 0x55, 0x47, 0x37, 0x73, 0x7a, 0x41, 0x0a, 0x68, 0x31, + 0x78, 0x41, 0x32, 0x73, 0x79, 0x56, 0x50, 0x31, 0x58, 0x67, 0x4e, 0x63, + 0x65, 0x34, 0x68, 0x4c, 0x36, 0x30, 0x58, 0x63, 0x31, 0x36, 0x67, 0x77, + 0x46, 0x79, 0x37, 0x6f, 0x66, 0x6d, 0x58, 0x78, 0x32, 0x75, 0x74, 0x59, + 0x58, 0x47, 0x4a, 0x74, 0x2f, 0x6d, 0x77, 0x5a, 0x72, 0x70, 0x48, 0x67, + 0x4a, 0x48, 0x6e, 0x79, 0x71, 0x6f, 0x62, 0x61, 0x6c, 0x62, 0x7a, 0x2b, + 0x78, 0x46, 0x0a, 0x64, 0x33, 0x2b, 0x59, 0x4a, 0x35, 0x6f, 0x79, 0x58, + 0x53, 0x72, 0x6a, 0x68, 0x4f, 0x37, 0x46, 0x6d, 0x47, 0x59, 0x76, 0x6c, + 0x69, 0x41, 0x64, 0x33, 0x64, 0x6a, 0x44, 0x4a, 0x39, 0x65, 0x77, 0x2b, + 0x66, 0x37, 0x5a, 0x66, 0x63, 0x33, 0x51, 0x6e, 0x34, 0x38, 0x4c, 0x46, + 0x46, 0x68, 0x52, 0x6e, 0x79, 0x2b, 0x4c, 0x77, 0x7a, 0x67, 0x74, 0x33, + 0x75, 0x69, 0x50, 0x31, 0x6f, 0x32, 0x48, 0x0a, 0x70, 0x50, 0x56, 0x57, + 0x51, 0x78, 0x61, 0x5a, 0x4c, 0x50, 0x53, 0x6b, 0x56, 0x72, 0x51, 0x30, + 0x75, 0x47, 0x45, 0x33, 0x79, 0x63, 0x4a, 0x59, 0x67, 0x42, 0x75, 0x67, + 0x6c, 0x36, 0x48, 0x38, 0x57, 0x59, 0x33, 0x70, 0x45, 0x66, 0x62, 0x52, + 0x44, 0x30, 0x74, 0x56, 0x4e, 0x45, 0x59, 0x71, 0x69, 0x34, 0x59, 0x37, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x54, 0x57, 0x43, 0x41, 0x20, 0x47, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x20, 0x4f, 0x3d, 0x54, 0x41, 0x49, 0x57, 0x41, 0x4e, 0x2d, 0x43, 0x41, + 0x20, 0x4f, 0x55, 0x3d, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x0a, + 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x54, 0x57, 0x43, 0x41, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, + 0x54, 0x41, 0x49, 0x57, 0x41, 0x4e, 0x2d, 0x43, 0x41, 0x20, 0x4f, 0x55, + 0x3d, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x54, 0x57, 0x43, 0x41, 0x20, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x3a, 0x20, 0x33, 0x32, 0x36, 0x32, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x66, 0x39, 0x3a, 0x30, 0x33, 0x3a, 0x37, 0x65, 0x3a, 0x63, + 0x66, 0x3a, 0x65, 0x36, 0x3a, 0x39, 0x65, 0x3a, 0x33, 0x63, 0x3a, 0x37, + 0x33, 0x3a, 0x37, 0x61, 0x3a, 0x32, 0x61, 0x3a, 0x39, 0x30, 0x3a, 0x30, + 0x37, 0x3a, 0x36, 0x39, 0x3a, 0x66, 0x66, 0x3a, 0x32, 0x62, 0x3a, 0x39, + 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x63, + 0x3a, 0x62, 0x62, 0x3a, 0x34, 0x38, 0x3a, 0x35, 0x33, 0x3a, 0x66, 0x36, + 0x3a, 0x61, 0x34, 0x3a, 0x66, 0x36, 0x3a, 0x64, 0x33, 0x3a, 0x35, 0x32, + 0x3a, 0x61, 0x34, 0x3a, 0x65, 0x38, 0x3a, 0x33, 0x32, 0x3a, 0x35, 0x32, + 0x3a, 0x35, 0x35, 0x3a, 0x36, 0x30, 0x3a, 0x31, 0x33, 0x3a, 0x66, 0x35, + 0x3a, 0x61, 0x64, 0x3a, 0x61, 0x66, 0x3a, 0x36, 0x35, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x39, 0x3a, 0x37, + 0x36, 0x3a, 0x39, 0x30, 0x3a, 0x30, 0x37, 0x3a, 0x66, 0x37, 0x3a, 0x36, + 0x38, 0x3a, 0x35, 0x64, 0x3a, 0x30, 0x66, 0x3a, 0x63, 0x64, 0x3a, 0x35, + 0x30, 0x3a, 0x38, 0x37, 0x3a, 0x32, 0x66, 0x3a, 0x39, 0x66, 0x3a, 0x39, + 0x35, 0x3a, 0x64, 0x35, 0x3a, 0x37, 0x35, 0x3a, 0x35, 0x61, 0x3a, 0x35, + 0x62, 0x3a, 0x32, 0x62, 0x3a, 0x34, 0x35, 0x3a, 0x37, 0x64, 0x3a, 0x38, + 0x31, 0x3a, 0x66, 0x33, 0x3a, 0x36, 0x39, 0x3a, 0x32, 0x62, 0x3a, 0x36, + 0x31, 0x3a, 0x30, 0x61, 0x3a, 0x39, 0x38, 0x3a, 0x36, 0x37, 0x3a, 0x32, + 0x66, 0x3a, 0x30, 0x65, 0x3a, 0x31, 0x62, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x46, 0x51, 0x54, 0x43, 0x43, 0x41, 0x79, 0x6d, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x43, 0x44, 0x4c, 0x34, 0x77, + 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, + 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x77, 0x55, 0x54, 0x45, 0x4c, + 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, + 0x56, 0x46, 0x63, 0x78, 0x0a, 0x45, 0x6a, 0x41, 0x51, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x54, 0x43, 0x56, 0x52, 0x42, 0x53, 0x56, 0x64, + 0x42, 0x54, 0x69, 0x31, 0x44, 0x51, 0x54, 0x45, 0x51, 0x4d, 0x41, 0x34, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x48, 0x55, 0x6d, 0x39, + 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x54, 0x45, 0x63, 0x4d, 0x42, 0x6f, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x54, 0x0a, 0x56, 0x46, + 0x64, 0x44, 0x51, 0x53, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, + 0x77, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x54, + 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4d, 0x6a, 0x41, 0x32, 0x4d, 0x6a, + 0x63, 0x77, 0x4e, 0x6a, 0x49, 0x34, 0x4d, 0x7a, 0x4e, 0x61, 0x46, 0x77, + 0x30, 0x7a, 0x4d, 0x44, 0x45, 0x79, 0x4d, 0x7a, 0x45, 0x78, 0x4e, 0x54, + 0x55, 0x35, 0x0a, 0x4e, 0x54, 0x6c, 0x61, 0x4d, 0x46, 0x45, 0x78, 0x43, + 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, + 0x6c, 0x52, 0x58, 0x4d, 0x52, 0x49, 0x77, 0x45, 0x41, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x4b, 0x45, 0x77, 0x6c, 0x55, 0x51, 0x55, 0x6c, 0x58, 0x51, + 0x55, 0x34, 0x74, 0x51, 0x30, 0x45, 0x78, 0x45, 0x44, 0x41, 0x4f, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x0a, 0x42, 0x31, 0x4a, 0x76, + 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x48, 0x44, 0x41, 0x61, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x45, 0x31, 0x52, 0x58, + 0x51, 0x30, 0x45, 0x67, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, + 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x77, + 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, + 0x0a, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, + 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, + 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51, 0x43, 0x77, 0x42, 0x64, 0x76, + 0x49, 0x36, 0x34, 0x7a, 0x45, 0x62, 0x6f, 0x6f, 0x68, 0x37, 0x34, 0x35, + 0x4e, 0x6e, 0x48, 0x45, 0x4b, 0x48, 0x31, 0x4a, 0x77, 0x37, 0x57, 0x32, + 0x43, 0x6e, 0x4a, 0x66, 0x46, 0x0a, 0x31, 0x30, 0x78, 0x4f, 0x52, 0x55, + 0x6e, 0x4c, 0x51, 0x45, 0x4b, 0x31, 0x45, 0x6a, 0x52, 0x73, 0x47, 0x63, + 0x4a, 0x30, 0x70, 0x44, 0x46, 0x66, 0x68, 0x51, 0x4b, 0x58, 0x37, 0x45, + 0x4d, 0x7a, 0x43, 0x6c, 0x50, 0x53, 0x6e, 0x49, 0x79, 0x4f, 0x74, 0x37, + 0x68, 0x35, 0x32, 0x79, 0x76, 0x56, 0x61, 0x76, 0x4b, 0x4f, 0x5a, 0x73, + 0x54, 0x75, 0x4b, 0x77, 0x45, 0x48, 0x6b, 0x74, 0x53, 0x7a, 0x0a, 0x30, + 0x41, 0x4c, 0x66, 0x55, 0x50, 0x5a, 0x56, 0x72, 0x32, 0x59, 0x4f, 0x79, + 0x2b, 0x42, 0x48, 0x59, 0x43, 0x38, 0x72, 0x4d, 0x6a, 0x6b, 0x31, 0x55, + 0x6a, 0x6f, 0x6f, 0x67, 0x2f, 0x68, 0x37, 0x46, 0x73, 0x59, 0x59, 0x75, + 0x47, 0x4c, 0x57, 0x52, 0x79, 0x57, 0x52, 0x7a, 0x76, 0x41, 0x5a, 0x45, + 0x6b, 0x32, 0x74, 0x59, 0x2f, 0x58, 0x54, 0x50, 0x33, 0x56, 0x66, 0x4b, + 0x66, 0x43, 0x68, 0x0a, 0x4d, 0x42, 0x77, 0x71, 0x6f, 0x4a, 0x69, 0x6d, + 0x46, 0x62, 0x33, 0x75, 0x2f, 0x52, 0x6b, 0x32, 0x38, 0x4f, 0x4b, 0x52, + 0x51, 0x34, 0x2f, 0x36, 0x79, 0x74, 0x59, 0x51, 0x4a, 0x30, 0x6c, 0x4d, + 0x37, 0x39, 0x33, 0x42, 0x38, 0x59, 0x56, 0x77, 0x6d, 0x38, 0x72, 0x71, + 0x71, 0x46, 0x70, 0x44, 0x2f, 0x47, 0x32, 0x47, 0x62, 0x33, 0x50, 0x70, + 0x4e, 0x30, 0x57, 0x70, 0x38, 0x44, 0x62, 0x48, 0x0a, 0x7a, 0x49, 0x68, + 0x31, 0x48, 0x72, 0x74, 0x73, 0x42, 0x76, 0x2b, 0x62, 0x61, 0x7a, 0x34, + 0x58, 0x37, 0x47, 0x47, 0x71, 0x63, 0x58, 0x7a, 0x47, 0x48, 0x61, 0x4c, + 0x33, 0x53, 0x65, 0x6b, 0x56, 0x74, 0x54, 0x7a, 0x57, 0x6f, 0x57, 0x48, + 0x31, 0x45, 0x66, 0x63, 0x46, 0x62, 0x78, 0x33, 0x39, 0x45, 0x62, 0x37, + 0x51, 0x4d, 0x41, 0x66, 0x43, 0x4b, 0x62, 0x41, 0x4a, 0x54, 0x69, 0x62, + 0x63, 0x0a, 0x34, 0x36, 0x4b, 0x6f, 0x6b, 0x57, 0x6f, 0x66, 0x77, 0x70, + 0x46, 0x46, 0x69, 0x46, 0x7a, 0x6c, 0x6d, 0x4c, 0x68, 0x78, 0x70, 0x52, + 0x55, 0x5a, 0x79, 0x58, 0x78, 0x31, 0x45, 0x63, 0x78, 0x77, 0x64, 0x45, + 0x38, 0x74, 0x6d, 0x78, 0x32, 0x52, 0x52, 0x50, 0x31, 0x57, 0x4b, 0x4b, + 0x44, 0x2b, 0x75, 0x34, 0x5a, 0x71, 0x79, 0x50, 0x70, 0x63, 0x43, 0x31, + 0x6a, 0x63, 0x78, 0x6b, 0x74, 0x32, 0x0a, 0x79, 0x4b, 0x73, 0x69, 0x32, + 0x58, 0x4d, 0x50, 0x70, 0x66, 0x52, 0x61, 0x41, 0x6f, 0x6b, 0x2f, 0x54, + 0x35, 0x34, 0x69, 0x67, 0x75, 0x36, 0x69, 0x64, 0x46, 0x4d, 0x71, 0x50, + 0x56, 0x4d, 0x6e, 0x61, 0x52, 0x31, 0x73, 0x6a, 0x6a, 0x49, 0x73, 0x5a, + 0x41, 0x41, 0x6d, 0x59, 0x32, 0x45, 0x32, 0x54, 0x71, 0x4e, 0x47, 0x74, + 0x7a, 0x39, 0x39, 0x73, 0x79, 0x32, 0x73, 0x62, 0x5a, 0x43, 0x69, 0x0a, + 0x6c, 0x61, 0x4c, 0x4f, 0x7a, 0x39, 0x71, 0x43, 0x35, 0x77, 0x63, 0x30, + 0x47, 0x5a, 0x62, 0x70, 0x75, 0x43, 0x47, 0x71, 0x4b, 0x58, 0x36, 0x6d, + 0x4f, 0x4c, 0x36, 0x4f, 0x4b, 0x55, 0x6f, 0x68, 0x5a, 0x6e, 0x6b, 0x66, + 0x73, 0x38, 0x4f, 0x31, 0x43, 0x57, 0x66, 0x65, 0x31, 0x74, 0x51, 0x48, + 0x52, 0x76, 0x4d, 0x71, 0x32, 0x75, 0x59, 0x69, 0x4e, 0x32, 0x44, 0x4c, + 0x67, 0x62, 0x59, 0x50, 0x0a, 0x6f, 0x41, 0x2f, 0x70, 0x79, 0x4a, 0x56, + 0x2f, 0x76, 0x31, 0x57, 0x52, 0x42, 0x58, 0x72, 0x50, 0x50, 0x52, 0x58, + 0x41, 0x62, 0x39, 0x34, 0x4a, 0x6c, 0x41, 0x47, 0x44, 0x31, 0x7a, 0x51, + 0x62, 0x7a, 0x45, 0x43, 0x6c, 0x38, 0x4c, 0x69, 0x62, 0x5a, 0x39, 0x57, + 0x59, 0x6b, 0x54, 0x75, 0x6e, 0x68, 0x48, 0x69, 0x56, 0x4a, 0x71, 0x52, + 0x61, 0x43, 0x50, 0x67, 0x72, 0x64, 0x4c, 0x51, 0x41, 0x0a, 0x42, 0x44, + 0x7a, 0x66, 0x75, 0x42, 0x53, 0x4f, 0x36, 0x4e, 0x2b, 0x70, 0x6a, 0x57, + 0x78, 0x6e, 0x6b, 0x6a, 0x4d, 0x64, 0x77, 0x4c, 0x66, 0x53, 0x37, 0x4a, + 0x4c, 0x49, 0x76, 0x67, 0x6d, 0x2f, 0x4c, 0x43, 0x6b, 0x46, 0x62, 0x77, + 0x4a, 0x72, 0x6e, 0x75, 0x2b, 0x38, 0x76, 0x79, 0x71, 0x38, 0x57, 0x38, + 0x42, 0x51, 0x6a, 0x30, 0x46, 0x77, 0x63, 0x59, 0x65, 0x79, 0x54, 0x62, + 0x63, 0x45, 0x0a, 0x71, 0x59, 0x53, 0x6a, 0x4d, 0x71, 0x2b, 0x75, 0x37, + 0x6d, 0x73, 0x58, 0x69, 0x37, 0x4b, 0x78, 0x2f, 0x6d, 0x7a, 0x68, 0x6b, + 0x49, 0x79, 0x49, 0x71, 0x4a, 0x64, 0x49, 0x7a, 0x73, 0x68, 0x4e, 0x79, + 0x2f, 0x4d, 0x47, 0x7a, 0x31, 0x39, 0x71, 0x43, 0x6b, 0x4b, 0x78, 0x48, + 0x68, 0x35, 0x33, 0x4c, 0x34, 0x36, 0x67, 0x35, 0x70, 0x49, 0x4f, 0x42, + 0x76, 0x77, 0x46, 0x49, 0x74, 0x49, 0x6d, 0x0a, 0x34, 0x54, 0x46, 0x52, + 0x66, 0x54, 0x4c, 0x63, 0x44, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, + 0x6f, 0x79, 0x4d, 0x77, 0x49, 0x54, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, + 0x41, 0x51, 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, + 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, + 0x0a, 0x2f, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x41, 0x4f, + 0x43, 0x41, 0x67, 0x45, 0x41, 0x58, 0x7a, 0x53, 0x42, 0x64, 0x75, 0x2b, + 0x57, 0x48, 0x64, 0x58, 0x6c, 0x74, 0x64, 0x6b, 0x43, 0x59, 0x34, 0x51, + 0x57, 0x77, 0x61, 0x36, 0x67, 0x63, 0x46, 0x47, 0x6e, 0x39, 0x30, 0x78, + 0x48, 0x4e, 0x63, 0x67, 0x4c, 0x0a, 0x31, 0x79, 0x67, 0x39, 0x69, 0x58, + 0x48, 0x5a, 0x71, 0x6a, 0x4e, 0x42, 0x36, 0x68, 0x51, 0x62, 0x62, 0x43, + 0x45, 0x41, 0x77, 0x47, 0x78, 0x43, 0x47, 0x58, 0x36, 0x66, 0x61, 0x56, + 0x73, 0x67, 0x51, 0x74, 0x2b, 0x69, 0x30, 0x74, 0x72, 0x45, 0x66, 0x4a, + 0x64, 0x4c, 0x6a, 0x62, 0x44, 0x6f, 0x72, 0x4d, 0x6a, 0x75, 0x70, 0x57, + 0x6b, 0x45, 0x6d, 0x51, 0x71, 0x53, 0x70, 0x71, 0x73, 0x6e, 0x0a, 0x4c, + 0x68, 0x70, 0x4e, 0x67, 0x62, 0x2b, 0x45, 0x31, 0x48, 0x41, 0x65, 0x72, + 0x55, 0x66, 0x2b, 0x2f, 0x55, 0x71, 0x64, 0x4d, 0x2b, 0x44, 0x79, 0x75, + 0x63, 0x52, 0x46, 0x43, 0x43, 0x45, 0x4b, 0x32, 0x6d, 0x6c, 0x70, 0x63, + 0x33, 0x49, 0x4e, 0x76, 0x6a, 0x54, 0x2b, 0x6c, 0x49, 0x75, 0x74, 0x77, + 0x78, 0x34, 0x31, 0x31, 0x36, 0x4b, 0x44, 0x37, 0x2b, 0x55, 0x34, 0x78, + 0x36, 0x57, 0x46, 0x0a, 0x48, 0x36, 0x76, 0x50, 0x4e, 0x4f, 0x77, 0x2f, + 0x4b, 0x50, 0x34, 0x4d, 0x38, 0x56, 0x65, 0x47, 0x54, 0x73, 0x6c, 0x56, + 0x39, 0x78, 0x7a, 0x55, 0x32, 0x4b, 0x56, 0x39, 0x42, 0x6e, 0x70, 0x76, + 0x31, 0x64, 0x38, 0x51, 0x33, 0x34, 0x46, 0x4f, 0x49, 0x57, 0x57, 0x78, + 0x74, 0x75, 0x45, 0x58, 0x65, 0x5a, 0x56, 0x46, 0x42, 0x73, 0x35, 0x66, + 0x7a, 0x4e, 0x78, 0x47, 0x69, 0x57, 0x4e, 0x6f, 0x0a, 0x52, 0x49, 0x32, + 0x54, 0x39, 0x47, 0x52, 0x77, 0x6f, 0x44, 0x32, 0x64, 0x4b, 0x41, 0x58, + 0x44, 0x4f, 0x58, 0x43, 0x34, 0x59, 0x6e, 0x73, 0x67, 0x2f, 0x65, 0x54, + 0x62, 0x36, 0x51, 0x69, 0x68, 0x75, 0x4a, 0x34, 0x39, 0x43, 0x63, 0x64, + 0x50, 0x2b, 0x79, 0x7a, 0x34, 0x6b, 0x33, 0x5a, 0x42, 0x33, 0x6c, 0x4c, + 0x67, 0x34, 0x56, 0x66, 0x53, 0x6e, 0x51, 0x4f, 0x38, 0x64, 0x35, 0x37, + 0x2b, 0x0a, 0x6e, 0x69, 0x6c, 0x65, 0x39, 0x38, 0x46, 0x52, 0x59, 0x42, + 0x2f, 0x65, 0x32, 0x67, 0x75, 0x79, 0x4c, 0x58, 0x57, 0x33, 0x51, 0x30, + 0x69, 0x54, 0x35, 0x2f, 0x5a, 0x35, 0x78, 0x6f, 0x52, 0x64, 0x67, 0x46, + 0x6c, 0x67, 0x6c, 0x50, 0x78, 0x34, 0x6d, 0x49, 0x38, 0x38, 0x6b, 0x31, + 0x48, 0x74, 0x51, 0x4a, 0x41, 0x48, 0x33, 0x32, 0x52, 0x6a, 0x4a, 0x4d, + 0x74, 0x4f, 0x63, 0x51, 0x57, 0x68, 0x0a, 0x31, 0x35, 0x51, 0x61, 0x69, + 0x44, 0x4c, 0x78, 0x49, 0x6e, 0x51, 0x69, 0x72, 0x71, 0x57, 0x6d, 0x32, + 0x42, 0x4a, 0x70, 0x54, 0x47, 0x43, 0x6a, 0x41, 0x75, 0x34, 0x72, 0x37, + 0x4e, 0x52, 0x6a, 0x6b, 0x67, 0x74, 0x65, 0x76, 0x69, 0x39, 0x32, 0x61, + 0x36, 0x4f, 0x32, 0x4a, 0x72, 0x79, 0x50, 0x41, 0x39, 0x67, 0x4b, 0x38, + 0x6b, 0x78, 0x6b, 0x52, 0x72, 0x30, 0x35, 0x59, 0x75, 0x57, 0x57, 0x0a, + 0x36, 0x7a, 0x52, 0x6a, 0x45, 0x53, 0x6a, 0x4d, 0x6c, 0x66, 0x47, 0x74, + 0x37, 0x2b, 0x2f, 0x63, 0x67, 0x46, 0x68, 0x49, 0x36, 0x55, 0x75, 0x34, + 0x36, 0x6d, 0x57, 0x73, 0x36, 0x66, 0x79, 0x41, 0x74, 0x62, 0x58, 0x49, + 0x52, 0x66, 0x6d, 0x73, 0x77, 0x5a, 0x2f, 0x5a, 0x75, 0x65, 0x70, 0x69, + 0x69, 0x49, 0x37, 0x45, 0x38, 0x55, 0x75, 0x44, 0x45, 0x71, 0x33, 0x6d, + 0x69, 0x34, 0x54, 0x57, 0x0a, 0x6e, 0x73, 0x4c, 0x72, 0x67, 0x78, 0x69, + 0x66, 0x61, 0x72, 0x73, 0x62, 0x4a, 0x47, 0x41, 0x7a, 0x63, 0x4d, 0x7a, + 0x73, 0x39, 0x7a, 0x4c, 0x7a, 0x58, 0x4e, 0x6c, 0x35, 0x66, 0x65, 0x2b, + 0x65, 0x70, 0x50, 0x37, 0x4a, 0x49, 0x38, 0x4d, 0x6b, 0x37, 0x68, 0x57, + 0x53, 0x73, 0x54, 0x32, 0x52, 0x54, 0x79, 0x61, 0x47, 0x76, 0x57, 0x5a, + 0x7a, 0x4a, 0x42, 0x50, 0x71, 0x70, 0x4b, 0x35, 0x6a, 0x0a, 0x77, 0x61, + 0x31, 0x39, 0x68, 0x41, 0x4d, 0x38, 0x45, 0x48, 0x69, 0x47, 0x47, 0x33, + 0x6e, 0x6a, 0x78, 0x50, 0x50, 0x79, 0x42, 0x4a, 0x55, 0x67, 0x72, 0x69, + 0x4f, 0x43, 0x78, 0x4c, 0x4d, 0x36, 0x41, 0x47, 0x4b, 0x2f, 0x35, 0x6a, + 0x59, 0x6b, 0x34, 0x56, 0x65, 0x36, 0x78, 0x78, 0x36, 0x51, 0x64, 0x64, + 0x56, 0x66, 0x50, 0x35, 0x56, 0x68, 0x4b, 0x38, 0x45, 0x37, 0x7a, 0x65, + 0x57, 0x7a, 0x0a, 0x61, 0x47, 0x48, 0x51, 0x52, 0x69, 0x61, 0x70, 0x49, + 0x56, 0x4a, 0x70, 0x4c, 0x65, 0x73, 0x75, 0x78, 0x2b, 0x74, 0x33, 0x7a, + 0x71, 0x59, 0x36, 0x74, 0x51, 0x4d, 0x7a, 0x54, 0x33, 0x62, 0x52, 0x35, + 0x31, 0x78, 0x55, 0x41, 0x56, 0x33, 0x4c, 0x65, 0x50, 0x54, 0x4a, 0x44, + 0x4c, 0x2f, 0x50, 0x45, 0x6f, 0x34, 0x58, 0x4c, 0x53, 0x4e, 0x6f, 0x6c, + 0x4f, 0x65, 0x72, 0x2f, 0x71, 0x6d, 0x79, 0x0a, 0x4b, 0x77, 0x62, 0x51, + 0x42, 0x4d, 0x30, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x54, 0x65, 0x6c, + 0x69, 0x61, 0x53, 0x6f, 0x6e, 0x65, 0x72, 0x61, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x41, 0x20, 0x76, 0x31, 0x20, 0x4f, 0x3d, 0x54, 0x65, + 0x6c, 0x69, 0x61, 0x53, 0x6f, 0x6e, 0x65, 0x72, 0x61, 0x0a, 0x23, 0x20, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x54, 0x65, 0x6c, 0x69, 0x61, 0x53, 0x6f, 0x6e, 0x65, 0x72, 0x61, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x76, 0x31, 0x20, 0x4f, + 0x3d, 0x54, 0x65, 0x6c, 0x69, 0x61, 0x53, 0x6f, 0x6e, 0x65, 0x72, 0x61, + 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x54, + 0x65, 0x6c, 0x69, 0x61, 0x53, 0x6f, 0x6e, 0x65, 0x72, 0x61, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x76, 0x31, 0x22, 0x0a, 0x23, + 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x39, 0x39, + 0x30, 0x34, 0x31, 0x39, 0x36, 0x36, 0x37, 0x34, 0x31, 0x30, 0x39, 0x30, + 0x31, 0x30, 0x37, 0x39, 0x36, 0x34, 0x39, 0x30, 0x34, 0x32, 0x38, 0x37, + 0x32, 0x31, 0x37, 0x37, 0x38, 0x36, 0x38, 0x30, 0x31, 0x35, 0x35, 0x38, + 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x37, 0x3a, 0x34, + 0x31, 0x3a, 0x34, 0x39, 0x3a, 0x31, 0x62, 0x3a, 0x31, 0x38, 0x3a, 0x35, + 0x36, 0x3a, 0x39, 0x61, 0x3a, 0x32, 0x36, 0x3a, 0x66, 0x35, 0x3a, 0x61, + 0x64, 0x3a, 0x63, 0x32, 0x3a, 0x36, 0x36, 0x3a, 0x66, 0x62, 0x3a, 0x34, + 0x30, 0x3a, 0x61, 0x35, 0x3a, 0x34, 0x63, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x33, 0x3a, 0x31, 0x33, 0x3a, 0x62, 0x62, + 0x3a, 0x39, 0x36, 0x3a, 0x66, 0x31, 0x3a, 0x64, 0x35, 0x3a, 0x38, 0x36, + 0x3a, 0x39, 0x62, 0x3a, 0x63, 0x31, 0x3a, 0x34, 0x65, 0x3a, 0x36, 0x61, + 0x3a, 0x39, 0x32, 0x3a, 0x66, 0x36, 0x3a, 0x63, 0x66, 0x3a, 0x66, 0x36, + 0x3a, 0x33, 0x34, 0x3a, 0x36, 0x39, 0x3a, 0x38, 0x37, 0x3a, 0x38, 0x32, + 0x3a, 0x33, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x64, 0x64, 0x3a, 0x36, 0x39, 0x3a, 0x33, 0x36, 0x3a, 0x66, + 0x65, 0x3a, 0x32, 0x31, 0x3a, 0x66, 0x38, 0x3a, 0x66, 0x30, 0x3a, 0x37, + 0x37, 0x3a, 0x63, 0x31, 0x3a, 0x32, 0x33, 0x3a, 0x61, 0x31, 0x3a, 0x61, + 0x35, 0x3a, 0x32, 0x31, 0x3a, 0x63, 0x31, 0x3a, 0x32, 0x32, 0x3a, 0x32, + 0x34, 0x3a, 0x66, 0x37, 0x3a, 0x32, 0x32, 0x3a, 0x35, 0x35, 0x3a, 0x62, + 0x37, 0x3a, 0x33, 0x65, 0x3a, 0x30, 0x33, 0x3a, 0x61, 0x37, 0x3a, 0x32, + 0x36, 0x3a, 0x30, 0x36, 0x3a, 0x39, 0x33, 0x3a, 0x65, 0x38, 0x3a, 0x61, + 0x32, 0x3a, 0x34, 0x62, 0x3a, 0x30, 0x66, 0x3a, 0x61, 0x33, 0x3a, 0x38, + 0x39, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x4f, 0x44, + 0x43, 0x43, 0x41, 0x79, 0x43, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, + 0x49, 0x52, 0x41, 0x4a, 0x57, 0x2b, 0x46, 0x71, 0x44, 0x33, 0x4c, 0x6b, + 0x62, 0x78, 0x65, 0x7a, 0x6d, 0x43, 0x63, 0x76, 0x71, 0x4c, 0x7a, 0x5a, + 0x59, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x77, 0x0a, 0x4e, + 0x7a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x67, 0x77, 0x4c, 0x56, 0x47, 0x56, 0x73, 0x61, 0x57, 0x46, 0x54, 0x62, + 0x32, 0x35, 0x6c, 0x63, 0x6d, 0x45, 0x78, 0x48, 0x7a, 0x41, 0x64, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x46, 0x6c, 0x52, 0x6c, 0x62, + 0x47, 0x6c, 0x68, 0x55, 0x32, 0x39, 0x75, 0x5a, 0x58, 0x4a, 0x68, 0x49, + 0x46, 0x4a, 0x76, 0x0a, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, + 0x64, 0x6a, 0x45, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x63, 0x78, + 0x4d, 0x44, 0x45, 0x34, 0x4d, 0x54, 0x49, 0x77, 0x4d, 0x44, 0x55, 0x77, + 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x49, 0x78, 0x4d, 0x44, 0x45, 0x34, + 0x4d, 0x54, 0x49, 0x77, 0x4d, 0x44, 0x55, 0x77, 0x57, 0x6a, 0x41, 0x33, + 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, + 0x4b, 0x44, 0x41, 0x74, 0x55, 0x5a, 0x57, 0x78, 0x70, 0x59, 0x56, 0x4e, + 0x76, 0x62, 0x6d, 0x56, 0x79, 0x59, 0x54, 0x45, 0x66, 0x4d, 0x42, 0x30, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x57, 0x56, 0x47, 0x56, + 0x73, 0x61, 0x57, 0x46, 0x54, 0x62, 0x32, 0x35, 0x6c, 0x63, 0x6d, 0x45, + 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x53, 0x42, + 0x32, 0x0a, 0x4d, 0x54, 0x43, 0x43, 0x41, 0x69, 0x49, 0x77, 0x44, 0x51, + 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, + 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x50, 0x41, 0x44, + 0x43, 0x43, 0x41, 0x67, 0x6f, 0x43, 0x67, 0x67, 0x49, 0x42, 0x41, 0x4d, + 0x4b, 0x2b, 0x36, 0x79, 0x66, 0x77, 0x49, 0x61, 0x50, 0x7a, 0x61, 0x53, + 0x5a, 0x56, 0x66, 0x70, 0x33, 0x46, 0x0a, 0x56, 0x52, 0x61, 0x52, 0x58, + 0x50, 0x33, 0x76, 0x49, 0x62, 0x39, 0x54, 0x67, 0x48, 0x6f, 0x74, 0x30, + 0x70, 0x47, 0x4d, 0x59, 0x7a, 0x48, 0x77, 0x37, 0x43, 0x54, 0x77, 0x77, + 0x36, 0x58, 0x53, 0x63, 0x6e, 0x77, 0x51, 0x62, 0x66, 0x51, 0x33, 0x74, + 0x2b, 0x58, 0x6d, 0x66, 0x48, 0x6e, 0x71, 0x6a, 0x4c, 0x57, 0x43, 0x69, + 0x36, 0x35, 0x49, 0x74, 0x71, 0x77, 0x41, 0x33, 0x47, 0x56, 0x31, 0x0a, + 0x37, 0x43, 0x70, 0x4e, 0x58, 0x38, 0x47, 0x48, 0x39, 0x53, 0x42, 0x6c, + 0x4b, 0x34, 0x47, 0x6f, 0x52, 0x7a, 0x36, 0x4a, 0x49, 0x35, 0x55, 0x77, + 0x46, 0x70, 0x42, 0x2f, 0x36, 0x46, 0x63, 0x48, 0x53, 0x4f, 0x63, 0x5a, + 0x72, 0x72, 0x39, 0x46, 0x5a, 0x37, 0x45, 0x33, 0x47, 0x77, 0x59, 0x71, + 0x2f, 0x74, 0x37, 0x35, 0x72, 0x48, 0x32, 0x44, 0x2b, 0x31, 0x36, 0x36, + 0x35, 0x49, 0x2b, 0x58, 0x0a, 0x5a, 0x37, 0x35, 0x4c, 0x6a, 0x6f, 0x31, + 0x6b, 0x42, 0x31, 0x63, 0x34, 0x56, 0x57, 0x6b, 0x30, 0x4e, 0x6a, 0x30, + 0x54, 0x53, 0x4f, 0x39, 0x50, 0x34, 0x74, 0x4e, 0x6d, 0x48, 0x71, 0x54, + 0x50, 0x47, 0x72, 0x64, 0x65, 0x4e, 0x6a, 0x50, 0x55, 0x74, 0x41, 0x61, + 0x39, 0x47, 0x41, 0x48, 0x39, 0x64, 0x34, 0x52, 0x51, 0x41, 0x45, 0x58, + 0x31, 0x6a, 0x46, 0x33, 0x6f, 0x49, 0x37, 0x78, 0x2b, 0x0a, 0x2f, 0x6a, + 0x58, 0x68, 0x37, 0x56, 0x42, 0x37, 0x71, 0x54, 0x43, 0x4e, 0x47, 0x64, + 0x4d, 0x4a, 0x6a, 0x6d, 0x68, 0x6e, 0x58, 0x62, 0x38, 0x38, 0x6c, 0x78, + 0x68, 0x54, 0x75, 0x79, 0x6c, 0x69, 0x78, 0x63, 0x70, 0x65, 0x63, 0x73, + 0x48, 0x48, 0x6c, 0x74, 0x54, 0x62, 0x4c, 0x61, 0x43, 0x30, 0x48, 0x32, + 0x6b, 0x44, 0x37, 0x4f, 0x72, 0x69, 0x55, 0x50, 0x45, 0x4d, 0x50, 0x50, + 0x43, 0x73, 0x0a, 0x38, 0x31, 0x4d, 0x74, 0x38, 0x42, 0x7a, 0x31, 0x37, + 0x57, 0x77, 0x35, 0x4f, 0x58, 0x4f, 0x41, 0x46, 0x73, 0x68, 0x53, 0x73, + 0x43, 0x50, 0x4e, 0x34, 0x44, 0x37, 0x63, 0x33, 0x54, 0x78, 0x48, 0x6f, + 0x4c, 0x73, 0x31, 0x69, 0x75, 0x4b, 0x59, 0x61, 0x49, 0x75, 0x2b, 0x35, + 0x62, 0x39, 0x79, 0x37, 0x74, 0x4c, 0x36, 0x70, 0x65, 0x30, 0x53, 0x37, + 0x66, 0x79, 0x59, 0x47, 0x4b, 0x6b, 0x6d, 0x0a, 0x64, 0x74, 0x77, 0x6f, + 0x53, 0x78, 0x41, 0x67, 0x48, 0x4e, 0x4e, 0x2f, 0x46, 0x6e, 0x63, 0x74, + 0x37, 0x57, 0x2b, 0x41, 0x39, 0x30, 0x6d, 0x37, 0x55, 0x77, 0x57, 0x37, + 0x58, 0x57, 0x6a, 0x48, 0x31, 0x4d, 0x68, 0x31, 0x46, 0x6a, 0x2b, 0x4a, + 0x57, 0x6f, 0x76, 0x33, 0x46, 0x30, 0x66, 0x55, 0x54, 0x50, 0x48, 0x53, + 0x69, 0x58, 0x6b, 0x2b, 0x54, 0x54, 0x32, 0x59, 0x71, 0x47, 0x48, 0x65, + 0x0a, 0x4f, 0x68, 0x37, 0x53, 0x2b, 0x46, 0x34, 0x44, 0x34, 0x4d, 0x48, + 0x4a, 0x48, 0x49, 0x7a, 0x54, 0x6a, 0x55, 0x33, 0x54, 0x6c, 0x54, 0x61, + 0x7a, 0x4e, 0x31, 0x39, 0x6a, 0x59, 0x35, 0x73, 0x7a, 0x46, 0x50, 0x41, + 0x74, 0x4a, 0x6d, 0x74, 0x54, 0x66, 0x49, 0x6d, 0x4d, 0x4d, 0x73, 0x4a, + 0x75, 0x37, 0x44, 0x30, 0x68, 0x41, 0x44, 0x6e, 0x4a, 0x6f, 0x57, 0x6a, + 0x69, 0x55, 0x49, 0x4d, 0x75, 0x0a, 0x73, 0x44, 0x6f, 0x72, 0x38, 0x7a, + 0x61, 0x67, 0x72, 0x43, 0x2f, 0x6b, 0x62, 0x32, 0x48, 0x43, 0x55, 0x51, + 0x6b, 0x35, 0x50, 0x6f, 0x74, 0x54, 0x75, 0x62, 0x74, 0x6e, 0x32, 0x74, + 0x78, 0x54, 0x75, 0x58, 0x5a, 0x5a, 0x4e, 0x70, 0x31, 0x44, 0x35, 0x53, + 0x44, 0x67, 0x50, 0x54, 0x4a, 0x67, 0x68, 0x53, 0x4a, 0x52, 0x74, 0x38, + 0x63, 0x7a, 0x75, 0x39, 0x30, 0x56, 0x4c, 0x36, 0x52, 0x34, 0x0a, 0x70, + 0x67, 0x64, 0x37, 0x67, 0x55, 0x59, 0x32, 0x42, 0x49, 0x62, 0x64, 0x65, + 0x54, 0x58, 0x48, 0x6c, 0x53, 0x77, 0x37, 0x73, 0x4b, 0x4d, 0x58, 0x4e, + 0x65, 0x56, 0x7a, 0x48, 0x37, 0x52, 0x63, 0x57, 0x65, 0x2f, 0x61, 0x36, + 0x68, 0x42, 0x6c, 0x65, 0x33, 0x72, 0x51, 0x66, 0x35, 0x2b, 0x7a, 0x74, + 0x43, 0x6f, 0x33, 0x4f, 0x33, 0x43, 0x4c, 0x6d, 0x31, 0x75, 0x35, 0x4b, + 0x37, 0x66, 0x73, 0x0a, 0x73, 0x6c, 0x45, 0x53, 0x6c, 0x31, 0x4d, 0x70, + 0x57, 0x74, 0x54, 0x77, 0x45, 0x68, 0x44, 0x63, 0x54, 0x77, 0x4b, 0x37, + 0x45, 0x70, 0x49, 0x76, 0x59, 0x74, 0x51, 0x2f, 0x61, 0x55, 0x4e, 0x38, + 0x44, 0x64, 0x62, 0x38, 0x57, 0x48, 0x55, 0x42, 0x69, 0x4a, 0x31, 0x59, + 0x46, 0x6b, 0x76, 0x65, 0x75, 0x70, 0x44, 0x2f, 0x52, 0x77, 0x47, 0x4a, + 0x42, 0x6d, 0x72, 0x32, 0x58, 0x37, 0x4b, 0x51, 0x0a, 0x61, 0x72, 0x4d, + 0x43, 0x70, 0x67, 0x4b, 0x49, 0x76, 0x37, 0x4e, 0x48, 0x66, 0x69, 0x72, + 0x5a, 0x31, 0x66, 0x70, 0x6f, 0x65, 0x44, 0x56, 0x4e, 0x41, 0x67, 0x4d, + 0x42, 0x41, 0x41, 0x47, 0x6a, 0x50, 0x7a, 0x41, 0x39, 0x4d, 0x41, 0x38, + 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, + 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x43, 0x77, 0x59, + 0x44, 0x0a, 0x56, 0x52, 0x30, 0x50, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, + 0x45, 0x47, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, + 0x51, 0x57, 0x42, 0x42, 0x54, 0x77, 0x6a, 0x31, 0x6b, 0x34, 0x41, 0x4c, + 0x50, 0x31, 0x6a, 0x35, 0x71, 0x57, 0x44, 0x4e, 0x58, 0x72, 0x2b, 0x6e, + 0x75, 0x71, 0x46, 0x2b, 0x67, 0x54, 0x45, 0x6a, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x0a, 0x39, 0x77, 0x30, 0x42, 0x41, + 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, 0x76, + 0x75, 0x52, 0x63, 0x59, 0x6b, 0x34, 0x6b, 0x39, 0x41, 0x77, 0x49, 0x2f, + 0x2f, 0x44, 0x54, 0x44, 0x47, 0x6a, 0x6b, 0x6b, 0x30, 0x6b, 0x69, 0x50, + 0x30, 0x51, 0x6e, 0x62, 0x37, 0x74, 0x74, 0x33, 0x6f, 0x4e, 0x6d, 0x7a, + 0x71, 0x6a, 0x4d, 0x44, 0x66, 0x7a, 0x31, 0x6d, 0x67, 0x62, 0x6c, 0x0a, + 0x64, 0x78, 0x53, 0x52, 0x36, 0x35, 0x31, 0x42, 0x65, 0x35, 0x6b, 0x71, + 0x68, 0x4f, 0x58, 0x2f, 0x2f, 0x43, 0x48, 0x42, 0x58, 0x66, 0x44, 0x6b, + 0x48, 0x31, 0x65, 0x33, 0x64, 0x61, 0x6d, 0x68, 0x58, 0x77, 0x49, 0x6d, + 0x2f, 0x39, 0x66, 0x48, 0x39, 0x30, 0x37, 0x65, 0x54, 0x2f, 0x6a, 0x33, + 0x48, 0x45, 0x62, 0x41, 0x65, 0x6b, 0x39, 0x41, 0x4c, 0x43, 0x49, 0x31, + 0x38, 0x42, 0x6d, 0x78, 0x0a, 0x30, 0x47, 0x74, 0x6e, 0x4c, 0x4c, 0x43, + 0x6f, 0x34, 0x4d, 0x42, 0x41, 0x4e, 0x7a, 0x58, 0x32, 0x68, 0x46, 0x78, + 0x63, 0x34, 0x36, 0x39, 0x43, 0x65, 0x50, 0x36, 0x6e, 0x79, 0x51, 0x31, + 0x51, 0x36, 0x67, 0x32, 0x45, 0x64, 0x76, 0x5a, 0x52, 0x37, 0x34, 0x4e, + 0x54, 0x78, 0x6e, 0x72, 0x2f, 0x44, 0x6c, 0x5a, 0x4a, 0x4c, 0x6f, 0x39, + 0x36, 0x31, 0x67, 0x7a, 0x6d, 0x4a, 0x31, 0x54, 0x6a, 0x0a, 0x54, 0x51, + 0x70, 0x67, 0x63, 0x6d, 0x4c, 0x4e, 0x6b, 0x51, 0x66, 0x57, 0x70, 0x62, + 0x2f, 0x49, 0x6d, 0x57, 0x76, 0x74, 0x78, 0x42, 0x6e, 0x6d, 0x71, 0x30, + 0x77, 0x52, 0x4f, 0x4d, 0x56, 0x76, 0x4d, 0x65, 0x4a, 0x75, 0x53, 0x63, + 0x67, 0x2f, 0x64, 0x6f, 0x41, 0x6d, 0x41, 0x79, 0x59, 0x70, 0x34, 0x44, + 0x62, 0x32, 0x39, 0x69, 0x42, 0x54, 0x34, 0x78, 0x64, 0x77, 0x4e, 0x42, + 0x65, 0x64, 0x0a, 0x59, 0x32, 0x67, 0x65, 0x61, 0x2b, 0x7a, 0x44, 0x54, + 0x59, 0x61, 0x34, 0x45, 0x7a, 0x41, 0x76, 0x58, 0x55, 0x59, 0x4e, 0x52, + 0x30, 0x50, 0x56, 0x47, 0x36, 0x70, 0x5a, 0x44, 0x72, 0x6c, 0x63, 0x6a, + 0x51, 0x5a, 0x49, 0x72, 0x58, 0x53, 0x48, 0x58, 0x38, 0x66, 0x38, 0x4d, + 0x56, 0x52, 0x42, 0x45, 0x2b, 0x4c, 0x48, 0x49, 0x51, 0x36, 0x65, 0x34, + 0x42, 0x34, 0x4e, 0x34, 0x63, 0x42, 0x37, 0x0a, 0x51, 0x34, 0x57, 0x51, + 0x78, 0x59, 0x70, 0x59, 0x78, 0x6d, 0x55, 0x4b, 0x65, 0x46, 0x66, 0x79, + 0x78, 0x69, 0x4d, 0x50, 0x41, 0x64, 0x6b, 0x67, 0x53, 0x39, 0x34, 0x50, + 0x2b, 0x35, 0x4b, 0x46, 0x64, 0x53, 0x70, 0x63, 0x63, 0x34, 0x31, 0x74, + 0x65, 0x79, 0x57, 0x52, 0x79, 0x75, 0x35, 0x46, 0x72, 0x67, 0x5a, 0x4c, + 0x41, 0x4d, 0x7a, 0x54, 0x73, 0x56, 0x6c, 0x51, 0x32, 0x6a, 0x71, 0x49, + 0x0a, 0x4f, 0x79, 0x6c, 0x44, 0x52, 0x6c, 0x36, 0x58, 0x4b, 0x31, 0x54, + 0x4f, 0x55, 0x32, 0x2b, 0x4e, 0x53, 0x75, 0x65, 0x57, 0x2b, 0x72, 0x39, + 0x78, 0x44, 0x6b, 0x4b, 0x4c, 0x66, 0x50, 0x30, 0x6f, 0x6f, 0x4e, 0x42, + 0x49, 0x79, 0x74, 0x72, 0x45, 0x67, 0x55, 0x79, 0x37, 0x6f, 0x6e, 0x4f, + 0x54, 0x4a, 0x73, 0x6a, 0x72, 0x44, 0x4e, 0x59, 0x6d, 0x69, 0x4c, 0x62, + 0x41, 0x4a, 0x4d, 0x2b, 0x37, 0x0a, 0x76, 0x56, 0x76, 0x72, 0x64, 0x58, + 0x33, 0x70, 0x43, 0x49, 0x36, 0x47, 0x4d, 0x79, 0x78, 0x35, 0x64, 0x77, + 0x6c, 0x70, 0x70, 0x59, 0x6e, 0x38, 0x73, 0x33, 0x43, 0x51, 0x68, 0x33, + 0x61, 0x50, 0x30, 0x79, 0x4b, 0x37, 0x51, 0x73, 0x36, 0x39, 0x63, 0x77, + 0x73, 0x67, 0x4a, 0x69, 0x72, 0x51, 0x6d, 0x7a, 0x31, 0x77, 0x48, 0x69, + 0x52, 0x73, 0x7a, 0x59, 0x64, 0x32, 0x71, 0x52, 0x65, 0x57, 0x0a, 0x74, + 0x38, 0x38, 0x4e, 0x6b, 0x76, 0x75, 0x4f, 0x47, 0x4b, 0x6d, 0x59, 0x53, + 0x64, 0x47, 0x65, 0x2f, 0x6d, 0x42, 0x45, 0x63, 0x69, 0x47, 0x35, 0x47, + 0x65, 0x33, 0x43, 0x39, 0x54, 0x48, 0x78, 0x4f, 0x55, 0x69, 0x49, 0x6b, + 0x43, 0x52, 0x31, 0x56, 0x42, 0x61, 0x74, 0x7a, 0x76, 0x54, 0x34, 0x61, + 0x52, 0x52, 0x6b, 0x4f, 0x66, 0x75, 0x6a, 0x75, 0x4c, 0x70, 0x77, 0x51, + 0x4d, 0x63, 0x6e, 0x0a, 0x48, 0x4c, 0x2f, 0x45, 0x56, 0x6c, 0x50, 0x36, + 0x59, 0x32, 0x58, 0x51, 0x38, 0x78, 0x77, 0x4f, 0x46, 0x76, 0x56, 0x72, + 0x68, 0x6c, 0x68, 0x4e, 0x47, 0x4e, 0x54, 0x6b, 0x44, 0x59, 0x36, 0x6c, + 0x6e, 0x56, 0x75, 0x52, 0x33, 0x48, 0x59, 0x6b, 0x55, 0x44, 0x2f, 0x47, + 0x4b, 0x76, 0x76, 0x5a, 0x74, 0x35, 0x79, 0x31, 0x31, 0x75, 0x62, 0x51, + 0x32, 0x65, 0x67, 0x5a, 0x69, 0x78, 0x56, 0x78, 0x0a, 0x53, 0x4b, 0x32, + 0x33, 0x36, 0x74, 0x68, 0x5a, 0x69, 0x4e, 0x53, 0x51, 0x76, 0x78, 0x61, + 0x7a, 0x32, 0x65, 0x6d, 0x73, 0x57, 0x57, 0x46, 0x55, 0x79, 0x42, 0x79, + 0x36, 0x79, 0x73, 0x48, 0x4b, 0x34, 0x62, 0x6b, 0x67, 0x54, 0x49, 0x38, + 0x36, 0x6b, 0x34, 0x6d, 0x6c, 0x6f, 0x4d, 0x79, 0x2f, 0x30, 0x2f, 0x5a, + 0x31, 0x70, 0x48, 0x57, 0x57, 0x62, 0x56, 0x59, 0x3d, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x45, 0x2d, 0x54, 0x75, 0x67, 0x72, 0x61, 0x20, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, + 0x45, 0x2d, 0x54, 0x75, 0xc4, 0x9f, 0x72, 0x61, 0x20, 0x45, 0x42, 0x47, + 0x20, 0x42, 0x69, 0x6c, 0x69, 0xc5, 0x9f, 0x69, 0x6d, 0x20, 0x54, 0x65, + 0x6b, 0x6e, 0x6f, 0x6c, 0x6f, 0x6a, 0x69, 0x6c, 0x65, 0x72, 0x69, 0x20, + 0x76, 0x65, 0x20, 0x48, 0x69, 0x7a, 0x6d, 0x65, 0x74, 0x6c, 0x65, 0x72, + 0x69, 0x20, 0x41, 0x2e, 0xc5, 0x9e, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x45, + 0x2d, 0x54, 0x75, 0x67, 0x72, 0x61, 0x20, 0x53, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x6b, 0x61, 0x73, 0x79, 0x6f, 0x6e, 0x20, 0x4d, 0x65, 0x72, + 0x6b, 0x65, 0x7a, 0x69, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45, 0x2d, 0x54, 0x75, 0x67, + 0x72, 0x61, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x45, 0x2d, 0x54, 0x75, 0xc4, 0x9f, 0x72, + 0x61, 0x20, 0x45, 0x42, 0x47, 0x20, 0x42, 0x69, 0x6c, 0x69, 0xc5, 0x9f, + 0x69, 0x6d, 0x20, 0x54, 0x65, 0x6b, 0x6e, 0x6f, 0x6c, 0x6f, 0x6a, 0x69, + 0x6c, 0x65, 0x72, 0x69, 0x20, 0x76, 0x65, 0x20, 0x48, 0x69, 0x7a, 0x6d, + 0x65, 0x74, 0x6c, 0x65, 0x72, 0x69, 0x20, 0x41, 0x2e, 0xc5, 0x9e, 0x2e, + 0x20, 0x4f, 0x55, 0x3d, 0x45, 0x2d, 0x54, 0x75, 0x67, 0x72, 0x61, 0x20, + 0x53, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x6b, 0x61, 0x73, 0x79, 0x6f, + 0x6e, 0x20, 0x4d, 0x65, 0x72, 0x6b, 0x65, 0x7a, 0x69, 0x0a, 0x23, 0x20, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x45, 0x2d, 0x54, 0x75, + 0x67, 0x72, 0x61, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x37, 0x36, 0x36, 0x37, 0x34, 0x34, 0x37, 0x32, 0x30, + 0x36, 0x37, 0x30, 0x33, 0x32, 0x35, 0x34, 0x33, 0x35, 0x35, 0x0a, 0x23, + 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x38, 0x3a, 0x61, 0x31, 0x3a, + 0x30, 0x33, 0x3a, 0x36, 0x33, 0x3a, 0x62, 0x30, 0x3a, 0x62, 0x64, 0x3a, + 0x32, 0x31, 0x3a, 0x37, 0x31, 0x3a, 0x37, 0x30, 0x3a, 0x38, 0x61, 0x3a, + 0x36, 0x66, 0x3a, 0x31, 0x33, 0x3a, 0x33, 0x61, 0x3a, 0x62, 0x62, 0x3a, + 0x37, 0x39, 0x3a, 0x34, 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x35, 0x31, 0x3a, 0x63, 0x36, 0x3a, 0x65, 0x37, 0x3a, 0x30, + 0x38, 0x3a, 0x34, 0x39, 0x3a, 0x30, 0x36, 0x3a, 0x36, 0x65, 0x3a, 0x66, + 0x33, 0x3a, 0x39, 0x32, 0x3a, 0x64, 0x34, 0x3a, 0x35, 0x63, 0x3a, 0x61, + 0x30, 0x3a, 0x30, 0x64, 0x3a, 0x36, 0x64, 0x3a, 0x61, 0x33, 0x3a, 0x36, + 0x32, 0x3a, 0x38, 0x66, 0x3a, 0x63, 0x33, 0x3a, 0x35, 0x32, 0x3a, 0x33, + 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x62, 0x30, 0x3a, 0x62, 0x66, 0x3a, 0x64, 0x35, 0x3a, 0x32, 0x62, 0x3a, + 0x62, 0x30, 0x3a, 0x64, 0x37, 0x3a, 0x64, 0x39, 0x3a, 0x62, 0x64, 0x3a, + 0x39, 0x32, 0x3a, 0x62, 0x66, 0x3a, 0x35, 0x64, 0x3a, 0x34, 0x64, 0x3a, + 0x63, 0x31, 0x3a, 0x33, 0x64, 0x3a, 0x61, 0x32, 0x3a, 0x35, 0x35, 0x3a, + 0x63, 0x30, 0x3a, 0x32, 0x63, 0x3a, 0x35, 0x34, 0x3a, 0x32, 0x66, 0x3a, + 0x33, 0x37, 0x3a, 0x38, 0x33, 0x3a, 0x36, 0x35, 0x3a, 0x65, 0x61, 0x3a, + 0x38, 0x39, 0x3a, 0x33, 0x39, 0x3a, 0x31, 0x31, 0x3a, 0x66, 0x35, 0x3a, + 0x35, 0x65, 0x3a, 0x35, 0x35, 0x3a, 0x66, 0x32, 0x3a, 0x33, 0x63, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x47, 0x53, 0x7a, 0x43, 0x43, + 0x42, 0x44, 0x4f, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x49, + 0x61, 0x6d, 0x67, 0x2b, 0x6e, 0x46, 0x47, 0x62, 0x79, 0x31, 0x4d, 0x77, + 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, + 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x77, 0x67, 0x62, 0x49, 0x78, + 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x59, + 0x54, 0x41, 0x6c, 0x52, 0x53, 0x4d, 0x51, 0x38, 0x77, 0x44, 0x51, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x5a, 0x42, 0x62, 0x6d, 0x74, + 0x68, 0x63, 0x6d, 0x45, 0x78, 0x51, 0x44, 0x41, 0x2b, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x4e, 0x30, 0x55, 0x74, 0x56, 0x48, 0x58, + 0x45, 0x6e, 0x33, 0x4a, 0x68, 0x49, 0x45, 0x56, 0x43, 0x52, 0x79, 0x42, + 0x43, 0x0a, 0x61, 0x57, 0x78, 0x70, 0x78, 0x5a, 0x39, 0x70, 0x62, 0x53, + 0x42, 0x55, 0x5a, 0x57, 0x74, 0x75, 0x62, 0x32, 0x78, 0x76, 0x61, 0x6d, + 0x6c, 0x73, 0x5a, 0x58, 0x4a, 0x70, 0x49, 0x48, 0x5a, 0x6c, 0x49, 0x45, + 0x68, 0x70, 0x65, 0x6d, 0x31, 0x6c, 0x64, 0x47, 0x78, 0x6c, 0x63, 0x6d, + 0x6b, 0x67, 0x51, 0x53, 0x37, 0x46, 0x6e, 0x69, 0x34, 0x78, 0x4a, 0x6a, + 0x41, 0x6b, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x73, 0x4d, 0x48, + 0x55, 0x55, 0x74, 0x56, 0x48, 0x56, 0x6e, 0x63, 0x6d, 0x45, 0x67, 0x55, + 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x74, 0x68, 0x63, + 0x33, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x4e, 0x5a, 0x58, 0x4a, 0x72, 0x5a, + 0x58, 0x70, 0x70, 0x4d, 0x53, 0x67, 0x77, 0x4a, 0x67, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x44, 0x44, 0x42, 0x39, 0x46, 0x4c, 0x56, 0x52, 0x31, 0x0a, + 0x5a, 0x33, 0x4a, 0x68, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, + 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, + 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, + 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x7a, 0x4d, 0x44, 0x4d, 0x77, + 0x4e, 0x54, 0x45, 0x79, 0x4d, 0x44, 0x6b, 0x30, 0x4f, 0x46, 0x6f, 0x58, + 0x44, 0x54, 0x49, 0x7a, 0x0a, 0x4d, 0x44, 0x4d, 0x77, 0x4d, 0x7a, 0x45, + 0x79, 0x4d, 0x44, 0x6b, 0x30, 0x4f, 0x46, 0x6f, 0x77, 0x67, 0x62, 0x49, + 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, + 0x54, 0x41, 0x6c, 0x52, 0x53, 0x4d, 0x51, 0x38, 0x77, 0x44, 0x51, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x5a, 0x42, 0x62, 0x6d, 0x74, + 0x68, 0x63, 0x6d, 0x45, 0x78, 0x51, 0x44, 0x41, 0x2b, 0x0a, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x4e, 0x30, 0x55, 0x74, 0x56, 0x48, + 0x58, 0x45, 0x6e, 0x33, 0x4a, 0x68, 0x49, 0x45, 0x56, 0x43, 0x52, 0x79, + 0x42, 0x43, 0x61, 0x57, 0x78, 0x70, 0x78, 0x5a, 0x39, 0x70, 0x62, 0x53, + 0x42, 0x55, 0x5a, 0x57, 0x74, 0x75, 0x62, 0x32, 0x78, 0x76, 0x61, 0x6d, + 0x6c, 0x73, 0x5a, 0x58, 0x4a, 0x70, 0x49, 0x48, 0x5a, 0x6c, 0x49, 0x45, + 0x68, 0x70, 0x0a, 0x65, 0x6d, 0x31, 0x6c, 0x64, 0x47, 0x78, 0x6c, 0x63, + 0x6d, 0x6b, 0x67, 0x51, 0x53, 0x37, 0x46, 0x6e, 0x69, 0x34, 0x78, 0x4a, + 0x6a, 0x41, 0x6b, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x4d, 0x48, + 0x55, 0x55, 0x74, 0x56, 0x48, 0x56, 0x6e, 0x63, 0x6d, 0x45, 0x67, 0x55, + 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x74, 0x68, 0x63, + 0x33, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x4e, 0x0a, 0x5a, 0x58, 0x4a, 0x72, + 0x5a, 0x58, 0x70, 0x70, 0x4d, 0x53, 0x67, 0x77, 0x4a, 0x67, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, 0x39, 0x46, 0x4c, 0x56, 0x52, 0x31, + 0x5a, 0x33, 0x4a, 0x68, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, + 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, + 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, + 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, + 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, + 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x38, 0x41, 0x4d, 0x49, 0x49, + 0x43, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x67, 0x45, 0x41, 0x34, 0x76, 0x55, + 0x2f, 0x6b, 0x77, 0x56, 0x52, 0x48, 0x6f, 0x56, 0x69, 0x56, 0x46, 0x35, + 0x36, 0x43, 0x2f, 0x55, 0x59, 0x0a, 0x42, 0x34, 0x4f, 0x75, 0x66, 0x71, + 0x39, 0x38, 0x39, 0x39, 0x53, 0x4b, 0x61, 0x36, 0x56, 0x6a, 0x51, 0x7a, + 0x6d, 0x35, 0x53, 0x2f, 0x66, 0x44, 0x78, 0x6d, 0x53, 0x4a, 0x50, 0x5a, + 0x51, 0x75, 0x56, 0x49, 0x42, 0x53, 0x4f, 0x54, 0x6b, 0x48, 0x53, 0x30, + 0x76, 0x64, 0x68, 0x51, 0x64, 0x32, 0x68, 0x38, 0x79, 0x2f, 0x4c, 0x35, + 0x56, 0x4d, 0x7a, 0x48, 0x32, 0x6e, 0x50, 0x62, 0x78, 0x48, 0x0a, 0x44, + 0x35, 0x68, 0x77, 0x2b, 0x49, 0x79, 0x46, 0x48, 0x6e, 0x53, 0x4f, 0x6b, + 0x6d, 0x30, 0x62, 0x51, 0x4e, 0x47, 0x5a, 0x44, 0x62, 0x74, 0x31, 0x62, + 0x73, 0x69, 0x70, 0x61, 0x35, 0x72, 0x41, 0x68, 0x44, 0x47, 0x76, 0x79, + 0x6b, 0x50, 0x4c, 0x36, 0x79, 0x73, 0x30, 0x36, 0x49, 0x2b, 0x58, 0x61, + 0x77, 0x47, 0x62, 0x31, 0x51, 0x35, 0x4b, 0x43, 0x4b, 0x70, 0x62, 0x6b, + 0x6e, 0x53, 0x46, 0x0a, 0x51, 0x39, 0x4f, 0x41, 0x72, 0x71, 0x47, 0x49, + 0x57, 0x36, 0x36, 0x7a, 0x36, 0x6c, 0x37, 0x4c, 0x46, 0x70, 0x70, 0x33, + 0x52, 0x4d, 0x69, 0x68, 0x39, 0x6c, 0x52, 0x6f, 0x7a, 0x74, 0x36, 0x50, + 0x6c, 0x79, 0x75, 0x36, 0x57, 0x30, 0x41, 0x43, 0x44, 0x47, 0x51, 0x58, + 0x77, 0x4c, 0x57, 0x54, 0x7a, 0x65, 0x48, 0x78, 0x45, 0x32, 0x62, 0x4f, + 0x44, 0x48, 0x6e, 0x76, 0x30, 0x5a, 0x45, 0x6f, 0x0a, 0x71, 0x31, 0x2b, + 0x67, 0x45, 0x6c, 0x49, 0x77, 0x63, 0x78, 0x6d, 0x4f, 0x6a, 0x2b, 0x47, + 0x4d, 0x42, 0x36, 0x4c, 0x44, 0x75, 0x30, 0x72, 0x77, 0x36, 0x68, 0x38, + 0x56, 0x71, 0x4f, 0x34, 0x6c, 0x7a, 0x4b, 0x52, 0x47, 0x2b, 0x42, 0x73, + 0x69, 0x37, 0x37, 0x4d, 0x4f, 0x51, 0x37, 0x6f, 0x73, 0x4a, 0x4c, 0x6a, + 0x46, 0x4c, 0x46, 0x7a, 0x55, 0x48, 0x50, 0x68, 0x64, 0x5a, 0x4c, 0x33, + 0x44, 0x0a, 0x6b, 0x31, 0x34, 0x6f, 0x70, 0x7a, 0x38, 0x6e, 0x38, 0x59, + 0x34, 0x65, 0x30, 0x79, 0x70, 0x51, 0x42, 0x61, 0x4e, 0x56, 0x32, 0x63, + 0x76, 0x6e, 0x4f, 0x56, 0x50, 0x41, 0x6d, 0x4a, 0x36, 0x4d, 0x56, 0x47, + 0x4b, 0x4c, 0x4a, 0x72, 0x44, 0x33, 0x66, 0x59, 0x31, 0x38, 0x35, 0x4d, + 0x61, 0x65, 0x5a, 0x6b, 0x4a, 0x56, 0x67, 0x6b, 0x66, 0x6e, 0x73, 0x6c, + 0x69, 0x4e, 0x5a, 0x76, 0x63, 0x48, 0x0a, 0x66, 0x43, 0x34, 0x32, 0x35, + 0x6c, 0x41, 0x63, 0x50, 0x39, 0x74, 0x44, 0x4a, 0x4d, 0x57, 0x2f, 0x68, + 0x6b, 0x64, 0x35, 0x73, 0x33, 0x6b, 0x63, 0x39, 0x31, 0x72, 0x30, 0x45, + 0x2b, 0x78, 0x73, 0x2b, 0x44, 0x2f, 0x69, 0x57, 0x52, 0x2b, 0x56, 0x37, + 0x6b, 0x49, 0x2b, 0x75, 0x61, 0x32, 0x6f, 0x4d, 0x6f, 0x56, 0x4a, 0x6c, + 0x30, 0x62, 0x2b, 0x53, 0x7a, 0x47, 0x50, 0x57, 0x73, 0x75, 0x74, 0x0a, + 0x64, 0x45, 0x63, 0x66, 0x36, 0x5a, 0x47, 0x33, 0x33, 0x79, 0x67, 0x45, + 0x49, 0x71, 0x44, 0x55, 0x44, 0x31, 0x33, 0x69, 0x65, 0x55, 0x2f, 0x71, + 0x62, 0x49, 0x57, 0x47, 0x76, 0x61, 0x69, 0x6d, 0x7a, 0x75, 0x54, 0x36, + 0x77, 0x2b, 0x47, 0x7a, 0x72, 0x74, 0x34, 0x38, 0x55, 0x65, 0x37, 0x4c, + 0x45, 0x33, 0x77, 0x42, 0x66, 0x34, 0x51, 0x4f, 0x58, 0x56, 0x47, 0x55, + 0x6e, 0x68, 0x4d, 0x4d, 0x0a, 0x74, 0x69, 0x36, 0x6c, 0x54, 0x50, 0x6b, + 0x35, 0x63, 0x44, 0x5a, 0x76, 0x6c, 0x73, 0x6f, 0x75, 0x44, 0x45, 0x52, + 0x56, 0x78, 0x63, 0x72, 0x36, 0x58, 0x51, 0x4b, 0x6a, 0x33, 0x39, 0x5a, + 0x6b, 0x6a, 0x46, 0x71, 0x7a, 0x41, 0x51, 0x71, 0x70, 0x74, 0x51, 0x70, + 0x48, 0x46, 0x2f, 0x2f, 0x76, 0x6b, 0x55, 0x41, 0x71, 0x6a, 0x71, 0x46, + 0x47, 0x4f, 0x6a, 0x47, 0x59, 0x35, 0x52, 0x48, 0x38, 0x0a, 0x7a, 0x4c, + 0x74, 0x4a, 0x56, 0x6f, 0x72, 0x38, 0x75, 0x64, 0x42, 0x68, 0x6d, 0x6d, + 0x39, 0x6c, 0x62, 0x4f, 0x62, 0x44, 0x79, 0x7a, 0x35, 0x31, 0x53, 0x66, + 0x36, 0x50, 0x70, 0x2b, 0x4b, 0x4a, 0x78, 0x57, 0x66, 0x58, 0x6e, 0x55, + 0x59, 0x54, 0x54, 0x6a, 0x46, 0x32, 0x4f, 0x79, 0x53, 0x7a, 0x6e, 0x68, + 0x46, 0x6c, 0x68, 0x71, 0x74, 0x2f, 0x37, 0x78, 0x33, 0x55, 0x2b, 0x4c, + 0x7a, 0x6e, 0x0a, 0x72, 0x46, 0x70, 0x63, 0x74, 0x31, 0x70, 0x48, 0x58, + 0x46, 0x58, 0x4f, 0x56, 0x62, 0x51, 0x69, 0x63, 0x56, 0x74, 0x62, 0x43, + 0x2f, 0x44, 0x50, 0x33, 0x4b, 0x42, 0x68, 0x5a, 0x4f, 0x71, 0x70, 0x31, + 0x32, 0x67, 0x4b, 0x59, 0x36, 0x66, 0x67, 0x44, 0x54, 0x2b, 0x67, 0x72, + 0x39, 0x4f, 0x71, 0x30, 0x6e, 0x37, 0x76, 0x55, 0x61, 0x44, 0x6d, 0x55, + 0x53, 0x74, 0x56, 0x6b, 0x68, 0x55, 0x58, 0x0a, 0x55, 0x38, 0x75, 0x33, + 0x5a, 0x67, 0x35, 0x6d, 0x54, 0x50, 0x6a, 0x35, 0x64, 0x55, 0x79, 0x51, + 0x35, 0x78, 0x4a, 0x77, 0x78, 0x30, 0x55, 0x43, 0x41, 0x77, 0x45, 0x41, + 0x41, 0x61, 0x4e, 0x6a, 0x4d, 0x47, 0x45, 0x77, 0x48, 0x51, 0x59, 0x44, + 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x43, 0x37, 0x6a, + 0x32, 0x37, 0x4a, 0x4a, 0x30, 0x4a, 0x78, 0x55, 0x65, 0x56, 0x7a, 0x36, + 0x0a, 0x4a, 0x79, 0x72, 0x2b, 0x7a, 0x45, 0x37, 0x53, 0x36, 0x45, 0x35, + 0x55, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, + 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, + 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, + 0x77, 0x46, 0x6f, 0x41, 0x55, 0x4c, 0x75, 0x50, 0x62, 0x73, 0x6b, 0x6e, + 0x51, 0x6e, 0x46, 0x52, 0x35, 0x0a, 0x58, 0x50, 0x6f, 0x6e, 0x4b, 0x76, + 0x37, 0x4d, 0x54, 0x74, 0x4c, 0x6f, 0x54, 0x6c, 0x51, 0x77, 0x44, 0x67, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, + 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, + 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, + 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x41, 0x51, 0x41, 0x46, 0x0a, 0x4e, + 0x7a, 0x72, 0x30, 0x54, 0x62, 0x64, 0x46, 0x34, 0x6b, 0x56, 0x31, 0x4a, + 0x49, 0x2b, 0x32, 0x64, 0x31, 0x4c, 0x6f, 0x48, 0x4e, 0x67, 0x51, 0x6b, + 0x32, 0x58, 0x7a, 0x38, 0x6c, 0x6b, 0x47, 0x70, 0x44, 0x34, 0x65, 0x4b, + 0x65, 0x78, 0x64, 0x30, 0x64, 0x43, 0x72, 0x66, 0x4f, 0x41, 0x4b, 0x6b, + 0x45, 0x68, 0x34, 0x37, 0x55, 0x36, 0x59, 0x41, 0x35, 0x6e, 0x2b, 0x4b, + 0x47, 0x43, 0x52, 0x0a, 0x48, 0x54, 0x41, 0x64, 0x75, 0x47, 0x4e, 0x38, + 0x71, 0x4f, 0x59, 0x31, 0x74, 0x66, 0x72, 0x54, 0x59, 0x58, 0x62, 0x6d, + 0x31, 0x67, 0x64, 0x4c, 0x79, 0x6d, 0x6d, 0x61, 0x73, 0x6f, 0x52, 0x36, + 0x64, 0x35, 0x4e, 0x46, 0x46, 0x78, 0x57, 0x66, 0x4a, 0x4e, 0x43, 0x59, + 0x45, 0x78, 0x4c, 0x2f, 0x75, 0x36, 0x41, 0x75, 0x2f, 0x55, 0x35, 0x4d, + 0x68, 0x2f, 0x6a, 0x4f, 0x58, 0x4b, 0x71, 0x59, 0x0a, 0x47, 0x77, 0x58, + 0x67, 0x41, 0x45, 0x5a, 0x4b, 0x67, 0x6f, 0x43, 0x6c, 0x4d, 0x34, 0x73, + 0x6f, 0x33, 0x4f, 0x30, 0x34, 0x30, 0x39, 0x2f, 0x6c, 0x50, 0x75, 0x6e, + 0x2b, 0x2b, 0x31, 0x6e, 0x64, 0x59, 0x59, 0x52, 0x50, 0x30, 0x6c, 0x53, + 0x57, 0x45, 0x32, 0x45, 0x54, 0x50, 0x6f, 0x2b, 0x41, 0x61, 0x62, 0x36, + 0x54, 0x52, 0x37, 0x55, 0x31, 0x51, 0x39, 0x4a, 0x61, 0x75, 0x7a, 0x31, + 0x63, 0x0a, 0x37, 0x37, 0x4e, 0x43, 0x52, 0x38, 0x30, 0x37, 0x56, 0x52, + 0x4d, 0x47, 0x73, 0x41, 0x6e, 0x62, 0x2f, 0x57, 0x50, 0x32, 0x4f, 0x6f, + 0x67, 0x4b, 0x6d, 0x57, 0x39, 0x2b, 0x34, 0x63, 0x34, 0x62, 0x55, 0x32, + 0x70, 0x45, 0x5a, 0x69, 0x4e, 0x52, 0x43, 0x48, 0x75, 0x38, 0x57, 0x31, + 0x4b, 0x69, 0x2f, 0x51, 0x59, 0x33, 0x4f, 0x45, 0x42, 0x68, 0x6a, 0x30, + 0x71, 0x57, 0x75, 0x4a, 0x41, 0x33, 0x0a, 0x2b, 0x47, 0x62, 0x48, 0x65, + 0x4a, 0x41, 0x41, 0x46, 0x53, 0x36, 0x4c, 0x72, 0x56, 0x45, 0x31, 0x55, + 0x77, 0x65, 0x6f, 0x61, 0x32, 0x69, 0x75, 0x2b, 0x55, 0x34, 0x38, 0x42, + 0x79, 0x62, 0x4e, 0x43, 0x41, 0x56, 0x77, 0x7a, 0x44, 0x6b, 0x2f, 0x64, + 0x72, 0x32, 0x6c, 0x30, 0x32, 0x63, 0x6d, 0x41, 0x59, 0x61, 0x6d, 0x55, + 0x39, 0x4a, 0x67, 0x4f, 0x33, 0x78, 0x44, 0x66, 0x31, 0x57, 0x4b, 0x0a, + 0x76, 0x4a, 0x55, 0x61, 0x77, 0x53, 0x67, 0x35, 0x54, 0x42, 0x39, 0x44, + 0x30, 0x70, 0x48, 0x30, 0x63, 0x6c, 0x6d, 0x4b, 0x75, 0x56, 0x62, 0x38, + 0x50, 0x37, 0x53, 0x64, 0x32, 0x6e, 0x43, 0x63, 0x64, 0x6c, 0x71, 0x4d, + 0x51, 0x31, 0x44, 0x75, 0x6a, 0x6a, 0x42, 0x79, 0x54, 0x64, 0x2f, 0x2f, + 0x53, 0x66, 0x66, 0x47, 0x71, 0x57, 0x66, 0x5a, 0x62, 0x61, 0x77, 0x43, + 0x45, 0x65, 0x49, 0x36, 0x0a, 0x46, 0x69, 0x57, 0x6e, 0x57, 0x41, 0x6a, + 0x4c, 0x62, 0x31, 0x4e, 0x42, 0x6e, 0x45, 0x67, 0x34, 0x52, 0x32, 0x67, + 0x7a, 0x30, 0x64, 0x66, 0x48, 0x6a, 0x39, 0x52, 0x30, 0x49, 0x64, 0x54, + 0x44, 0x42, 0x5a, 0x42, 0x36, 0x2f, 0x38, 0x36, 0x57, 0x69, 0x4c, 0x45, + 0x56, 0x4b, 0x56, 0x30, 0x6a, 0x71, 0x39, 0x42, 0x67, 0x6f, 0x52, 0x4a, + 0x50, 0x33, 0x76, 0x51, 0x58, 0x7a, 0x54, 0x4c, 0x6c, 0x0a, 0x79, 0x62, + 0x2f, 0x49, 0x51, 0x36, 0x33, 0x39, 0x4c, 0x6f, 0x37, 0x78, 0x72, 0x2b, + 0x4c, 0x30, 0x6d, 0x50, 0x6f, 0x53, 0x48, 0x79, 0x44, 0x59, 0x77, 0x4b, + 0x63, 0x4d, 0x68, 0x63, 0x57, 0x51, 0x39, 0x44, 0x73, 0x74, 0x6c, 0x69, + 0x61, 0x78, 0x4c, 0x4c, 0x35, 0x4d, 0x71, 0x2b, 0x75, 0x78, 0x30, 0x6f, + 0x72, 0x4a, 0x32, 0x33, 0x67, 0x54, 0x44, 0x78, 0x34, 0x4a, 0x6e, 0x57, + 0x32, 0x50, 0x0a, 0x41, 0x4a, 0x38, 0x43, 0x32, 0x73, 0x48, 0x36, 0x48, + 0x33, 0x70, 0x36, 0x43, 0x63, 0x52, 0x4b, 0x35, 0x6f, 0x67, 0x71, 0x6c, + 0x35, 0x2b, 0x4a, 0x69, 0x2f, 0x30, 0x33, 0x58, 0x31, 0x38, 0x36, 0x7a, + 0x6a, 0x68, 0x5a, 0x68, 0x6b, 0x75, 0x76, 0x63, 0x51, 0x75, 0x30, 0x32, + 0x50, 0x4a, 0x77, 0x54, 0x35, 0x38, 0x79, 0x45, 0x2b, 0x4f, 0x77, 0x70, + 0x31, 0x66, 0x6c, 0x32, 0x74, 0x70, 0x44, 0x0a, 0x79, 0x34, 0x51, 0x30, + 0x38, 0x69, 0x6a, 0x45, 0x36, 0x6d, 0x33, 0x30, 0x4b, 0x75, 0x2f, 0x42, + 0x61, 0x33, 0x62, 0x61, 0x2b, 0x33, 0x36, 0x37, 0x68, 0x54, 0x7a, 0x53, + 0x55, 0x38, 0x4a, 0x4e, 0x76, 0x6e, 0x48, 0x68, 0x52, 0x64, 0x48, 0x39, + 0x49, 0x32, 0x63, 0x4e, 0x45, 0x33, 0x58, 0x37, 0x7a, 0x32, 0x56, 0x6e, + 0x49, 0x70, 0x32, 0x75, 0x73, 0x41, 0x6e, 0x52, 0x43, 0x66, 0x38, 0x64, + 0x0a, 0x4e, 0x4c, 0x2f, 0x2b, 0x49, 0x35, 0x63, 0x33, 0x30, 0x6a, 0x6e, + 0x36, 0x50, 0x51, 0x30, 0x47, 0x43, 0x37, 0x54, 0x62, 0x4f, 0x36, 0x4f, + 0x72, 0x62, 0x31, 0x77, 0x64, 0x74, 0x6e, 0x37, 0x6f, 0x73, 0x34, 0x49, + 0x30, 0x37, 0x51, 0x5a, 0x63, 0x4a, 0x41, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x54, 0x2d, 0x54, 0x65, 0x6c, 0x65, 0x53, 0x65, 0x63, 0x20, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x4f, 0x3d, 0x54, 0x2d, 0x53, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x45, 0x6e, 0x74, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x20, 0x4f, 0x55, 0x3d, 0x54, + 0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x0a, 0x23, 0x20, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x54, 0x2d, 0x54, 0x65, 0x6c, 0x65, 0x53, 0x65, 0x63, 0x20, 0x47, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x6c, 0x61, + 0x73, 0x73, 0x20, 0x32, 0x20, 0x4f, 0x3d, 0x54, 0x2d, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x73, 0x20, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x73, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x20, 0x47, 0x6d, 0x62, 0x48, 0x20, 0x4f, 0x55, 0x3d, 0x54, 0x2d, 0x53, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x54, 0x2d, 0x54, 0x65, 0x6c, 0x65, + 0x53, 0x65, 0x63, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x0a, + 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x62, 0x3a, 0x39, 0x62, + 0x3a, 0x39, 0x65, 0x3a, 0x65, 0x34, 0x3a, 0x37, 0x62, 0x3a, 0x36, 0x63, + 0x3a, 0x31, 0x66, 0x3a, 0x30, 0x30, 0x3a, 0x37, 0x32, 0x3a, 0x31, 0x61, + 0x3a, 0x63, 0x63, 0x3a, 0x63, 0x31, 0x3a, 0x37, 0x37, 0x3a, 0x37, 0x39, + 0x3a, 0x64, 0x66, 0x3a, 0x36, 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x35, 0x39, 0x3a, 0x30, 0x64, 0x3a, 0x32, 0x64, 0x3a, + 0x37, 0x64, 0x3a, 0x38, 0x38, 0x3a, 0x34, 0x66, 0x3a, 0x34, 0x30, 0x3a, + 0x32, 0x65, 0x3a, 0x36, 0x31, 0x3a, 0x37, 0x65, 0x3a, 0x61, 0x35, 0x3a, + 0x36, 0x32, 0x3a, 0x33, 0x32, 0x3a, 0x31, 0x37, 0x3a, 0x36, 0x35, 0x3a, + 0x63, 0x66, 0x3a, 0x31, 0x37, 0x3a, 0x64, 0x38, 0x3a, 0x39, 0x34, 0x3a, + 0x65, 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x39, 0x31, 0x3a, 0x65, 0x32, 0x3a, 0x66, 0x35, 0x3a, 0x37, 0x38, + 0x3a, 0x38, 0x64, 0x3a, 0x35, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x65, 0x62, + 0x3a, 0x61, 0x37, 0x3a, 0x62, 0x61, 0x3a, 0x35, 0x38, 0x3a, 0x37, 0x33, + 0x3a, 0x37, 0x64, 0x3a, 0x65, 0x31, 0x3a, 0x35, 0x34, 0x3a, 0x38, 0x61, + 0x3a, 0x38, 0x65, 0x3a, 0x63, 0x61, 0x3a, 0x63, 0x64, 0x3a, 0x30, 0x31, + 0x3a, 0x34, 0x35, 0x3a, 0x39, 0x38, 0x3a, 0x62, 0x63, 0x3a, 0x30, 0x62, + 0x3a, 0x31, 0x34, 0x3a, 0x33, 0x65, 0x3a, 0x30, 0x34, 0x3a, 0x31, 0x62, + 0x3a, 0x31, 0x37, 0x3a, 0x30, 0x35, 0x3a, 0x32, 0x35, 0x3a, 0x35, 0x32, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x77, 0x7a, 0x43, + 0x43, 0x41, 0x71, 0x75, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x43, + 0x42, 0x67, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x45, 0x55, 0x78, 0x0a, 0x4b, 0x7a, + 0x41, 0x70, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x49, 0x6c, + 0x51, 0x74, 0x55, 0x33, 0x6c, 0x7a, 0x64, 0x47, 0x56, 0x74, 0x63, 0x79, + 0x42, 0x46, 0x62, 0x6e, 0x52, 0x6c, 0x63, 0x6e, 0x42, 0x79, 0x61, 0x58, + 0x4e, 0x6c, 0x49, 0x46, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, + 0x56, 0x7a, 0x49, 0x45, 0x64, 0x74, 0x59, 0x6b, 0x67, 0x78, 0x48, 0x7a, + 0x41, 0x64, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x4d, 0x46, + 0x6c, 0x51, 0x74, 0x55, 0x33, 0x6c, 0x7a, 0x64, 0x47, 0x56, 0x74, 0x63, + 0x79, 0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x44, 0x5a, + 0x57, 0x35, 0x30, 0x5a, 0x58, 0x49, 0x78, 0x4a, 0x54, 0x41, 0x6a, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x48, 0x46, 0x51, 0x74, 0x56, + 0x47, 0x56, 0x73, 0x5a, 0x56, 0x4e, 0x6c, 0x0a, 0x59, 0x79, 0x42, 0x48, + 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x78, 0x53, 0x62, 0x32, 0x39, 0x30, + 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4e, 0x7a, 0x49, 0x44, 0x49, 0x77, + 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, 0x67, 0x78, 0x4d, 0x44, 0x41, 0x78, + 0x4d, 0x54, 0x41, 0x30, 0x4d, 0x44, 0x45, 0x30, 0x57, 0x68, 0x63, 0x4e, + 0x4d, 0x7a, 0x4d, 0x78, 0x4d, 0x44, 0x41, 0x78, 0x4d, 0x6a, 0x4d, 0x31, + 0x0a, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, 0x43, 0x42, 0x67, 0x6a, 0x45, + 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x52, 0x45, 0x55, 0x78, 0x4b, 0x7a, 0x41, 0x70, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x49, 0x6c, 0x51, 0x74, 0x55, 0x33, 0x6c, + 0x7a, 0x64, 0x47, 0x56, 0x74, 0x63, 0x79, 0x42, 0x46, 0x62, 0x6e, 0x52, + 0x6c, 0x63, 0x6e, 0x42, 0x79, 0x0a, 0x61, 0x58, 0x4e, 0x6c, 0x49, 0x46, + 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, 0x7a, 0x49, 0x45, + 0x64, 0x74, 0x59, 0x6b, 0x67, 0x78, 0x48, 0x7a, 0x41, 0x64, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x73, 0x4d, 0x46, 0x6c, 0x51, 0x74, 0x55, 0x33, + 0x6c, 0x7a, 0x64, 0x47, 0x56, 0x74, 0x63, 0x79, 0x42, 0x55, 0x63, 0x6e, + 0x56, 0x7a, 0x64, 0x43, 0x42, 0x44, 0x5a, 0x57, 0x35, 0x30, 0x0a, 0x5a, + 0x58, 0x49, 0x78, 0x4a, 0x54, 0x41, 0x6a, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x4d, 0x4d, 0x48, 0x46, 0x51, 0x74, 0x56, 0x47, 0x56, 0x73, 0x5a, + 0x56, 0x4e, 0x6c, 0x59, 0x79, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, + 0x57, 0x78, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x73, 0x59, + 0x58, 0x4e, 0x7a, 0x49, 0x44, 0x49, 0x77, 0x67, 0x67, 0x45, 0x69, 0x4d, + 0x41, 0x30, 0x47, 0x0a, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, + 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x42, + 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, 0x49, 0x42, + 0x41, 0x51, 0x43, 0x71, 0x58, 0x39, 0x6f, 0x62, 0x58, 0x2b, 0x68, 0x7a, + 0x6b, 0x65, 0x58, 0x61, 0x58, 0x50, 0x53, 0x69, 0x35, 0x6b, 0x66, 0x6c, + 0x38, 0x32, 0x68, 0x56, 0x59, 0x41, 0x55, 0x64, 0x0a, 0x41, 0x71, 0x53, + 0x7a, 0x6d, 0x31, 0x6e, 0x7a, 0x48, 0x6f, 0x71, 0x76, 0x4e, 0x4b, 0x33, + 0x38, 0x44, 0x63, 0x4c, 0x5a, 0x53, 0x42, 0x6e, 0x75, 0x61, 0x59, 0x2f, + 0x4a, 0x49, 0x50, 0x77, 0x68, 0x71, 0x67, 0x63, 0x5a, 0x37, 0x62, 0x42, + 0x63, 0x72, 0x47, 0x58, 0x48, 0x58, 0x2b, 0x30, 0x43, 0x66, 0x48, 0x74, + 0x38, 0x4c, 0x52, 0x76, 0x57, 0x75, 0x72, 0x6d, 0x41, 0x77, 0x68, 0x69, + 0x43, 0x0a, 0x46, 0x6f, 0x54, 0x36, 0x5a, 0x72, 0x41, 0x49, 0x78, 0x6c, + 0x51, 0x6a, 0x67, 0x65, 0x54, 0x4e, 0x75, 0x55, 0x6b, 0x2f, 0x39, 0x6b, + 0x39, 0x75, 0x4e, 0x30, 0x67, 0x6f, 0x4f, 0x41, 0x2f, 0x46, 0x76, 0x75, + 0x64, 0x6f, 0x63, 0x50, 0x30, 0x35, 0x6c, 0x30, 0x33, 0x53, 0x78, 0x35, + 0x69, 0x52, 0x55, 0x4b, 0x72, 0x45, 0x52, 0x4c, 0x4d, 0x6a, 0x66, 0x54, + 0x6c, 0x48, 0x36, 0x56, 0x4a, 0x69, 0x0a, 0x31, 0x68, 0x4b, 0x54, 0x58, + 0x72, 0x63, 0x78, 0x6c, 0x6b, 0x49, 0x46, 0x2b, 0x33, 0x61, 0x6e, 0x48, + 0x71, 0x50, 0x31, 0x77, 0x76, 0x7a, 0x70, 0x65, 0x73, 0x56, 0x73, 0x71, + 0x58, 0x46, 0x50, 0x36, 0x73, 0x74, 0x34, 0x76, 0x47, 0x43, 0x76, 0x78, + 0x39, 0x37, 0x30, 0x32, 0x63, 0x75, 0x2b, 0x66, 0x6a, 0x4f, 0x6c, 0x62, + 0x70, 0x53, 0x44, 0x38, 0x44, 0x54, 0x36, 0x49, 0x61, 0x76, 0x71, 0x0a, + 0x6a, 0x6e, 0x4b, 0x67, 0x50, 0x36, 0x54, 0x65, 0x4d, 0x46, 0x76, 0x76, + 0x68, 0x6b, 0x31, 0x71, 0x6c, 0x56, 0x74, 0x44, 0x52, 0x4b, 0x67, 0x51, + 0x46, 0x52, 0x7a, 0x6c, 0x41, 0x56, 0x66, 0x46, 0x6d, 0x50, 0x48, 0x6d, + 0x42, 0x69, 0x69, 0x52, 0x71, 0x69, 0x44, 0x46, 0x74, 0x31, 0x4d, 0x6d, + 0x55, 0x55, 0x4f, 0x79, 0x43, 0x78, 0x47, 0x56, 0x57, 0x4f, 0x48, 0x41, + 0x44, 0x33, 0x62, 0x5a, 0x0a, 0x77, 0x49, 0x31, 0x38, 0x67, 0x66, 0x4e, + 0x79, 0x63, 0x4a, 0x35, 0x76, 0x2f, 0x68, 0x71, 0x4f, 0x32, 0x56, 0x38, + 0x31, 0x78, 0x72, 0x4a, 0x76, 0x4e, 0x48, 0x79, 0x2b, 0x53, 0x45, 0x2f, + 0x69, 0x57, 0x6a, 0x6e, 0x58, 0x32, 0x4a, 0x31, 0x34, 0x6e, 0x70, 0x2b, + 0x47, 0x50, 0x67, 0x4e, 0x65, 0x47, 0x59, 0x74, 0x45, 0x6f, 0x74, 0x58, + 0x48, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x0a, 0x51, 0x6a, + 0x42, 0x41, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, + 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, + 0x38, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, + 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, + 0x53, 0x2f, 0x0a, 0x57, 0x53, 0x41, 0x32, 0x41, 0x48, 0x6d, 0x67, 0x6f, + 0x43, 0x4a, 0x72, 0x6a, 0x4e, 0x58, 0x79, 0x59, 0x64, 0x4b, 0x34, 0x4c, + 0x4d, 0x75, 0x43, 0x53, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, + 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x4d, 0x51, 0x4f, 0x69, 0x59, + 0x51, 0x73, 0x66, 0x64, 0x4f, 0x68, 0x79, 0x0a, 0x4e, 0x73, 0x5a, 0x74, + 0x2b, 0x55, 0x32, 0x65, 0x2b, 0x69, 0x4b, 0x6f, 0x34, 0x59, 0x46, 0x57, + 0x7a, 0x38, 0x32, 0x37, 0x6e, 0x2b, 0x71, 0x72, 0x6b, 0x52, 0x6b, 0x34, + 0x72, 0x36, 0x70, 0x38, 0x46, 0x55, 0x33, 0x7a, 0x74, 0x71, 0x4f, 0x4e, + 0x70, 0x66, 0x53, 0x4f, 0x39, 0x6b, 0x53, 0x70, 0x70, 0x2b, 0x67, 0x68, + 0x6c, 0x61, 0x30, 0x2b, 0x41, 0x47, 0x49, 0x57, 0x69, 0x50, 0x41, 0x43, + 0x0a, 0x75, 0x76, 0x78, 0x68, 0x49, 0x2b, 0x59, 0x7a, 0x6d, 0x7a, 0x42, + 0x36, 0x61, 0x7a, 0x5a, 0x69, 0x65, 0x36, 0x30, 0x45, 0x49, 0x34, 0x52, + 0x59, 0x5a, 0x65, 0x4c, 0x62, 0x4b, 0x34, 0x72, 0x6e, 0x4a, 0x56, 0x4d, + 0x33, 0x59, 0x6c, 0x4e, 0x66, 0x76, 0x4e, 0x6f, 0x42, 0x59, 0x69, 0x6d, + 0x69, 0x70, 0x69, 0x64, 0x78, 0x35, 0x6a, 0x6f, 0x69, 0x66, 0x73, 0x46, + 0x76, 0x48, 0x5a, 0x56, 0x77, 0x0a, 0x49, 0x45, 0x6f, 0x48, 0x4e, 0x4e, + 0x2f, 0x71, 0x2f, 0x78, 0x57, 0x41, 0x35, 0x62, 0x72, 0x58, 0x65, 0x74, + 0x68, 0x62, 0x64, 0x58, 0x77, 0x46, 0x65, 0x69, 0x6c, 0x48, 0x66, 0x6b, + 0x43, 0x6f, 0x4d, 0x52, 0x4e, 0x33, 0x7a, 0x55, 0x41, 0x37, 0x74, 0x46, + 0x46, 0x48, 0x65, 0x69, 0x34, 0x52, 0x34, 0x30, 0x63, 0x52, 0x33, 0x70, + 0x31, 0x6d, 0x30, 0x49, 0x76, 0x56, 0x56, 0x47, 0x62, 0x36, 0x0a, 0x67, + 0x31, 0x58, 0x71, 0x66, 0x4d, 0x49, 0x70, 0x69, 0x52, 0x76, 0x70, 0x62, + 0x37, 0x50, 0x4f, 0x34, 0x67, 0x57, 0x45, 0x79, 0x53, 0x38, 0x2b, 0x65, + 0x49, 0x56, 0x69, 0x62, 0x73, 0x6c, 0x66, 0x77, 0x58, 0x68, 0x6a, 0x64, + 0x46, 0x6a, 0x41, 0x53, 0x42, 0x67, 0x4d, 0x6d, 0x54, 0x6e, 0x72, 0x70, + 0x4d, 0x77, 0x61, 0x74, 0x58, 0x6c, 0x61, 0x6a, 0x52, 0x57, 0x63, 0x32, + 0x42, 0x51, 0x4e, 0x0a, 0x39, 0x6e, 0x6f, 0x48, 0x56, 0x38, 0x63, 0x69, + 0x67, 0x77, 0x55, 0x74, 0x50, 0x4a, 0x73, 0x6c, 0x4a, 0x6a, 0x30, 0x59, + 0x73, 0x36, 0x6c, 0x44, 0x66, 0x4d, 0x6a, 0x49, 0x71, 0x32, 0x53, 0x50, + 0x44, 0x71, 0x4f, 0x2f, 0x6e, 0x42, 0x75, 0x64, 0x4d, 0x4e, 0x76, 0x61, + 0x30, 0x42, 0x6b, 0x75, 0x71, 0x6a, 0x7a, 0x78, 0x2b, 0x7a, 0x4f, 0x41, + 0x64, 0x75, 0x54, 0x4e, 0x72, 0x52, 0x6c, 0x50, 0x0a, 0x42, 0x53, 0x65, + 0x4f, 0x45, 0x36, 0x46, 0x75, 0x77, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x41, 0x74, 0x6f, 0x73, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x65, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x32, 0x30, 0x31, 0x31, 0x20, + 0x4f, 0x3d, 0x41, 0x74, 0x6f, 0x73, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x74, 0x6f, + 0x73, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x32, 0x30, 0x31, 0x31, 0x20, 0x4f, 0x3d, 0x41, 0x74, 0x6f, + 0x73, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x41, 0x74, 0x6f, 0x73, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x32, 0x30, 0x31, 0x31, 0x22, 0x0a, 0x23, + 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x36, 0x36, 0x34, + 0x33, 0x38, 0x37, 0x37, 0x34, 0x39, 0x37, 0x38, 0x31, 0x33, 0x33, 0x31, + 0x36, 0x34, 0x30, 0x32, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x61, 0x65, 0x3a, 0x62, 0x39, 0x3a, 0x63, 0x34, 0x3a, 0x33, 0x32, 0x3a, + 0x34, 0x62, 0x3a, 0x61, 0x63, 0x3a, 0x37, 0x66, 0x3a, 0x35, 0x64, 0x3a, + 0x36, 0x36, 0x3a, 0x63, 0x63, 0x3a, 0x37, 0x37, 0x3a, 0x39, 0x34, 0x3a, + 0x62, 0x62, 0x3a, 0x32, 0x61, 0x3a, 0x37, 0x37, 0x3a, 0x35, 0x36, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x62, 0x3a, 0x62, + 0x31, 0x3a, 0x66, 0x35, 0x3a, 0x33, 0x65, 0x3a, 0x35, 0x35, 0x3a, 0x30, + 0x63, 0x3a, 0x31, 0x64, 0x3a, 0x63, 0x35, 0x3a, 0x66, 0x31, 0x3a, 0x64, + 0x34, 0x3a, 0x65, 0x36, 0x3a, 0x62, 0x37, 0x3a, 0x36, 0x61, 0x3a, 0x34, + 0x36, 0x3a, 0x34, 0x62, 0x3a, 0x35, 0x35, 0x3a, 0x30, 0x36, 0x3a, 0x30, + 0x32, 0x3a, 0x61, 0x63, 0x3a, 0x32, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x66, 0x33, 0x3a, 0x35, 0x36, 0x3a, + 0x62, 0x65, 0x3a, 0x61, 0x32, 0x3a, 0x34, 0x34, 0x3a, 0x62, 0x37, 0x3a, + 0x61, 0x39, 0x3a, 0x31, 0x65, 0x3a, 0x62, 0x33, 0x3a, 0x35, 0x64, 0x3a, + 0x35, 0x33, 0x3a, 0x63, 0x61, 0x3a, 0x39, 0x61, 0x3a, 0x64, 0x37, 0x3a, + 0x38, 0x36, 0x3a, 0x34, 0x61, 0x3a, 0x63, 0x65, 0x3a, 0x30, 0x31, 0x3a, + 0x38, 0x65, 0x3a, 0x32, 0x64, 0x3a, 0x33, 0x35, 0x3a, 0x64, 0x35, 0x3a, + 0x66, 0x38, 0x3a, 0x66, 0x39, 0x3a, 0x36, 0x64, 0x3a, 0x64, 0x66, 0x3a, + 0x36, 0x38, 0x3a, 0x61, 0x36, 0x3a, 0x66, 0x34, 0x3a, 0x31, 0x61, 0x3a, + 0x61, 0x34, 0x3a, 0x37, 0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, + 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, + 0x49, 0x44, 0x64, 0x7a, 0x43, 0x43, 0x41, 0x6c, 0x2b, 0x67, 0x41, 0x77, + 0x49, 0x42, 0x41, 0x67, 0x49, 0x49, 0x58, 0x44, 0x50, 0x4c, 0x59, 0x69, + 0x78, 0x66, 0x73, 0x7a, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, + 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, + 0x41, 0x77, 0x50, 0x44, 0x45, 0x65, 0x4d, 0x42, 0x77, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x0a, 0x41, 0x77, 0x77, 0x56, 0x51, 0x58, 0x52, 0x76, 0x63, + 0x79, 0x42, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x6b, 0x55, + 0x6d, 0x39, 0x76, 0x64, 0x43, 0x41, 0x79, 0x4d, 0x44, 0x45, 0x78, 0x4d, + 0x51, 0x30, 0x77, 0x43, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, + 0x41, 0x52, 0x42, 0x64, 0x47, 0x39, 0x7a, 0x4d, 0x51, 0x73, 0x77, 0x43, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x0a, 0x45, 0x77, 0x4a, 0x45, + 0x52, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4d, 0x54, 0x41, 0x33, + 0x4d, 0x44, 0x63, 0x78, 0x4e, 0x44, 0x55, 0x34, 0x4d, 0x7a, 0x42, 0x61, + 0x46, 0x77, 0x30, 0x7a, 0x4d, 0x44, 0x45, 0x79, 0x4d, 0x7a, 0x45, 0x79, + 0x4d, 0x7a, 0x55, 0x35, 0x4e, 0x54, 0x6c, 0x61, 0x4d, 0x44, 0x77, 0x78, + 0x48, 0x6a, 0x41, 0x63, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, + 0x0a, 0x46, 0x55, 0x46, 0x30, 0x62, 0x33, 0x4d, 0x67, 0x56, 0x48, 0x4a, + 0x31, 0x63, 0x33, 0x52, 0x6c, 0x5a, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, + 0x67, 0x4d, 0x6a, 0x41, 0x78, 0x4d, 0x54, 0x45, 0x4e, 0x4d, 0x41, 0x73, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x45, 0x51, 0x58, 0x52, + 0x76, 0x63, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x42, 0x68, 0x4d, 0x43, 0x0a, 0x52, 0x45, 0x55, 0x77, 0x67, 0x67, + 0x45, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, + 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, + 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, + 0x49, 0x42, 0x41, 0x51, 0x43, 0x56, 0x68, 0x54, 0x75, 0x58, 0x62, 0x79, + 0x6f, 0x37, 0x4c, 0x6a, 0x76, 0x50, 0x70, 0x76, 0x4d, 0x70, 0x0a, 0x4e, + 0x62, 0x37, 0x50, 0x47, 0x4b, 0x77, 0x2b, 0x71, 0x74, 0x6e, 0x34, 0x54, + 0x61, 0x41, 0x2b, 0x47, 0x6b, 0x65, 0x35, 0x76, 0x4a, 0x72, 0x66, 0x38, + 0x76, 0x37, 0x4d, 0x50, 0x6b, 0x66, 0x6f, 0x65, 0x70, 0x62, 0x43, 0x4a, + 0x49, 0x34, 0x31, 0x39, 0x4b, 0x6b, 0x4d, 0x2f, 0x49, 0x4c, 0x39, 0x62, + 0x63, 0x46, 0x79, 0x59, 0x69, 0x65, 0x39, 0x36, 0x6d, 0x76, 0x72, 0x35, + 0x34, 0x72, 0x4d, 0x0a, 0x56, 0x44, 0x36, 0x51, 0x55, 0x4d, 0x2b, 0x41, + 0x31, 0x4a, 0x58, 0x37, 0x36, 0x4c, 0x57, 0x43, 0x31, 0x42, 0x54, 0x46, + 0x74, 0x71, 0x6c, 0x56, 0x4a, 0x56, 0x66, 0x62, 0x73, 0x56, 0x44, 0x32, + 0x73, 0x47, 0x42, 0x6b, 0x57, 0x58, 0x70, 0x70, 0x7a, 0x77, 0x4f, 0x33, + 0x62, 0x77, 0x32, 0x2b, 0x79, 0x6a, 0x35, 0x76, 0x64, 0x48, 0x4c, 0x71, + 0x71, 0x6a, 0x41, 0x71, 0x63, 0x32, 0x4b, 0x2b, 0x0a, 0x53, 0x5a, 0x46, + 0x68, 0x79, 0x42, 0x48, 0x2b, 0x44, 0x67, 0x4d, 0x71, 0x39, 0x32, 0x6f, + 0x67, 0x33, 0x41, 0x49, 0x56, 0x44, 0x56, 0x34, 0x56, 0x61, 0x76, 0x7a, + 0x6a, 0x67, 0x73, 0x47, 0x31, 0x78, 0x5a, 0x31, 0x6b, 0x43, 0x57, 0x79, + 0x6a, 0x57, 0x5a, 0x67, 0x48, 0x4a, 0x38, 0x63, 0x62, 0x6c, 0x69, 0x74, + 0x68, 0x64, 0x48, 0x46, 0x73, 0x51, 0x2f, 0x48, 0x33, 0x4e, 0x59, 0x6b, + 0x51, 0x0a, 0x34, 0x4a, 0x37, 0x73, 0x56, 0x61, 0x45, 0x33, 0x49, 0x71, + 0x4b, 0x48, 0x42, 0x41, 0x55, 0x73, 0x52, 0x33, 0x32, 0x30, 0x48, 0x4c, + 0x6c, 0x69, 0x4b, 0x57, 0x59, 0x6f, 0x79, 0x72, 0x66, 0x68, 0x6b, 0x2f, + 0x57, 0x6b, 0x6c, 0x41, 0x4f, 0x5a, 0x75, 0x58, 0x43, 0x46, 0x74, 0x65, + 0x5a, 0x49, 0x36, 0x6f, 0x31, 0x51, 0x2f, 0x4e, 0x6e, 0x65, 0x7a, 0x47, + 0x38, 0x48, 0x44, 0x74, 0x30, 0x4c, 0x0a, 0x63, 0x70, 0x32, 0x41, 0x4d, + 0x42, 0x59, 0x48, 0x6c, 0x54, 0x38, 0x6f, 0x44, 0x76, 0x33, 0x46, 0x64, + 0x55, 0x39, 0x54, 0x31, 0x6e, 0x53, 0x61, 0x74, 0x43, 0x51, 0x75, 0x6a, + 0x67, 0x4b, 0x52, 0x7a, 0x33, 0x62, 0x46, 0x6d, 0x78, 0x35, 0x56, 0x64, + 0x4a, 0x78, 0x34, 0x49, 0x62, 0x48, 0x77, 0x4c, 0x66, 0x45, 0x4c, 0x6e, + 0x38, 0x4c, 0x56, 0x6c, 0x68, 0x67, 0x66, 0x38, 0x46, 0x51, 0x69, 0x0a, + 0x65, 0x6f, 0x77, 0x48, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, + 0x66, 0x54, 0x42, 0x37, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x53, 0x6e, 0x70, 0x51, 0x61, 0x78, + 0x4c, 0x4b, 0x59, 0x4a, 0x59, 0x4f, 0x37, 0x52, 0x6c, 0x2b, 0x6c, 0x77, + 0x72, 0x72, 0x77, 0x37, 0x47, 0x57, 0x7a, 0x62, 0x49, 0x54, 0x41, 0x50, + 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, + 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x42, 0x38, + 0x47, 0x41, 0x31, 0x55, 0x64, 0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, 0x61, + 0x41, 0x46, 0x4b, 0x65, 0x6c, 0x42, 0x72, 0x45, 0x73, 0x70, 0x67, 0x6c, + 0x67, 0x37, 0x74, 0x47, 0x58, 0x36, 0x58, 0x43, 0x75, 0x76, 0x44, 0x73, + 0x5a, 0x62, 0x4e, 0x73, 0x68, 0x4d, 0x42, 0x67, 0x47, 0x0a, 0x41, 0x31, + 0x55, 0x64, 0x49, 0x41, 0x51, 0x52, 0x4d, 0x41, 0x38, 0x77, 0x44, 0x51, + 0x59, 0x4c, 0x4b, 0x77, 0x59, 0x42, 0x42, 0x41, 0x47, 0x77, 0x4c, 0x51, + 0x4d, 0x45, 0x41, 0x51, 0x45, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, + 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, + 0x47, 0x47, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, + 0x62, 0x33, 0x0a, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, + 0x34, 0x49, 0x42, 0x41, 0x51, 0x41, 0x6d, 0x64, 0x7a, 0x54, 0x62, 0x6c, + 0x45, 0x69, 0x47, 0x4b, 0x6b, 0x47, 0x64, 0x4c, 0x44, 0x34, 0x47, 0x6b, + 0x47, 0x44, 0x45, 0x6a, 0x4b, 0x77, 0x4c, 0x56, 0x4c, 0x67, 0x66, 0x75, + 0x58, 0x76, 0x54, 0x42, 0x7a, 0x6e, 0x6b, 0x2b, 0x6a, 0x35, 0x37, 0x73, + 0x6a, 0x31, 0x4f, 0x37, 0x5a, 0x38, 0x6a, 0x0a, 0x76, 0x5a, 0x66, 0x7a, + 0x61, 0x31, 0x7a, 0x76, 0x37, 0x76, 0x31, 0x41, 0x70, 0x74, 0x2b, 0x68, + 0x6b, 0x36, 0x45, 0x4b, 0x68, 0x71, 0x7a, 0x76, 0x49, 0x4e, 0x42, 0x35, + 0x41, 0x62, 0x31, 0x34, 0x39, 0x78, 0x6e, 0x59, 0x4a, 0x44, 0x45, 0x30, + 0x42, 0x41, 0x47, 0x6d, 0x75, 0x68, 0x57, 0x61, 0x77, 0x79, 0x66, 0x63, + 0x32, 0x45, 0x38, 0x50, 0x7a, 0x42, 0x68, 0x6a, 0x2f, 0x35, 0x6b, 0x50, + 0x0a, 0x44, 0x70, 0x46, 0x72, 0x64, 0x52, 0x62, 0x68, 0x49, 0x66, 0x7a, + 0x59, 0x4a, 0x73, 0x64, 0x48, 0x74, 0x36, 0x62, 0x50, 0x57, 0x48, 0x4a, + 0x78, 0x66, 0x72, 0x72, 0x68, 0x54, 0x5a, 0x56, 0x48, 0x4f, 0x38, 0x6d, + 0x76, 0x62, 0x61, 0x47, 0x30, 0x77, 0x65, 0x79, 0x4a, 0x39, 0x72, 0x51, + 0x50, 0x4f, 0x4c, 0x58, 0x69, 0x5a, 0x4e, 0x77, 0x6c, 0x7a, 0x36, 0x62, + 0x62, 0x36, 0x35, 0x70, 0x63, 0x0a, 0x6d, 0x61, 0x48, 0x46, 0x43, 0x4e, + 0x37, 0x39, 0x35, 0x74, 0x72, 0x56, 0x31, 0x6c, 0x70, 0x46, 0x44, 0x4d, + 0x53, 0x33, 0x77, 0x72, 0x55, 0x55, 0x37, 0x37, 0x51, 0x52, 0x2f, 0x77, + 0x34, 0x56, 0x74, 0x66, 0x58, 0x31, 0x32, 0x38, 0x61, 0x39, 0x36, 0x31, + 0x71, 0x6e, 0x38, 0x46, 0x59, 0x69, 0x71, 0x54, 0x78, 0x6c, 0x56, 0x4d, + 0x59, 0x56, 0x71, 0x4c, 0x32, 0x47, 0x6e, 0x73, 0x32, 0x44, 0x0a, 0x6c, + 0x6d, 0x68, 0x36, 0x63, 0x59, 0x47, 0x4a, 0x34, 0x51, 0x76, 0x68, 0x36, + 0x68, 0x45, 0x62, 0x61, 0x41, 0x6a, 0x4d, 0x61, 0x5a, 0x37, 0x73, 0x6e, + 0x6b, 0x47, 0x65, 0x52, 0x44, 0x49, 0x6d, 0x65, 0x75, 0x4b, 0x48, 0x43, + 0x6e, 0x45, 0x39, 0x36, 0x2b, 0x52, 0x61, 0x70, 0x4e, 0x4c, 0x62, 0x78, + 0x63, 0x33, 0x47, 0x33, 0x6d, 0x42, 0x2f, 0x75, 0x66, 0x4e, 0x50, 0x52, + 0x4a, 0x4c, 0x76, 0x0a, 0x4b, 0x72, 0x63, 0x59, 0x50, 0x71, 0x63, 0x5a, + 0x32, 0x51, 0x74, 0x39, 0x73, 0x54, 0x64, 0x42, 0x51, 0x72, 0x43, 0x36, + 0x59, 0x42, 0x33, 0x79, 0x2f, 0x67, 0x6b, 0x52, 0x73, 0x50, 0x43, 0x48, + 0x65, 0x36, 0x65, 0x64, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x51, 0x75, 0x6f, + 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x20, 0x31, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x51, 0x75, 0x6f, + 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, + 0x64, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x20, 0x47, + 0x33, 0x20, 0x4f, 0x3d, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, + 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x51, 0x75, 0x6f, 0x56, 0x61, + 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, + 0x31, 0x20, 0x47, 0x33, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x36, 0x38, 0x37, 0x30, 0x34, 0x39, 0x36, 0x34, + 0x39, 0x36, 0x32, 0x36, 0x36, 0x36, 0x39, 0x32, 0x35, 0x30, 0x37, 0x33, + 0x36, 0x32, 0x37, 0x31, 0x30, 0x33, 0x37, 0x36, 0x30, 0x36, 0x35, 0x35, + 0x34, 0x36, 0x32, 0x34, 0x30, 0x37, 0x38, 0x37, 0x32, 0x30, 0x30, 0x33, + 0x34, 0x31, 0x39, 0x35, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x61, 0x34, 0x3a, 0x62, 0x63, 0x3a, 0x35, 0x62, 0x3a, 0x33, 0x66, 0x3a, + 0x66, 0x65, 0x3a, 0x33, 0x37, 0x3a, 0x39, 0x61, 0x3a, 0x66, 0x61, 0x3a, + 0x36, 0x34, 0x3a, 0x66, 0x30, 0x3a, 0x65, 0x32, 0x3a, 0x66, 0x61, 0x3a, + 0x30, 0x35, 0x3a, 0x33, 0x64, 0x3a, 0x30, 0x62, 0x3a, 0x61, 0x62, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x62, 0x3a, 0x38, + 0x65, 0x3a, 0x65, 0x61, 0x3a, 0x35, 0x37, 0x3a, 0x39, 0x36, 0x3a, 0x32, + 0x39, 0x3a, 0x31, 0x61, 0x3a, 0x63, 0x39, 0x3a, 0x33, 0x39, 0x3a, 0x65, + 0x61, 0x3a, 0x62, 0x38, 0x3a, 0x30, 0x61, 0x3a, 0x38, 0x31, 0x3a, 0x31, + 0x61, 0x3a, 0x37, 0x33, 0x3a, 0x37, 0x33, 0x3a, 0x63, 0x30, 0x3a, 0x39, + 0x33, 0x3a, 0x37, 0x39, 0x3a, 0x36, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x61, 0x3a, 0x38, 0x36, 0x3a, + 0x36, 0x66, 0x3a, 0x64, 0x31, 0x3a, 0x62, 0x32, 0x3a, 0x37, 0x36, 0x3a, + 0x62, 0x35, 0x3a, 0x37, 0x65, 0x3a, 0x35, 0x37, 0x3a, 0x38, 0x65, 0x3a, + 0x39, 0x32, 0x3a, 0x31, 0x63, 0x3a, 0x36, 0x35, 0x3a, 0x38, 0x32, 0x3a, + 0x38, 0x61, 0x3a, 0x32, 0x62, 0x3a, 0x65, 0x64, 0x3a, 0x35, 0x38, 0x3a, + 0x65, 0x39, 0x3a, 0x66, 0x32, 0x3a, 0x66, 0x32, 0x3a, 0x38, 0x38, 0x3a, + 0x30, 0x35, 0x3a, 0x34, 0x31, 0x3a, 0x33, 0x34, 0x3a, 0x62, 0x37, 0x3a, + 0x66, 0x31, 0x3a, 0x66, 0x34, 0x3a, 0x62, 0x66, 0x3a, 0x63, 0x39, 0x3a, + 0x63, 0x63, 0x3a, 0x37, 0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, + 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, + 0x49, 0x46, 0x59, 0x44, 0x43, 0x43, 0x41, 0x30, 0x69, 0x67, 0x41, 0x77, + 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x65, 0x46, 0x68, 0x66, 0x4c, 0x71, + 0x30, 0x73, 0x47, 0x55, 0x76, 0x6a, 0x4e, 0x77, 0x63, 0x31, 0x4e, 0x42, + 0x4d, 0x6f, 0x74, 0x5a, 0x62, 0x55, 0x5a, 0x5a, 0x4d, 0x77, 0x44, 0x51, + 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, + 0x45, 0x4c, 0x0a, 0x42, 0x51, 0x41, 0x77, 0x53, 0x44, 0x45, 0x4c, 0x4d, + 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x51, + 0x6b, 0x30, 0x78, 0x47, 0x54, 0x41, 0x58, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x6f, 0x54, 0x45, 0x46, 0x46, 0x31, 0x62, 0x31, 0x5a, 0x68, 0x5a, + 0x47, 0x6c, 0x7a, 0x49, 0x45, 0x78, 0x70, 0x62, 0x57, 0x6c, 0x30, 0x5a, + 0x57, 0x51, 0x78, 0x48, 0x6a, 0x41, 0x63, 0x0a, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x4d, 0x54, 0x46, 0x56, 0x46, 0x31, 0x62, 0x31, 0x5a, 0x68, + 0x5a, 0x47, 0x6c, 0x7a, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, + 0x51, 0x30, 0x45, 0x67, 0x4d, 0x53, 0x42, 0x48, 0x4d, 0x7a, 0x41, 0x65, + 0x46, 0x77, 0x30, 0x78, 0x4d, 0x6a, 0x41, 0x78, 0x4d, 0x54, 0x49, 0x78, + 0x4e, 0x7a, 0x49, 0x33, 0x4e, 0x44, 0x52, 0x61, 0x46, 0x77, 0x30, 0x30, + 0x0a, 0x4d, 0x6a, 0x41, 0x78, 0x4d, 0x54, 0x49, 0x78, 0x4e, 0x7a, 0x49, + 0x33, 0x4e, 0x44, 0x52, 0x61, 0x4d, 0x45, 0x67, 0x78, 0x43, 0x7a, 0x41, + 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x4a, + 0x4e, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x4b, 0x45, 0x78, 0x42, 0x52, 0x64, 0x57, 0x39, 0x57, 0x59, 0x57, 0x52, + 0x70, 0x63, 0x79, 0x42, 0x4d, 0x0a, 0x61, 0x57, 0x31, 0x70, 0x64, 0x47, + 0x56, 0x6b, 0x4d, 0x52, 0x34, 0x77, 0x48, 0x41, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x44, 0x45, 0x78, 0x56, 0x52, 0x64, 0x57, 0x39, 0x57, 0x59, 0x57, + 0x52, 0x70, 0x63, 0x79, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, + 0x4e, 0x42, 0x49, 0x44, 0x45, 0x67, 0x52, 0x7a, 0x4d, 0x77, 0x67, 0x67, + 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x0a, 0x53, + 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, + 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, + 0x6f, 0x49, 0x43, 0x41, 0x51, 0x43, 0x67, 0x76, 0x6c, 0x41, 0x51, 0x6a, + 0x75, 0x6e, 0x79, 0x62, 0x45, 0x43, 0x30, 0x42, 0x4a, 0x79, 0x46, 0x75, + 0x54, 0x48, 0x4b, 0x33, 0x43, 0x33, 0x6b, 0x45, 0x61, 0x6b, 0x45, 0x50, + 0x42, 0x74, 0x56, 0x0a, 0x77, 0x65, 0x64, 0x59, 0x4d, 0x42, 0x30, 0x6b, + 0x74, 0x4d, 0x50, 0x76, 0x68, 0x64, 0x36, 0x4d, 0x4c, 0x4f, 0x48, 0x42, + 0x50, 0x64, 0x2b, 0x43, 0x35, 0x6b, 0x2b, 0x74, 0x52, 0x34, 0x64, 0x73, + 0x37, 0x46, 0x74, 0x4a, 0x77, 0x55, 0x72, 0x56, 0x75, 0x34, 0x2f, 0x73, + 0x68, 0x36, 0x78, 0x2f, 0x67, 0x70, 0x71, 0x47, 0x37, 0x44, 0x30, 0x44, + 0x6d, 0x56, 0x49, 0x42, 0x30, 0x6a, 0x57, 0x65, 0x0a, 0x72, 0x4e, 0x72, + 0x77, 0x55, 0x38, 0x6c, 0x6d, 0x50, 0x4e, 0x53, 0x73, 0x41, 0x67, 0x48, + 0x61, 0x4a, 0x4e, 0x4d, 0x37, 0x71, 0x41, 0x4a, 0x47, 0x72, 0x36, 0x51, + 0x63, 0x34, 0x2f, 0x68, 0x7a, 0x57, 0x48, 0x61, 0x33, 0x39, 0x67, 0x36, + 0x51, 0x44, 0x62, 0x58, 0x77, 0x7a, 0x38, 0x7a, 0x36, 0x2b, 0x63, 0x5a, + 0x4d, 0x35, 0x63, 0x4f, 0x47, 0x4d, 0x41, 0x71, 0x4e, 0x46, 0x33, 0x34, + 0x31, 0x0a, 0x36, 0x38, 0x58, 0x66, 0x75, 0x77, 0x36, 0x63, 0x77, 0x49, + 0x32, 0x48, 0x34, 0x34, 0x67, 0x34, 0x68, 0x57, 0x66, 0x36, 0x50, 0x73, + 0x65, 0x72, 0x34, 0x42, 0x4f, 0x63, 0x42, 0x52, 0x69, 0x59, 0x7a, 0x35, + 0x50, 0x31, 0x73, 0x5a, 0x4b, 0x30, 0x2f, 0x43, 0x50, 0x54, 0x7a, 0x39, + 0x58, 0x45, 0x4a, 0x30, 0x6e, 0x67, 0x6e, 0x6a, 0x79, 0x62, 0x43, 0x4b, + 0x4f, 0x4c, 0x58, 0x53, 0x6f, 0x68, 0x0a, 0x34, 0x50, 0x77, 0x35, 0x71, + 0x6c, 0x50, 0x61, 0x66, 0x58, 0x37, 0x50, 0x47, 0x67, 0x6c, 0x54, 0x76, + 0x46, 0x30, 0x46, 0x42, 0x4d, 0x2b, 0x68, 0x53, 0x6f, 0x2b, 0x4c, 0x64, + 0x6f, 0x49, 0x4e, 0x6f, 0x66, 0x6a, 0x53, 0x78, 0x78, 0x52, 0x33, 0x57, + 0x35, 0x41, 0x32, 0x42, 0x34, 0x47, 0x62, 0x50, 0x67, 0x62, 0x36, 0x55, + 0x6c, 0x35, 0x6a, 0x78, 0x61, 0x59, 0x41, 0x2f, 0x71, 0x58, 0x70, 0x0a, + 0x55, 0x68, 0x74, 0x53, 0x74, 0x5a, 0x49, 0x35, 0x63, 0x67, 0x4d, 0x4a, + 0x59, 0x72, 0x32, 0x77, 0x59, 0x42, 0x5a, 0x75, 0x70, 0x74, 0x30, 0x6c, + 0x77, 0x67, 0x4e, 0x6d, 0x33, 0x66, 0x4d, 0x45, 0x30, 0x55, 0x44, 0x69, + 0x54, 0x6f, 0x75, 0x47, 0x39, 0x47, 0x2f, 0x6c, 0x67, 0x36, 0x41, 0x6e, + 0x68, 0x46, 0x34, 0x45, 0x77, 0x66, 0x57, 0x51, 0x76, 0x54, 0x41, 0x39, + 0x78, 0x4f, 0x2b, 0x6f, 0x0a, 0x61, 0x62, 0x77, 0x34, 0x6d, 0x36, 0x53, + 0x6b, 0x6c, 0x74, 0x46, 0x69, 0x32, 0x6d, 0x6e, 0x41, 0x41, 0x5a, 0x61, + 0x75, 0x79, 0x38, 0x52, 0x52, 0x4e, 0x4f, 0x6f, 0x4d, 0x71, 0x76, 0x38, + 0x68, 0x6a, 0x6c, 0x6d, 0x50, 0x53, 0x6c, 0x7a, 0x6b, 0x59, 0x5a, 0x71, + 0x6e, 0x30, 0x75, 0x6b, 0x71, 0x65, 0x49, 0x31, 0x52, 0x50, 0x54, 0x6f, + 0x56, 0x37, 0x71, 0x4a, 0x5a, 0x6a, 0x71, 0x6c, 0x63, 0x0a, 0x33, 0x73, + 0x58, 0x35, 0x6b, 0x43, 0x4c, 0x6c, 0x69, 0x45, 0x56, 0x78, 0x33, 0x5a, + 0x47, 0x5a, 0x62, 0x48, 0x71, 0x66, 0x50, 0x54, 0x32, 0x59, 0x66, 0x46, + 0x37, 0x32, 0x76, 0x68, 0x5a, 0x6f, 0x6f, 0x46, 0x36, 0x75, 0x43, 0x79, + 0x50, 0x38, 0x57, 0x67, 0x2b, 0x71, 0x49, 0x6e, 0x59, 0x74, 0x79, 0x61, + 0x45, 0x51, 0x48, 0x65, 0x54, 0x54, 0x52, 0x43, 0x4f, 0x51, 0x69, 0x4a, + 0x2f, 0x47, 0x0a, 0x4b, 0x75, 0x62, 0x58, 0x39, 0x5a, 0x71, 0x7a, 0x57, + 0x42, 0x34, 0x76, 0x4d, 0x49, 0x6b, 0x49, 0x47, 0x31, 0x53, 0x69, 0x74, + 0x5a, 0x67, 0x6a, 0x37, 0x41, 0x68, 0x33, 0x48, 0x4a, 0x56, 0x64, 0x59, + 0x64, 0x48, 0x4c, 0x69, 0x5a, 0x78, 0x66, 0x6f, 0x6b, 0x71, 0x52, 0x6d, + 0x75, 0x38, 0x68, 0x71, 0x6b, 0x6b, 0x57, 0x43, 0x4b, 0x69, 0x39, 0x59, + 0x53, 0x67, 0x78, 0x79, 0x58, 0x53, 0x74, 0x0a, 0x68, 0x66, 0x62, 0x5a, + 0x78, 0x62, 0x47, 0x4c, 0x30, 0x65, 0x55, 0x51, 0x4d, 0x6b, 0x31, 0x66, + 0x69, 0x79, 0x41, 0x36, 0x50, 0x45, 0x6b, 0x66, 0x4d, 0x34, 0x56, 0x5a, + 0x44, 0x64, 0x76, 0x4c, 0x43, 0x58, 0x56, 0x44, 0x61, 0x58, 0x50, 0x37, + 0x61, 0x33, 0x46, 0x39, 0x38, 0x4e, 0x2f, 0x45, 0x54, 0x48, 0x33, 0x47, + 0x6f, 0x79, 0x37, 0x49, 0x6c, 0x58, 0x6e, 0x4c, 0x63, 0x36, 0x4b, 0x4f, + 0x0a, 0x54, 0x6b, 0x30, 0x6b, 0x2b, 0x31, 0x37, 0x6b, 0x42, 0x4c, 0x35, + 0x79, 0x47, 0x36, 0x59, 0x6e, 0x4c, 0x55, 0x6c, 0x61, 0x6d, 0x58, 0x72, + 0x58, 0x58, 0x41, 0x6b, 0x67, 0x74, 0x33, 0x2b, 0x55, 0x75, 0x55, 0x2f, + 0x78, 0x44, 0x52, 0x78, 0x65, 0x69, 0x45, 0x49, 0x62, 0x45, 0x62, 0x66, + 0x6e, 0x6b, 0x64, 0x75, 0x65, 0x62, 0x50, 0x52, 0x71, 0x33, 0x34, 0x77, + 0x47, 0x6d, 0x41, 0x4f, 0x74, 0x0a, 0x7a, 0x43, 0x6a, 0x76, 0x70, 0x55, + 0x66, 0x7a, 0x55, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x30, + 0x49, 0x77, 0x51, 0x44, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, + 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, + 0x48, 0x2f, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, + 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x0a, 0x42, + 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, + 0x67, 0x51, 0x55, 0x6f, 0x35, 0x66, 0x57, 0x38, 0x31, 0x36, 0x69, 0x45, + 0x4f, 0x47, 0x72, 0x52, 0x5a, 0x38, 0x38, 0x46, 0x32, 0x51, 0x38, 0x37, + 0x67, 0x46, 0x77, 0x6e, 0x4d, 0x77, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, + 0x51, 0x41, 0x44, 0x0a, 0x67, 0x67, 0x49, 0x42, 0x41, 0x42, 0x6a, 0x36, + 0x57, 0x33, 0x58, 0x38, 0x50, 0x6e, 0x72, 0x48, 0x58, 0x33, 0x66, 0x48, + 0x79, 0x74, 0x2f, 0x50, 0x58, 0x38, 0x4d, 0x53, 0x78, 0x45, 0x42, 0x64, + 0x31, 0x44, 0x4b, 0x71, 0x75, 0x47, 0x72, 0x58, 0x31, 0x52, 0x55, 0x56, + 0x52, 0x70, 0x67, 0x6a, 0x70, 0x65, 0x61, 0x51, 0x57, 0x78, 0x69, 0x5a, + 0x54, 0x4f, 0x4f, 0x74, 0x51, 0x71, 0x4f, 0x43, 0x0a, 0x4d, 0x54, 0x61, + 0x49, 0x7a, 0x65, 0x6e, 0x37, 0x78, 0x41, 0x53, 0x57, 0x53, 0x49, 0x73, + 0x42, 0x78, 0x34, 0x30, 0x42, 0x7a, 0x31, 0x73, 0x7a, 0x42, 0x70, 0x5a, + 0x47, 0x5a, 0x6e, 0x51, 0x64, 0x54, 0x2b, 0x33, 0x42, 0x74, 0x72, 0x6d, + 0x30, 0x44, 0x57, 0x48, 0x4d, 0x59, 0x33, 0x37, 0x58, 0x4c, 0x6e, 0x65, + 0x4d, 0x6c, 0x68, 0x77, 0x71, 0x49, 0x32, 0x68, 0x72, 0x68, 0x56, 0x64, + 0x32, 0x0a, 0x63, 0x44, 0x4d, 0x54, 0x2f, 0x75, 0x46, 0x50, 0x70, 0x69, + 0x4e, 0x33, 0x47, 0x50, 0x6f, 0x61, 0x6a, 0x4f, 0x69, 0x39, 0x5a, 0x63, + 0x6e, 0x50, 0x50, 0x2f, 0x54, 0x4a, 0x46, 0x39, 0x7a, 0x72, 0x78, 0x37, + 0x7a, 0x41, 0x42, 0x43, 0x34, 0x74, 0x52, 0x69, 0x39, 0x70, 0x5a, 0x73, + 0x4d, 0x62, 0x6a, 0x2f, 0x37, 0x73, 0x50, 0x74, 0x50, 0x4b, 0x6c, 0x4c, + 0x39, 0x32, 0x43, 0x69, 0x55, 0x4e, 0x0a, 0x71, 0x58, 0x73, 0x43, 0x48, + 0x4b, 0x6e, 0x51, 0x4f, 0x31, 0x38, 0x4c, 0x77, 0x49, 0x45, 0x36, 0x50, + 0x57, 0x54, 0x68, 0x76, 0x36, 0x63, 0x74, 0x54, 0x72, 0x31, 0x4e, 0x78, + 0x4e, 0x67, 0x70, 0x78, 0x69, 0x49, 0x59, 0x30, 0x4d, 0x57, 0x73, 0x63, + 0x67, 0x4b, 0x43, 0x50, 0x36, 0x6f, 0x36, 0x6f, 0x6a, 0x6f, 0x69, 0x6c, + 0x7a, 0x48, 0x64, 0x43, 0x47, 0x50, 0x44, 0x64, 0x52, 0x53, 0x35, 0x0a, + 0x59, 0x43, 0x67, 0x74, 0x57, 0x32, 0x6a, 0x67, 0x46, 0x71, 0x6c, 0x6d, + 0x67, 0x69, 0x4e, 0x52, 0x39, 0x65, 0x74, 0x54, 0x32, 0x44, 0x47, 0x62, + 0x65, 0x2b, 0x6d, 0x33, 0x6e, 0x55, 0x76, 0x72, 0x69, 0x42, 0x62, 0x50, + 0x2b, 0x56, 0x30, 0x34, 0x69, 0x6b, 0x6b, 0x77, 0x6a, 0x2b, 0x33, 0x78, + 0x36, 0x78, 0x6e, 0x30, 0x64, 0x78, 0x6f, 0x78, 0x47, 0x45, 0x31, 0x6e, + 0x56, 0x47, 0x77, 0x76, 0x0a, 0x62, 0x32, 0x58, 0x35, 0x32, 0x7a, 0x33, + 0x73, 0x49, 0x65, 0x78, 0x65, 0x39, 0x50, 0x53, 0x4c, 0x79, 0x6d, 0x42, + 0x6c, 0x56, 0x4e, 0x46, 0x78, 0x5a, 0x50, 0x54, 0x35, 0x70, 0x71, 0x4f, + 0x42, 0x4d, 0x7a, 0x59, 0x7a, 0x63, 0x66, 0x43, 0x6b, 0x65, 0x46, 0x39, + 0x4f, 0x72, 0x59, 0x4d, 0x68, 0x33, 0x6a, 0x52, 0x4a, 0x6a, 0x65, 0x68, + 0x5a, 0x72, 0x4a, 0x33, 0x79, 0x64, 0x6c, 0x6f, 0x32, 0x0a, 0x38, 0x68, + 0x50, 0x30, 0x72, 0x2b, 0x41, 0x4a, 0x78, 0x32, 0x45, 0x71, 0x62, 0x50, + 0x66, 0x67, 0x6e, 0x61, 0x36, 0x37, 0x68, 0x6b, 0x6f, 0x6f, 0x62, 0x79, + 0x37, 0x75, 0x74, 0x48, 0x6e, 0x4e, 0x6b, 0x44, 0x50, 0x44, 0x73, 0x33, + 0x62, 0x36, 0x39, 0x66, 0x42, 0x73, 0x6e, 0x51, 0x47, 0x51, 0x2b, 0x70, + 0x36, 0x51, 0x39, 0x70, 0x78, 0x79, 0x7a, 0x30, 0x66, 0x61, 0x77, 0x78, + 0x2f, 0x6b, 0x0a, 0x4e, 0x53, 0x42, 0x54, 0x38, 0x6c, 0x54, 0x52, 0x33, + 0x32, 0x47, 0x44, 0x70, 0x67, 0x4c, 0x69, 0x4a, 0x54, 0x6a, 0x65, 0x68, + 0x54, 0x49, 0x74, 0x58, 0x6e, 0x4f, 0x51, 0x55, 0x6c, 0x31, 0x43, 0x78, + 0x4d, 0x34, 0x39, 0x53, 0x2b, 0x48, 0x35, 0x47, 0x59, 0x51, 0x64, 0x31, + 0x61, 0x4a, 0x51, 0x7a, 0x45, 0x48, 0x37, 0x51, 0x52, 0x54, 0x44, 0x76, + 0x64, 0x62, 0x4a, 0x57, 0x71, 0x4e, 0x6a, 0x0a, 0x5a, 0x67, 0x4b, 0x41, + 0x76, 0x51, 0x55, 0x36, 0x4f, 0x30, 0x65, 0x63, 0x37, 0x41, 0x41, 0x6d, + 0x54, 0x50, 0x57, 0x49, 0x55, 0x62, 0x2b, 0x6f, 0x49, 0x33, 0x38, 0x59, + 0x42, 0x37, 0x41, 0x4c, 0x37, 0x59, 0x73, 0x6d, 0x6f, 0x57, 0x54, 0x54, + 0x59, 0x55, 0x72, 0x72, 0x58, 0x4a, 0x2f, 0x65, 0x73, 0x36, 0x39, 0x6e, + 0x41, 0x37, 0x4d, 0x66, 0x33, 0x57, 0x31, 0x64, 0x61, 0x57, 0x68, 0x70, + 0x0a, 0x71, 0x31, 0x34, 0x36, 0x37, 0x48, 0x78, 0x70, 0x76, 0x4d, 0x63, + 0x37, 0x68, 0x55, 0x36, 0x65, 0x46, 0x62, 0x6d, 0x30, 0x46, 0x55, 0x2f, + 0x44, 0x6c, 0x58, 0x70, 0x59, 0x31, 0x38, 0x6c, 0x73, 0x36, 0x57, 0x79, + 0x35, 0x38, 0x79, 0x6c, 0x6a, 0x58, 0x72, 0x51, 0x73, 0x38, 0x43, 0x30, + 0x39, 0x37, 0x56, 0x70, 0x6c, 0x34, 0x4b, 0x6c, 0x62, 0x51, 0x4d, 0x4a, + 0x49, 0x6d, 0x59, 0x46, 0x74, 0x0a, 0x6e, 0x68, 0x38, 0x47, 0x4b, 0x6a, + 0x77, 0x53, 0x74, 0x49, 0x73, 0x50, 0x6d, 0x36, 0x49, 0x6b, 0x38, 0x4b, + 0x61, 0x4e, 0x31, 0x6e, 0x72, 0x67, 0x53, 0x37, 0x5a, 0x6b, 0x6c, 0x6d, + 0x4f, 0x56, 0x68, 0x4d, 0x4a, 0x4b, 0x7a, 0x52, 0x77, 0x75, 0x4a, 0x49, + 0x63, 0x7a, 0x59, 0x4f, 0x58, 0x44, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, + 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x51, + 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x32, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x51, + 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, + 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, + 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, + 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, + 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, + 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x51, 0x75, 0x6f, + 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x20, 0x32, 0x20, 0x47, 0x33, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x33, 0x39, 0x30, 0x31, 0x35, 0x36, + 0x30, 0x37, 0x39, 0x34, 0x35, 0x38, 0x39, 0x35, 0x39, 0x32, 0x35, 0x37, + 0x34, 0x34, 0x36, 0x31, 0x33, 0x33, 0x31, 0x36, 0x39, 0x32, 0x36, 0x36, + 0x30, 0x37, 0x39, 0x39, 0x36, 0x32, 0x30, 0x32, 0x36, 0x38, 0x32, 0x34, + 0x37, 0x32, 0x35, 0x38, 0x30, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x61, 0x66, 0x3a, 0x30, 0x63, 0x3a, 0x38, 0x36, 0x3a, 0x36, + 0x65, 0x3a, 0x62, 0x66, 0x3a, 0x34, 0x30, 0x3a, 0x32, 0x64, 0x3a, 0x37, + 0x66, 0x3a, 0x30, 0x62, 0x3a, 0x33, 0x65, 0x3a, 0x31, 0x32, 0x3a, 0x35, + 0x30, 0x3a, 0x62, 0x61, 0x3a, 0x31, 0x32, 0x3a, 0x33, 0x64, 0x3a, 0x30, + 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x39, + 0x3a, 0x33, 0x63, 0x3a, 0x36, 0x31, 0x3a, 0x66, 0x33, 0x3a, 0x38, 0x62, + 0x3a, 0x38, 0x62, 0x3a, 0x64, 0x63, 0x3a, 0x37, 0x64, 0x3a, 0x35, 0x35, + 0x3a, 0x64, 0x66, 0x3a, 0x37, 0x35, 0x3a, 0x33, 0x38, 0x3a, 0x30, 0x32, + 0x3a, 0x30, 0x35, 0x3a, 0x30, 0x30, 0x3a, 0x65, 0x31, 0x3a, 0x32, 0x35, + 0x3a, 0x66, 0x35, 0x3a, 0x63, 0x38, 0x3a, 0x33, 0x36, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x66, 0x3a, 0x65, + 0x34, 0x3a, 0x66, 0x62, 0x3a, 0x30, 0x61, 0x3a, 0x66, 0x39, 0x3a, 0x33, + 0x61, 0x3a, 0x34, 0x64, 0x3a, 0x30, 0x64, 0x3a, 0x36, 0x37, 0x3a, 0x64, + 0x62, 0x3a, 0x30, 0x62, 0x3a, 0x65, 0x62, 0x3a, 0x62, 0x32, 0x3a, 0x33, + 0x65, 0x3a, 0x33, 0x37, 0x3a, 0x63, 0x37, 0x3a, 0x31, 0x62, 0x3a, 0x66, + 0x33, 0x3a, 0x32, 0x35, 0x3a, 0x64, 0x63, 0x3a, 0x62, 0x63, 0x3a, 0x64, + 0x64, 0x3a, 0x32, 0x34, 0x3a, 0x30, 0x65, 0x3a, 0x61, 0x30, 0x3a, 0x34, + 0x64, 0x3a, 0x61, 0x66, 0x3a, 0x35, 0x38, 0x3a, 0x62, 0x34, 0x3a, 0x37, + 0x65, 0x3a, 0x31, 0x38, 0x3a, 0x34, 0x30, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x46, 0x59, 0x44, 0x43, 0x43, 0x41, 0x30, 0x69, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x52, 0x46, 0x63, 0x30, + 0x4a, 0x46, 0x75, 0x42, 0x69, 0x5a, 0x73, 0x31, 0x38, 0x73, 0x36, 0x34, + 0x4b, 0x7a, 0x74, 0x62, 0x70, 0x79, 0x62, 0x77, 0x64, 0x53, 0x67, 0x77, + 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, + 0x41, 0x51, 0x45, 0x4c, 0x0a, 0x42, 0x51, 0x41, 0x77, 0x53, 0x44, 0x45, + 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x51, 0x6b, 0x30, 0x78, 0x47, 0x54, 0x41, 0x58, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x54, 0x45, 0x46, 0x46, 0x31, 0x62, 0x31, 0x5a, + 0x68, 0x5a, 0x47, 0x6c, 0x7a, 0x49, 0x45, 0x78, 0x70, 0x62, 0x57, 0x6c, + 0x30, 0x5a, 0x57, 0x51, 0x78, 0x48, 0x6a, 0x41, 0x63, 0x0a, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x46, 0x56, 0x46, 0x31, 0x62, 0x31, + 0x5a, 0x68, 0x5a, 0x47, 0x6c, 0x7a, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, + 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4d, 0x69, 0x42, 0x48, 0x4d, 0x7a, + 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4d, 0x6a, 0x41, 0x78, 0x4d, 0x54, + 0x49, 0x78, 0x4f, 0x44, 0x55, 0x35, 0x4d, 0x7a, 0x4a, 0x61, 0x46, 0x77, + 0x30, 0x30, 0x0a, 0x4d, 0x6a, 0x41, 0x78, 0x4d, 0x54, 0x49, 0x78, 0x4f, + 0x44, 0x55, 0x35, 0x4d, 0x7a, 0x4a, 0x61, 0x4d, 0x45, 0x67, 0x78, 0x43, + 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, + 0x6b, 0x4a, 0x4e, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x4b, 0x45, 0x78, 0x42, 0x52, 0x64, 0x57, 0x39, 0x57, 0x59, + 0x57, 0x52, 0x70, 0x63, 0x79, 0x42, 0x4d, 0x0a, 0x61, 0x57, 0x31, 0x70, + 0x64, 0x47, 0x56, 0x6b, 0x4d, 0x52, 0x34, 0x77, 0x48, 0x41, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x56, 0x52, 0x64, 0x57, 0x39, 0x57, + 0x59, 0x57, 0x52, 0x70, 0x63, 0x79, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, + 0x49, 0x45, 0x4e, 0x42, 0x49, 0x44, 0x49, 0x67, 0x52, 0x7a, 0x4d, 0x77, + 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, + 0x0a, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, + 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, + 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51, 0x43, 0x68, 0x72, 0x69, 0x57, + 0x79, 0x41, 0x52, 0x6a, 0x63, 0x56, 0x34, 0x67, 0x2f, 0x52, 0x75, 0x76, + 0x35, 0x72, 0x2b, 0x4c, 0x72, 0x49, 0x33, 0x48, 0x69, 0x6d, 0x74, 0x46, + 0x68, 0x5a, 0x69, 0x46, 0x66, 0x0a, 0x71, 0x71, 0x38, 0x6e, 0x55, 0x65, + 0x56, 0x75, 0x47, 0x78, 0x62, 0x55, 0x4c, 0x58, 0x31, 0x51, 0x73, 0x46, + 0x4e, 0x33, 0x76, 0x58, 0x67, 0x36, 0x59, 0x4f, 0x4a, 0x6b, 0x41, 0x70, + 0x74, 0x38, 0x68, 0x70, 0x76, 0x57, 0x47, 0x6f, 0x36, 0x74, 0x2f, 0x78, + 0x38, 0x56, 0x66, 0x39, 0x57, 0x56, 0x48, 0x68, 0x4c, 0x4c, 0x35, 0x68, + 0x53, 0x45, 0x42, 0x4d, 0x48, 0x66, 0x4e, 0x72, 0x4d, 0x57, 0x0a, 0x6e, + 0x34, 0x72, 0x6a, 0x79, 0x64, 0x75, 0x59, 0x4e, 0x4d, 0x37, 0x59, 0x4d, + 0x78, 0x63, 0x6f, 0x52, 0x76, 0x79, 0x6e, 0x79, 0x66, 0x44, 0x53, 0x74, + 0x4e, 0x56, 0x4e, 0x43, 0x58, 0x4a, 0x4a, 0x2b, 0x66, 0x4b, 0x48, 0x34, + 0x36, 0x6e, 0x61, 0x66, 0x61, 0x46, 0x39, 0x61, 0x37, 0x49, 0x36, 0x4a, + 0x61, 0x6c, 0x74, 0x55, 0x6b, 0x53, 0x73, 0x2b, 0x4c, 0x35, 0x75, 0x2b, + 0x39, 0x79, 0x6d, 0x0a, 0x63, 0x35, 0x47, 0x51, 0x59, 0x61, 0x59, 0x44, + 0x46, 0x43, 0x44, 0x79, 0x35, 0x34, 0x65, 0x6a, 0x69, 0x4b, 0x32, 0x74, + 0x6f, 0x49, 0x7a, 0x2f, 0x70, 0x67, 0x73, 0x6c, 0x55, 0x69, 0x58, 0x6e, + 0x46, 0x67, 0x48, 0x56, 0x79, 0x37, 0x67, 0x31, 0x67, 0x51, 0x79, 0x6a, + 0x4f, 0x2f, 0x44, 0x68, 0x34, 0x66, 0x78, 0x61, 0x58, 0x63, 0x36, 0x41, + 0x63, 0x57, 0x33, 0x34, 0x53, 0x61, 0x73, 0x2b, 0x0a, 0x4f, 0x37, 0x71, + 0x34, 0x31, 0x34, 0x41, 0x42, 0x2b, 0x36, 0x58, 0x72, 0x57, 0x37, 0x50, + 0x46, 0x58, 0x6d, 0x41, 0x71, 0x4d, 0x61, 0x43, 0x76, 0x4e, 0x2b, 0x67, + 0x67, 0x4f, 0x70, 0x2b, 0x6f, 0x4d, 0x69, 0x77, 0x4d, 0x7a, 0x41, 0x6b, + 0x64, 0x30, 0x35, 0x36, 0x4f, 0x58, 0x62, 0x78, 0x4d, 0x6d, 0x4f, 0x37, + 0x46, 0x47, 0x6d, 0x68, 0x37, 0x37, 0x46, 0x4f, 0x6d, 0x36, 0x52, 0x51, + 0x31, 0x0a, 0x6f, 0x39, 0x2f, 0x4e, 0x67, 0x4a, 0x38, 0x4d, 0x53, 0x50, + 0x73, 0x63, 0x39, 0x50, 0x47, 0x2f, 0x53, 0x72, 0x6a, 0x36, 0x31, 0x59, + 0x78, 0x78, 0x53, 0x73, 0x63, 0x66, 0x72, 0x66, 0x35, 0x42, 0x6d, 0x72, + 0x4f, 0x44, 0x58, 0x66, 0x4b, 0x45, 0x56, 0x75, 0x2b, 0x6c, 0x56, 0x30, + 0x50, 0x4f, 0x4b, 0x61, 0x32, 0x4d, 0x71, 0x31, 0x57, 0x2f, 0x78, 0x50, + 0x74, 0x62, 0x41, 0x64, 0x30, 0x6a, 0x0a, 0x49, 0x61, 0x46, 0x59, 0x41, + 0x49, 0x37, 0x44, 0x30, 0x47, 0x6f, 0x54, 0x37, 0x52, 0x50, 0x6a, 0x45, + 0x69, 0x75, 0x41, 0x33, 0x47, 0x66, 0x6d, 0x6c, 0x62, 0x4c, 0x4e, 0x48, + 0x69, 0x4a, 0x75, 0x4b, 0x76, 0x68, 0x42, 0x31, 0x50, 0x4c, 0x4b, 0x46, + 0x41, 0x65, 0x4e, 0x69, 0x6c, 0x55, 0x53, 0x78, 0x6d, 0x6e, 0x31, 0x75, + 0x49, 0x5a, 0x6f, 0x4c, 0x31, 0x4e, 0x65, 0x73, 0x4e, 0x4b, 0x71, 0x0a, + 0x49, 0x63, 0x47, 0x59, 0x35, 0x6a, 0x44, 0x6a, 0x5a, 0x31, 0x58, 0x48, + 0x6d, 0x32, 0x36, 0x73, 0x47, 0x61, 0x68, 0x56, 0x70, 0x6b, 0x55, 0x47, + 0x30, 0x43, 0x4d, 0x36, 0x32, 0x2b, 0x74, 0x6c, 0x58, 0x53, 0x6f, 0x52, + 0x45, 0x66, 0x41, 0x37, 0x54, 0x38, 0x70, 0x74, 0x39, 0x44, 0x54, 0x45, + 0x63, 0x65, 0x54, 0x2f, 0x41, 0x46, 0x72, 0x32, 0x58, 0x4b, 0x34, 0x6a, + 0x59, 0x49, 0x56, 0x7a, 0x0a, 0x38, 0x65, 0x51, 0x51, 0x73, 0x53, 0x57, + 0x75, 0x31, 0x5a, 0x4b, 0x37, 0x45, 0x38, 0x45, 0x4d, 0x34, 0x44, 0x6e, + 0x61, 0x74, 0x44, 0x6c, 0x58, 0x74, 0x61, 0x73, 0x31, 0x71, 0x6e, 0x49, + 0x68, 0x4f, 0x34, 0x4d, 0x31, 0x35, 0x7a, 0x48, 0x66, 0x65, 0x69, 0x46, + 0x75, 0x75, 0x44, 0x49, 0x49, 0x66, 0x52, 0x30, 0x79, 0x6b, 0x52, 0x56, + 0x4b, 0x59, 0x6e, 0x4c, 0x50, 0x34, 0x33, 0x65, 0x68, 0x0a, 0x76, 0x4e, + 0x55, 0x52, 0x47, 0x33, 0x59, 0x42, 0x5a, 0x77, 0x6a, 0x67, 0x51, 0x51, + 0x76, 0x44, 0x36, 0x78, 0x56, 0x75, 0x2b, 0x4b, 0x51, 0x5a, 0x32, 0x61, + 0x4b, 0x72, 0x72, 0x2b, 0x49, 0x6e, 0x55, 0x6c, 0x59, 0x72, 0x41, 0x6f, + 0x6f, 0x73, 0x46, 0x43, 0x54, 0x35, 0x76, 0x30, 0x49, 0x43, 0x76, 0x79, + 0x62, 0x49, 0x78, 0x6f, 0x2f, 0x67, 0x62, 0x6a, 0x68, 0x39, 0x55, 0x79, + 0x33, 0x6c, 0x0a, 0x37, 0x5a, 0x69, 0x7a, 0x6c, 0x57, 0x4e, 0x6f, 0x66, + 0x2f, 0x6b, 0x31, 0x39, 0x4e, 0x2b, 0x49, 0x78, 0x57, 0x41, 0x31, 0x6b, + 0x73, 0x42, 0x38, 0x61, 0x52, 0x78, 0x68, 0x6c, 0x52, 0x62, 0x51, 0x36, + 0x39, 0x34, 0x4c, 0x72, 0x7a, 0x34, 0x45, 0x45, 0x45, 0x56, 0x6c, 0x57, + 0x46, 0x41, 0x34, 0x72, 0x30, 0x6a, 0x79, 0x57, 0x62, 0x59, 0x57, 0x38, + 0x6a, 0x77, 0x4e, 0x6b, 0x41, 0x4c, 0x47, 0x0a, 0x63, 0x43, 0x34, 0x42, + 0x72, 0x54, 0x77, 0x56, 0x31, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, + 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, + 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, + 0x0a, 0x42, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, + 0x45, 0x46, 0x67, 0x51, 0x55, 0x37, 0x65, 0x64, 0x76, 0x64, 0x6c, 0x71, + 0x2f, 0x59, 0x4f, 0x78, 0x4a, 0x57, 0x38, 0x61, 0x6c, 0x64, 0x37, 0x74, + 0x79, 0x46, 0x6e, 0x47, 0x62, 0x78, 0x44, 0x30, 0x77, 0x44, 0x51, 0x59, + 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, + 0x4c, 0x42, 0x51, 0x41, 0x44, 0x0a, 0x67, 0x67, 0x49, 0x42, 0x41, 0x4a, + 0x48, 0x66, 0x67, 0x44, 0x39, 0x44, 0x43, 0x58, 0x35, 0x78, 0x77, 0x76, + 0x66, 0x72, 0x73, 0x34, 0x69, 0x50, 0x34, 0x56, 0x47, 0x79, 0x76, 0x44, + 0x31, 0x31, 0x2b, 0x53, 0x68, 0x64, 0x79, 0x4c, 0x79, 0x5a, 0x6d, 0x33, + 0x74, 0x64, 0x71, 0x75, 0x58, 0x4b, 0x34, 0x51, 0x72, 0x33, 0x36, 0x4c, + 0x4c, 0x54, 0x6e, 0x39, 0x31, 0x6e, 0x4d, 0x58, 0x36, 0x36, 0x0a, 0x41, + 0x61, 0x72, 0x48, 0x61, 0x6b, 0x45, 0x37, 0x6b, 0x4e, 0x51, 0x49, 0x58, + 0x4c, 0x4a, 0x67, 0x61, 0x70, 0x44, 0x77, 0x79, 0x4d, 0x34, 0x44, 0x59, + 0x76, 0x6d, 0x4c, 0x37, 0x66, 0x74, 0x75, 0x4b, 0x74, 0x77, 0x47, 0x54, + 0x54, 0x77, 0x70, 0x44, 0x34, 0x6b, 0x57, 0x69, 0x6c, 0x68, 0x4d, 0x53, + 0x41, 0x2f, 0x6f, 0x68, 0x47, 0x48, 0x71, 0x50, 0x48, 0x4b, 0x6d, 0x64, + 0x2b, 0x52, 0x43, 0x0a, 0x72, 0x6f, 0x69, 0x6a, 0x51, 0x31, 0x68, 0x35, + 0x66, 0x71, 0x37, 0x4b, 0x70, 0x56, 0x4d, 0x4e, 0x71, 0x54, 0x31, 0x77, + 0x76, 0x53, 0x41, 0x5a, 0x59, 0x61, 0x52, 0x73, 0x4f, 0x50, 0x78, 0x44, + 0x4d, 0x75, 0x48, 0x42, 0x52, 0x2f, 0x2f, 0x34, 0x37, 0x50, 0x45, 0x52, + 0x49, 0x6a, 0x4b, 0x57, 0x6e, 0x4d, 0x4c, 0x32, 0x57, 0x32, 0x6d, 0x57, + 0x65, 0x79, 0x41, 0x4d, 0x51, 0x30, 0x47, 0x61, 0x0a, 0x57, 0x2f, 0x5a, + 0x5a, 0x47, 0x59, 0x6a, 0x65, 0x56, 0x59, 0x67, 0x33, 0x55, 0x51, 0x74, + 0x34, 0x58, 0x41, 0x6f, 0x65, 0x6f, 0x30, 0x4c, 0x39, 0x78, 0x35, 0x32, + 0x49, 0x44, 0x38, 0x44, 0x79, 0x65, 0x41, 0x49, 0x6b, 0x56, 0x4a, 0x4f, + 0x76, 0x69, 0x59, 0x65, 0x49, 0x79, 0x55, 0x71, 0x41, 0x48, 0x65, 0x72, + 0x51, 0x62, 0x6a, 0x35, 0x68, 0x4c, 0x6a, 0x61, 0x37, 0x4e, 0x51, 0x34, + 0x6e, 0x0a, 0x6c, 0x76, 0x31, 0x6d, 0x4e, 0x44, 0x74, 0x68, 0x63, 0x6e, + 0x50, 0x78, 0x46, 0x6c, 0x78, 0x48, 0x42, 0x6c, 0x52, 0x4a, 0x41, 0x48, + 0x70, 0x59, 0x45, 0x72, 0x41, 0x4b, 0x37, 0x34, 0x58, 0x39, 0x73, 0x62, + 0x67, 0x7a, 0x64, 0x57, 0x71, 0x54, 0x48, 0x42, 0x4c, 0x6d, 0x59, 0x46, + 0x35, 0x76, 0x48, 0x58, 0x2f, 0x4a, 0x48, 0x79, 0x50, 0x4c, 0x68, 0x47, + 0x47, 0x66, 0x48, 0x6f, 0x4a, 0x45, 0x0a, 0x2b, 0x56, 0x2b, 0x74, 0x59, + 0x6c, 0x55, 0x6b, 0x6d, 0x6c, 0x4b, 0x59, 0x37, 0x56, 0x48, 0x6e, 0x6f, + 0x58, 0x36, 0x58, 0x4f, 0x75, 0x59, 0x76, 0x48, 0x78, 0x48, 0x61, 0x55, + 0x34, 0x41, 0x73, 0x68, 0x5a, 0x36, 0x72, 0x4e, 0x52, 0x44, 0x62, 0x49, + 0x6c, 0x39, 0x71, 0x78, 0x56, 0x36, 0x58, 0x55, 0x2f, 0x49, 0x79, 0x41, + 0x67, 0x6b, 0x77, 0x6f, 0x31, 0x6a, 0x77, 0x44, 0x51, 0x48, 0x56, 0x0a, + 0x63, 0x73, 0x61, 0x78, 0x66, 0x47, 0x6c, 0x37, 0x77, 0x2f, 0x55, 0x32, + 0x52, 0x63, 0x78, 0x68, 0x62, 0x6c, 0x35, 0x4d, 0x6c, 0x4d, 0x56, 0x65, + 0x72, 0x75, 0x67, 0x4f, 0x58, 0x6f, 0x75, 0x2f, 0x39, 0x38, 0x33, 0x67, + 0x37, 0x61, 0x45, 0x4f, 0x47, 0x7a, 0x50, 0x75, 0x56, 0x42, 0x6a, 0x2b, + 0x44, 0x37, 0x37, 0x76, 0x66, 0x6f, 0x52, 0x72, 0x51, 0x2b, 0x4e, 0x77, + 0x6d, 0x4e, 0x74, 0x64, 0x0a, 0x64, 0x62, 0x49, 0x4e, 0x57, 0x51, 0x65, + 0x46, 0x46, 0x53, 0x4d, 0x35, 0x31, 0x76, 0x48, 0x66, 0x71, 0x53, 0x59, + 0x50, 0x31, 0x6b, 0x6a, 0x48, 0x73, 0x36, 0x59, 0x69, 0x39, 0x54, 0x4d, + 0x33, 0x57, 0x70, 0x56, 0x48, 0x6e, 0x33, 0x75, 0x36, 0x47, 0x42, 0x56, + 0x76, 0x2f, 0x39, 0x59, 0x55, 0x5a, 0x49, 0x4e, 0x4a, 0x30, 0x67, 0x70, + 0x6e, 0x49, 0x64, 0x73, 0x50, 0x4e, 0x57, 0x4e, 0x67, 0x0a, 0x4b, 0x43, + 0x4c, 0x6a, 0x73, 0x5a, 0x57, 0x44, 0x7a, 0x59, 0x57, 0x6d, 0x33, 0x53, + 0x38, 0x50, 0x35, 0x32, 0x64, 0x53, 0x62, 0x72, 0x73, 0x76, 0x68, 0x58, + 0x7a, 0x31, 0x53, 0x6e, 0x50, 0x6e, 0x78, 0x54, 0x37, 0x41, 0x76, 0x53, + 0x45, 0x53, 0x42, 0x54, 0x2f, 0x38, 0x74, 0x77, 0x4e, 0x4a, 0x41, 0x6c, + 0x76, 0x49, 0x4a, 0x65, 0x62, 0x69, 0x56, 0x44, 0x6a, 0x31, 0x65, 0x59, + 0x65, 0x4d, 0x0a, 0x48, 0x56, 0x4f, 0x79, 0x54, 0x6f, 0x56, 0x37, 0x42, + 0x6a, 0x6a, 0x48, 0x4c, 0x50, 0x6a, 0x34, 0x73, 0x48, 0x4b, 0x4e, 0x4a, + 0x65, 0x56, 0x33, 0x55, 0x76, 0x51, 0x44, 0x48, 0x45, 0x69, 0x6d, 0x55, + 0x46, 0x2b, 0x49, 0x49, 0x44, 0x42, 0x75, 0x38, 0x6f, 0x4a, 0x44, 0x71, + 0x7a, 0x32, 0x58, 0x68, 0x4f, 0x64, 0x54, 0x2b, 0x79, 0x48, 0x42, 0x54, + 0x77, 0x38, 0x69, 0x6d, 0x6f, 0x61, 0x34, 0x0a, 0x57, 0x53, 0x72, 0x32, + 0x52, 0x7a, 0x30, 0x5a, 0x69, 0x43, 0x33, 0x6f, 0x68, 0x65, 0x47, 0x65, + 0x37, 0x49, 0x55, 0x49, 0x61, 0x72, 0x46, 0x73, 0x4e, 0x4d, 0x6b, 0x64, + 0x37, 0x45, 0x67, 0x72, 0x4f, 0x33, 0x6a, 0x74, 0x5a, 0x73, 0x53, 0x4f, + 0x65, 0x57, 0x6d, 0x44, 0x33, 0x6e, 0x2b, 0x4d, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, + 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, 0x20, 0x47, 0x33, 0x20, 0x4f, + 0x3d, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x51, 0x75, 0x6f, 0x56, + 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x20, 0x33, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x51, 0x75, 0x6f, 0x56, + 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, + 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x51, + 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x33, 0x20, 0x47, 0x33, 0x22, 0x0a, 0x23, 0x20, + 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x32, 0x36, 0x38, 0x30, + 0x39, 0x30, 0x37, 0x36, 0x31, 0x31, 0x37, 0x30, 0x34, 0x36, 0x31, 0x34, + 0x36, 0x32, 0x34, 0x36, 0x33, 0x39, 0x39, 0x35, 0x39, 0x35, 0x32, 0x31, + 0x35, 0x37, 0x33, 0x32, 0x37, 0x32, 0x34, 0x32, 0x31, 0x33, 0x37, 0x30, + 0x38, 0x39, 0x32, 0x33, 0x39, 0x35, 0x38, 0x31, 0x0a, 0x23, 0x20, 0x4d, + 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x66, 0x3a, 0x37, 0x64, 0x3a, 0x62, 0x39, + 0x3a, 0x61, 0x64, 0x3a, 0x35, 0x34, 0x3a, 0x36, 0x66, 0x3a, 0x36, 0x38, + 0x3a, 0x61, 0x31, 0x3a, 0x64, 0x66, 0x3a, 0x38, 0x39, 0x3a, 0x35, 0x37, + 0x3a, 0x30, 0x33, 0x3a, 0x39, 0x37, 0x3a, 0x34, 0x33, 0x3a, 0x62, 0x30, + 0x3a, 0x64, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x34, 0x38, 0x3a, 0x31, 0x32, 0x3a, 0x62, 0x64, 0x3a, 0x39, 0x32, 0x3a, + 0x33, 0x63, 0x3a, 0x61, 0x38, 0x3a, 0x63, 0x34, 0x3a, 0x33, 0x39, 0x3a, + 0x30, 0x36, 0x3a, 0x65, 0x37, 0x3a, 0x33, 0x30, 0x3a, 0x36, 0x64, 0x3a, + 0x32, 0x37, 0x3a, 0x39, 0x36, 0x3a, 0x65, 0x36, 0x3a, 0x61, 0x34, 0x3a, + 0x63, 0x66, 0x3a, 0x32, 0x32, 0x3a, 0x32, 0x65, 0x3a, 0x37, 0x64, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x38, + 0x3a, 0x65, 0x66, 0x3a, 0x38, 0x31, 0x3a, 0x64, 0x65, 0x3a, 0x32, 0x30, + 0x3a, 0x32, 0x65, 0x3a, 0x62, 0x30, 0x3a, 0x31, 0x38, 0x3a, 0x34, 0x35, + 0x3a, 0x32, 0x65, 0x3a, 0x34, 0x33, 0x3a, 0x66, 0x38, 0x3a, 0x36, 0x34, + 0x3a, 0x37, 0x32, 0x3a, 0x35, 0x63, 0x3a, 0x65, 0x61, 0x3a, 0x35, 0x66, + 0x3a, 0x62, 0x64, 0x3a, 0x31, 0x66, 0x3a, 0x63, 0x32, 0x3a, 0x64, 0x39, + 0x3a, 0x64, 0x32, 0x3a, 0x30, 0x35, 0x3a, 0x37, 0x33, 0x3a, 0x30, 0x37, + 0x3a, 0x30, 0x39, 0x3a, 0x63, 0x35, 0x3a, 0x64, 0x38, 0x3a, 0x62, 0x38, + 0x3a, 0x36, 0x39, 0x3a, 0x30, 0x66, 0x3a, 0x34, 0x36, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x59, 0x44, 0x43, 0x43, 0x41, 0x30, + 0x69, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x4c, 0x76, + 0x57, 0x62, 0x41, 0x69, 0x69, 0x6e, 0x32, 0x33, 0x72, 0x2f, 0x31, 0x61, + 0x4f, 0x70, 0x37, 0x72, 0x30, 0x44, 0x6f, 0x4d, 0x38, 0x53, 0x61, 0x68, + 0x30, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x0a, 0x42, 0x51, 0x41, 0x77, 0x53, + 0x44, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x68, 0x4d, 0x43, 0x51, 0x6b, 0x30, 0x78, 0x47, 0x54, 0x41, 0x58, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x45, 0x46, 0x46, 0x31, 0x62, + 0x31, 0x5a, 0x68, 0x5a, 0x47, 0x6c, 0x7a, 0x49, 0x45, 0x78, 0x70, 0x62, + 0x57, 0x6c, 0x30, 0x5a, 0x57, 0x51, 0x78, 0x48, 0x6a, 0x41, 0x63, 0x0a, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x46, 0x56, 0x46, 0x31, + 0x62, 0x31, 0x5a, 0x68, 0x5a, 0x47, 0x6c, 0x7a, 0x49, 0x46, 0x4a, 0x76, + 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4d, 0x79, 0x42, 0x48, + 0x4d, 0x7a, 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4d, 0x6a, 0x41, 0x78, + 0x4d, 0x54, 0x49, 0x79, 0x4d, 0x44, 0x49, 0x32, 0x4d, 0x7a, 0x4a, 0x61, + 0x46, 0x77, 0x30, 0x30, 0x0a, 0x4d, 0x6a, 0x41, 0x78, 0x4d, 0x54, 0x49, + 0x79, 0x4d, 0x44, 0x49, 0x32, 0x4d, 0x7a, 0x4a, 0x61, 0x4d, 0x45, 0x67, + 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, + 0x54, 0x41, 0x6b, 0x4a, 0x4e, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x42, 0x52, 0x64, 0x57, 0x39, + 0x57, 0x59, 0x57, 0x52, 0x70, 0x63, 0x79, 0x42, 0x4d, 0x0a, 0x61, 0x57, + 0x31, 0x70, 0x64, 0x47, 0x56, 0x6b, 0x4d, 0x52, 0x34, 0x77, 0x48, 0x41, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x56, 0x52, 0x64, 0x57, + 0x39, 0x57, 0x59, 0x57, 0x52, 0x70, 0x63, 0x79, 0x42, 0x53, 0x62, 0x32, + 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x44, 0x4d, 0x67, 0x52, 0x7a, + 0x4d, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, + 0x71, 0x47, 0x0a, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, + 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, + 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51, 0x43, 0x7a, 0x79, + 0x77, 0x34, 0x51, 0x5a, 0x34, 0x37, 0x71, 0x46, 0x4a, 0x65, 0x6e, 0x4d, + 0x69, 0x6f, 0x4b, 0x56, 0x6a, 0x5a, 0x2f, 0x61, 0x45, 0x7a, 0x48, 0x73, + 0x32, 0x38, 0x36, 0x49, 0x78, 0x53, 0x52, 0x0a, 0x2f, 0x78, 0x6c, 0x2f, + 0x70, 0x63, 0x71, 0x73, 0x37, 0x72, 0x4e, 0x32, 0x6e, 0x58, 0x72, 0x70, + 0x69, 0x78, 0x75, 0x72, 0x61, 0x7a, 0x48, 0x62, 0x2b, 0x67, 0x74, 0x54, + 0x54, 0x4b, 0x2f, 0x46, 0x70, 0x52, 0x70, 0x35, 0x50, 0x49, 0x70, 0x4d, + 0x2f, 0x36, 0x7a, 0x66, 0x4a, 0x64, 0x35, 0x4f, 0x32, 0x59, 0x49, 0x79, + 0x43, 0x30, 0x54, 0x65, 0x79, 0x74, 0x75, 0x4d, 0x72, 0x4b, 0x4e, 0x75, + 0x0a, 0x46, 0x6f, 0x4d, 0x37, 0x70, 0x6d, 0x52, 0x4c, 0x4d, 0x6f, 0x6e, + 0x37, 0x46, 0x68, 0x59, 0x34, 0x66, 0x75, 0x74, 0x44, 0x34, 0x74, 0x4e, + 0x30, 0x53, 0x73, 0x4a, 0x69, 0x43, 0x6e, 0x4d, 0x4b, 0x33, 0x55, 0x6d, + 0x7a, 0x56, 0x39, 0x4b, 0x77, 0x43, 0x6f, 0x57, 0x64, 0x63, 0x54, 0x7a, + 0x65, 0x6f, 0x38, 0x76, 0x41, 0x4d, 0x76, 0x4d, 0x42, 0x4f, 0x53, 0x42, + 0x44, 0x47, 0x7a, 0x58, 0x52, 0x0a, 0x55, 0x37, 0x4f, 0x78, 0x37, 0x73, + 0x57, 0x54, 0x61, 0x59, 0x49, 0x2b, 0x46, 0x72, 0x55, 0x6f, 0x52, 0x71, + 0x48, 0x65, 0x36, 0x6f, 0x6b, 0x4a, 0x37, 0x55, 0x4f, 0x34, 0x42, 0x55, + 0x61, 0x4b, 0x68, 0x76, 0x56, 0x5a, 0x52, 0x37, 0x34, 0x62, 0x62, 0x77, + 0x45, 0x68, 0x45, 0x4c, 0x6e, 0x39, 0x71, 0x64, 0x49, 0x6f, 0x79, 0x68, + 0x41, 0x35, 0x43, 0x63, 0x6f, 0x54, 0x4e, 0x73, 0x2b, 0x63, 0x0a, 0x72, + 0x61, 0x31, 0x41, 0x64, 0x48, 0x6b, 0x72, 0x41, 0x6a, 0x38, 0x30, 0x2f, + 0x2f, 0x6f, 0x67, 0x61, 0x58, 0x33, 0x54, 0x37, 0x6d, 0x48, 0x31, 0x75, + 0x72, 0x50, 0x6e, 0x4d, 0x4e, 0x41, 0x33, 0x49, 0x34, 0x5a, 0x79, 0x59, + 0x55, 0x55, 0x70, 0x53, 0x46, 0x6c, 0x6f, 0x62, 0x33, 0x65, 0x6d, 0x4c, + 0x6f, 0x47, 0x2b, 0x42, 0x30, 0x31, 0x76, 0x72, 0x38, 0x37, 0x45, 0x52, + 0x52, 0x4f, 0x52, 0x0a, 0x46, 0x48, 0x41, 0x47, 0x6a, 0x78, 0x2b, 0x66, + 0x2b, 0x49, 0x64, 0x70, 0x73, 0x51, 0x37, 0x76, 0x77, 0x34, 0x6b, 0x5a, + 0x36, 0x2b, 0x6f, 0x63, 0x59, 0x66, 0x78, 0x36, 0x62, 0x49, 0x72, 0x63, + 0x31, 0x67, 0x4d, 0x4c, 0x6e, 0x69, 0x61, 0x36, 0x45, 0x74, 0x33, 0x55, + 0x56, 0x44, 0x6d, 0x72, 0x4a, 0x71, 0x4d, 0x7a, 0x36, 0x6e, 0x57, 0x42, + 0x32, 0x69, 0x33, 0x4e, 0x44, 0x30, 0x2f, 0x6b, 0x0a, 0x41, 0x39, 0x48, + 0x76, 0x46, 0x5a, 0x63, 0x62, 0x61, 0x35, 0x44, 0x46, 0x41, 0x70, 0x43, + 0x54, 0x5a, 0x67, 0x49, 0x68, 0x73, 0x55, 0x66, 0x65, 0x69, 0x35, 0x70, + 0x4b, 0x67, 0x4c, 0x6c, 0x56, 0x6a, 0x37, 0x57, 0x69, 0x4c, 0x38, 0x44, + 0x57, 0x4d, 0x32, 0x66, 0x61, 0x66, 0x73, 0x53, 0x6e, 0x74, 0x41, 0x52, + 0x45, 0x36, 0x30, 0x66, 0x37, 0x35, 0x6c, 0x69, 0x35, 0x39, 0x77, 0x7a, + 0x77, 0x0a, 0x65, 0x79, 0x75, 0x78, 0x77, 0x48, 0x41, 0x70, 0x77, 0x30, + 0x42, 0x69, 0x4c, 0x54, 0x74, 0x49, 0x61, 0x64, 0x77, 0x6a, 0x50, 0x45, + 0x6a, 0x72, 0x65, 0x77, 0x6c, 0x35, 0x71, 0x57, 0x33, 0x61, 0x71, 0x44, + 0x43, 0x59, 0x7a, 0x34, 0x42, 0x79, 0x41, 0x34, 0x69, 0x6d, 0x57, 0x30, + 0x61, 0x75, 0x63, 0x6e, 0x6c, 0x38, 0x43, 0x41, 0x4d, 0x68, 0x5a, 0x61, + 0x36, 0x33, 0x34, 0x52, 0x79, 0x6c, 0x0a, 0x73, 0x53, 0x71, 0x69, 0x4d, + 0x64, 0x35, 0x6d, 0x42, 0x50, 0x66, 0x41, 0x64, 0x4f, 0x68, 0x78, 0x33, + 0x76, 0x38, 0x39, 0x57, 0x63, 0x79, 0x57, 0x4a, 0x68, 0x4b, 0x4c, 0x68, + 0x5a, 0x56, 0x58, 0x47, 0x71, 0x74, 0x72, 0x64, 0x51, 0x74, 0x45, 0x50, + 0x52, 0x45, 0x6f, 0x50, 0x48, 0x74, 0x68, 0x74, 0x2b, 0x4b, 0x50, 0x5a, + 0x30, 0x2f, 0x6c, 0x37, 0x44, 0x78, 0x4d, 0x59, 0x49, 0x42, 0x70, 0x0a, + 0x56, 0x7a, 0x67, 0x65, 0x41, 0x56, 0x75, 0x4e, 0x56, 0x65, 0x6a, 0x48, + 0x33, 0x38, 0x44, 0x4d, 0x64, 0x79, 0x4d, 0x30, 0x53, 0x58, 0x56, 0x38, + 0x39, 0x70, 0x67, 0x52, 0x36, 0x79, 0x33, 0x65, 0x37, 0x55, 0x45, 0x75, + 0x46, 0x41, 0x55, 0x43, 0x66, 0x2b, 0x44, 0x2b, 0x49, 0x4f, 0x73, 0x31, + 0x35, 0x78, 0x47, 0x73, 0x49, 0x73, 0x35, 0x58, 0x50, 0x64, 0x37, 0x4a, + 0x4d, 0x47, 0x30, 0x51, 0x0a, 0x41, 0x34, 0x58, 0x4e, 0x38, 0x66, 0x2b, + 0x4d, 0x46, 0x72, 0x58, 0x42, 0x73, 0x6a, 0x36, 0x49, 0x62, 0x47, 0x42, + 0x2f, 0x6b, 0x45, 0x2b, 0x56, 0x39, 0x2f, 0x59, 0x74, 0x72, 0x51, 0x45, + 0x35, 0x42, 0x77, 0x54, 0x36, 0x64, 0x59, 0x42, 0x39, 0x76, 0x30, 0x6c, + 0x51, 0x37, 0x65, 0x2f, 0x4a, 0x78, 0x48, 0x77, 0x63, 0x36, 0x34, 0x42, + 0x2b, 0x32, 0x37, 0x62, 0x51, 0x33, 0x52, 0x50, 0x2b, 0x0a, 0x79, 0x64, + 0x4f, 0x63, 0x31, 0x37, 0x4b, 0x58, 0x71, 0x51, 0x49, 0x44, 0x41, 0x51, + 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x50, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, + 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, + 0x49, 0x42, 0x0a, 0x42, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x78, 0x68, 0x66, 0x51, 0x76, + 0x4b, 0x6a, 0x71, 0x41, 0x6b, 0x50, 0x79, 0x47, 0x77, 0x61, 0x5a, 0x58, + 0x53, 0x75, 0x51, 0x49, 0x4c, 0x6e, 0x58, 0x6e, 0x4f, 0x51, 0x77, 0x44, + 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, + 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, 0x0a, 0x67, 0x67, 0x49, 0x42, + 0x41, 0x44, 0x52, 0x68, 0x32, 0x56, 0x61, 0x31, 0x45, 0x6f, 0x64, 0x56, + 0x54, 0x64, 0x32, 0x6a, 0x4e, 0x54, 0x46, 0x47, 0x75, 0x36, 0x51, 0x48, + 0x63, 0x72, 0x78, 0x66, 0x59, 0x57, 0x4c, 0x6f, 0x70, 0x66, 0x73, 0x4c, + 0x4e, 0x37, 0x45, 0x38, 0x74, 0x72, 0x50, 0x36, 0x4b, 0x5a, 0x31, 0x2f, + 0x41, 0x76, 0x57, 0x6b, 0x79, 0x61, 0x69, 0x54, 0x74, 0x33, 0x70, 0x78, + 0x0a, 0x4b, 0x47, 0x6d, 0x50, 0x63, 0x2b, 0x46, 0x53, 0x6b, 0x4e, 0x72, + 0x56, 0x76, 0x6a, 0x72, 0x6c, 0x74, 0x33, 0x5a, 0x71, 0x56, 0x6f, 0x41, + 0x68, 0x33, 0x31, 0x33, 0x6d, 0x36, 0x54, 0x71, 0x65, 0x35, 0x54, 0x37, + 0x32, 0x6f, 0x6d, 0x6e, 0x48, 0x4b, 0x67, 0x71, 0x77, 0x47, 0x45, 0x66, + 0x63, 0x49, 0x48, 0x42, 0x39, 0x55, 0x71, 0x4d, 0x2b, 0x57, 0x58, 0x7a, + 0x42, 0x75, 0x73, 0x6e, 0x49, 0x0a, 0x46, 0x55, 0x42, 0x68, 0x79, 0x6e, + 0x4c, 0x57, 0x63, 0x4b, 0x7a, 0x53, 0x74, 0x2f, 0x41, 0x63, 0x35, 0x49, + 0x59, 0x70, 0x38, 0x4d, 0x37, 0x76, 0x61, 0x47, 0x50, 0x51, 0x74, 0x53, + 0x43, 0x4b, 0x46, 0x57, 0x47, 0x61, 0x66, 0x6f, 0x61, 0x59, 0x74, 0x4d, + 0x6e, 0x43, 0x64, 0x76, 0x76, 0x4d, 0x75, 0x6a, 0x41, 0x57, 0x7a, 0x4b, + 0x4e, 0x68, 0x78, 0x6e, 0x51, 0x54, 0x35, 0x57, 0x76, 0x76, 0x0a, 0x6f, + 0x78, 0x58, 0x71, 0x41, 0x2f, 0x34, 0x54, 0x69, 0x32, 0x54, 0x6b, 0x30, + 0x38, 0x48, 0x53, 0x36, 0x49, 0x54, 0x37, 0x53, 0x64, 0x45, 0x51, 0x54, + 0x58, 0x6c, 0x6d, 0x36, 0x36, 0x72, 0x39, 0x39, 0x49, 0x30, 0x78, 0x48, + 0x6e, 0x41, 0x55, 0x72, 0x64, 0x7a, 0x65, 0x5a, 0x78, 0x4e, 0x4d, 0x67, + 0x52, 0x56, 0x68, 0x76, 0x4c, 0x66, 0x5a, 0x6b, 0x58, 0x64, 0x78, 0x47, + 0x59, 0x46, 0x67, 0x0a, 0x75, 0x2f, 0x42, 0x59, 0x70, 0x62, 0x57, 0x63, + 0x43, 0x2f, 0x65, 0x50, 0x49, 0x6c, 0x55, 0x6e, 0x77, 0x45, 0x73, 0x42, + 0x62, 0x54, 0x75, 0x5a, 0x44, 0x64, 0x51, 0x64, 0x6d, 0x32, 0x4e, 0x6e, + 0x4c, 0x39, 0x44, 0x75, 0x44, 0x63, 0x70, 0x6d, 0x76, 0x4a, 0x52, 0x50, + 0x70, 0x71, 0x33, 0x74, 0x2f, 0x4f, 0x35, 0x6a, 0x72, 0x46, 0x63, 0x2f, + 0x5a, 0x53, 0x58, 0x50, 0x73, 0x6f, 0x61, 0x50, 0x0a, 0x30, 0x41, 0x6a, + 0x2f, 0x75, 0x48, 0x59, 0x55, 0x62, 0x74, 0x37, 0x6c, 0x4a, 0x2b, 0x79, + 0x72, 0x65, 0x4c, 0x56, 0x54, 0x75, 0x62, 0x59, 0x2f, 0x36, 0x43, 0x44, + 0x35, 0x30, 0x71, 0x69, 0x2b, 0x59, 0x55, 0x62, 0x4b, 0x68, 0x34, 0x79, + 0x45, 0x38, 0x2f, 0x6e, 0x78, 0x6f, 0x47, 0x69, 0x62, 0x49, 0x68, 0x36, + 0x42, 0x4a, 0x70, 0x73, 0x51, 0x42, 0x4a, 0x46, 0x78, 0x77, 0x41, 0x59, + 0x66, 0x0a, 0x33, 0x4b, 0x44, 0x54, 0x75, 0x56, 0x61, 0x6e, 0x34, 0x35, + 0x67, 0x74, 0x66, 0x34, 0x4f, 0x64, 0x33, 0x34, 0x77, 0x72, 0x6e, 0x44, + 0x4b, 0x4f, 0x4d, 0x70, 0x54, 0x77, 0x41, 0x54, 0x77, 0x69, 0x4b, 0x70, + 0x39, 0x44, 0x77, 0x69, 0x37, 0x44, 0x6d, 0x44, 0x6b, 0x48, 0x4f, 0x48, + 0x76, 0x38, 0x58, 0x67, 0x42, 0x43, 0x48, 0x2f, 0x4d, 0x79, 0x4a, 0x6e, + 0x6d, 0x44, 0x68, 0x50, 0x62, 0x6c, 0x0a, 0x38, 0x4d, 0x46, 0x52, 0x45, + 0x73, 0x41, 0x4c, 0x48, 0x67, 0x51, 0x6a, 0x44, 0x46, 0x53, 0x6c, 0x54, + 0x43, 0x39, 0x4a, 0x78, 0x55, 0x72, 0x52, 0x74, 0x6d, 0x35, 0x67, 0x44, + 0x57, 0x76, 0x38, 0x61, 0x34, 0x75, 0x46, 0x4a, 0x47, 0x53, 0x33, 0x69, + 0x51, 0x36, 0x72, 0x4a, 0x55, 0x64, 0x62, 0x50, 0x4d, 0x39, 0x2b, 0x53, + 0x62, 0x33, 0x48, 0x36, 0x51, 0x72, 0x47, 0x32, 0x76, 0x64, 0x2b, 0x0a, + 0x44, 0x68, 0x63, 0x49, 0x30, 0x30, 0x69, 0x58, 0x30, 0x48, 0x47, 0x53, + 0x38, 0x41, 0x38, 0x35, 0x50, 0x6a, 0x52, 0x71, 0x48, 0x48, 0x33, 0x59, + 0x38, 0x69, 0x4b, 0x75, 0x75, 0x32, 0x6e, 0x30, 0x4d, 0x37, 0x53, 0x6d, + 0x53, 0x46, 0x58, 0x52, 0x44, 0x77, 0x34, 0x6d, 0x36, 0x4f, 0x79, 0x32, + 0x43, 0x79, 0x32, 0x6e, 0x68, 0x54, 0x58, 0x4e, 0x2f, 0x56, 0x6e, 0x49, + 0x6e, 0x39, 0x48, 0x4e, 0x0a, 0x50, 0x6c, 0x6f, 0x70, 0x4e, 0x4c, 0x6b, + 0x39, 0x68, 0x4d, 0x36, 0x78, 0x5a, 0x64, 0x52, 0x5a, 0x6b, 0x5a, 0x46, + 0x57, 0x64, 0x53, 0x48, 0x42, 0x64, 0x35, 0x37, 0x35, 0x65, 0x75, 0x46, + 0x67, 0x6e, 0x64, 0x4f, 0x74, 0x42, 0x42, 0x6a, 0x30, 0x66, 0x4f, 0x74, + 0x65, 0x6b, 0x34, 0x39, 0x54, 0x53, 0x69, 0x49, 0x70, 0x2b, 0x45, 0x67, + 0x72, 0x50, 0x6b, 0x32, 0x47, 0x72, 0x46, 0x74, 0x2f, 0x0a, 0x79, 0x77, + 0x61, 0x5a, 0x57, 0x57, 0x44, 0x59, 0x57, 0x47, 0x57, 0x56, 0x6a, 0x55, + 0x54, 0x52, 0x39, 0x33, 0x39, 0x2b, 0x4a, 0x33, 0x39, 0x39, 0x72, 0x6f, + 0x44, 0x31, 0x42, 0x30, 0x79, 0x32, 0x50, 0x70, 0x78, 0x78, 0x56, 0x4a, + 0x6b, 0x45, 0x53, 0x2f, 0x31, 0x59, 0x2b, 0x5a, 0x6a, 0x30, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, + 0x41, 0x73, 0x73, 0x75, 0x72, 0x65, 0x64, 0x20, 0x49, 0x44, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x44, 0x69, 0x67, + 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, + 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69, + 0x43, 0x65, 0x72, 0x74, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x65, 0x64, + 0x20, 0x49, 0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x32, 0x20, + 0x4f, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, + 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, + 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, + 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x44, 0x69, 0x67, + 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x65, + 0x64, 0x20, 0x49, 0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x32, + 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, + 0x31, 0x35, 0x33, 0x38, 0x35, 0x33, 0x34, 0x38, 0x31, 0x36, 0x30, 0x38, + 0x34, 0x30, 0x32, 0x31, 0x33, 0x39, 0x33, 0x38, 0x36, 0x34, 0x33, 0x30, + 0x33, 0x33, 0x36, 0x32, 0x30, 0x38, 0x39, 0x34, 0x39, 0x30, 0x35, 0x34, + 0x31, 0x39, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x32, + 0x3a, 0x33, 0x38, 0x3a, 0x62, 0x39, 0x3a, 0x66, 0x38, 0x3a, 0x36, 0x33, + 0x3a, 0x32, 0x34, 0x3a, 0x38, 0x32, 0x3a, 0x36, 0x35, 0x3a, 0x32, 0x63, + 0x3a, 0x35, 0x37, 0x3a, 0x33, 0x33, 0x3a, 0x65, 0x36, 0x3a, 0x66, 0x65, + 0x3a, 0x38, 0x31, 0x3a, 0x38, 0x66, 0x3a, 0x39, 0x64, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x31, 0x3a, 0x34, 0x62, 0x3a, + 0x34, 0x38, 0x3a, 0x64, 0x39, 0x3a, 0x34, 0x33, 0x3a, 0x65, 0x65, 0x3a, + 0x30, 0x61, 0x3a, 0x30, 0x65, 0x3a, 0x34, 0x30, 0x3a, 0x39, 0x30, 0x3a, + 0x34, 0x66, 0x3a, 0x33, 0x63, 0x3a, 0x65, 0x30, 0x3a, 0x61, 0x34, 0x3a, + 0x63, 0x30, 0x3a, 0x39, 0x31, 0x3a, 0x39, 0x33, 0x3a, 0x35, 0x31, 0x3a, + 0x35, 0x64, 0x3a, 0x33, 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x64, 0x3a, 0x30, 0x35, 0x3a, 0x65, 0x62, + 0x3a, 0x62, 0x36, 0x3a, 0x38, 0x32, 0x3a, 0x33, 0x33, 0x3a, 0x39, 0x66, + 0x3a, 0x38, 0x63, 0x3a, 0x39, 0x34, 0x3a, 0x35, 0x31, 0x3a, 0x65, 0x65, + 0x3a, 0x30, 0x39, 0x3a, 0x34, 0x65, 0x3a, 0x65, 0x62, 0x3a, 0x66, 0x65, + 0x3a, 0x66, 0x61, 0x3a, 0x37, 0x39, 0x3a, 0x35, 0x33, 0x3a, 0x61, 0x31, + 0x3a, 0x31, 0x34, 0x3a, 0x65, 0x64, 0x3a, 0x62, 0x32, 0x3a, 0x66, 0x34, + 0x3a, 0x34, 0x39, 0x3a, 0x34, 0x39, 0x3a, 0x34, 0x35, 0x3a, 0x32, 0x66, + 0x3a, 0x61, 0x62, 0x3a, 0x37, 0x64, 0x3a, 0x32, 0x66, 0x3a, 0x63, 0x31, + 0x3a, 0x38, 0x35, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, + 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, + 0x6c, 0x6a, 0x43, 0x43, 0x41, 0x6e, 0x36, 0x67, 0x41, 0x77, 0x49, 0x42, + 0x41, 0x67, 0x49, 0x51, 0x43, 0x35, 0x4d, 0x63, 0x4f, 0x74, 0x59, 0x35, + 0x5a, 0x2b, 0x70, 0x6e, 0x49, 0x37, 0x2f, 0x44, 0x72, 0x35, 0x72, 0x30, + 0x53, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, + 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x6c, + 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x56, 0x4d, 0x42, 0x4d, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4d, 0x52, 0x47, 0x6c, + 0x6e, 0x61, 0x55, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x67, 0x53, 0x57, 0x35, + 0x6a, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x4c, 0x45, 0x78, 0x42, 0x33, 0x0a, 0x64, 0x33, 0x63, 0x75, 0x5a, 0x47, + 0x6c, 0x6e, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x75, 0x59, 0x32, + 0x39, 0x74, 0x4d, 0x53, 0x51, 0x77, 0x49, 0x67, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x44, 0x45, 0x78, 0x74, 0x45, 0x61, 0x57, 0x64, 0x70, 0x51, 0x32, + 0x56, 0x79, 0x64, 0x43, 0x42, 0x42, 0x63, 0x33, 0x4e, 0x31, 0x63, 0x6d, + 0x56, 0x6b, 0x49, 0x45, 0x6c, 0x45, 0x49, 0x46, 0x4a, 0x76, 0x0a, 0x62, + 0x33, 0x51, 0x67, 0x52, 0x7a, 0x49, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, + 0x54, 0x4d, 0x77, 0x4f, 0x44, 0x41, 0x78, 0x4d, 0x54, 0x49, 0x77, 0x4d, + 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x67, 0x77, 0x4d, + 0x54, 0x45, 0x31, 0x4d, 0x54, 0x49, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, + 0x6a, 0x42, 0x6c, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x47, 0x0a, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x56, + 0x4d, 0x42, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4d, + 0x52, 0x47, 0x6c, 0x6e, 0x61, 0x55, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x67, + 0x53, 0x57, 0x35, 0x6a, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x42, 0x33, 0x64, 0x33, 0x63, 0x75, + 0x5a, 0x47, 0x6c, 0x6e, 0x61, 0x57, 0x4e, 0x6c, 0x0a, 0x63, 0x6e, 0x51, + 0x75, 0x59, 0x32, 0x39, 0x74, 0x4d, 0x53, 0x51, 0x77, 0x49, 0x67, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x74, 0x45, 0x61, 0x57, 0x64, + 0x70, 0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x42, 0x42, 0x63, 0x33, 0x4e, + 0x31, 0x63, 0x6d, 0x56, 0x6b, 0x49, 0x45, 0x6c, 0x45, 0x49, 0x46, 0x4a, + 0x76, 0x62, 0x33, 0x51, 0x67, 0x52, 0x7a, 0x49, 0x77, 0x67, 0x67, 0x45, + 0x69, 0x0a, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, + 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, + 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, 0x6f, + 0x49, 0x42, 0x41, 0x51, 0x44, 0x5a, 0x35, 0x79, 0x67, 0x76, 0x55, 0x6a, + 0x38, 0x32, 0x63, 0x6b, 0x6d, 0x49, 0x6b, 0x7a, 0x54, 0x7a, 0x2b, 0x47, + 0x6f, 0x65, 0x4d, 0x56, 0x53, 0x41, 0x0a, 0x6e, 0x36, 0x31, 0x55, 0x51, + 0x62, 0x56, 0x48, 0x33, 0x35, 0x61, 0x6f, 0x31, 0x4b, 0x2b, 0x41, 0x4c, + 0x62, 0x6b, 0x4b, 0x7a, 0x33, 0x58, 0x39, 0x69, 0x61, 0x56, 0x39, 0x4a, + 0x50, 0x72, 0x6a, 0x49, 0x67, 0x77, 0x72, 0x76, 0x4a, 0x55, 0x58, 0x43, + 0x7a, 0x4f, 0x2f, 0x47, 0x55, 0x31, 0x42, 0x42, 0x70, 0x41, 0x41, 0x76, + 0x51, 0x78, 0x4e, 0x45, 0x50, 0x34, 0x48, 0x74, 0x65, 0x63, 0x63, 0x0a, + 0x62, 0x69, 0x4a, 0x56, 0x4d, 0x57, 0x57, 0x58, 0x76, 0x64, 0x4d, 0x58, + 0x30, 0x68, 0x35, 0x69, 0x38, 0x39, 0x76, 0x71, 0x62, 0x46, 0x43, 0x4d, + 0x50, 0x34, 0x51, 0x4d, 0x6c, 0x73, 0x2b, 0x33, 0x79, 0x77, 0x50, 0x67, + 0x79, 0x6d, 0x32, 0x68, 0x46, 0x45, 0x77, 0x62, 0x69, 0x64, 0x33, 0x74, + 0x41, 0x4c, 0x42, 0x53, 0x66, 0x4b, 0x2b, 0x52, 0x62, 0x4c, 0x45, 0x34, + 0x45, 0x39, 0x48, 0x70, 0x0a, 0x45, 0x67, 0x6a, 0x41, 0x41, 0x4c, 0x41, + 0x63, 0x4b, 0x78, 0x48, 0x61, 0x64, 0x33, 0x41, 0x32, 0x6d, 0x36, 0x37, + 0x4f, 0x65, 0x59, 0x66, 0x63, 0x67, 0x6e, 0x44, 0x6d, 0x43, 0x58, 0x52, + 0x77, 0x56, 0x57, 0x6d, 0x76, 0x6f, 0x32, 0x69, 0x66, 0x76, 0x39, 0x32, + 0x32, 0x65, 0x62, 0x50, 0x79, 0x6e, 0x58, 0x41, 0x70, 0x56, 0x66, 0x53, + 0x72, 0x2f, 0x35, 0x56, 0x68, 0x38, 0x38, 0x6c, 0x41, 0x0a, 0x62, 0x78, + 0x33, 0x52, 0x76, 0x70, 0x4f, 0x37, 0x30, 0x34, 0x67, 0x71, 0x75, 0x35, + 0x32, 0x2f, 0x63, 0x6c, 0x70, 0x57, 0x63, 0x54, 0x73, 0x2f, 0x31, 0x50, + 0x50, 0x52, 0x43, 0x76, 0x34, 0x6f, 0x37, 0x36, 0x50, 0x75, 0x32, 0x5a, + 0x6d, 0x76, 0x41, 0x39, 0x4f, 0x50, 0x59, 0x4c, 0x66, 0x79, 0x6b, 0x71, + 0x47, 0x78, 0x76, 0x59, 0x6d, 0x4a, 0x48, 0x7a, 0x44, 0x4e, 0x77, 0x36, + 0x59, 0x75, 0x0a, 0x59, 0x6a, 0x4f, 0x75, 0x46, 0x67, 0x4a, 0x33, 0x52, + 0x46, 0x72, 0x6e, 0x67, 0x51, 0x6f, 0x38, 0x70, 0x30, 0x51, 0x75, 0x65, + 0x62, 0x67, 0x2f, 0x42, 0x4c, 0x78, 0x63, 0x6f, 0x49, 0x66, 0x68, 0x47, + 0x36, 0x39, 0x52, 0x6a, 0x73, 0x33, 0x73, 0x4c, 0x50, 0x72, 0x34, 0x2f, + 0x6d, 0x33, 0x77, 0x4f, 0x6e, 0x79, 0x71, 0x69, 0x2b, 0x52, 0x6e, 0x6c, + 0x54, 0x47, 0x4e, 0x41, 0x67, 0x4d, 0x42, 0x0a, 0x41, 0x41, 0x47, 0x6a, + 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, + 0x41, 0x66, 0x38, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, + 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x47, 0x47, + 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, + 0x0a, 0x42, 0x42, 0x54, 0x4f, 0x77, 0x30, 0x71, 0x35, 0x6d, 0x56, 0x58, + 0x79, 0x75, 0x4e, 0x74, 0x67, 0x76, 0x36, 0x6c, 0x2b, 0x76, 0x56, 0x61, + 0x31, 0x6c, 0x7a, 0x61, 0x6e, 0x31, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, + 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, + 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x79, 0x71, 0x56, + 0x56, 0x6a, 0x4f, 0x50, 0x49, 0x0a, 0x51, 0x57, 0x35, 0x70, 0x4a, 0x36, + 0x64, 0x31, 0x45, 0x65, 0x38, 0x38, 0x68, 0x6a, 0x5a, 0x76, 0x30, 0x70, + 0x33, 0x47, 0x65, 0x44, 0x67, 0x64, 0x61, 0x5a, 0x61, 0x69, 0x6b, 0x6d, + 0x6b, 0x75, 0x4f, 0x47, 0x79, 0x62, 0x66, 0x51, 0x54, 0x55, 0x69, 0x61, + 0x57, 0x78, 0x4d, 0x54, 0x65, 0x4b, 0x79, 0x53, 0x48, 0x4d, 0x71, 0x32, + 0x7a, 0x4e, 0x69, 0x78, 0x79, 0x61, 0x31, 0x72, 0x39, 0x49, 0x0a, 0x30, + 0x6a, 0x4a, 0x6d, 0x77, 0x59, 0x72, 0x41, 0x38, 0x79, 0x38, 0x36, 0x37, + 0x38, 0x44, 0x6a, 0x31, 0x4a, 0x47, 0x47, 0x30, 0x56, 0x44, 0x6a, 0x41, + 0x39, 0x74, 0x7a, 0x64, 0x32, 0x39, 0x4b, 0x4f, 0x56, 0x50, 0x74, 0x33, + 0x69, 0x62, 0x48, 0x74, 0x58, 0x32, 0x76, 0x4b, 0x30, 0x4c, 0x52, 0x64, + 0x57, 0x4c, 0x6a, 0x53, 0x69, 0x73, 0x43, 0x78, 0x31, 0x42, 0x4c, 0x34, + 0x47, 0x6e, 0x69, 0x0a, 0x6c, 0x6d, 0x77, 0x4f, 0x52, 0x47, 0x59, 0x51, + 0x52, 0x49, 0x2b, 0x74, 0x42, 0x65, 0x76, 0x34, 0x65, 0x61, 0x79, 0x6d, + 0x47, 0x2b, 0x67, 0x33, 0x4e, 0x4a, 0x31, 0x54, 0x79, 0x57, 0x47, 0x71, + 0x6f, 0x6c, 0x4b, 0x76, 0x53, 0x6e, 0x41, 0x57, 0x68, 0x73, 0x49, 0x36, + 0x79, 0x4c, 0x45, 0x54, 0x63, 0x44, 0x62, 0x59, 0x7a, 0x2b, 0x37, 0x30, + 0x43, 0x6a, 0x54, 0x56, 0x57, 0x30, 0x7a, 0x39, 0x0a, 0x42, 0x35, 0x79, + 0x69, 0x75, 0x74, 0x6b, 0x42, 0x63, 0x6c, 0x7a, 0x7a, 0x54, 0x63, 0x48, + 0x64, 0x44, 0x72, 0x45, 0x63, 0x44, 0x63, 0x52, 0x6a, 0x76, 0x71, 0x33, + 0x30, 0x46, 0x50, 0x75, 0x4a, 0x37, 0x4b, 0x4a, 0x42, 0x44, 0x6b, 0x7a, + 0x4d, 0x79, 0x46, 0x64, 0x41, 0x30, 0x47, 0x34, 0x44, 0x71, 0x73, 0x30, + 0x4d, 0x6a, 0x6f, 0x6d, 0x5a, 0x6d, 0x57, 0x7a, 0x77, 0x50, 0x44, 0x43, + 0x76, 0x0a, 0x4f, 0x4e, 0x39, 0x76, 0x76, 0x4b, 0x4f, 0x2b, 0x4b, 0x53, + 0x41, 0x6e, 0x71, 0x33, 0x54, 0x2f, 0x45, 0x79, 0x4a, 0x34, 0x33, 0x70, + 0x64, 0x53, 0x56, 0x52, 0x36, 0x44, 0x74, 0x56, 0x51, 0x67, 0x41, 0x2b, + 0x36, 0x75, 0x77, 0x45, 0x39, 0x57, 0x33, 0x6a, 0x66, 0x4d, 0x77, 0x33, + 0x2b, 0x71, 0x42, 0x43, 0x65, 0x37, 0x30, 0x33, 0x65, 0x34, 0x59, 0x74, + 0x73, 0x58, 0x66, 0x4a, 0x77, 0x6f, 0x0a, 0x49, 0x68, 0x4e, 0x7a, 0x62, + 0x4d, 0x38, 0x6d, 0x39, 0x59, 0x6f, 0x70, 0x35, 0x77, 0x3d, 0x3d, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, + 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x65, 0x64, 0x20, 0x49, 0x44, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, + 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, + 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, + 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x65, + 0x64, 0x20, 0x49, 0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x33, + 0x20, 0x4f, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64, + 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, + 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, + 0x65, 0x64, 0x20, 0x49, 0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, + 0x33, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x31, 0x35, 0x34, 0x35, 0x39, 0x33, 0x31, 0x32, 0x39, 0x38, 0x31, + 0x30, 0x30, 0x38, 0x35, 0x35, 0x33, 0x37, 0x33, 0x31, 0x39, 0x32, 0x38, + 0x33, 0x38, 0x34, 0x39, 0x35, 0x33, 0x31, 0x33, 0x35, 0x34, 0x32, 0x36, + 0x37, 0x39, 0x36, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, + 0x63, 0x3a, 0x37, 0x66, 0x3a, 0x36, 0x35, 0x3a, 0x33, 0x31, 0x3a, 0x30, + 0x63, 0x3a, 0x38, 0x31, 0x3a, 0x64, 0x66, 0x3a, 0x38, 0x64, 0x3a, 0x62, + 0x61, 0x3a, 0x33, 0x65, 0x3a, 0x39, 0x39, 0x3a, 0x65, 0x32, 0x3a, 0x35, + 0x63, 0x3a, 0x61, 0x64, 0x3a, 0x36, 0x65, 0x3a, 0x66, 0x62, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x66, 0x35, 0x3a, 0x31, 0x37, + 0x3a, 0x61, 0x32, 0x3a, 0x34, 0x66, 0x3a, 0x39, 0x61, 0x3a, 0x34, 0x38, + 0x3a, 0x63, 0x36, 0x3a, 0x63, 0x39, 0x3a, 0x66, 0x38, 0x3a, 0x61, 0x32, + 0x3a, 0x30, 0x30, 0x3a, 0x32, 0x36, 0x3a, 0x39, 0x66, 0x3a, 0x64, 0x63, + 0x3a, 0x30, 0x66, 0x3a, 0x34, 0x38, 0x3a, 0x32, 0x63, 0x3a, 0x61, 0x62, + 0x3a, 0x33, 0x30, 0x3a, 0x38, 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x65, 0x3a, 0x33, 0x37, 0x3a, 0x63, + 0x62, 0x3a, 0x38, 0x62, 0x3a, 0x34, 0x63, 0x3a, 0x34, 0x37, 0x3a, 0x30, + 0x39, 0x3a, 0x30, 0x63, 0x3a, 0x61, 0x62, 0x3a, 0x33, 0x36, 0x3a, 0x35, + 0x35, 0x3a, 0x31, 0x62, 0x3a, 0x61, 0x36, 0x3a, 0x66, 0x34, 0x3a, 0x35, + 0x64, 0x3a, 0x62, 0x38, 0x3a, 0x34, 0x30, 0x3a, 0x36, 0x38, 0x3a, 0x30, + 0x66, 0x3a, 0x62, 0x61, 0x3a, 0x31, 0x36, 0x3a, 0x36, 0x61, 0x3a, 0x39, + 0x35, 0x3a, 0x32, 0x64, 0x3a, 0x62, 0x31, 0x3a, 0x30, 0x30, 0x3a, 0x37, + 0x31, 0x3a, 0x37, 0x66, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x35, 0x3a, 0x33, + 0x66, 0x3a, 0x63, 0x32, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x43, 0x52, 0x6a, 0x43, 0x43, 0x41, 0x63, 0x32, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x51, 0x43, 0x36, 0x46, 0x61, 0x2b, 0x68, 0x33, + 0x66, 0x6f, 0x4c, 0x56, 0x4a, 0x52, 0x4b, 0x2f, 0x4e, 0x4a, 0x4b, 0x42, + 0x73, 0x37, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, + 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x7a, 0x42, 0x6c, 0x4d, 0x51, 0x73, + 0x77, 0x0a, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, + 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x56, 0x4d, 0x42, 0x4d, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4d, 0x52, 0x47, 0x6c, 0x6e, 0x61, 0x55, + 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d, 0x52, + 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, + 0x42, 0x33, 0x64, 0x33, 0x63, 0x75, 0x0a, 0x5a, 0x47, 0x6c, 0x6e, 0x61, + 0x57, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4d, + 0x53, 0x51, 0x77, 0x49, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, + 0x78, 0x74, 0x45, 0x61, 0x57, 0x64, 0x70, 0x51, 0x32, 0x56, 0x79, 0x64, + 0x43, 0x42, 0x42, 0x63, 0x33, 0x4e, 0x31, 0x63, 0x6d, 0x56, 0x6b, 0x49, + 0x45, 0x6c, 0x45, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x0a, + 0x52, 0x7a, 0x4d, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x4d, 0x77, + 0x4f, 0x44, 0x41, 0x78, 0x4d, 0x54, 0x49, 0x77, 0x4d, 0x44, 0x41, 0x77, + 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x67, 0x77, 0x4d, 0x54, 0x45, 0x31, + 0x4d, 0x54, 0x49, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x6a, 0x42, 0x6c, + 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, + 0x45, 0x77, 0x4a, 0x56, 0x0a, 0x55, 0x7a, 0x45, 0x56, 0x4d, 0x42, 0x4d, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4d, 0x52, 0x47, 0x6c, + 0x6e, 0x61, 0x55, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x67, 0x53, 0x57, 0x35, + 0x6a, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x4c, 0x45, 0x78, 0x42, 0x33, 0x64, 0x33, 0x63, 0x75, 0x5a, 0x47, 0x6c, + 0x6e, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x75, 0x0a, 0x59, 0x32, + 0x39, 0x74, 0x4d, 0x53, 0x51, 0x77, 0x49, 0x67, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x44, 0x45, 0x78, 0x74, 0x45, 0x61, 0x57, 0x64, 0x70, 0x51, 0x32, + 0x56, 0x79, 0x64, 0x43, 0x42, 0x42, 0x63, 0x33, 0x4e, 0x31, 0x63, 0x6d, + 0x56, 0x6b, 0x49, 0x45, 0x6c, 0x45, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, + 0x51, 0x67, 0x52, 0x7a, 0x4d, 0x77, 0x64, 0x6a, 0x41, 0x51, 0x42, 0x67, + 0x63, 0x71, 0x0a, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x49, 0x42, 0x42, + 0x67, 0x55, 0x72, 0x67, 0x51, 0x51, 0x41, 0x49, 0x67, 0x4e, 0x69, 0x41, + 0x41, 0x51, 0x5a, 0x35, 0x37, 0x79, 0x73, 0x52, 0x47, 0x58, 0x74, 0x7a, + 0x62, 0x67, 0x2f, 0x57, 0x50, 0x75, 0x4e, 0x73, 0x56, 0x65, 0x70, 0x52, + 0x43, 0x30, 0x46, 0x46, 0x66, 0x4c, 0x76, 0x43, 0x2f, 0x38, 0x51, 0x64, + 0x4a, 0x2b, 0x31, 0x59, 0x6c, 0x4a, 0x66, 0x0a, 0x5a, 0x6e, 0x34, 0x66, + 0x35, 0x64, 0x77, 0x62, 0x52, 0x58, 0x6b, 0x4c, 0x7a, 0x4d, 0x5a, 0x54, + 0x43, 0x70, 0x32, 0x4e, 0x58, 0x51, 0x4c, 0x5a, 0x71, 0x56, 0x6e, 0x65, + 0x41, 0x6c, 0x72, 0x32, 0x6c, 0x53, 0x6f, 0x4f, 0x6a, 0x54, 0x68, 0x4b, + 0x69, 0x6b, 0x6e, 0x47, 0x76, 0x4d, 0x59, 0x44, 0x4f, 0x41, 0x64, 0x66, + 0x56, 0x64, 0x70, 0x2b, 0x43, 0x57, 0x37, 0x69, 0x66, 0x31, 0x37, 0x51, + 0x0a, 0x52, 0x53, 0x41, 0x50, 0x57, 0x58, 0x59, 0x51, 0x31, 0x71, 0x41, + 0x6b, 0x38, 0x43, 0x33, 0x65, 0x4e, 0x76, 0x4a, 0x73, 0x4b, 0x54, 0x6d, + 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, + 0x42, 0x41, 0x66, 0x38, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, + 0x50, 0x41, 0x51, 0x48, 0x2f, 0x0a, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, + 0x47, 0x47, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, + 0x51, 0x57, 0x42, 0x42, 0x54, 0x4c, 0x30, 0x4c, 0x32, 0x70, 0x34, 0x5a, + 0x67, 0x46, 0x55, 0x61, 0x46, 0x4e, 0x4e, 0x36, 0x4b, 0x44, 0x65, 0x63, + 0x36, 0x4e, 0x48, 0x53, 0x72, 0x6b, 0x68, 0x44, 0x41, 0x4b, 0x42, 0x67, + 0x67, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x0a, 0x41, + 0x77, 0x4e, 0x6e, 0x41, 0x44, 0x42, 0x6b, 0x41, 0x6a, 0x41, 0x6c, 0x70, + 0x49, 0x46, 0x46, 0x41, 0x6d, 0x73, 0x53, 0x53, 0x33, 0x56, 0x30, 0x54, + 0x38, 0x67, 0x6a, 0x34, 0x33, 0x44, 0x79, 0x64, 0x58, 0x4c, 0x65, 0x66, + 0x49, 0x6e, 0x77, 0x7a, 0x35, 0x46, 0x79, 0x59, 0x5a, 0x35, 0x65, 0x45, + 0x4a, 0x4a, 0x5a, 0x56, 0x72, 0x6d, 0x44, 0x78, 0x78, 0x44, 0x6e, 0x4f, + 0x4f, 0x6c, 0x59, 0x0a, 0x4a, 0x6a, 0x5a, 0x39, 0x31, 0x65, 0x51, 0x30, + 0x68, 0x6a, 0x6b, 0x43, 0x4d, 0x48, 0x77, 0x32, 0x55, 0x2f, 0x41, 0x77, + 0x35, 0x57, 0x4a, 0x6a, 0x4f, 0x70, 0x6e, 0x69, 0x74, 0x71, 0x4d, 0x37, + 0x6d, 0x7a, 0x54, 0x36, 0x48, 0x74, 0x6f, 0x51, 0x6b, 0x6e, 0x46, 0x65, + 0x6b, 0x52, 0x4f, 0x6e, 0x33, 0x61, 0x52, 0x75, 0x6b, 0x73, 0x77, 0x79, + 0x31, 0x76, 0x55, 0x68, 0x5a, 0x73, 0x63, 0x76, 0x0a, 0x36, 0x70, 0x5a, + 0x6a, 0x61, 0x6d, 0x56, 0x46, 0x6b, 0x70, 0x55, 0x42, 0x74, 0x41, 0x3d, + 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, + 0x72, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x44, 0x69, 0x67, 0x69, + 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, + 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, + 0x65, 0x72, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x32, 0x20, 0x4f, 0x3d, 0x44, 0x69, 0x67, + 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, + 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, + 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x47, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x34, 0x32, 0x39, 0x33, 0x37, 0x34, 0x33, 0x35, 0x34, + 0x30, 0x30, 0x34, 0x36, 0x39, 0x37, 0x35, 0x33, 0x37, 0x38, 0x35, 0x33, + 0x34, 0x38, 0x37, 0x39, 0x35, 0x30, 0x33, 0x32, 0x30, 0x32, 0x32, 0x35, + 0x33, 0x35, 0x34, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x65, 0x34, 0x3a, 0x61, 0x36, 0x3a, 0x38, 0x61, 0x3a, 0x63, 0x38, 0x3a, + 0x35, 0x34, 0x3a, 0x61, 0x63, 0x3a, 0x35, 0x32, 0x3a, 0x34, 0x32, 0x3a, + 0x34, 0x36, 0x3a, 0x30, 0x61, 0x3a, 0x66, 0x64, 0x3a, 0x37, 0x32, 0x3a, + 0x34, 0x38, 0x3a, 0x31, 0x62, 0x3a, 0x32, 0x61, 0x3a, 0x34, 0x34, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x66, 0x3a, 0x33, + 0x63, 0x3a, 0x32, 0x34, 0x3a, 0x66, 0x39, 0x3a, 0x62, 0x66, 0x3a, 0x64, + 0x36, 0x3a, 0x36, 0x36, 0x3a, 0x37, 0x36, 0x3a, 0x31, 0x62, 0x3a, 0x32, + 0x36, 0x3a, 0x38, 0x30, 0x3a, 0x37, 0x33, 0x3a, 0x66, 0x65, 0x3a, 0x30, + 0x36, 0x3a, 0x64, 0x31, 0x3a, 0x63, 0x63, 0x3a, 0x38, 0x64, 0x3a, 0x34, + 0x66, 0x3a, 0x38, 0x32, 0x3a, 0x61, 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x62, 0x3a, 0x33, 0x63, 0x3a, + 0x63, 0x62, 0x3a, 0x62, 0x37, 0x3a, 0x36, 0x30, 0x3a, 0x33, 0x31, 0x3a, + 0x65, 0x35, 0x3a, 0x65, 0x30, 0x3a, 0x31, 0x33, 0x3a, 0x38, 0x66, 0x3a, + 0x38, 0x64, 0x3a, 0x64, 0x33, 0x3a, 0x39, 0x61, 0x3a, 0x32, 0x33, 0x3a, + 0x66, 0x39, 0x3a, 0x64, 0x65, 0x3a, 0x34, 0x37, 0x3a, 0x66, 0x66, 0x3a, + 0x63, 0x33, 0x3a, 0x35, 0x65, 0x3a, 0x34, 0x33, 0x3a, 0x63, 0x31, 0x3a, + 0x31, 0x34, 0x3a, 0x34, 0x63, 0x3a, 0x65, 0x61, 0x3a, 0x32, 0x37, 0x3a, + 0x64, 0x34, 0x3a, 0x36, 0x61, 0x3a, 0x35, 0x61, 0x3a, 0x62, 0x31, 0x3a, + 0x63, 0x62, 0x3a, 0x35, 0x66, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, + 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, + 0x49, 0x44, 0x6a, 0x6a, 0x43, 0x43, 0x41, 0x6e, 0x61, 0x67, 0x41, 0x77, + 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x41, 0x7a, 0x72, 0x78, 0x35, 0x71, + 0x63, 0x52, 0x71, 0x61, 0x43, 0x37, 0x4b, 0x47, 0x53, 0x78, 0x48, 0x51, + 0x6e, 0x36, 0x35, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, + 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, + 0x42, 0x68, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x56, 0x4d, + 0x42, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4d, 0x52, + 0x47, 0x6c, 0x6e, 0x61, 0x55, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x67, 0x53, + 0x57, 0x35, 0x6a, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x4c, 0x45, 0x78, 0x42, 0x33, 0x0a, 0x64, 0x33, 0x63, 0x75, + 0x5a, 0x47, 0x6c, 0x6e, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x75, + 0x59, 0x32, 0x39, 0x74, 0x4d, 0x53, 0x41, 0x77, 0x48, 0x67, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x64, 0x45, 0x61, 0x57, 0x64, 0x70, + 0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, + 0x59, 0x57, 0x77, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x48, + 0x0a, 0x4d, 0x6a, 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4d, 0x7a, 0x41, + 0x34, 0x4d, 0x44, 0x45, 0x78, 0x4d, 0x6a, 0x41, 0x77, 0x4d, 0x44, 0x42, + 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4f, 0x44, 0x41, 0x78, 0x4d, 0x54, 0x55, + 0x78, 0x4d, 0x6a, 0x41, 0x77, 0x4d, 0x44, 0x42, 0x61, 0x4d, 0x47, 0x45, + 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, + 0x54, 0x41, 0x6c, 0x56, 0x54, 0x0a, 0x4d, 0x52, 0x55, 0x77, 0x45, 0x77, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x78, 0x45, 0x61, 0x57, + 0x64, 0x70, 0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x42, 0x4a, 0x62, 0x6d, + 0x4d, 0x78, 0x47, 0x54, 0x41, 0x58, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x73, 0x54, 0x45, 0x48, 0x64, 0x33, 0x64, 0x79, 0x35, 0x6b, 0x61, 0x57, + 0x64, 0x70, 0x59, 0x32, 0x56, 0x79, 0x64, 0x43, 0x35, 0x6a, 0x0a, 0x62, + 0x32, 0x30, 0x78, 0x49, 0x44, 0x41, 0x65, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x4d, 0x54, 0x46, 0x30, 0x52, 0x70, 0x5a, 0x32, 0x6c, 0x44, 0x5a, + 0x58, 0x4a, 0x30, 0x49, 0x45, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62, + 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x63, 0x79, 0x4d, + 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x0a, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, + 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, + 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x75, 0x7a, 0x66, 0x4e, + 0x4e, 0x4e, 0x78, 0x37, 0x61, 0x38, 0x6d, 0x79, 0x61, 0x4a, 0x43, 0x74, + 0x53, 0x6e, 0x58, 0x2f, 0x52, 0x72, 0x6f, 0x68, 0x43, 0x67, 0x69, 0x4e, + 0x39, 0x52, 0x6c, 0x55, 0x79, 0x66, 0x75, 0x49, 0x0a, 0x32, 0x2f, 0x4f, + 0x75, 0x38, 0x6a, 0x71, 0x4a, 0x6b, 0x54, 0x78, 0x36, 0x35, 0x71, 0x73, + 0x47, 0x47, 0x6d, 0x76, 0x50, 0x72, 0x43, 0x33, 0x6f, 0x58, 0x67, 0x6b, + 0x6b, 0x52, 0x4c, 0x70, 0x69, 0x6d, 0x6e, 0x37, 0x57, 0x6f, 0x36, 0x68, + 0x2b, 0x34, 0x46, 0x52, 0x31, 0x49, 0x41, 0x57, 0x73, 0x55, 0x4c, 0x65, + 0x63, 0x59, 0x78, 0x70, 0x73, 0x4d, 0x4e, 0x7a, 0x61, 0x48, 0x78, 0x6d, + 0x78, 0x0a, 0x31, 0x78, 0x37, 0x65, 0x2f, 0x64, 0x66, 0x67, 0x79, 0x35, + 0x53, 0x44, 0x4e, 0x36, 0x37, 0x73, 0x48, 0x30, 0x4e, 0x4f, 0x33, 0x58, + 0x73, 0x73, 0x30, 0x72, 0x30, 0x75, 0x70, 0x53, 0x2f, 0x6b, 0x71, 0x62, + 0x69, 0x74, 0x4f, 0x74, 0x53, 0x5a, 0x70, 0x4c, 0x59, 0x6c, 0x36, 0x5a, + 0x74, 0x72, 0x41, 0x47, 0x43, 0x53, 0x59, 0x50, 0x39, 0x50, 0x49, 0x55, + 0x6b, 0x59, 0x39, 0x32, 0x65, 0x51, 0x0a, 0x71, 0x32, 0x45, 0x47, 0x6e, + 0x49, 0x2f, 0x79, 0x75, 0x75, 0x6d, 0x30, 0x36, 0x5a, 0x49, 0x79, 0x61, + 0x37, 0x58, 0x7a, 0x56, 0x2b, 0x68, 0x64, 0x47, 0x38, 0x32, 0x4d, 0x48, + 0x61, 0x75, 0x56, 0x42, 0x4a, 0x56, 0x4a, 0x38, 0x7a, 0x55, 0x74, 0x6c, + 0x75, 0x4e, 0x4a, 0x62, 0x64, 0x31, 0x33, 0x34, 0x2f, 0x74, 0x4a, 0x53, + 0x37, 0x53, 0x73, 0x56, 0x51, 0x65, 0x70, 0x6a, 0x35, 0x57, 0x7a, 0x0a, + 0x74, 0x43, 0x4f, 0x37, 0x54, 0x47, 0x31, 0x46, 0x38, 0x50, 0x61, 0x70, + 0x73, 0x70, 0x55, 0x77, 0x74, 0x50, 0x31, 0x4d, 0x56, 0x59, 0x77, 0x6e, + 0x53, 0x6c, 0x63, 0x55, 0x66, 0x49, 0x4b, 0x64, 0x7a, 0x58, 0x4f, 0x53, + 0x30, 0x78, 0x5a, 0x4b, 0x42, 0x67, 0x79, 0x4d, 0x55, 0x4e, 0x47, 0x50, + 0x48, 0x67, 0x6d, 0x2b, 0x46, 0x36, 0x48, 0x6d, 0x49, 0x63, 0x72, 0x39, + 0x67, 0x2b, 0x55, 0x51, 0x0a, 0x76, 0x49, 0x4f, 0x6c, 0x43, 0x73, 0x52, + 0x6e, 0x4b, 0x50, 0x5a, 0x7a, 0x46, 0x42, 0x51, 0x39, 0x52, 0x6e, 0x62, + 0x44, 0x68, 0x78, 0x53, 0x4a, 0x49, 0x54, 0x52, 0x4e, 0x72, 0x77, 0x39, + 0x46, 0x44, 0x4b, 0x5a, 0x4a, 0x6f, 0x62, 0x71, 0x37, 0x6e, 0x4d, 0x57, + 0x78, 0x4d, 0x34, 0x4d, 0x70, 0x68, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, + 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x50, 0x0a, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, + 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, + 0x49, 0x42, 0x68, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, + 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x54, 0x69, 0x4a, 0x55, 0x49, 0x42, + 0x69, 0x56, 0x0a, 0x35, 0x75, 0x4e, 0x75, 0x35, 0x67, 0x2f, 0x36, 0x2b, + 0x72, 0x6b, 0x53, 0x37, 0x51, 0x59, 0x58, 0x6a, 0x7a, 0x6b, 0x77, 0x44, + 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, + 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, + 0x47, 0x42, 0x6e, 0x4b, 0x4a, 0x52, 0x76, 0x44, 0x6b, 0x68, 0x6a, 0x36, + 0x7a, 0x48, 0x64, 0x36, 0x6d, 0x63, 0x59, 0x0a, 0x31, 0x59, 0x6c, 0x39, + 0x50, 0x4d, 0x57, 0x4c, 0x53, 0x6e, 0x2f, 0x70, 0x76, 0x74, 0x73, 0x72, + 0x46, 0x39, 0x2b, 0x77, 0x58, 0x33, 0x4e, 0x33, 0x4b, 0x6a, 0x49, 0x54, + 0x4f, 0x59, 0x46, 0x6e, 0x51, 0x6f, 0x51, 0x6a, 0x38, 0x6b, 0x56, 0x6e, + 0x4e, 0x65, 0x79, 0x49, 0x76, 0x2f, 0x69, 0x50, 0x73, 0x47, 0x45, 0x4d, + 0x4e, 0x4b, 0x53, 0x75, 0x49, 0x45, 0x79, 0x45, 0x78, 0x74, 0x76, 0x34, + 0x0a, 0x4e, 0x65, 0x46, 0x32, 0x32, 0x64, 0x2b, 0x6d, 0x51, 0x72, 0x76, + 0x48, 0x52, 0x41, 0x69, 0x47, 0x66, 0x7a, 0x5a, 0x30, 0x4a, 0x46, 0x72, + 0x61, 0x62, 0x41, 0x30, 0x55, 0x57, 0x54, 0x57, 0x39, 0x38, 0x6b, 0x6e, + 0x64, 0x74, 0x68, 0x2f, 0x4a, 0x73, 0x77, 0x31, 0x48, 0x4b, 0x6a, 0x32, + 0x5a, 0x4c, 0x37, 0x74, 0x63, 0x75, 0x37, 0x58, 0x55, 0x49, 0x4f, 0x47, + 0x5a, 0x58, 0x31, 0x4e, 0x47, 0x0a, 0x46, 0x64, 0x74, 0x6f, 0x6d, 0x2f, + 0x44, 0x7a, 0x4d, 0x4e, 0x55, 0x2b, 0x4d, 0x65, 0x4b, 0x4e, 0x68, 0x4a, + 0x37, 0x6a, 0x69, 0x74, 0x72, 0x61, 0x6c, 0x6a, 0x34, 0x31, 0x45, 0x36, + 0x56, 0x66, 0x38, 0x50, 0x6c, 0x77, 0x55, 0x48, 0x42, 0x48, 0x51, 0x52, + 0x46, 0x58, 0x47, 0x55, 0x37, 0x41, 0x6a, 0x36, 0x34, 0x47, 0x78, 0x4a, + 0x55, 0x54, 0x46, 0x79, 0x38, 0x62, 0x4a, 0x5a, 0x39, 0x31, 0x0a, 0x38, + 0x72, 0x47, 0x4f, 0x6d, 0x61, 0x46, 0x76, 0x45, 0x37, 0x46, 0x42, 0x63, + 0x66, 0x36, 0x49, 0x4b, 0x73, 0x68, 0x50, 0x45, 0x43, 0x42, 0x56, 0x31, + 0x2f, 0x4d, 0x55, 0x52, 0x65, 0x58, 0x67, 0x52, 0x50, 0x54, 0x71, 0x68, + 0x35, 0x55, 0x79, 0x6b, 0x77, 0x37, 0x2b, 0x55, 0x30, 0x62, 0x36, 0x4c, + 0x4a, 0x33, 0x2f, 0x69, 0x79, 0x4b, 0x35, 0x53, 0x39, 0x6b, 0x4a, 0x52, + 0x61, 0x54, 0x65, 0x0a, 0x70, 0x4c, 0x69, 0x61, 0x57, 0x4e, 0x30, 0x62, + 0x66, 0x56, 0x4b, 0x66, 0x6a, 0x6c, 0x6c, 0x44, 0x69, 0x49, 0x47, 0x6b, + 0x6e, 0x69, 0x62, 0x56, 0x62, 0x36, 0x33, 0x64, 0x44, 0x63, 0x59, 0x33, + 0x66, 0x65, 0x30, 0x44, 0x6b, 0x68, 0x76, 0x6c, 0x64, 0x31, 0x39, 0x32, + 0x37, 0x6a, 0x79, 0x4e, 0x78, 0x46, 0x31, 0x57, 0x57, 0x36, 0x4c, 0x5a, + 0x5a, 0x6d, 0x36, 0x7a, 0x4e, 0x54, 0x66, 0x6c, 0x0a, 0x4d, 0x72, 0x59, + 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, + 0x72, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x44, 0x69, 0x67, 0x69, + 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, + 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, + 0x65, 0x72, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x44, 0x69, 0x67, + 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, + 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, + 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x47, 0x33, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x37, 0x30, 0x38, 0x39, 0x32, 0x34, 0x34, 0x34, 0x36, + 0x39, 0x30, 0x33, 0x30, 0x32, 0x39, 0x33, 0x32, 0x39, 0x31, 0x37, 0x36, + 0x30, 0x30, 0x38, 0x33, 0x33, 0x33, 0x33, 0x38, 0x38, 0x34, 0x33, 0x36, + 0x34, 0x31, 0x34, 0x36, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x66, 0x35, 0x3a, 0x35, 0x64, 0x3a, 0x61, 0x34, 0x3a, 0x35, 0x30, 0x3a, + 0x61, 0x35, 0x3a, 0x66, 0x62, 0x3a, 0x32, 0x38, 0x3a, 0x37, 0x65, 0x3a, + 0x31, 0x65, 0x3a, 0x30, 0x66, 0x3a, 0x30, 0x64, 0x3a, 0x63, 0x63, 0x3a, + 0x39, 0x36, 0x3a, 0x35, 0x37, 0x3a, 0x35, 0x36, 0x3a, 0x63, 0x61, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x65, 0x3a, 0x30, + 0x34, 0x3a, 0x64, 0x65, 0x3a, 0x38, 0x39, 0x3a, 0x36, 0x61, 0x3a, 0x33, + 0x65, 0x3a, 0x36, 0x36, 0x3a, 0x36, 0x64, 0x3a, 0x30, 0x30, 0x3a, 0x65, + 0x36, 0x3a, 0x38, 0x37, 0x3a, 0x64, 0x33, 0x3a, 0x33, 0x66, 0x3a, 0x66, + 0x61, 0x3a, 0x64, 0x39, 0x3a, 0x33, 0x62, 0x3a, 0x65, 0x38, 0x3a, 0x33, + 0x64, 0x3a, 0x33, 0x34, 0x3a, 0x39, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x31, 0x3a, 0x61, 0x64, 0x3a, + 0x36, 0x36, 0x3a, 0x34, 0x38, 0x3a, 0x66, 0x38, 0x3a, 0x31, 0x30, 0x3a, + 0x34, 0x31, 0x3a, 0x33, 0x38, 0x3a, 0x63, 0x37, 0x3a, 0x33, 0x38, 0x3a, + 0x66, 0x33, 0x3a, 0x39, 0x65, 0x3a, 0x61, 0x34, 0x3a, 0x33, 0x32, 0x3a, + 0x30, 0x31, 0x3a, 0x33, 0x33, 0x3a, 0x33, 0x39, 0x3a, 0x33, 0x65, 0x3a, + 0x33, 0x61, 0x3a, 0x31, 0x38, 0x3a, 0x63, 0x63, 0x3a, 0x30, 0x32, 0x3a, + 0x32, 0x39, 0x3a, 0x36, 0x65, 0x3a, 0x66, 0x39, 0x3a, 0x37, 0x63, 0x3a, + 0x32, 0x61, 0x3a, 0x63, 0x39, 0x3a, 0x65, 0x66, 0x3a, 0x36, 0x37, 0x3a, + 0x33, 0x31, 0x3a, 0x64, 0x30, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, + 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, + 0x49, 0x43, 0x50, 0x7a, 0x43, 0x43, 0x41, 0x63, 0x57, 0x67, 0x41, 0x77, + 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x42, 0x56, 0x56, 0x57, 0x76, 0x50, + 0x4a, 0x65, 0x70, 0x44, 0x55, 0x31, 0x77, 0x36, 0x51, 0x50, 0x31, 0x61, + 0x74, 0x46, 0x63, 0x6a, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, + 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x7a, 0x42, 0x68, 0x4d, 0x51, + 0x73, 0x77, 0x0a, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, + 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x56, 0x4d, 0x42, 0x4d, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4d, 0x52, 0x47, 0x6c, 0x6e, 0x61, + 0x55, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d, + 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, + 0x78, 0x42, 0x33, 0x64, 0x33, 0x63, 0x75, 0x0a, 0x5a, 0x47, 0x6c, 0x6e, + 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, + 0x4d, 0x53, 0x41, 0x77, 0x48, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, + 0x45, 0x78, 0x64, 0x45, 0x61, 0x57, 0x64, 0x70, 0x51, 0x32, 0x56, 0x79, + 0x64, 0x43, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x77, 0x67, + 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x48, 0x4d, 0x7a, 0x41, 0x65, + 0x0a, 0x46, 0x77, 0x30, 0x78, 0x4d, 0x7a, 0x41, 0x34, 0x4d, 0x44, 0x45, + 0x78, 0x4d, 0x6a, 0x41, 0x77, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, + 0x7a, 0x4f, 0x44, 0x41, 0x78, 0x4d, 0x54, 0x55, 0x78, 0x4d, 0x6a, 0x41, + 0x77, 0x4d, 0x44, 0x42, 0x61, 0x4d, 0x47, 0x45, 0x78, 0x43, 0x7a, 0x41, + 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, + 0x54, 0x4d, 0x52, 0x55, 0x77, 0x0a, 0x45, 0x77, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4b, 0x45, 0x77, 0x78, 0x45, 0x61, 0x57, 0x64, 0x70, 0x51, 0x32, + 0x56, 0x79, 0x64, 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x78, 0x47, 0x54, + 0x41, 0x58, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x45, 0x48, + 0x64, 0x33, 0x64, 0x79, 0x35, 0x6b, 0x61, 0x57, 0x64, 0x70, 0x59, 0x32, + 0x56, 0x79, 0x64, 0x43, 0x35, 0x6a, 0x62, 0x32, 0x30, 0x78, 0x0a, 0x49, + 0x44, 0x41, 0x65, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x46, + 0x30, 0x52, 0x70, 0x5a, 0x32, 0x6c, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x49, + 0x45, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62, 0x43, 0x42, 0x53, 0x62, + 0x32, 0x39, 0x30, 0x49, 0x45, 0x63, 0x7a, 0x4d, 0x48, 0x59, 0x77, 0x45, + 0x41, 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x43, 0x41, + 0x51, 0x59, 0x46, 0x0a, 0x4b, 0x34, 0x45, 0x45, 0x41, 0x43, 0x49, 0x44, + 0x59, 0x67, 0x41, 0x45, 0x33, 0x61, 0x66, 0x5a, 0x75, 0x34, 0x71, 0x34, + 0x43, 0x2f, 0x73, 0x4c, 0x66, 0x79, 0x48, 0x53, 0x38, 0x4c, 0x36, 0x2b, + 0x63, 0x2f, 0x4d, 0x7a, 0x58, 0x52, 0x71, 0x38, 0x4e, 0x4f, 0x72, 0x65, + 0x78, 0x70, 0x75, 0x38, 0x30, 0x4a, 0x58, 0x32, 0x38, 0x4d, 0x7a, 0x51, + 0x43, 0x37, 0x70, 0x68, 0x57, 0x31, 0x46, 0x47, 0x0a, 0x66, 0x70, 0x34, + 0x74, 0x6e, 0x2b, 0x36, 0x4f, 0x59, 0x77, 0x77, 0x58, 0x37, 0x41, 0x64, + 0x77, 0x39, 0x63, 0x2b, 0x45, 0x4c, 0x6b, 0x43, 0x44, 0x6e, 0x4f, 0x67, + 0x2f, 0x51, 0x57, 0x30, 0x37, 0x72, 0x64, 0x4f, 0x6b, 0x46, 0x46, 0x6b, + 0x32, 0x65, 0x4a, 0x30, 0x44, 0x51, 0x2b, 0x34, 0x51, 0x45, 0x32, 0x78, + 0x79, 0x33, 0x71, 0x36, 0x49, 0x70, 0x36, 0x46, 0x72, 0x74, 0x55, 0x50, + 0x4f, 0x0a, 0x5a, 0x39, 0x77, 0x6a, 0x2f, 0x77, 0x4d, 0x63, 0x6f, 0x2b, + 0x49, 0x2b, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x50, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, + 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, + 0x49, 0x42, 0x68, 0x6a, 0x41, 0x64, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x73, 0x39, 0x74, 0x49, 0x70, + 0x50, 0x6d, 0x68, 0x78, 0x64, 0x69, 0x75, 0x4e, 0x6b, 0x48, 0x4d, 0x45, + 0x57, 0x4e, 0x70, 0x59, 0x69, 0x6d, 0x38, 0x53, 0x38, 0x59, 0x77, 0x43, + 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, + 0x77, 0x4d, 0x44, 0x61, 0x41, 0x41, 0x77, 0x5a, 0x51, 0x49, 0x78, 0x0a, + 0x41, 0x4b, 0x32, 0x38, 0x38, 0x6d, 0x77, 0x2f, 0x45, 0x6b, 0x72, 0x52, + 0x4c, 0x54, 0x6e, 0x44, 0x43, 0x67, 0x6d, 0x58, 0x63, 0x2f, 0x53, 0x49, + 0x4e, 0x6f, 0x79, 0x49, 0x4a, 0x37, 0x76, 0x6d, 0x69, 0x49, 0x31, 0x51, + 0x68, 0x61, 0x64, 0x6a, 0x2b, 0x5a, 0x34, 0x79, 0x33, 0x6d, 0x61, 0x54, + 0x44, 0x2f, 0x48, 0x4d, 0x73, 0x51, 0x6d, 0x50, 0x33, 0x57, 0x79, 0x72, + 0x2b, 0x6d, 0x74, 0x2f, 0x0a, 0x6f, 0x41, 0x49, 0x77, 0x4f, 0x57, 0x5a, + 0x62, 0x77, 0x6d, 0x53, 0x4e, 0x75, 0x4a, 0x35, 0x51, 0x33, 0x4b, 0x6a, + 0x56, 0x53, 0x61, 0x4c, 0x74, 0x78, 0x39, 0x7a, 0x52, 0x53, 0x58, 0x38, + 0x58, 0x41, 0x62, 0x6a, 0x49, 0x68, 0x6f, 0x39, 0x4f, 0x6a, 0x49, 0x67, + 0x72, 0x71, 0x4a, 0x71, 0x70, 0x69, 0x73, 0x58, 0x52, 0x41, 0x4c, 0x33, + 0x34, 0x56, 0x4f, 0x4b, 0x61, 0x35, 0x56, 0x74, 0x38, 0x0a, 0x73, 0x79, + 0x63, 0x58, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, 0x69, 0x43, + 0x65, 0x72, 0x74, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x34, 0x20, 0x4f, 0x3d, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, + 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, + 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x44, 0x69, 0x67, + 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, + 0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x34, 0x20, 0x4f, 0x3d, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x20, 0x4f, 0x55, 0x3d, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, + 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, + 0x65, 0x72, 0x74, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x34, 0x22, 0x0a, 0x23, 0x20, 0x53, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x37, 0x34, 0x35, 0x31, 0x35, + 0x30, 0x30, 0x35, 0x35, 0x38, 0x39, 0x37, 0x37, 0x33, 0x37, 0x30, 0x37, + 0x37, 0x37, 0x39, 0x33, 0x30, 0x30, 0x38, 0x34, 0x38, 0x36, 0x39, 0x30, + 0x31, 0x36, 0x36, 0x31, 0x34, 0x32, 0x33, 0x36, 0x0a, 0x23, 0x20, 0x4d, + 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x38, 0x3a, 0x66, 0x32, 0x3a, 0x66, 0x63, + 0x3a, 0x61, 0x61, 0x3a, 0x36, 0x30, 0x3a, 0x31, 0x66, 0x3a, 0x32, 0x66, + 0x3a, 0x62, 0x34, 0x3a, 0x65, 0x62, 0x3a, 0x63, 0x39, 0x3a, 0x33, 0x37, + 0x3a, 0x62, 0x61, 0x3a, 0x35, 0x33, 0x3a, 0x32, 0x65, 0x3a, 0x37, 0x35, + 0x3a, 0x34, 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x64, 0x64, 0x3a, 0x66, 0x62, 0x3a, 0x31, 0x36, 0x3a, 0x63, 0x64, 0x3a, + 0x34, 0x39, 0x3a, 0x33, 0x31, 0x3a, 0x63, 0x39, 0x3a, 0x37, 0x33, 0x3a, + 0x61, 0x32, 0x3a, 0x30, 0x33, 0x3a, 0x37, 0x64, 0x3a, 0x33, 0x66, 0x3a, + 0x63, 0x38, 0x3a, 0x33, 0x61, 0x3a, 0x34, 0x64, 0x3a, 0x37, 0x64, 0x3a, + 0x37, 0x37, 0x3a, 0x35, 0x64, 0x3a, 0x30, 0x35, 0x3a, 0x65, 0x34, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x35, + 0x3a, 0x32, 0x66, 0x3a, 0x37, 0x62, 0x3a, 0x64, 0x63, 0x3a, 0x66, 0x31, + 0x3a, 0x61, 0x37, 0x3a, 0x61, 0x66, 0x3a, 0x39, 0x65, 0x3a, 0x36, 0x63, + 0x3a, 0x65, 0x36, 0x3a, 0x37, 0x32, 0x3a, 0x30, 0x31, 0x3a, 0x37, 0x66, + 0x3a, 0x34, 0x66, 0x3a, 0x31, 0x32, 0x3a, 0x61, 0x62, 0x3a, 0x66, 0x37, + 0x3a, 0x37, 0x32, 0x3a, 0x34, 0x30, 0x3a, 0x63, 0x37, 0x3a, 0x38, 0x65, + 0x3a, 0x37, 0x36, 0x3a, 0x31, 0x61, 0x3a, 0x63, 0x32, 0x3a, 0x30, 0x33, + 0x3a, 0x64, 0x31, 0x3a, 0x64, 0x39, 0x3a, 0x64, 0x32, 0x3a, 0x30, 0x61, + 0x3a, 0x63, 0x38, 0x3a, 0x39, 0x39, 0x3a, 0x38, 0x38, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x6b, 0x44, 0x43, 0x43, 0x41, 0x33, + 0x69, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x42, 0x5a, + 0x73, 0x62, 0x56, 0x35, 0x36, 0x4f, 0x49, 0x54, 0x4c, 0x69, 0x4f, 0x51, + 0x65, 0x39, 0x70, 0x33, 0x64, 0x31, 0x58, 0x44, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x77, 0x46, 0x41, 0x44, 0x42, 0x69, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, + 0x7a, 0x45, 0x56, 0x4d, 0x42, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x68, 0x4d, 0x4d, 0x52, 0x47, 0x6c, 0x6e, 0x61, 0x55, 0x4e, 0x6c, 0x63, + 0x6e, 0x51, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d, 0x52, 0x6b, 0x77, 0x46, + 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x42, 0x33, 0x0a, + 0x64, 0x33, 0x63, 0x75, 0x5a, 0x47, 0x6c, 0x6e, 0x61, 0x57, 0x4e, 0x6c, + 0x63, 0x6e, 0x51, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4d, 0x53, 0x45, 0x77, + 0x48, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x68, 0x45, + 0x61, 0x57, 0x64, 0x70, 0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x42, 0x55, + 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x6b, 0x49, 0x46, 0x4a, 0x76, + 0x62, 0x33, 0x51, 0x67, 0x0a, 0x52, 0x7a, 0x51, 0x77, 0x48, 0x68, 0x63, + 0x4e, 0x4d, 0x54, 0x4d, 0x77, 0x4f, 0x44, 0x41, 0x78, 0x4d, 0x54, 0x49, + 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x67, + 0x77, 0x4d, 0x54, 0x45, 0x31, 0x4d, 0x54, 0x49, 0x77, 0x4d, 0x44, 0x41, + 0x77, 0x57, 0x6a, 0x42, 0x69, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x0a, 0x55, 0x7a, + 0x45, 0x56, 0x4d, 0x42, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, + 0x4d, 0x4d, 0x52, 0x47, 0x6c, 0x6e, 0x61, 0x55, 0x4e, 0x6c, 0x63, 0x6e, + 0x51, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x42, 0x33, 0x64, 0x33, + 0x63, 0x75, 0x5a, 0x47, 0x6c, 0x6e, 0x61, 0x57, 0x4e, 0x6c, 0x63, 0x6e, + 0x51, 0x75, 0x0a, 0x59, 0x32, 0x39, 0x74, 0x4d, 0x53, 0x45, 0x77, 0x48, + 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x68, 0x45, 0x61, + 0x57, 0x64, 0x70, 0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x42, 0x55, 0x63, + 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x6b, 0x49, 0x46, 0x4a, 0x76, 0x62, + 0x33, 0x51, 0x67, 0x52, 0x7a, 0x51, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, + 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x0a, 0x53, 0x49, 0x62, 0x33, + 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, + 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, + 0x41, 0x51, 0x43, 0x2f, 0x35, 0x70, 0x42, 0x7a, 0x61, 0x4e, 0x36, 0x37, + 0x35, 0x46, 0x31, 0x4b, 0x50, 0x44, 0x41, 0x69, 0x4d, 0x47, 0x6b, 0x7a, + 0x37, 0x4d, 0x4b, 0x6e, 0x4a, 0x53, 0x37, 0x4a, 0x49, 0x54, 0x33, 0x79, + 0x0a, 0x69, 0x74, 0x68, 0x5a, 0x77, 0x75, 0x45, 0x70, 0x70, 0x7a, 0x31, + 0x59, 0x71, 0x33, 0x61, 0x61, 0x7a, 0x61, 0x35, 0x37, 0x47, 0x34, 0x51, + 0x4e, 0x78, 0x44, 0x41, 0x66, 0x38, 0x78, 0x75, 0x6b, 0x4f, 0x42, 0x62, + 0x72, 0x56, 0x73, 0x61, 0x58, 0x62, 0x52, 0x32, 0x72, 0x73, 0x6e, 0x6e, + 0x79, 0x79, 0x68, 0x48, 0x53, 0x35, 0x46, 0x2f, 0x57, 0x42, 0x54, 0x78, + 0x53, 0x44, 0x31, 0x49, 0x66, 0x0a, 0x78, 0x70, 0x34, 0x56, 0x70, 0x58, + 0x36, 0x2b, 0x6e, 0x36, 0x6c, 0x58, 0x46, 0x6c, 0x6c, 0x56, 0x63, 0x71, + 0x39, 0x6f, 0x6b, 0x33, 0x44, 0x43, 0x73, 0x72, 0x70, 0x31, 0x6d, 0x57, + 0x70, 0x7a, 0x4d, 0x70, 0x54, 0x52, 0x45, 0x45, 0x51, 0x51, 0x4c, 0x74, + 0x2b, 0x43, 0x38, 0x77, 0x65, 0x45, 0x35, 0x6e, 0x51, 0x37, 0x62, 0x58, + 0x48, 0x69, 0x4c, 0x51, 0x77, 0x62, 0x37, 0x69, 0x44, 0x56, 0x0a, 0x79, + 0x53, 0x41, 0x64, 0x59, 0x79, 0x6b, 0x74, 0x7a, 0x75, 0x78, 0x65, 0x54, + 0x73, 0x69, 0x54, 0x2b, 0x43, 0x46, 0x68, 0x6d, 0x7a, 0x54, 0x72, 0x42, + 0x63, 0x5a, 0x65, 0x37, 0x46, 0x73, 0x61, 0x76, 0x4f, 0x76, 0x4a, 0x7a, + 0x38, 0x32, 0x73, 0x4e, 0x45, 0x42, 0x66, 0x73, 0x58, 0x70, 0x6d, 0x37, + 0x6e, 0x66, 0x49, 0x53, 0x4b, 0x68, 0x6d, 0x56, 0x31, 0x65, 0x66, 0x56, + 0x46, 0x69, 0x4f, 0x0a, 0x44, 0x43, 0x75, 0x33, 0x54, 0x36, 0x63, 0x77, + 0x32, 0x56, 0x62, 0x75, 0x79, 0x6e, 0x74, 0x64, 0x34, 0x36, 0x33, 0x4a, + 0x54, 0x31, 0x37, 0x6c, 0x4e, 0x65, 0x63, 0x78, 0x79, 0x39, 0x71, 0x54, + 0x58, 0x74, 0x79, 0x4f, 0x6a, 0x34, 0x44, 0x61, 0x74, 0x70, 0x47, 0x59, + 0x51, 0x4a, 0x42, 0x35, 0x77, 0x33, 0x6a, 0x48, 0x74, 0x72, 0x48, 0x45, + 0x74, 0x57, 0x6f, 0x59, 0x4f, 0x41, 0x4d, 0x51, 0x0a, 0x6a, 0x64, 0x6a, + 0x55, 0x4e, 0x36, 0x51, 0x75, 0x42, 0x58, 0x32, 0x49, 0x39, 0x59, 0x49, + 0x2b, 0x45, 0x4a, 0x46, 0x77, 0x71, 0x31, 0x57, 0x43, 0x51, 0x54, 0x4c, + 0x58, 0x32, 0x77, 0x52, 0x7a, 0x4b, 0x6d, 0x36, 0x52, 0x41, 0x58, 0x77, + 0x68, 0x54, 0x4e, 0x53, 0x38, 0x72, 0x68, 0x73, 0x44, 0x64, 0x56, 0x31, + 0x34, 0x5a, 0x74, 0x6b, 0x36, 0x4d, 0x55, 0x53, 0x61, 0x4d, 0x30, 0x43, + 0x2f, 0x0a, 0x43, 0x4e, 0x64, 0x61, 0x53, 0x61, 0x54, 0x43, 0x35, 0x71, + 0x6d, 0x67, 0x5a, 0x39, 0x32, 0x6b, 0x4a, 0x37, 0x79, 0x68, 0x54, 0x7a, + 0x6d, 0x31, 0x45, 0x56, 0x67, 0x58, 0x39, 0x79, 0x52, 0x63, 0x52, 0x6f, + 0x39, 0x6b, 0x39, 0x38, 0x46, 0x70, 0x69, 0x48, 0x61, 0x59, 0x64, 0x6a, + 0x31, 0x5a, 0x58, 0x55, 0x4a, 0x32, 0x68, 0x34, 0x6d, 0x58, 0x61, 0x58, + 0x70, 0x49, 0x38, 0x4f, 0x43, 0x69, 0x0a, 0x45, 0x68, 0x74, 0x6d, 0x6d, + 0x6e, 0x54, 0x4b, 0x33, 0x6b, 0x73, 0x65, 0x35, 0x77, 0x35, 0x6a, 0x72, + 0x75, 0x62, 0x55, 0x37, 0x35, 0x4b, 0x53, 0x4f, 0x70, 0x34, 0x39, 0x33, + 0x41, 0x44, 0x6b, 0x52, 0x53, 0x57, 0x4a, 0x74, 0x70, 0x70, 0x45, 0x47, + 0x53, 0x74, 0x2b, 0x77, 0x4a, 0x53, 0x30, 0x30, 0x6d, 0x46, 0x74, 0x36, + 0x7a, 0x50, 0x5a, 0x78, 0x64, 0x39, 0x4c, 0x42, 0x41, 0x44, 0x4d, 0x0a, + 0x66, 0x52, 0x79, 0x56, 0x77, 0x34, 0x2f, 0x33, 0x49, 0x62, 0x4b, 0x79, + 0x45, 0x62, 0x65, 0x37, 0x66, 0x2f, 0x4c, 0x56, 0x6a, 0x48, 0x41, 0x73, + 0x51, 0x57, 0x43, 0x71, 0x73, 0x57, 0x4d, 0x59, 0x52, 0x4a, 0x55, 0x61, + 0x64, 0x6d, 0x4a, 0x2b, 0x39, 0x6f, 0x43, 0x77, 0x2b, 0x2b, 0x68, 0x6b, + 0x70, 0x6a, 0x50, 0x52, 0x69, 0x51, 0x66, 0x68, 0x76, 0x62, 0x66, 0x6d, + 0x51, 0x36, 0x51, 0x59, 0x0a, 0x75, 0x4b, 0x5a, 0x33, 0x41, 0x65, 0x45, + 0x50, 0x6c, 0x41, 0x77, 0x68, 0x48, 0x62, 0x4a, 0x55, 0x4b, 0x53, 0x57, + 0x4a, 0x62, 0x4f, 0x55, 0x4f, 0x55, 0x6c, 0x46, 0x48, 0x64, 0x4c, 0x34, + 0x6d, 0x72, 0x4c, 0x5a, 0x42, 0x64, 0x64, 0x35, 0x36, 0x72, 0x46, 0x2b, + 0x4e, 0x50, 0x38, 0x6d, 0x38, 0x30, 0x30, 0x45, 0x52, 0x45, 0x6c, 0x76, + 0x6c, 0x45, 0x46, 0x44, 0x72, 0x4d, 0x63, 0x58, 0x4b, 0x0a, 0x63, 0x68, + 0x59, 0x69, 0x43, 0x64, 0x39, 0x38, 0x54, 0x48, 0x55, 0x2f, 0x59, 0x2b, + 0x77, 0x68, 0x58, 0x38, 0x51, 0x67, 0x55, 0x57, 0x74, 0x76, 0x73, 0x61, + 0x75, 0x47, 0x69, 0x30, 0x2f, 0x43, 0x31, 0x6b, 0x56, 0x66, 0x6e, 0x53, + 0x44, 0x38, 0x6f, 0x52, 0x37, 0x46, 0x77, 0x49, 0x2b, 0x69, 0x73, 0x58, + 0x34, 0x4b, 0x4a, 0x70, 0x6e, 0x31, 0x35, 0x47, 0x6b, 0x76, 0x6d, 0x42, + 0x30, 0x74, 0x0a, 0x39, 0x64, 0x6d, 0x70, 0x73, 0x68, 0x33, 0x6c, 0x47, + 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, + 0x44, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, + 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, + 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, + 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x0a, 0x68, 0x6a, 0x41, 0x64, + 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, + 0x37, 0x4e, 0x66, 0x6a, 0x67, 0x74, 0x4a, 0x78, 0x58, 0x57, 0x52, 0x4d, + 0x33, 0x79, 0x35, 0x6e, 0x50, 0x2b, 0x65, 0x36, 0x6d, 0x4b, 0x34, 0x63, + 0x44, 0x30, 0x38, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4d, 0x42, 0x51, 0x41, 0x44, + 0x0a, 0x67, 0x67, 0x49, 0x42, 0x41, 0x4c, 0x74, 0x68, 0x32, 0x58, 0x32, + 0x70, 0x62, 0x4c, 0x34, 0x58, 0x78, 0x4a, 0x45, 0x62, 0x77, 0x36, 0x47, + 0x69, 0x41, 0x49, 0x33, 0x6a, 0x5a, 0x47, 0x67, 0x50, 0x56, 0x73, 0x39, + 0x33, 0x72, 0x6e, 0x44, 0x35, 0x2f, 0x5a, 0x70, 0x4b, 0x6d, 0x62, 0x6e, + 0x4a, 0x65, 0x46, 0x77, 0x4d, 0x44, 0x46, 0x2f, 0x6b, 0x35, 0x68, 0x51, + 0x70, 0x56, 0x67, 0x73, 0x32, 0x0a, 0x53, 0x56, 0x31, 0x45, 0x59, 0x2b, + 0x43, 0x74, 0x6e, 0x4a, 0x59, 0x59, 0x5a, 0x68, 0x73, 0x6a, 0x44, 0x54, + 0x31, 0x35, 0x36, 0x57, 0x31, 0x72, 0x31, 0x6c, 0x54, 0x34, 0x30, 0x6a, + 0x7a, 0x42, 0x51, 0x30, 0x43, 0x75, 0x48, 0x56, 0x44, 0x31, 0x55, 0x76, + 0x79, 0x51, 0x4f, 0x37, 0x75, 0x59, 0x6d, 0x57, 0x6c, 0x72, 0x78, 0x38, + 0x47, 0x6e, 0x71, 0x47, 0x69, 0x6b, 0x4a, 0x39, 0x79, 0x64, 0x0a, 0x2b, + 0x53, 0x65, 0x75, 0x4d, 0x49, 0x57, 0x35, 0x39, 0x6d, 0x64, 0x4e, 0x4f, + 0x6a, 0x36, 0x50, 0x57, 0x54, 0x6b, 0x69, 0x55, 0x30, 0x54, 0x72, 0x79, + 0x46, 0x30, 0x44, 0x79, 0x75, 0x31, 0x51, 0x65, 0x6e, 0x31, 0x69, 0x49, + 0x51, 0x71, 0x41, 0x79, 0x48, 0x4e, 0x6d, 0x30, 0x61, 0x41, 0x46, 0x59, + 0x46, 0x2f, 0x6f, 0x70, 0x62, 0x53, 0x6e, 0x72, 0x36, 0x6a, 0x33, 0x62, + 0x54, 0x57, 0x63, 0x0a, 0x66, 0x46, 0x71, 0x4b, 0x31, 0x71, 0x49, 0x34, + 0x6d, 0x66, 0x4e, 0x34, 0x69, 0x2f, 0x52, 0x4e, 0x30, 0x69, 0x41, 0x4c, + 0x33, 0x67, 0x54, 0x75, 0x6a, 0x4a, 0x74, 0x48, 0x67, 0x58, 0x49, 0x4e, + 0x77, 0x42, 0x51, 0x79, 0x37, 0x7a, 0x42, 0x5a, 0x4c, 0x71, 0x37, 0x67, + 0x63, 0x66, 0x4a, 0x57, 0x35, 0x47, 0x71, 0x58, 0x62, 0x35, 0x4a, 0x51, + 0x62, 0x5a, 0x61, 0x4e, 0x61, 0x48, 0x71, 0x61, 0x0a, 0x73, 0x6a, 0x59, + 0x55, 0x65, 0x67, 0x62, 0x79, 0x4a, 0x4c, 0x6b, 0x4a, 0x45, 0x56, 0x44, + 0x58, 0x43, 0x4c, 0x47, 0x34, 0x69, 0x58, 0x71, 0x45, 0x49, 0x32, 0x46, + 0x43, 0x4b, 0x65, 0x57, 0x6a, 0x7a, 0x61, 0x49, 0x67, 0x51, 0x64, 0x66, + 0x52, 0x6e, 0x47, 0x54, 0x5a, 0x36, 0x69, 0x61, 0x68, 0x69, 0x78, 0x54, + 0x58, 0x54, 0x42, 0x6d, 0x79, 0x55, 0x45, 0x46, 0x78, 0x50, 0x54, 0x39, + 0x4e, 0x0a, 0x63, 0x43, 0x4f, 0x47, 0x44, 0x45, 0x72, 0x63, 0x67, 0x64, + 0x4c, 0x4d, 0x4d, 0x70, 0x53, 0x45, 0x44, 0x51, 0x67, 0x4a, 0x6c, 0x78, + 0x78, 0x50, 0x77, 0x4f, 0x35, 0x72, 0x49, 0x48, 0x51, 0x77, 0x30, 0x75, + 0x41, 0x35, 0x4e, 0x42, 0x43, 0x46, 0x49, 0x52, 0x55, 0x42, 0x43, 0x4f, + 0x68, 0x56, 0x4d, 0x74, 0x35, 0x78, 0x53, 0x64, 0x6b, 0x6f, 0x46, 0x31, + 0x42, 0x4e, 0x35, 0x72, 0x35, 0x4e, 0x0a, 0x30, 0x58, 0x57, 0x73, 0x30, + 0x4d, 0x72, 0x37, 0x51, 0x62, 0x68, 0x44, 0x70, 0x61, 0x72, 0x54, 0x77, + 0x77, 0x56, 0x45, 0x54, 0x79, 0x77, 0x32, 0x6d, 0x2b, 0x4c, 0x36, 0x34, + 0x6b, 0x57, 0x34, 0x49, 0x31, 0x4e, 0x73, 0x42, 0x6d, 0x39, 0x6e, 0x56, + 0x58, 0x39, 0x47, 0x74, 0x55, 0x77, 0x2f, 0x62, 0x69, 0x68, 0x61, 0x65, + 0x53, 0x62, 0x53, 0x70, 0x4b, 0x68, 0x69, 0x6c, 0x39, 0x49, 0x65, 0x0a, + 0x34, 0x75, 0x31, 0x4b, 0x69, 0x37, 0x77, 0x62, 0x2f, 0x55, 0x64, 0x4b, + 0x44, 0x64, 0x39, 0x6e, 0x5a, 0x6e, 0x36, 0x79, 0x57, 0x30, 0x48, 0x51, + 0x4f, 0x2b, 0x54, 0x30, 0x4f, 0x2f, 0x51, 0x45, 0x59, 0x2b, 0x6e, 0x76, + 0x77, 0x6c, 0x51, 0x41, 0x55, 0x61, 0x43, 0x4b, 0x4b, 0x73, 0x6e, 0x4f, + 0x65, 0x4d, 0x7a, 0x56, 0x36, 0x6f, 0x63, 0x45, 0x47, 0x4c, 0x50, 0x4f, + 0x72, 0x30, 0x6d, 0x49, 0x0a, 0x72, 0x2f, 0x4f, 0x53, 0x6d, 0x62, 0x61, + 0x7a, 0x35, 0x6d, 0x45, 0x50, 0x30, 0x6f, 0x55, 0x41, 0x35, 0x31, 0x41, + 0x61, 0x35, 0x42, 0x75, 0x56, 0x6e, 0x52, 0x6d, 0x68, 0x75, 0x5a, 0x79, + 0x78, 0x6d, 0x37, 0x45, 0x41, 0x48, 0x75, 0x2f, 0x51, 0x44, 0x30, 0x39, + 0x43, 0x62, 0x4d, 0x6b, 0x4b, 0x76, 0x4f, 0x35, 0x44, 0x2b, 0x6a, 0x70, + 0x78, 0x70, 0x63, 0x68, 0x4e, 0x4a, 0x71, 0x55, 0x31, 0x0a, 0x2f, 0x59, + 0x6c, 0x64, 0x76, 0x49, 0x56, 0x69, 0x48, 0x54, 0x4c, 0x53, 0x6f, 0x43, + 0x74, 0x55, 0x37, 0x5a, 0x70, 0x58, 0x77, 0x64, 0x76, 0x36, 0x45, 0x4d, + 0x38, 0x5a, 0x74, 0x34, 0x74, 0x4b, 0x47, 0x34, 0x38, 0x42, 0x74, 0x69, + 0x65, 0x56, 0x55, 0x2b, 0x69, 0x32, 0x69, 0x57, 0x31, 0x62, 0x76, 0x47, + 0x6a, 0x55, 0x49, 0x2b, 0x69, 0x4c, 0x55, 0x61, 0x4a, 0x57, 0x2b, 0x66, + 0x43, 0x6d, 0x0a, 0x67, 0x4b, 0x44, 0x57, 0x48, 0x72, 0x4f, 0x38, 0x44, + 0x77, 0x39, 0x54, 0x64, 0x53, 0x6d, 0x71, 0x36, 0x68, 0x4e, 0x33, 0x35, + 0x4e, 0x36, 0x4d, 0x67, 0x53, 0x47, 0x74, 0x42, 0x78, 0x42, 0x48, 0x45, + 0x61, 0x32, 0x48, 0x50, 0x51, 0x66, 0x52, 0x64, 0x62, 0x7a, 0x50, 0x38, + 0x32, 0x5a, 0x2b, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x4f, 0x4d, 0x4f, + 0x44, 0x4f, 0x20, 0x52, 0x53, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x43, 0x4f, 0x4d, + 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, + 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, + 0x52, 0x53, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, + 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x0a, + 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x4f, + 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x52, 0x53, 0x41, 0x20, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a, 0x23, 0x20, + 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x30, 0x31, 0x39, + 0x30, 0x39, 0x30, 0x38, 0x34, 0x35, 0x33, 0x37, 0x35, 0x38, 0x32, 0x30, + 0x39, 0x33, 0x33, 0x30, 0x38, 0x39, 0x34, 0x31, 0x33, 0x36, 0x33, 0x35, + 0x32, 0x34, 0x38, 0x37, 0x33, 0x31, 0x39, 0x33, 0x31, 0x31, 0x37, 0x0a, + 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x62, 0x3a, 0x33, 0x31, + 0x3a, 0x62, 0x30, 0x3a, 0x37, 0x31, 0x3a, 0x34, 0x30, 0x3a, 0x33, 0x36, + 0x3a, 0x63, 0x63, 0x3a, 0x31, 0x34, 0x3a, 0x33, 0x36, 0x3a, 0x39, 0x31, + 0x3a, 0x61, 0x64, 0x3a, 0x63, 0x34, 0x3a, 0x33, 0x65, 0x3a, 0x66, 0x64, + 0x3a, 0x65, 0x63, 0x3a, 0x31, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x61, 0x66, 0x3a, 0x65, 0x35, 0x3a, 0x64, 0x32, 0x3a, + 0x34, 0x34, 0x3a, 0x61, 0x38, 0x3a, 0x64, 0x31, 0x3a, 0x31, 0x39, 0x3a, + 0x34, 0x32, 0x3a, 0x33, 0x30, 0x3a, 0x66, 0x66, 0x3a, 0x34, 0x37, 0x3a, + 0x39, 0x66, 0x3a, 0x65, 0x32, 0x3a, 0x66, 0x38, 0x3a, 0x39, 0x37, 0x3a, + 0x62, 0x62, 0x3a, 0x63, 0x64, 0x3a, 0x37, 0x61, 0x3a, 0x38, 0x63, 0x3a, + 0x62, 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x35, 0x32, 0x3a, 0x66, 0x30, 0x3a, 0x65, 0x31, 0x3a, 0x63, 0x34, + 0x3a, 0x65, 0x35, 0x3a, 0x38, 0x65, 0x3a, 0x63, 0x36, 0x3a, 0x32, 0x39, + 0x3a, 0x32, 0x39, 0x3a, 0x31, 0x62, 0x3a, 0x36, 0x30, 0x3a, 0x33, 0x31, + 0x3a, 0x37, 0x66, 0x3a, 0x30, 0x37, 0x3a, 0x34, 0x36, 0x3a, 0x37, 0x31, + 0x3a, 0x62, 0x38, 0x3a, 0x35, 0x64, 0x3a, 0x37, 0x65, 0x3a, 0x61, 0x38, + 0x3a, 0x30, 0x64, 0x3a, 0x35, 0x62, 0x3a, 0x30, 0x37, 0x3a, 0x32, 0x37, + 0x3a, 0x33, 0x34, 0x3a, 0x36, 0x33, 0x3a, 0x35, 0x33, 0x3a, 0x34, 0x62, + 0x3a, 0x33, 0x32, 0x3a, 0x62, 0x34, 0x3a, 0x30, 0x32, 0x3a, 0x33, 0x34, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x32, 0x44, 0x43, + 0x43, 0x41, 0x38, 0x43, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x51, 0x54, 0x4b, 0x72, 0x35, 0x79, 0x74, 0x74, 0x6a, 0x62, 0x2b, 0x41, + 0x66, 0x39, 0x30, 0x37, 0x59, 0x57, 0x77, 0x4f, 0x47, 0x6e, 0x54, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, + 0x42, 0x41, 0x51, 0x77, 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x68, 0x54, + 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, + 0x4d, 0x43, 0x52, 0x30, 0x49, 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x67, 0x54, 0x45, 0x6b, 0x64, 0x79, 0x5a, 0x57, + 0x46, 0x30, 0x5a, 0x58, 0x49, 0x67, 0x54, 0x57, 0x46, 0x75, 0x59, 0x32, + 0x68, 0x6c, 0x63, 0x33, 0x52, 0x6c, 0x63, 0x6a, 0x45, 0x51, 0x4d, 0x41, + 0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, 0x78, 0x4d, 0x48, 0x55, + 0x32, 0x46, 0x73, 0x5a, 0x6d, 0x39, 0x79, 0x5a, 0x44, 0x45, 0x61, 0x4d, + 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x52, 0x51, + 0x30, 0x39, 0x4e, 0x54, 0x30, 0x52, 0x50, 0x49, 0x45, 0x4e, 0x42, 0x49, + 0x45, 0x78, 0x70, 0x62, 0x57, 0x6c, 0x30, 0x5a, 0x57, 0x51, 0x78, 0x4b, + 0x7a, 0x41, 0x70, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x4d, 0x54, + 0x49, 0x6b, 0x4e, 0x50, 0x54, 0x55, 0x39, 0x45, 0x54, 0x79, 0x42, 0x53, + 0x55, 0x30, 0x45, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, + 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, + 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, + 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x41, 0x77, 0x4d, 0x54, 0x45, 0x35, + 0x0a, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, + 0x4e, 0x4d, 0x7a, 0x67, 0x77, 0x4d, 0x54, 0x45, 0x34, 0x4d, 0x6a, 0x4d, + 0x31, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, 0x43, 0x42, 0x68, 0x54, 0x45, + 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x52, 0x30, 0x49, 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x67, 0x54, 0x0a, 0x45, 0x6b, 0x64, 0x79, 0x5a, 0x57, + 0x46, 0x30, 0x5a, 0x58, 0x49, 0x67, 0x54, 0x57, 0x46, 0x75, 0x59, 0x32, + 0x68, 0x6c, 0x63, 0x33, 0x52, 0x6c, 0x63, 0x6a, 0x45, 0x51, 0x4d, 0x41, + 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x78, 0x4d, 0x48, 0x55, 0x32, + 0x46, 0x73, 0x5a, 0x6d, 0x39, 0x79, 0x5a, 0x44, 0x45, 0x61, 0x4d, 0x42, + 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x52, 0x0a, 0x51, + 0x30, 0x39, 0x4e, 0x54, 0x30, 0x52, 0x50, 0x49, 0x45, 0x4e, 0x42, 0x49, + 0x45, 0x78, 0x70, 0x62, 0x57, 0x6c, 0x30, 0x5a, 0x57, 0x51, 0x78, 0x4b, + 0x7a, 0x41, 0x70, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x49, + 0x6b, 0x4e, 0x50, 0x54, 0x55, 0x39, 0x45, 0x54, 0x79, 0x42, 0x53, 0x55, + 0x30, 0x45, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, + 0x57, 0x4e, 0x68, 0x0a, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, + 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, + 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, + 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, + 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, + 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51, 0x43, 0x52, 0x0a, 0x36, 0x46, 0x53, + 0x53, 0x30, 0x67, 0x70, 0x57, 0x73, 0x61, 0x77, 0x4e, 0x4a, 0x4e, 0x33, + 0x46, 0x7a, 0x30, 0x52, 0x6e, 0x64, 0x4a, 0x6b, 0x72, 0x4e, 0x36, 0x4e, + 0x39, 0x49, 0x33, 0x41, 0x41, 0x63, 0x62, 0x78, 0x54, 0x33, 0x38, 0x54, + 0x36, 0x4b, 0x68, 0x4b, 0x50, 0x53, 0x33, 0x38, 0x51, 0x56, 0x72, 0x32, + 0x66, 0x63, 0x48, 0x4b, 0x33, 0x59, 0x58, 0x2f, 0x4a, 0x53, 0x77, 0x38, + 0x58, 0x0a, 0x70, 0x7a, 0x33, 0x6a, 0x73, 0x41, 0x52, 0x68, 0x37, 0x76, + 0x38, 0x52, 0x6c, 0x38, 0x66, 0x30, 0x68, 0x6a, 0x34, 0x4b, 0x2b, 0x6a, + 0x35, 0x63, 0x2b, 0x5a, 0x50, 0x6d, 0x4e, 0x48, 0x72, 0x5a, 0x46, 0x47, + 0x76, 0x6e, 0x6e, 0x4c, 0x4f, 0x46, 0x6f, 0x49, 0x4a, 0x36, 0x64, 0x71, + 0x39, 0x78, 0x6b, 0x4e, 0x66, 0x73, 0x2f, 0x51, 0x33, 0x36, 0x6e, 0x47, + 0x7a, 0x36, 0x33, 0x37, 0x43, 0x43, 0x0a, 0x39, 0x42, 0x52, 0x2b, 0x2b, + 0x62, 0x37, 0x45, 0x70, 0x69, 0x39, 0x50, 0x66, 0x35, 0x6c, 0x2f, 0x74, + 0x66, 0x78, 0x6e, 0x51, 0x33, 0x4b, 0x39, 0x44, 0x41, 0x44, 0x57, 0x69, + 0x65, 0x74, 0x72, 0x4c, 0x4e, 0x50, 0x74, 0x6a, 0x35, 0x67, 0x63, 0x46, + 0x4b, 0x74, 0x2b, 0x35, 0x65, 0x4e, 0x75, 0x2f, 0x4e, 0x69, 0x6f, 0x35, + 0x4a, 0x49, 0x6b, 0x32, 0x6b, 0x4e, 0x72, 0x59, 0x72, 0x68, 0x56, 0x0a, + 0x2f, 0x65, 0x72, 0x42, 0x76, 0x47, 0x79, 0x32, 0x69, 0x2f, 0x4d, 0x4f, + 0x6a, 0x5a, 0x72, 0x6b, 0x6d, 0x32, 0x78, 0x70, 0x6d, 0x66, 0x68, 0x34, + 0x53, 0x44, 0x42, 0x46, 0x31, 0x61, 0x33, 0x68, 0x44, 0x54, 0x78, 0x46, + 0x59, 0x50, 0x77, 0x79, 0x6c, 0x6c, 0x45, 0x6e, 0x76, 0x47, 0x66, 0x44, + 0x79, 0x69, 0x36, 0x32, 0x61, 0x2b, 0x70, 0x47, 0x78, 0x38, 0x63, 0x67, + 0x6f, 0x4c, 0x45, 0x66, 0x0a, 0x5a, 0x64, 0x35, 0x49, 0x43, 0x4c, 0x71, + 0x6b, 0x54, 0x71, 0x6e, 0x79, 0x67, 0x30, 0x59, 0x33, 0x68, 0x4f, 0x76, + 0x6f, 0x7a, 0x49, 0x46, 0x49, 0x51, 0x32, 0x64, 0x4f, 0x63, 0x69, 0x71, + 0x62, 0x58, 0x4c, 0x31, 0x4d, 0x47, 0x79, 0x69, 0x4b, 0x58, 0x43, 0x4a, + 0x37, 0x74, 0x4b, 0x75, 0x59, 0x32, 0x65, 0x37, 0x67, 0x55, 0x59, 0x50, + 0x44, 0x43, 0x55, 0x5a, 0x4f, 0x62, 0x54, 0x36, 0x5a, 0x0a, 0x2b, 0x70, + 0x55, 0x58, 0x32, 0x6e, 0x77, 0x7a, 0x56, 0x30, 0x45, 0x38, 0x6a, 0x56, + 0x48, 0x74, 0x43, 0x37, 0x5a, 0x63, 0x72, 0x79, 0x78, 0x6a, 0x47, 0x74, + 0x39, 0x58, 0x79, 0x44, 0x2b, 0x38, 0x36, 0x56, 0x33, 0x45, 0x6d, 0x36, + 0x39, 0x46, 0x6d, 0x65, 0x4b, 0x6a, 0x57, 0x69, 0x53, 0x30, 0x75, 0x71, + 0x6c, 0x57, 0x50, 0x63, 0x39, 0x76, 0x71, 0x76, 0x39, 0x4a, 0x57, 0x4c, + 0x37, 0x77, 0x0a, 0x71, 0x50, 0x2f, 0x30, 0x75, 0x4b, 0x33, 0x70, 0x4e, + 0x2f, 0x75, 0x36, 0x75, 0x50, 0x51, 0x4c, 0x4f, 0x76, 0x6e, 0x6f, 0x51, + 0x30, 0x49, 0x65, 0x69, 0x64, 0x69, 0x45, 0x79, 0x78, 0x50, 0x78, 0x32, + 0x62, 0x76, 0x68, 0x69, 0x57, 0x43, 0x34, 0x6a, 0x43, 0x68, 0x57, 0x72, + 0x42, 0x51, 0x64, 0x6e, 0x41, 0x72, 0x6e, 0x63, 0x65, 0x76, 0x50, 0x44, + 0x74, 0x30, 0x39, 0x71, 0x5a, 0x61, 0x68, 0x0a, 0x53, 0x4c, 0x30, 0x38, + 0x39, 0x36, 0x2b, 0x31, 0x44, 0x53, 0x4a, 0x4d, 0x77, 0x42, 0x47, 0x42, + 0x37, 0x46, 0x59, 0x37, 0x39, 0x74, 0x4f, 0x69, 0x34, 0x6c, 0x75, 0x33, + 0x73, 0x67, 0x51, 0x69, 0x55, 0x70, 0x57, 0x41, 0x6b, 0x32, 0x6e, 0x6f, + 0x6a, 0x6b, 0x78, 0x6c, 0x38, 0x5a, 0x45, 0x44, 0x4c, 0x58, 0x42, 0x30, + 0x41, 0x75, 0x71, 0x4c, 0x5a, 0x78, 0x55, 0x70, 0x61, 0x56, 0x49, 0x43, + 0x0a, 0x75, 0x39, 0x66, 0x66, 0x55, 0x47, 0x70, 0x56, 0x52, 0x72, 0x2b, + 0x67, 0x6f, 0x79, 0x68, 0x68, 0x66, 0x33, 0x44, 0x51, 0x77, 0x36, 0x4b, + 0x71, 0x4c, 0x43, 0x47, 0x71, 0x52, 0x38, 0x34, 0x6f, 0x6e, 0x41, 0x5a, + 0x46, 0x64, 0x72, 0x2b, 0x43, 0x47, 0x43, 0x65, 0x30, 0x31, 0x61, 0x36, + 0x30, 0x79, 0x31, 0x44, 0x6d, 0x61, 0x2f, 0x52, 0x4d, 0x68, 0x6e, 0x45, + 0x77, 0x36, 0x61, 0x62, 0x66, 0x0a, 0x46, 0x6f, 0x62, 0x67, 0x32, 0x50, + 0x39, 0x41, 0x33, 0x66, 0x76, 0x51, 0x51, 0x6f, 0x68, 0x2f, 0x6f, 0x7a, + 0x4d, 0x36, 0x4c, 0x6c, 0x77, 0x65, 0x51, 0x52, 0x47, 0x42, 0x59, 0x38, + 0x34, 0x59, 0x63, 0x57, 0x73, 0x72, 0x37, 0x4b, 0x61, 0x4b, 0x74, 0x7a, + 0x46, 0x63, 0x4f, 0x6d, 0x70, 0x48, 0x34, 0x4d, 0x4e, 0x35, 0x57, 0x64, + 0x59, 0x67, 0x47, 0x71, 0x2f, 0x79, 0x61, 0x70, 0x69, 0x71, 0x0a, 0x63, + 0x72, 0x78, 0x58, 0x53, 0x74, 0x4a, 0x4c, 0x6e, 0x62, 0x73, 0x51, 0x2f, + 0x4c, 0x42, 0x4d, 0x51, 0x65, 0x58, 0x74, 0x48, 0x54, 0x31, 0x65, 0x4b, + 0x4a, 0x32, 0x63, 0x7a, 0x4c, 0x2b, 0x7a, 0x55, 0x64, 0x71, 0x6e, 0x52, + 0x2b, 0x57, 0x45, 0x55, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, + 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x51, 0x34, 0x45, 0x0a, 0x46, 0x67, 0x51, 0x55, 0x75, 0x36, 0x39, 0x2b, + 0x41, 0x6a, 0x33, 0x36, 0x70, 0x76, 0x45, 0x38, 0x68, 0x49, 0x36, 0x74, + 0x37, 0x6a, 0x69, 0x59, 0x37, 0x4e, 0x6b, 0x79, 0x4d, 0x74, 0x51, 0x77, + 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, + 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x41, 0x38, 0x47, + 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x0a, 0x2f, 0x77, 0x51, + 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x44, 0x51, 0x59, + 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, + 0x4d, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x42, 0x41, 0x41, 0x72, + 0x78, 0x31, 0x55, 0x61, 0x45, 0x74, 0x36, 0x35, 0x52, 0x75, 0x32, 0x79, + 0x79, 0x54, 0x55, 0x45, 0x55, 0x41, 0x4a, 0x4e, 0x4d, 0x6e, 0x4d, 0x76, + 0x6c, 0x0a, 0x77, 0x46, 0x54, 0x50, 0x6f, 0x43, 0x57, 0x4f, 0x41, 0x76, + 0x6e, 0x39, 0x73, 0x4b, 0x49, 0x4e, 0x39, 0x53, 0x43, 0x59, 0x50, 0x42, + 0x4d, 0x74, 0x72, 0x46, 0x61, 0x69, 0x73, 0x4e, 0x5a, 0x2b, 0x45, 0x5a, + 0x4c, 0x70, 0x4c, 0x72, 0x71, 0x65, 0x4c, 0x70, 0x70, 0x79, 0x73, 0x62, + 0x30, 0x5a, 0x52, 0x47, 0x78, 0x68, 0x4e, 0x61, 0x4b, 0x61, 0x74, 0x42, + 0x59, 0x53, 0x61, 0x56, 0x71, 0x4d, 0x0a, 0x34, 0x64, 0x63, 0x2b, 0x70, + 0x42, 0x72, 0x6f, 0x4c, 0x77, 0x50, 0x30, 0x72, 0x6d, 0x45, 0x64, 0x45, + 0x42, 0x73, 0x71, 0x70, 0x49, 0x74, 0x36, 0x78, 0x66, 0x34, 0x46, 0x70, + 0x75, 0x48, 0x41, 0x31, 0x73, 0x6a, 0x2b, 0x6e, 0x71, 0x36, 0x50, 0x4b, + 0x37, 0x6f, 0x39, 0x6d, 0x66, 0x6a, 0x59, 0x63, 0x77, 0x6c, 0x59, 0x52, + 0x6d, 0x36, 0x6d, 0x6e, 0x50, 0x54, 0x58, 0x4a, 0x39, 0x4f, 0x56, 0x0a, + 0x32, 0x6a, 0x65, 0x44, 0x63, 0x68, 0x7a, 0x54, 0x63, 0x2b, 0x43, 0x69, + 0x52, 0x35, 0x6b, 0x44, 0x4f, 0x46, 0x33, 0x56, 0x53, 0x58, 0x6b, 0x41, + 0x4b, 0x52, 0x7a, 0x48, 0x37, 0x4a, 0x73, 0x67, 0x48, 0x41, 0x63, 0x6b, + 0x61, 0x56, 0x64, 0x34, 0x73, 0x6a, 0x6e, 0x38, 0x4f, 0x6f, 0x53, 0x67, + 0x74, 0x5a, 0x78, 0x38, 0x6a, 0x62, 0x38, 0x75, 0x6b, 0x32, 0x49, 0x6e, + 0x74, 0x7a, 0x6e, 0x61, 0x0a, 0x46, 0x78, 0x69, 0x75, 0x76, 0x54, 0x77, + 0x4a, 0x61, 0x50, 0x2b, 0x45, 0x6d, 0x7a, 0x7a, 0x56, 0x31, 0x67, 0x73, + 0x44, 0x34, 0x31, 0x65, 0x65, 0x46, 0x50, 0x66, 0x52, 0x36, 0x30, 0x2f, + 0x49, 0x76, 0x59, 0x63, 0x6a, 0x74, 0x37, 0x5a, 0x4a, 0x51, 0x33, 0x6d, + 0x46, 0x58, 0x4c, 0x72, 0x72, 0x6b, 0x67, 0x75, 0x68, 0x78, 0x75, 0x68, + 0x6f, 0x71, 0x45, 0x77, 0x57, 0x73, 0x52, 0x71, 0x5a, 0x0a, 0x43, 0x75, + 0x68, 0x54, 0x4c, 0x4a, 0x4b, 0x37, 0x6f, 0x51, 0x6b, 0x59, 0x64, 0x51, + 0x78, 0x6c, 0x71, 0x48, 0x76, 0x4c, 0x49, 0x37, 0x63, 0x61, 0x77, 0x69, + 0x69, 0x46, 0x77, 0x78, 0x76, 0x2f, 0x30, 0x43, 0x74, 0x69, 0x37, 0x36, + 0x52, 0x37, 0x43, 0x5a, 0x47, 0x59, 0x5a, 0x34, 0x77, 0x55, 0x41, 0x63, + 0x31, 0x6f, 0x42, 0x6d, 0x70, 0x6a, 0x49, 0x58, 0x55, 0x44, 0x67, 0x49, + 0x69, 0x4b, 0x0a, 0x62, 0x6f, 0x48, 0x47, 0x68, 0x66, 0x4b, 0x70, 0x70, + 0x43, 0x33, 0x6e, 0x39, 0x4b, 0x55, 0x6b, 0x45, 0x45, 0x65, 0x44, 0x79, + 0x73, 0x33, 0x30, 0x6a, 0x58, 0x6c, 0x59, 0x73, 0x51, 0x61, 0x62, 0x35, + 0x78, 0x6f, 0x71, 0x32, 0x5a, 0x30, 0x42, 0x31, 0x35, 0x52, 0x39, 0x37, + 0x51, 0x4e, 0x4b, 0x79, 0x76, 0x44, 0x62, 0x36, 0x4b, 0x6b, 0x42, 0x50, + 0x76, 0x56, 0x57, 0x6d, 0x63, 0x6b, 0x65, 0x0a, 0x6a, 0x6b, 0x6b, 0x39, + 0x75, 0x2b, 0x55, 0x4a, 0x75, 0x65, 0x42, 0x50, 0x53, 0x5a, 0x49, 0x39, + 0x46, 0x6f, 0x4a, 0x41, 0x7a, 0x4d, 0x78, 0x5a, 0x78, 0x75, 0x59, 0x36, + 0x37, 0x52, 0x49, 0x75, 0x61, 0x54, 0x78, 0x73, 0x6c, 0x62, 0x48, 0x39, + 0x71, 0x68, 0x31, 0x37, 0x66, 0x34, 0x61, 0x2b, 0x48, 0x67, 0x34, 0x79, + 0x52, 0x76, 0x76, 0x37, 0x45, 0x34, 0x39, 0x31, 0x66, 0x30, 0x79, 0x4c, + 0x0a, 0x53, 0x30, 0x5a, 0x6a, 0x2f, 0x67, 0x41, 0x30, 0x51, 0x48, 0x44, + 0x42, 0x77, 0x37, 0x6d, 0x68, 0x33, 0x61, 0x5a, 0x77, 0x34, 0x67, 0x53, + 0x7a, 0x51, 0x62, 0x7a, 0x70, 0x67, 0x4a, 0x48, 0x71, 0x5a, 0x4a, 0x78, + 0x36, 0x34, 0x53, 0x49, 0x44, 0x71, 0x5a, 0x78, 0x75, 0x62, 0x77, 0x35, + 0x6c, 0x54, 0x32, 0x79, 0x48, 0x68, 0x31, 0x37, 0x7a, 0x62, 0x71, 0x44, + 0x35, 0x64, 0x61, 0x57, 0x62, 0x0a, 0x51, 0x4f, 0x68, 0x54, 0x73, 0x69, + 0x65, 0x64, 0x53, 0x72, 0x6e, 0x41, 0x64, 0x79, 0x47, 0x4e, 0x2f, 0x34, + 0x66, 0x79, 0x33, 0x72, 0x79, 0x4d, 0x37, 0x78, 0x66, 0x66, 0x74, 0x30, + 0x6b, 0x4c, 0x30, 0x66, 0x4a, 0x75, 0x4d, 0x41, 0x73, 0x61, 0x44, 0x6b, + 0x35, 0x32, 0x37, 0x52, 0x48, 0x38, 0x39, 0x65, 0x6c, 0x57, 0x73, 0x6e, + 0x32, 0x2f, 0x78, 0x32, 0x30, 0x4b, 0x6b, 0x34, 0x79, 0x6c, 0x0a, 0x30, + 0x4d, 0x43, 0x32, 0x48, 0x62, 0x34, 0x36, 0x54, 0x70, 0x53, 0x69, 0x31, + 0x32, 0x35, 0x73, 0x43, 0x38, 0x4b, 0x4b, 0x66, 0x50, 0x6f, 0x67, 0x38, + 0x38, 0x54, 0x6b, 0x35, 0x63, 0x30, 0x4e, 0x71, 0x4d, 0x75, 0x52, 0x6b, + 0x72, 0x46, 0x38, 0x68, 0x65, 0x79, 0x31, 0x46, 0x47, 0x6c, 0x6d, 0x44, + 0x6f, 0x4c, 0x6e, 0x7a, 0x63, 0x37, 0x49, 0x4c, 0x61, 0x5a, 0x52, 0x66, + 0x79, 0x48, 0x42, 0x0a, 0x4e, 0x56, 0x4f, 0x46, 0x42, 0x6b, 0x70, 0x64, + 0x6e, 0x36, 0x32, 0x37, 0x47, 0x31, 0x39, 0x30, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, + 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x55, 0x53, 0x45, 0x52, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, + 0x53, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, + 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x55, 0x53, 0x45, 0x52, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x20, 0x52, 0x53, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x54, 0x68, 0x65, + 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x55, 0x53, 0x45, 0x52, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x20, 0x52, 0x53, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x32, 0x36, 0x34, 0x35, 0x30, 0x39, + 0x33, 0x37, 0x36, 0x34, 0x37, 0x38, 0x31, 0x30, 0x35, 0x38, 0x37, 0x38, + 0x37, 0x35, 0x39, 0x31, 0x38, 0x37, 0x31, 0x36, 0x34, 0x35, 0x36, 0x36, + 0x35, 0x37, 0x38, 0x38, 0x37, 0x31, 0x37, 0x0a, 0x23, 0x20, 0x4d, 0x44, + 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x31, 0x62, 0x3a, 0x66, 0x65, 0x3a, 0x36, 0x39, 0x3a, + 0x64, 0x31, 0x3a, 0x39, 0x31, 0x3a, 0x62, 0x37, 0x3a, 0x31, 0x39, 0x3a, + 0x33, 0x33, 0x3a, 0x61, 0x33, 0x3a, 0x37, 0x32, 0x3a, 0x61, 0x38, 0x3a, + 0x30, 0x66, 0x3a, 0x65, 0x31, 0x3a, 0x35, 0x35, 0x3a, 0x65, 0x35, 0x3a, + 0x62, 0x35, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, + 0x62, 0x3a, 0x38, 0x66, 0x3a, 0x31, 0x62, 0x3a, 0x35, 0x37, 0x3a, 0x33, + 0x33, 0x3a, 0x30, 0x64, 0x3a, 0x62, 0x62, 0x3a, 0x61, 0x32, 0x3a, 0x64, + 0x30, 0x3a, 0x37, 0x61, 0x3a, 0x36, 0x63, 0x3a, 0x35, 0x31, 0x3a, 0x66, + 0x37, 0x3a, 0x30, 0x65, 0x3a, 0x65, 0x39, 0x3a, 0x30, 0x64, 0x3a, 0x64, + 0x61, 0x3a, 0x62, 0x39, 0x3a, 0x61, 0x64, 0x3a, 0x38, 0x65, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x37, 0x3a, + 0x39, 0x33, 0x3a, 0x63, 0x39, 0x3a, 0x62, 0x30, 0x3a, 0x32, 0x66, 0x3a, + 0x64, 0x38, 0x3a, 0x61, 0x61, 0x3a, 0x31, 0x33, 0x3a, 0x65, 0x32, 0x3a, + 0x31, 0x63, 0x3a, 0x33, 0x31, 0x3a, 0x32, 0x32, 0x3a, 0x38, 0x61, 0x3a, + 0x63, 0x63, 0x3a, 0x62, 0x30, 0x3a, 0x38, 0x31, 0x3a, 0x31, 0x39, 0x3a, + 0x36, 0x34, 0x3a, 0x33, 0x62, 0x3a, 0x37, 0x34, 0x3a, 0x39, 0x63, 0x3a, + 0x38, 0x39, 0x3a, 0x38, 0x39, 0x3a, 0x36, 0x34, 0x3a, 0x62, 0x31, 0x3a, + 0x37, 0x34, 0x3a, 0x36, 0x64, 0x3a, 0x34, 0x36, 0x3a, 0x63, 0x33, 0x3a, + 0x64, 0x34, 0x3a, 0x63, 0x62, 0x3a, 0x64, 0x32, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x33, 0x6a, 0x43, 0x43, 0x41, 0x38, 0x61, + 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x41, 0x66, 0x31, + 0x74, 0x4d, 0x50, 0x79, 0x6a, 0x79, 0x6c, 0x47, 0x6f, 0x47, 0x37, 0x78, + 0x6b, 0x44, 0x6a, 0x55, 0x44, 0x4c, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, + 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x77, + 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x69, 0x44, 0x45, 0x4c, 0x4d, 0x41, + 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, + 0x4d, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x67, 0x54, 0x43, 0x6b, 0x35, 0x6c, 0x64, 0x79, 0x42, 0x4b, 0x5a, 0x58, + 0x4a, 0x7a, 0x5a, 0x58, 0x6b, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x43, 0x30, 0x70, 0x6c, 0x0a, 0x63, + 0x6e, 0x4e, 0x6c, 0x65, 0x53, 0x42, 0x44, 0x61, 0x58, 0x52, 0x35, 0x4d, + 0x52, 0x34, 0x77, 0x48, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, + 0x78, 0x56, 0x55, 0x61, 0x47, 0x55, 0x67, 0x56, 0x56, 0x4e, 0x46, 0x55, + 0x6c, 0x52, 0x53, 0x56, 0x56, 0x4e, 0x55, 0x49, 0x45, 0x35, 0x6c, 0x64, + 0x48, 0x64, 0x76, 0x63, 0x6d, 0x73, 0x78, 0x4c, 0x6a, 0x41, 0x73, 0x42, + 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x4d, 0x54, 0x4a, 0x56, 0x56, 0x54, + 0x52, 0x56, 0x4a, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x42, 0x53, + 0x55, 0x30, 0x45, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, + 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, + 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, + 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x41, 0x77, 0x0a, 0x4d, 0x6a, 0x41, + 0x78, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, + 0x4e, 0x4d, 0x7a, 0x67, 0x77, 0x4d, 0x54, 0x45, 0x34, 0x4d, 0x6a, 0x4d, + 0x31, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, 0x43, 0x42, 0x69, 0x44, 0x45, + 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x56, 0x56, 0x4d, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, + 0x56, 0x0a, 0x42, 0x41, 0x67, 0x54, 0x43, 0x6b, 0x35, 0x6c, 0x64, 0x79, + 0x42, 0x4b, 0x5a, 0x58, 0x4a, 0x7a, 0x5a, 0x58, 0x6b, 0x78, 0x46, 0x44, + 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x43, 0x30, + 0x70, 0x6c, 0x63, 0x6e, 0x4e, 0x6c, 0x65, 0x53, 0x42, 0x44, 0x61, 0x58, + 0x52, 0x35, 0x4d, 0x52, 0x34, 0x77, 0x48, 0x41, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4b, 0x45, 0x78, 0x56, 0x55, 0x0a, 0x61, 0x47, 0x55, 0x67, 0x56, + 0x56, 0x4e, 0x46, 0x55, 0x6c, 0x52, 0x53, 0x56, 0x56, 0x4e, 0x55, 0x49, + 0x45, 0x35, 0x6c, 0x64, 0x48, 0x64, 0x76, 0x63, 0x6d, 0x73, 0x78, 0x4c, + 0x6a, 0x41, 0x73, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x4a, + 0x56, 0x56, 0x54, 0x52, 0x56, 0x4a, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, + 0x43, 0x42, 0x53, 0x55, 0x30, 0x45, 0x67, 0x51, 0x32, 0x56, 0x79, 0x0a, + 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, + 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, + 0x64, 0x48, 0x6b, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, + 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, + 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, + 0x67, 0x67, 0x49, 0x4b, 0x0a, 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51, 0x43, + 0x41, 0x45, 0x6d, 0x55, 0x58, 0x4e, 0x67, 0x37, 0x44, 0x32, 0x77, 0x69, + 0x7a, 0x30, 0x4b, 0x78, 0x58, 0x44, 0x58, 0x62, 0x74, 0x7a, 0x53, 0x66, + 0x54, 0x54, 0x4b, 0x31, 0x51, 0x67, 0x32, 0x48, 0x69, 0x71, 0x69, 0x42, + 0x4e, 0x43, 0x53, 0x31, 0x6b, 0x43, 0x64, 0x7a, 0x4f, 0x69, 0x5a, 0x2f, + 0x4d, 0x50, 0x61, 0x6e, 0x73, 0x39, 0x73, 0x2f, 0x42, 0x0a, 0x33, 0x50, + 0x48, 0x54, 0x73, 0x64, 0x5a, 0x37, 0x4e, 0x79, 0x67, 0x52, 0x4b, 0x30, + 0x66, 0x61, 0x4f, 0x63, 0x61, 0x38, 0x4f, 0x68, 0x6d, 0x30, 0x58, 0x36, + 0x61, 0x39, 0x66, 0x5a, 0x32, 0x6a, 0x59, 0x30, 0x4b, 0x32, 0x64, 0x76, + 0x4b, 0x70, 0x4f, 0x79, 0x75, 0x52, 0x2b, 0x4f, 0x4a, 0x76, 0x30, 0x4f, + 0x77, 0x57, 0x49, 0x4a, 0x41, 0x4a, 0x50, 0x75, 0x4c, 0x6f, 0x64, 0x4d, + 0x6b, 0x59, 0x0a, 0x74, 0x4a, 0x48, 0x55, 0x59, 0x6d, 0x54, 0x62, 0x66, + 0x36, 0x4d, 0x47, 0x38, 0x59, 0x67, 0x59, 0x61, 0x70, 0x41, 0x69, 0x50, + 0x4c, 0x7a, 0x2b, 0x45, 0x2f, 0x43, 0x48, 0x46, 0x48, 0x76, 0x32, 0x35, + 0x42, 0x2b, 0x4f, 0x31, 0x4f, 0x52, 0x52, 0x78, 0x68, 0x46, 0x6e, 0x52, + 0x67, 0x68, 0x52, 0x79, 0x34, 0x59, 0x55, 0x56, 0x44, 0x2b, 0x38, 0x4d, + 0x2f, 0x35, 0x2b, 0x62, 0x4a, 0x7a, 0x2f, 0x0a, 0x46, 0x70, 0x30, 0x59, + 0x76, 0x56, 0x47, 0x4f, 0x4e, 0x61, 0x61, 0x6e, 0x5a, 0x73, 0x68, 0x79, + 0x5a, 0x39, 0x73, 0x68, 0x5a, 0x72, 0x48, 0x55, 0x6d, 0x33, 0x67, 0x44, + 0x77, 0x46, 0x41, 0x36, 0x36, 0x4d, 0x7a, 0x77, 0x33, 0x4c, 0x79, 0x65, + 0x54, 0x50, 0x36, 0x76, 0x42, 0x5a, 0x59, 0x31, 0x48, 0x31, 0x64, 0x61, + 0x74, 0x2f, 0x2f, 0x4f, 0x2b, 0x54, 0x32, 0x33, 0x4c, 0x4c, 0x62, 0x32, + 0x0a, 0x56, 0x4e, 0x33, 0x49, 0x35, 0x78, 0x49, 0x36, 0x54, 0x61, 0x35, + 0x4d, 0x69, 0x72, 0x64, 0x63, 0x6d, 0x72, 0x53, 0x33, 0x49, 0x44, 0x33, + 0x4b, 0x66, 0x79, 0x49, 0x30, 0x72, 0x6e, 0x34, 0x37, 0x61, 0x47, 0x59, + 0x42, 0x52, 0x4f, 0x63, 0x42, 0x54, 0x6b, 0x5a, 0x54, 0x6d, 0x7a, 0x4e, + 0x67, 0x39, 0x35, 0x53, 0x2b, 0x55, 0x7a, 0x65, 0x51, 0x63, 0x30, 0x50, + 0x7a, 0x4d, 0x73, 0x4e, 0x54, 0x0a, 0x37, 0x39, 0x75, 0x71, 0x2f, 0x6e, + 0x52, 0x4f, 0x61, 0x63, 0x64, 0x72, 0x6a, 0x47, 0x43, 0x54, 0x33, 0x73, + 0x54, 0x48, 0x44, 0x4e, 0x2f, 0x68, 0x4d, 0x71, 0x37, 0x4d, 0x6b, 0x7a, + 0x74, 0x52, 0x65, 0x4a, 0x56, 0x6e, 0x69, 0x2b, 0x34, 0x39, 0x56, 0x76, + 0x34, 0x4d, 0x30, 0x47, 0x6b, 0x50, 0x47, 0x77, 0x2f, 0x7a, 0x4a, 0x53, + 0x5a, 0x72, 0x4d, 0x32, 0x33, 0x33, 0x62, 0x6b, 0x66, 0x36, 0x0a, 0x63, + 0x30, 0x50, 0x6c, 0x66, 0x67, 0x36, 0x6c, 0x5a, 0x72, 0x45, 0x70, 0x66, + 0x44, 0x4b, 0x45, 0x59, 0x31, 0x57, 0x4a, 0x78, 0x41, 0x33, 0x42, 0x6b, + 0x31, 0x51, 0x77, 0x47, 0x52, 0x4f, 0x73, 0x30, 0x33, 0x30, 0x33, 0x70, + 0x2b, 0x74, 0x64, 0x4f, 0x6d, 0x77, 0x31, 0x58, 0x4e, 0x74, 0x42, 0x31, + 0x78, 0x4c, 0x61, 0x71, 0x55, 0x6b, 0x4c, 0x33, 0x39, 0x69, 0x41, 0x69, + 0x67, 0x6d, 0x54, 0x0a, 0x59, 0x6f, 0x36, 0x31, 0x5a, 0x73, 0x38, 0x6c, + 0x69, 0x4d, 0x32, 0x45, 0x75, 0x4c, 0x45, 0x2f, 0x70, 0x44, 0x6b, 0x50, + 0x32, 0x51, 0x4b, 0x65, 0x36, 0x78, 0x4a, 0x4d, 0x6c, 0x58, 0x7a, 0x7a, + 0x61, 0x77, 0x57, 0x70, 0x58, 0x68, 0x61, 0x44, 0x7a, 0x4c, 0x68, 0x6e, + 0x34, 0x75, 0x67, 0x54, 0x6e, 0x63, 0x78, 0x62, 0x67, 0x74, 0x4e, 0x4d, + 0x73, 0x2b, 0x31, 0x62, 0x2f, 0x39, 0x37, 0x6c, 0x0a, 0x63, 0x36, 0x77, + 0x6a, 0x4f, 0x79, 0x30, 0x41, 0x76, 0x7a, 0x56, 0x56, 0x64, 0x41, 0x6c, + 0x4a, 0x32, 0x45, 0x6c, 0x59, 0x47, 0x6e, 0x2b, 0x53, 0x4e, 0x75, 0x5a, + 0x52, 0x6b, 0x67, 0x37, 0x7a, 0x4a, 0x6e, 0x30, 0x63, 0x54, 0x52, 0x65, + 0x38, 0x79, 0x65, 0x78, 0x44, 0x4a, 0x74, 0x43, 0x2f, 0x51, 0x56, 0x39, + 0x41, 0x71, 0x55, 0x52, 0x45, 0x39, 0x4a, 0x6e, 0x6e, 0x56, 0x34, 0x65, + 0x65, 0x0a, 0x55, 0x42, 0x39, 0x58, 0x56, 0x4b, 0x67, 0x2b, 0x2f, 0x58, + 0x52, 0x6a, 0x4c, 0x37, 0x46, 0x51, 0x5a, 0x51, 0x6e, 0x6d, 0x57, 0x45, + 0x49, 0x75, 0x51, 0x78, 0x70, 0x4d, 0x74, 0x50, 0x41, 0x6c, 0x52, 0x31, + 0x6e, 0x36, 0x42, 0x42, 0x36, 0x54, 0x31, 0x43, 0x5a, 0x47, 0x53, 0x6c, + 0x43, 0x42, 0x73, 0x74, 0x36, 0x2b, 0x65, 0x4c, 0x66, 0x38, 0x5a, 0x78, + 0x58, 0x68, 0x79, 0x56, 0x65, 0x45, 0x0a, 0x48, 0x67, 0x39, 0x6a, 0x31, + 0x75, 0x6c, 0x69, 0x75, 0x74, 0x5a, 0x66, 0x56, 0x53, 0x37, 0x71, 0x58, + 0x4d, 0x59, 0x6f, 0x43, 0x41, 0x51, 0x6c, 0x4f, 0x62, 0x67, 0x4f, 0x4b, + 0x36, 0x6e, 0x79, 0x54, 0x4a, 0x63, 0x63, 0x42, 0x7a, 0x38, 0x4e, 0x55, + 0x76, 0x58, 0x74, 0x37, 0x79, 0x2b, 0x43, 0x44, 0x77, 0x49, 0x44, 0x41, + 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x64, 0x0a, + 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, + 0x55, 0x33, 0x6d, 0x2f, 0x57, 0x71, 0x6f, 0x72, 0x53, 0x73, 0x39, 0x55, + 0x67, 0x4f, 0x48, 0x59, 0x6d, 0x38, 0x43, 0x64, 0x38, 0x72, 0x49, 0x44, + 0x5a, 0x73, 0x73, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, + 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, + 0x4d, 0x41, 0x38, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, + 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, + 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, + 0x4e, 0x41, 0x51, 0x45, 0x4d, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, + 0x42, 0x41, 0x46, 0x7a, 0x55, 0x66, 0x41, 0x33, 0x50, 0x39, 0x77, 0x46, + 0x39, 0x51, 0x5a, 0x6c, 0x6c, 0x44, 0x48, 0x50, 0x46, 0x0a, 0x55, 0x70, + 0x2f, 0x4c, 0x2b, 0x4d, 0x2b, 0x5a, 0x42, 0x6e, 0x38, 0x62, 0x32, 0x6b, + 0x4d, 0x56, 0x6e, 0x35, 0x34, 0x43, 0x56, 0x56, 0x65, 0x57, 0x46, 0x50, + 0x46, 0x53, 0x50, 0x43, 0x65, 0x48, 0x6c, 0x43, 0x6a, 0x74, 0x48, 0x7a, + 0x6f, 0x42, 0x4e, 0x36, 0x4a, 0x32, 0x2f, 0x46, 0x4e, 0x51, 0x77, 0x49, + 0x53, 0x62, 0x78, 0x6d, 0x74, 0x4f, 0x75, 0x6f, 0x77, 0x68, 0x54, 0x36, + 0x4b, 0x4f, 0x0a, 0x56, 0x57, 0x4b, 0x52, 0x38, 0x32, 0x6b, 0x56, 0x32, + 0x4c, 0x79, 0x49, 0x34, 0x38, 0x53, 0x71, 0x43, 0x2f, 0x33, 0x76, 0x71, + 0x4f, 0x6c, 0x4c, 0x56, 0x53, 0x6f, 0x47, 0x49, 0x47, 0x31, 0x56, 0x65, + 0x43, 0x6b, 0x5a, 0x37, 0x6c, 0x38, 0x77, 0x58, 0x45, 0x73, 0x6b, 0x45, + 0x56, 0x58, 0x2f, 0x4a, 0x4a, 0x70, 0x75, 0x58, 0x69, 0x6f, 0x72, 0x37, + 0x67, 0x74, 0x4e, 0x6e, 0x33, 0x2f, 0x33, 0x0a, 0x41, 0x54, 0x69, 0x55, + 0x46, 0x4a, 0x56, 0x44, 0x42, 0x77, 0x6e, 0x37, 0x59, 0x4b, 0x6e, 0x75, + 0x48, 0x4b, 0x73, 0x53, 0x6a, 0x4b, 0x43, 0x61, 0x58, 0x71, 0x65, 0x59, + 0x61, 0x6c, 0x6c, 0x74, 0x69, 0x7a, 0x38, 0x49, 0x2b, 0x38, 0x6a, 0x52, + 0x52, 0x61, 0x38, 0x59, 0x46, 0x57, 0x53, 0x51, 0x45, 0x67, 0x39, 0x7a, + 0x4b, 0x43, 0x37, 0x46, 0x34, 0x69, 0x52, 0x4f, 0x2f, 0x46, 0x6a, 0x73, + 0x0a, 0x38, 0x50, 0x52, 0x46, 0x2f, 0x69, 0x4b, 0x7a, 0x36, 0x79, 0x2b, + 0x4f, 0x30, 0x74, 0x6c, 0x46, 0x59, 0x51, 0x58, 0x42, 0x6c, 0x32, 0x2b, + 0x6f, 0x64, 0x6e, 0x4b, 0x50, 0x69, 0x34, 0x77, 0x32, 0x72, 0x37, 0x38, + 0x4e, 0x42, 0x63, 0x35, 0x78, 0x6a, 0x65, 0x61, 0x6d, 0x62, 0x78, 0x39, + 0x73, 0x70, 0x6e, 0x46, 0x69, 0x78, 0x64, 0x6a, 0x51, 0x67, 0x33, 0x49, + 0x4d, 0x38, 0x57, 0x63, 0x52, 0x0a, 0x69, 0x51, 0x79, 0x63, 0x45, 0x30, + 0x78, 0x79, 0x4e, 0x4e, 0x2b, 0x38, 0x31, 0x58, 0x48, 0x66, 0x71, 0x6e, + 0x48, 0x64, 0x34, 0x62, 0x6c, 0x73, 0x6a, 0x44, 0x77, 0x53, 0x58, 0x57, + 0x58, 0x61, 0x76, 0x56, 0x63, 0x53, 0x74, 0x6b, 0x4e, 0x72, 0x2f, 0x2b, + 0x58, 0x65, 0x54, 0x57, 0x59, 0x52, 0x55, 0x63, 0x2b, 0x5a, 0x72, 0x75, + 0x77, 0x58, 0x74, 0x75, 0x68, 0x78, 0x6b, 0x59, 0x7a, 0x65, 0x0a, 0x53, + 0x66, 0x37, 0x64, 0x4e, 0x58, 0x47, 0x69, 0x46, 0x53, 0x65, 0x55, 0x48, + 0x4d, 0x39, 0x68, 0x34, 0x79, 0x61, 0x37, 0x62, 0x36, 0x4e, 0x6e, 0x4a, + 0x53, 0x46, 0x64, 0x35, 0x74, 0x30, 0x64, 0x43, 0x79, 0x35, 0x6f, 0x47, + 0x7a, 0x75, 0x43, 0x72, 0x2b, 0x79, 0x44, 0x5a, 0x34, 0x58, 0x55, 0x6d, + 0x46, 0x46, 0x30, 0x73, 0x62, 0x6d, 0x5a, 0x67, 0x49, 0x6e, 0x2f, 0x66, + 0x33, 0x67, 0x5a, 0x0a, 0x58, 0x48, 0x6c, 0x4b, 0x59, 0x43, 0x36, 0x53, + 0x51, 0x4b, 0x35, 0x4d, 0x4e, 0x79, 0x6f, 0x73, 0x79, 0x63, 0x64, 0x69, + 0x79, 0x41, 0x35, 0x64, 0x39, 0x7a, 0x5a, 0x62, 0x79, 0x75, 0x41, 0x6c, + 0x4a, 0x51, 0x47, 0x30, 0x33, 0x52, 0x6f, 0x48, 0x6e, 0x48, 0x63, 0x41, + 0x50, 0x39, 0x44, 0x63, 0x31, 0x65, 0x77, 0x39, 0x31, 0x50, 0x71, 0x37, + 0x50, 0x38, 0x79, 0x46, 0x31, 0x6d, 0x39, 0x2f, 0x0a, 0x71, 0x53, 0x33, + 0x66, 0x75, 0x51, 0x4c, 0x33, 0x39, 0x5a, 0x65, 0x61, 0x74, 0x54, 0x58, + 0x61, 0x77, 0x32, 0x65, 0x77, 0x68, 0x30, 0x71, 0x70, 0x4b, 0x4a, 0x34, + 0x6a, 0x6a, 0x76, 0x39, 0x63, 0x4a, 0x32, 0x76, 0x68, 0x73, 0x45, 0x2f, + 0x7a, 0x42, 0x2b, 0x34, 0x41, 0x4c, 0x74, 0x52, 0x5a, 0x68, 0x38, 0x74, + 0x53, 0x51, 0x5a, 0x58, 0x71, 0x39, 0x45, 0x66, 0x58, 0x37, 0x6d, 0x52, + 0x42, 0x0a, 0x56, 0x58, 0x79, 0x4e, 0x57, 0x51, 0x4b, 0x56, 0x33, 0x57, + 0x4b, 0x64, 0x77, 0x72, 0x6e, 0x75, 0x57, 0x69, 0x68, 0x30, 0x68, 0x4b, + 0x57, 0x62, 0x74, 0x35, 0x44, 0x48, 0x44, 0x41, 0x66, 0x66, 0x39, 0x59, + 0x6b, 0x32, 0x64, 0x44, 0x4c, 0x57, 0x4b, 0x4d, 0x47, 0x77, 0x73, 0x41, + 0x76, 0x67, 0x6e, 0x45, 0x7a, 0x44, 0x48, 0x4e, 0x62, 0x38, 0x34, 0x32, + 0x6d, 0x31, 0x52, 0x30, 0x61, 0x42, 0x0a, 0x4c, 0x36, 0x4b, 0x43, 0x71, + 0x39, 0x4e, 0x6a, 0x52, 0x48, 0x44, 0x45, 0x6a, 0x66, 0x38, 0x74, 0x4d, + 0x37, 0x71, 0x74, 0x6a, 0x33, 0x75, 0x31, 0x63, 0x49, 0x69, 0x75, 0x50, + 0x68, 0x6e, 0x50, 0x51, 0x43, 0x6a, 0x59, 0x2f, 0x4d, 0x69, 0x51, 0x75, + 0x31, 0x32, 0x5a, 0x49, 0x76, 0x56, 0x53, 0x35, 0x6c, 0x6a, 0x46, 0x48, + 0x34, 0x67, 0x78, 0x51, 0x2b, 0x36, 0x49, 0x48, 0x64, 0x66, 0x47, 0x0a, + 0x6a, 0x6a, 0x78, 0x44, 0x61, 0x68, 0x32, 0x6e, 0x47, 0x4e, 0x35, 0x39, + 0x50, 0x52, 0x62, 0x78, 0x59, 0x76, 0x6e, 0x4b, 0x6b, 0x4b, 0x6a, 0x39, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x55, 0x53, 0x45, 0x52, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x20, 0x45, 0x43, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, 0x3d, 0x54, 0x68, 0x65, + 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x55, 0x53, 0x45, + 0x52, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x43, 0x43, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x4f, + 0x3d, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52, 0x55, + 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x0a, 0x23, + 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x55, 0x53, 0x45, + 0x52, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x43, 0x43, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x32, + 0x33, 0x30, 0x31, 0x33, 0x38, 0x32, 0x33, 0x37, 0x32, 0x30, 0x31, 0x39, + 0x39, 0x34, 0x38, 0x31, 0x34, 0x35, 0x36, 0x35, 0x36, 0x39, 0x37, 0x32, + 0x30, 0x34, 0x34, 0x33, 0x39, 0x39, 0x37, 0x35, 0x37, 0x32, 0x31, 0x33, + 0x34, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x66, 0x61, 0x3a, + 0x36, 0x38, 0x3a, 0x62, 0x63, 0x3a, 0x64, 0x39, 0x3a, 0x62, 0x35, 0x3a, + 0x37, 0x66, 0x3a, 0x61, 0x64, 0x3a, 0x66, 0x64, 0x3a, 0x63, 0x39, 0x3a, + 0x31, 0x64, 0x3a, 0x30, 0x36, 0x3a, 0x38, 0x33, 0x3a, 0x32, 0x38, 0x3a, + 0x63, 0x63, 0x3a, 0x32, 0x34, 0x3a, 0x63, 0x31, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x31, 0x3a, 0x63, 0x62, 0x3a, 0x63, + 0x61, 0x3a, 0x35, 0x64, 0x3a, 0x62, 0x32, 0x3a, 0x64, 0x35, 0x3a, 0x32, + 0x61, 0x3a, 0x37, 0x66, 0x3a, 0x36, 0x39, 0x3a, 0x33, 0x62, 0x3a, 0x36, + 0x37, 0x3a, 0x34, 0x64, 0x3a, 0x65, 0x35, 0x3a, 0x66, 0x30, 0x3a, 0x35, + 0x61, 0x3a, 0x31, 0x64, 0x3a, 0x30, 0x63, 0x3a, 0x39, 0x35, 0x3a, 0x37, + 0x64, 0x3a, 0x66, 0x30, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, + 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x34, 0x66, 0x3a, 0x66, 0x34, 0x3a, 0x36, 0x30, 0x3a, + 0x64, 0x35, 0x3a, 0x34, 0x62, 0x3a, 0x39, 0x63, 0x3a, 0x38, 0x36, 0x3a, + 0x64, 0x61, 0x3a, 0x62, 0x66, 0x3a, 0x62, 0x63, 0x3a, 0x66, 0x63, 0x3a, + 0x35, 0x37, 0x3a, 0x31, 0x32, 0x3a, 0x65, 0x30, 0x3a, 0x34, 0x30, 0x3a, + 0x30, 0x64, 0x3a, 0x32, 0x62, 0x3a, 0x65, 0x64, 0x3a, 0x33, 0x66, 0x3a, + 0x62, 0x63, 0x3a, 0x34, 0x64, 0x3a, 0x34, 0x66, 0x3a, 0x62, 0x64, 0x3a, + 0x61, 0x61, 0x3a, 0x38, 0x36, 0x3a, 0x65, 0x30, 0x3a, 0x36, 0x61, 0x3a, + 0x64, 0x63, 0x3a, 0x64, 0x32, 0x3a, 0x61, 0x39, 0x3a, 0x61, 0x64, 0x3a, + 0x37, 0x61, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, + 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6a, + 0x7a, 0x43, 0x43, 0x41, 0x68, 0x57, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, + 0x67, 0x49, 0x51, 0x58, 0x49, 0x75, 0x5a, 0x78, 0x56, 0x71, 0x55, 0x78, + 0x64, 0x4a, 0x78, 0x56, 0x74, 0x37, 0x4e, 0x69, 0x59, 0x44, 0x4d, 0x4a, + 0x6a, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, + 0x51, 0x51, 0x44, 0x41, 0x7a, 0x43, 0x42, 0x69, 0x44, 0x45, 0x4c, 0x0a, + 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, + 0x56, 0x56, 0x4d, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x67, 0x54, 0x43, 0x6b, 0x35, 0x6c, 0x64, 0x79, 0x42, 0x4b, + 0x5a, 0x58, 0x4a, 0x7a, 0x5a, 0x58, 0x6b, 0x78, 0x46, 0x44, 0x41, 0x53, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x43, 0x30, 0x70, 0x6c, + 0x63, 0x6e, 0x4e, 0x6c, 0x0a, 0x65, 0x53, 0x42, 0x44, 0x61, 0x58, 0x52, + 0x35, 0x4d, 0x52, 0x34, 0x77, 0x48, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x4b, 0x45, 0x78, 0x56, 0x55, 0x61, 0x47, 0x55, 0x67, 0x56, 0x56, 0x4e, + 0x46, 0x55, 0x6c, 0x52, 0x53, 0x56, 0x56, 0x4e, 0x55, 0x49, 0x45, 0x35, + 0x6c, 0x64, 0x48, 0x64, 0x76, 0x63, 0x6d, 0x73, 0x78, 0x4c, 0x6a, 0x41, + 0x73, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x0a, 0x4a, 0x56, + 0x56, 0x54, 0x52, 0x56, 0x4a, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, + 0x42, 0x46, 0x51, 0x30, 0x4d, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, + 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, + 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, + 0x6b, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x41, 0x77, 0x4d, 0x6a, + 0x41, 0x78, 0x0a, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, + 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x67, 0x77, 0x4d, 0x54, 0x45, 0x34, 0x4d, + 0x6a, 0x4d, 0x31, 0x4f, 0x54, 0x55, 0x35, 0x57, 0x6a, 0x43, 0x42, 0x69, + 0x44, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x54, 0x0a, 0x43, 0x6b, 0x35, 0x6c, + 0x64, 0x79, 0x42, 0x4b, 0x5a, 0x58, 0x4a, 0x7a, 0x5a, 0x58, 0x6b, 0x78, + 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, + 0x43, 0x30, 0x70, 0x6c, 0x63, 0x6e, 0x4e, 0x6c, 0x65, 0x53, 0x42, 0x44, + 0x61, 0x58, 0x52, 0x35, 0x4d, 0x52, 0x34, 0x77, 0x48, 0x41, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4b, 0x45, 0x78, 0x56, 0x55, 0x61, 0x47, 0x55, 0x67, + 0x0a, 0x56, 0x56, 0x4e, 0x46, 0x55, 0x6c, 0x52, 0x53, 0x56, 0x56, 0x4e, + 0x55, 0x49, 0x45, 0x35, 0x6c, 0x64, 0x48, 0x64, 0x76, 0x63, 0x6d, 0x73, + 0x78, 0x4c, 0x6a, 0x41, 0x73, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, + 0x54, 0x4a, 0x56, 0x56, 0x54, 0x52, 0x56, 0x4a, 0x55, 0x63, 0x6e, 0x56, + 0x7a, 0x64, 0x43, 0x42, 0x46, 0x51, 0x30, 0x4d, 0x67, 0x51, 0x32, 0x56, + 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x0a, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, + 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, + 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x77, 0x64, 0x6a, 0x41, 0x51, 0x42, 0x67, + 0x63, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x49, 0x42, 0x42, 0x67, + 0x55, 0x72, 0x67, 0x51, 0x51, 0x41, 0x49, 0x67, 0x4e, 0x69, 0x41, 0x41, + 0x51, 0x61, 0x72, 0x46, 0x52, 0x61, 0x71, 0x66, 0x6c, 0x6f, 0x0a, 0x49, + 0x2b, 0x64, 0x36, 0x31, 0x53, 0x52, 0x76, 0x55, 0x38, 0x5a, 0x61, 0x32, + 0x45, 0x75, 0x72, 0x78, 0x74, 0x57, 0x32, 0x30, 0x65, 0x5a, 0x7a, 0x63, + 0x61, 0x37, 0x64, 0x6e, 0x4e, 0x59, 0x4d, 0x59, 0x66, 0x33, 0x62, 0x6f, + 0x49, 0x6b, 0x44, 0x75, 0x41, 0x55, 0x55, 0x37, 0x46, 0x66, 0x4f, 0x37, + 0x6c, 0x30, 0x2f, 0x34, 0x69, 0x47, 0x7a, 0x7a, 0x76, 0x66, 0x55, 0x69, + 0x6e, 0x6e, 0x67, 0x0a, 0x6f, 0x34, 0x4e, 0x2b, 0x4c, 0x5a, 0x66, 0x51, + 0x59, 0x63, 0x54, 0x78, 0x6d, 0x64, 0x77, 0x6c, 0x6b, 0x57, 0x4f, 0x72, + 0x66, 0x7a, 0x43, 0x6a, 0x74, 0x48, 0x44, 0x69, 0x78, 0x36, 0x45, 0x7a, + 0x6e, 0x50, 0x4f, 0x2f, 0x4c, 0x6c, 0x78, 0x54, 0x73, 0x56, 0x2b, 0x7a, + 0x66, 0x54, 0x4a, 0x2f, 0x69, 0x6a, 0x54, 0x6a, 0x65, 0x58, 0x6d, 0x6a, + 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x42, 0x30, 0x47, 0x0a, 0x41, 0x31, 0x55, + 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x51, 0x36, 0x34, 0x51, 0x6d, + 0x47, 0x31, 0x4d, 0x38, 0x5a, 0x77, 0x70, 0x5a, 0x32, 0x64, 0x45, 0x6c, + 0x32, 0x33, 0x4f, 0x41, 0x31, 0x78, 0x6d, 0x4e, 0x6a, 0x6d, 0x6a, 0x41, + 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, + 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x44, 0x77, 0x59, + 0x44, 0x0a, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, + 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4b, 0x42, 0x67, + 0x67, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x77, + 0x4e, 0x6f, 0x41, 0x44, 0x42, 0x6c, 0x41, 0x6a, 0x41, 0x32, 0x5a, 0x36, + 0x45, 0x57, 0x43, 0x4e, 0x7a, 0x6b, 0x6c, 0x77, 0x42, 0x42, 0x48, 0x55, + 0x36, 0x2b, 0x34, 0x57, 0x4d, 0x42, 0x0a, 0x7a, 0x7a, 0x75, 0x71, 0x51, + 0x68, 0x46, 0x6b, 0x6f, 0x4a, 0x32, 0x55, 0x4f, 0x51, 0x49, 0x52, 0x65, + 0x56, 0x78, 0x37, 0x48, 0x66, 0x70, 0x6b, 0x75, 0x65, 0x34, 0x57, 0x51, + 0x72, 0x4f, 0x2f, 0x69, 0x73, 0x49, 0x4a, 0x78, 0x4f, 0x7a, 0x6b, 0x73, + 0x55, 0x30, 0x43, 0x4d, 0x51, 0x44, 0x70, 0x4b, 0x6d, 0x46, 0x48, 0x6a, + 0x46, 0x4a, 0x4b, 0x53, 0x30, 0x34, 0x59, 0x63, 0x50, 0x62, 0x57, 0x0a, + 0x52, 0x4e, 0x5a, 0x75, 0x39, 0x59, 0x4f, 0x36, 0x62, 0x56, 0x69, 0x39, + 0x4a, 0x4e, 0x6c, 0x57, 0x53, 0x4f, 0x72, 0x76, 0x78, 0x4b, 0x4a, 0x47, + 0x67, 0x59, 0x68, 0x71, 0x4f, 0x6b, 0x62, 0x52, 0x71, 0x5a, 0x74, 0x4e, + 0x79, 0x57, 0x48, 0x61, 0x30, 0x56, 0x31, 0x58, 0x61, 0x68, 0x67, 0x3d, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, + 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x55, 0x3d, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x34, 0x0a, + 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x4f, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, + 0x6e, 0x20, 0x4f, 0x55, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, + 0x69, 0x67, 0x6e, 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x34, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x34, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x34, + 0x33, 0x36, 0x37, 0x31, 0x34, 0x38, 0x32, 0x39, 0x34, 0x39, 0x32, 0x32, + 0x39, 0x36, 0x34, 0x34, 0x38, 0x30, 0x38, 0x35, 0x39, 0x30, 0x32, 0x32, + 0x31, 0x32, 0x35, 0x38, 0x30, 0x30, 0x39, 0x37, 0x37, 0x38, 0x39, 0x37, + 0x34, 0x37, 0x34, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, + 0x30, 0x3a, 0x66, 0x30, 0x3a, 0x32, 0x37, 0x3a, 0x36, 0x38, 0x3a, 0x64, + 0x31, 0x3a, 0x37, 0x65, 0x3a, 0x61, 0x30, 0x3a, 0x39, 0x64, 0x3a, 0x30, + 0x65, 0x3a, 0x65, 0x36, 0x3a, 0x32, 0x61, 0x3a, 0x63, 0x61, 0x3a, 0x64, + 0x66, 0x3a, 0x35, 0x63, 0x3a, 0x38, 0x39, 0x3a, 0x38, 0x65, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x39, 0x3a, 0x36, 0x39, + 0x3a, 0x35, 0x36, 0x3a, 0x32, 0x65, 0x3a, 0x34, 0x30, 0x3a, 0x38, 0x30, + 0x3a, 0x66, 0x34, 0x3a, 0x32, 0x34, 0x3a, 0x61, 0x31, 0x3a, 0x65, 0x37, + 0x3a, 0x31, 0x39, 0x3a, 0x39, 0x66, 0x3a, 0x31, 0x34, 0x3a, 0x62, 0x61, + 0x3a, 0x66, 0x33, 0x3a, 0x65, 0x65, 0x3a, 0x35, 0x38, 0x3a, 0x61, 0x62, + 0x3a, 0x36, 0x61, 0x3a, 0x62, 0x62, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x65, 0x3a, 0x63, 0x39, 0x3a, 0x34, + 0x39, 0x3a, 0x31, 0x31, 0x3a, 0x63, 0x32, 0x3a, 0x39, 0x35, 0x3a, 0x35, + 0x36, 0x3a, 0x37, 0x36, 0x3a, 0x64, 0x62, 0x3a, 0x36, 0x63, 0x3a, 0x30, + 0x61, 0x3a, 0x35, 0x35, 0x3a, 0x30, 0x39, 0x3a, 0x38, 0x36, 0x3a, 0x64, + 0x37, 0x3a, 0x36, 0x65, 0x3a, 0x33, 0x62, 0x3a, 0x61, 0x30, 0x3a, 0x30, + 0x35, 0x3a, 0x36, 0x36, 0x3a, 0x37, 0x63, 0x3a, 0x34, 0x34, 0x3a, 0x32, + 0x63, 0x3a, 0x39, 0x37, 0x3a, 0x36, 0x32, 0x3a, 0x62, 0x34, 0x3a, 0x66, + 0x62, 0x3a, 0x62, 0x37, 0x3a, 0x37, 0x33, 0x3a, 0x64, 0x65, 0x3a, 0x32, + 0x32, 0x3a, 0x38, 0x63, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x42, 0x34, 0x54, 0x43, 0x43, 0x41, 0x59, 0x65, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x52, 0x4b, 0x6a, 0x69, 0x6b, 0x48, 0x4a, 0x59, + 0x4b, 0x42, 0x4e, 0x35, 0x43, 0x73, 0x69, 0x69, 0x6c, 0x43, 0x2b, 0x67, + 0x30, 0x6d, 0x41, 0x49, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, + 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x55, 0x44, 0x45, + 0x6b, 0x0a, 0x4d, 0x43, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, + 0x4d, 0x62, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, 0x55, 0x32, + 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x46, 0x51, 0x30, 0x4d, 0x67, 0x55, 0x6d, + 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x53, 0x41, 0x74, 0x49, 0x46, + 0x49, 0x30, 0x4d, 0x52, 0x4d, 0x77, 0x45, 0x51, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4b, 0x45, 0x77, 0x70, 0x48, 0x0a, 0x62, 0x47, 0x39, 0x69, 0x59, + 0x57, 0x78, 0x54, 0x61, 0x57, 0x64, 0x75, 0x4d, 0x52, 0x4d, 0x77, 0x45, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x77, 0x70, 0x48, 0x62, + 0x47, 0x39, 0x69, 0x59, 0x57, 0x78, 0x54, 0x61, 0x57, 0x64, 0x75, 0x4d, + 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x79, 0x4d, 0x54, 0x45, 0x78, 0x4d, + 0x7a, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x0a, + 0x44, 0x54, 0x4d, 0x34, 0x4d, 0x44, 0x45, 0x78, 0x4f, 0x54, 0x41, 0x7a, + 0x4d, 0x54, 0x51, 0x77, 0x4e, 0x31, 0x6f, 0x77, 0x55, 0x44, 0x45, 0x6b, + 0x4d, 0x43, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x62, + 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, 0x55, 0x32, 0x6c, 0x6e, + 0x62, 0x69, 0x42, 0x46, 0x51, 0x30, 0x4d, 0x67, 0x55, 0x6d, 0x39, 0x76, + 0x64, 0x43, 0x42, 0x44, 0x0a, 0x51, 0x53, 0x41, 0x74, 0x49, 0x46, 0x49, + 0x30, 0x4d, 0x52, 0x4d, 0x77, 0x45, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x4b, 0x45, 0x77, 0x70, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x78, + 0x54, 0x61, 0x57, 0x64, 0x75, 0x4d, 0x52, 0x4d, 0x77, 0x45, 0x51, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x77, 0x70, 0x48, 0x62, 0x47, 0x39, + 0x69, 0x59, 0x57, 0x78, 0x54, 0x61, 0x57, 0x64, 0x75, 0x0a, 0x4d, 0x46, + 0x6b, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, + 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, + 0x30, 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x75, 0x4d, + 0x5a, 0x35, 0x30, 0x34, 0x39, 0x73, 0x4a, 0x51, 0x36, 0x66, 0x4c, 0x6a, + 0x6b, 0x5a, 0x48, 0x41, 0x4f, 0x6b, 0x72, 0x70, 0x72, 0x6c, 0x4f, 0x51, + 0x63, 0x4a, 0x0a, 0x46, 0x73, 0x70, 0x6a, 0x73, 0x62, 0x6d, 0x47, 0x2b, + 0x49, 0x70, 0x58, 0x77, 0x56, 0x66, 0x4f, 0x51, 0x76, 0x70, 0x7a, 0x6f, + 0x66, 0x64, 0x6c, 0x51, 0x76, 0x38, 0x65, 0x77, 0x51, 0x43, 0x79, 0x62, + 0x6e, 0x4d, 0x4f, 0x2f, 0x38, 0x63, 0x68, 0x35, 0x52, 0x69, 0x6b, 0x71, + 0x74, 0x6c, 0x78, 0x50, 0x36, 0x6a, 0x55, 0x75, 0x63, 0x36, 0x4d, 0x48, + 0x61, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77, 0x0a, 0x44, 0x67, 0x59, 0x44, + 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, + 0x41, 0x67, 0x45, 0x47, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, + 0x41, 0x66, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, + 0x42, 0x42, 0x59, 0x45, 0x46, 0x46, 0x53, 0x77, 0x65, 0x36, 0x31, 0x46, + 0x0a, 0x75, 0x4f, 0x4a, 0x41, 0x66, 0x2f, 0x73, 0x4b, 0x62, 0x76, 0x75, + 0x2b, 0x4d, 0x38, 0x6b, 0x38, 0x6f, 0x34, 0x54, 0x56, 0x4d, 0x41, 0x6f, + 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, + 0x43, 0x41, 0x30, 0x67, 0x41, 0x4d, 0x45, 0x55, 0x43, 0x49, 0x51, 0x44, + 0x63, 0x6b, 0x71, 0x47, 0x67, 0x45, 0x36, 0x62, 0x50, 0x41, 0x37, 0x44, + 0x6d, 0x78, 0x43, 0x47, 0x58, 0x0a, 0x6b, 0x50, 0x6f, 0x55, 0x56, 0x79, + 0x30, 0x44, 0x37, 0x4f, 0x34, 0x38, 0x30, 0x32, 0x37, 0x4b, 0x71, 0x47, + 0x78, 0x32, 0x76, 0x4b, 0x4c, 0x65, 0x75, 0x77, 0x49, 0x67, 0x4a, 0x36, + 0x69, 0x46, 0x4a, 0x7a, 0x57, 0x62, 0x56, 0x73, 0x61, 0x6a, 0x38, 0x6b, + 0x66, 0x53, 0x74, 0x32, 0x34, 0x62, 0x41, 0x67, 0x41, 0x58, 0x71, 0x6d, + 0x65, 0x6d, 0x46, 0x5a, 0x48, 0x65, 0x2b, 0x70, 0x54, 0x73, 0x0a, 0x65, + 0x77, 0x76, 0x34, 0x6e, 0x34, 0x51, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, + 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, + 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, + 0x4f, 0x55, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, + 0x6e, 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x20, 0x2d, 0x20, 0x52, 0x35, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x3d, 0x47, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x55, 0x3d, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x45, + 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, + 0x20, 0x52, 0x35, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x20, 0x2d, 0x20, 0x52, 0x35, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x33, 0x32, 0x37, 0x38, 0x35, 0x37, 0x39, + 0x32, 0x30, 0x39, 0x39, 0x39, 0x39, 0x30, 0x35, 0x30, 0x37, 0x32, 0x32, + 0x36, 0x36, 0x38, 0x30, 0x36, 0x39, 0x38, 0x30, 0x31, 0x31, 0x35, 0x36, + 0x30, 0x39, 0x34, 0x37, 0x39, 0x33, 0x31, 0x32, 0x34, 0x34, 0x0a, 0x23, + 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x66, 0x3a, 0x61, 0x64, 0x3a, + 0x33, 0x62, 0x3a, 0x31, 0x63, 0x3a, 0x30, 0x32, 0x3a, 0x31, 0x65, 0x3a, + 0x38, 0x61, 0x3a, 0x62, 0x61, 0x3a, 0x31, 0x37, 0x3a, 0x37, 0x34, 0x3a, + 0x33, 0x38, 0x3a, 0x38, 0x31, 0x3a, 0x30, 0x63, 0x3a, 0x61, 0x32, 0x3a, + 0x62, 0x63, 0x3a, 0x30, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x31, 0x66, 0x3a, 0x32, 0x34, 0x3a, 0x63, 0x36, 0x3a, 0x33, + 0x30, 0x3a, 0x63, 0x64, 0x3a, 0x61, 0x34, 0x3a, 0x31, 0x38, 0x3a, 0x65, + 0x66, 0x3a, 0x32, 0x30, 0x3a, 0x36, 0x39, 0x3a, 0x66, 0x66, 0x3a, 0x61, + 0x64, 0x3a, 0x34, 0x66, 0x3a, 0x64, 0x64, 0x3a, 0x35, 0x66, 0x3a, 0x34, + 0x36, 0x3a, 0x33, 0x61, 0x3a, 0x31, 0x62, 0x3a, 0x36, 0x39, 0x3a, 0x61, + 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x31, 0x37, 0x3a, 0x39, 0x66, 0x3a, 0x62, 0x63, 0x3a, 0x31, 0x34, 0x3a, + 0x38, 0x61, 0x3a, 0x33, 0x64, 0x3a, 0x64, 0x30, 0x3a, 0x30, 0x66, 0x3a, + 0x64, 0x32, 0x3a, 0x34, 0x65, 0x3a, 0x61, 0x31, 0x3a, 0x33, 0x34, 0x3a, + 0x35, 0x38, 0x3a, 0x63, 0x63, 0x3a, 0x34, 0x33, 0x3a, 0x62, 0x66, 0x3a, + 0x61, 0x37, 0x3a, 0x66, 0x35, 0x3a, 0x39, 0x63, 0x3a, 0x38, 0x31, 0x3a, + 0x38, 0x32, 0x3a, 0x64, 0x37, 0x3a, 0x38, 0x33, 0x3a, 0x61, 0x35, 0x3a, + 0x31, 0x33, 0x3a, 0x66, 0x36, 0x3a, 0x65, 0x62, 0x3a, 0x65, 0x63, 0x3a, + 0x31, 0x30, 0x3a, 0x30, 0x63, 0x3a, 0x38, 0x39, 0x3a, 0x32, 0x34, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x48, 0x6a, 0x43, 0x43, + 0x41, 0x61, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x52, + 0x59, 0x46, 0x6c, 0x4a, 0x34, 0x43, 0x59, 0x75, 0x75, 0x31, 0x58, 0x35, + 0x43, 0x6e, 0x65, 0x4b, 0x63, 0x66, 0x6c, 0x4b, 0x32, 0x47, 0x77, 0x77, + 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, + 0x41, 0x77, 0x4d, 0x77, 0x55, 0x44, 0x45, 0x6b, 0x0a, 0x4d, 0x43, 0x49, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x62, 0x52, 0x32, 0x78, + 0x76, 0x59, 0x6d, 0x46, 0x73, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, + 0x46, 0x51, 0x30, 0x4d, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, + 0x44, 0x51, 0x53, 0x41, 0x74, 0x49, 0x46, 0x49, 0x31, 0x4d, 0x52, 0x4d, + 0x77, 0x45, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x70, + 0x48, 0x0a, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x78, 0x54, 0x61, 0x57, + 0x64, 0x75, 0x4d, 0x52, 0x4d, 0x77, 0x45, 0x51, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x44, 0x45, 0x77, 0x70, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, + 0x78, 0x54, 0x61, 0x57, 0x64, 0x75, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, + 0x45, 0x79, 0x4d, 0x54, 0x45, 0x78, 0x4d, 0x7a, 0x41, 0x77, 0x4d, 0x44, + 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x0a, 0x44, 0x54, 0x4d, 0x34, 0x4d, + 0x44, 0x45, 0x78, 0x4f, 0x54, 0x41, 0x7a, 0x4d, 0x54, 0x51, 0x77, 0x4e, + 0x31, 0x6f, 0x77, 0x55, 0x44, 0x45, 0x6b, 0x4d, 0x43, 0x49, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x62, 0x52, 0x32, 0x78, 0x76, 0x59, + 0x6d, 0x46, 0x73, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x69, 0x42, 0x46, 0x51, + 0x30, 0x4d, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x0a, + 0x51, 0x53, 0x41, 0x74, 0x49, 0x46, 0x49, 0x31, 0x4d, 0x52, 0x4d, 0x77, + 0x45, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x70, 0x48, + 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x78, 0x54, 0x61, 0x57, 0x64, 0x75, + 0x4d, 0x52, 0x4d, 0x77, 0x45, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, + 0x45, 0x77, 0x70, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x78, 0x54, + 0x61, 0x57, 0x64, 0x75, 0x0a, 0x4d, 0x48, 0x59, 0x77, 0x45, 0x41, 0x59, + 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x43, 0x41, 0x51, 0x59, + 0x46, 0x4b, 0x34, 0x45, 0x45, 0x41, 0x43, 0x49, 0x44, 0x59, 0x67, 0x41, + 0x45, 0x52, 0x30, 0x55, 0x4f, 0x6c, 0x76, 0x74, 0x39, 0x58, 0x62, 0x2f, + 0x70, 0x4f, 0x64, 0x45, 0x68, 0x2b, 0x4a, 0x38, 0x4c, 0x74, 0x74, 0x56, + 0x37, 0x48, 0x70, 0x49, 0x36, 0x53, 0x46, 0x6b, 0x63, 0x0a, 0x38, 0x47, + 0x49, 0x78, 0x4c, 0x63, 0x42, 0x36, 0x4b, 0x50, 0x34, 0x61, 0x70, 0x31, + 0x79, 0x7a, 0x74, 0x73, 0x79, 0x58, 0x35, 0x30, 0x58, 0x55, 0x57, 0x50, + 0x72, 0x52, 0x64, 0x32, 0x31, 0x44, 0x6f, 0x73, 0x43, 0x48, 0x5a, 0x54, + 0x51, 0x4b, 0x48, 0x33, 0x72, 0x64, 0x36, 0x7a, 0x77, 0x7a, 0x6f, 0x63, + 0x57, 0x64, 0x54, 0x61, 0x52, 0x76, 0x51, 0x5a, 0x55, 0x34, 0x66, 0x38, + 0x6b, 0x65, 0x0a, 0x68, 0x4f, 0x76, 0x52, 0x6e, 0x6b, 0x6d, 0x53, 0x68, + 0x35, 0x53, 0x48, 0x44, 0x44, 0x71, 0x46, 0x53, 0x6d, 0x61, 0x66, 0x6e, + 0x56, 0x6d, 0x54, 0x54, 0x5a, 0x64, 0x68, 0x42, 0x6f, 0x5a, 0x4b, 0x6f, + 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, + 0x51, 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x0a, 0x56, 0x52, 0x30, 0x54, + 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, + 0x2f, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, + 0x46, 0x67, 0x51, 0x55, 0x50, 0x65, 0x59, 0x70, 0x53, 0x4a, 0x76, 0x71, + 0x42, 0x38, 0x6f, 0x68, 0x52, 0x45, 0x6f, 0x6d, 0x33, 0x6d, 0x37, 0x65, + 0x30, 0x6f, 0x50, 0x51, 0x6e, 0x31, 0x6b, 0x77, 0x43, 0x67, 0x59, 0x49, + 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x4d, + 0x44, 0x61, 0x41, 0x41, 0x77, 0x5a, 0x51, 0x49, 0x78, 0x41, 0x4f, 0x56, + 0x70, 0x45, 0x73, 0x6c, 0x75, 0x32, 0x38, 0x59, 0x78, 0x75, 0x67, 0x6c, + 0x42, 0x34, 0x5a, 0x66, 0x34, 0x2b, 0x2f, 0x32, 0x61, 0x34, 0x6e, 0x30, + 0x53, 0x79, 0x65, 0x31, 0x38, 0x5a, 0x4e, 0x50, 0x4c, 0x42, 0x53, 0x57, + 0x4c, 0x56, 0x74, 0x6d, 0x67, 0x0a, 0x35, 0x31, 0x35, 0x64, 0x54, 0x67, + 0x75, 0x44, 0x6e, 0x46, 0x74, 0x32, 0x4b, 0x61, 0x41, 0x4a, 0x4a, 0x69, + 0x46, 0x71, 0x59, 0x67, 0x49, 0x77, 0x63, 0x64, 0x4b, 0x31, 0x6a, 0x31, + 0x7a, 0x71, 0x4f, 0x2b, 0x46, 0x34, 0x43, 0x59, 0x57, 0x6f, 0x64, 0x5a, + 0x49, 0x37, 0x79, 0x46, 0x7a, 0x39, 0x53, 0x4f, 0x38, 0x4e, 0x64, 0x43, + 0x4b, 0x6f, 0x43, 0x4f, 0x4a, 0x75, 0x78, 0x55, 0x6e, 0x4f, 0x0a, 0x78, + 0x77, 0x79, 0x38, 0x70, 0x32, 0x46, 0x70, 0x38, 0x66, 0x63, 0x37, 0x34, + 0x53, 0x72, 0x4c, 0x2b, 0x53, 0x76, 0x7a, 0x5a, 0x70, 0x41, 0x33, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x74, 0x61, 0x61, 0x74, 0x20, 0x64, 0x65, + 0x72, 0x20, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x65, + 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, + 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x53, 0x74, 0x61, 0x61, 0x74, 0x20, 0x64, + 0x65, 0x72, 0x20, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, + 0x65, 0x6e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x74, 0x61, 0x61, 0x74, 0x20, 0x64, + 0x65, 0x72, 0x20, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, + 0x65, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, + 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x53, 0x74, 0x61, 0x61, 0x74, 0x20, + 0x64, 0x65, 0x72, 0x20, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, + 0x64, 0x65, 0x6e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x53, 0x74, 0x61, 0x61, 0x74, 0x20, 0x64, 0x65, 0x72, 0x20, + 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x65, 0x6e, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, + 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, + 0x31, 0x30, 0x30, 0x30, 0x33, 0x30, 0x30, 0x31, 0x0a, 0x23, 0x20, 0x4d, + 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x62, 0x3a, 0x34, 0x36, 0x3a, 0x36, 0x37, + 0x3a, 0x30, 0x37, 0x3a, 0x64, 0x62, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x66, + 0x3a, 0x31, 0x39, 0x3a, 0x38, 0x63, 0x3a, 0x33, 0x35, 0x3a, 0x35, 0x30, + 0x3a, 0x36, 0x30, 0x3a, 0x64, 0x31, 0x3a, 0x30, 0x62, 0x3a, 0x66, 0x34, + 0x3a, 0x33, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x64, 0x38, 0x3a, 0x65, 0x62, 0x3a, 0x36, 0x62, 0x3a, 0x34, 0x31, 0x3a, + 0x35, 0x31, 0x3a, 0x39, 0x32, 0x3a, 0x35, 0x39, 0x3a, 0x65, 0x30, 0x3a, + 0x66, 0x33, 0x3a, 0x65, 0x37, 0x3a, 0x38, 0x35, 0x3a, 0x30, 0x30, 0x3a, + 0x63, 0x30, 0x3a, 0x33, 0x64, 0x3a, 0x62, 0x36, 0x3a, 0x38, 0x38, 0x3a, + 0x39, 0x37, 0x3a, 0x63, 0x39, 0x3a, 0x65, 0x65, 0x3a, 0x66, 0x63, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x63, + 0x3a, 0x34, 0x66, 0x3a, 0x62, 0x30, 0x3a, 0x62, 0x39, 0x3a, 0x35, 0x61, + 0x3a, 0x62, 0x38, 0x3a, 0x62, 0x33, 0x3a, 0x30, 0x30, 0x3a, 0x33, 0x32, + 0x3a, 0x66, 0x34, 0x3a, 0x33, 0x32, 0x3a, 0x62, 0x38, 0x3a, 0x36, 0x66, + 0x3a, 0x35, 0x33, 0x3a, 0x35, 0x66, 0x3a, 0x65, 0x31, 0x3a, 0x37, 0x32, + 0x3a, 0x63, 0x31, 0x3a, 0x38, 0x35, 0x3a, 0x64, 0x30, 0x3a, 0x66, 0x64, + 0x3a, 0x33, 0x39, 0x3a, 0x38, 0x36, 0x3a, 0x35, 0x38, 0x3a, 0x33, 0x37, + 0x3a, 0x63, 0x66, 0x3a, 0x33, 0x36, 0x3a, 0x31, 0x38, 0x3a, 0x37, 0x66, + 0x3a, 0x61, 0x36, 0x3a, 0x66, 0x34, 0x3a, 0x32, 0x38, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x64, 0x44, 0x43, 0x43, 0x41, 0x31, + 0x79, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x45, 0x41, 0x4a, + 0x69, 0x69, 0x4f, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, + 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, + 0x42, 0x61, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x47, 0x45, 0x77, 0x4a, 0x4f, 0x0a, 0x54, 0x44, 0x45, 0x65, 0x4d, + 0x42, 0x77, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x56, 0x55, + 0x33, 0x52, 0x68, 0x59, 0x58, 0x51, 0x67, 0x5a, 0x47, 0x56, 0x79, 0x49, + 0x45, 0x35, 0x6c, 0x5a, 0x47, 0x56, 0x79, 0x62, 0x47, 0x46, 0x75, 0x5a, + 0x47, 0x56, 0x75, 0x4d, 0x53, 0x73, 0x77, 0x4b, 0x51, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x44, 0x44, 0x43, 0x4a, 0x54, 0x64, 0x47, 0x46, 0x68, 0x0a, + 0x64, 0x43, 0x42, 0x6b, 0x5a, 0x58, 0x49, 0x67, 0x54, 0x6d, 0x56, 0x6b, + 0x5a, 0x58, 0x4a, 0x73, 0x59, 0x57, 0x35, 0x6b, 0x5a, 0x57, 0x34, 0x67, + 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x53, 0x41, 0x74, + 0x49, 0x45, 0x63, 0x7a, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x7a, + 0x4d, 0x54, 0x45, 0x78, 0x4e, 0x44, 0x45, 0x78, 0x4d, 0x6a, 0x67, 0x30, + 0x4d, 0x6c, 0x6f, 0x58, 0x0a, 0x44, 0x54, 0x49, 0x34, 0x4d, 0x54, 0x45, + 0x78, 0x4d, 0x7a, 0x49, 0x7a, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, + 0x77, 0x57, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x42, 0x68, 0x4d, 0x43, 0x54, 0x6b, 0x77, 0x78, 0x48, 0x6a, 0x41, + 0x63, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x46, 0x56, 0x4e, + 0x30, 0x59, 0x57, 0x46, 0x30, 0x49, 0x47, 0x52, 0x6c, 0x0a, 0x63, 0x69, + 0x42, 0x4f, 0x5a, 0x57, 0x52, 0x6c, 0x63, 0x6d, 0x78, 0x68, 0x62, 0x6d, + 0x52, 0x6c, 0x62, 0x6a, 0x45, 0x72, 0x4d, 0x43, 0x6b, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x41, 0x77, 0x77, 0x69, 0x55, 0x33, 0x52, 0x68, 0x59, 0x58, + 0x51, 0x67, 0x5a, 0x47, 0x56, 0x79, 0x49, 0x45, 0x35, 0x6c, 0x5a, 0x47, + 0x56, 0x79, 0x62, 0x47, 0x46, 0x75, 0x5a, 0x47, 0x56, 0x75, 0x49, 0x46, + 0x4a, 0x76, 0x0a, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4c, + 0x53, 0x42, 0x48, 0x4d, 0x7a, 0x43, 0x43, 0x41, 0x69, 0x49, 0x77, 0x44, + 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, + 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x50, 0x41, + 0x44, 0x43, 0x43, 0x41, 0x67, 0x6f, 0x43, 0x67, 0x67, 0x49, 0x42, 0x41, + 0x4c, 0x34, 0x79, 0x6f, 0x6c, 0x51, 0x50, 0x0a, 0x63, 0x50, 0x73, 0x73, + 0x58, 0x46, 0x6e, 0x72, 0x62, 0x4d, 0x53, 0x6b, 0x55, 0x65, 0x69, 0x46, + 0x4b, 0x72, 0x50, 0x4d, 0x53, 0x6a, 0x54, 0x79, 0x73, 0x46, 0x2f, 0x7a, + 0x44, 0x73, 0x63, 0x63, 0x50, 0x56, 0x4d, 0x65, 0x69, 0x41, 0x68, 0x6f, + 0x32, 0x47, 0x38, 0x39, 0x72, 0x63, 0x4b, 0x65, 0x7a, 0x49, 0x4a, 0x6e, + 0x42, 0x79, 0x65, 0x48, 0x61, 0x48, 0x45, 0x36, 0x6e, 0x33, 0x57, 0x57, + 0x0a, 0x49, 0x6b, 0x59, 0x46, 0x73, 0x4f, 0x32, 0x74, 0x78, 0x31, 0x75, + 0x65, 0x4b, 0x74, 0x36, 0x63, 0x2f, 0x44, 0x72, 0x47, 0x6c, 0x61, 0x66, + 0x31, 0x46, 0x32, 0x63, 0x59, 0x35, 0x79, 0x39, 0x4a, 0x43, 0x41, 0x78, + 0x63, 0x7a, 0x2b, 0x62, 0x4d, 0x4e, 0x4f, 0x31, 0x34, 0x2b, 0x31, 0x43, + 0x78, 0x33, 0x47, 0x73, 0x79, 0x38, 0x4b, 0x4c, 0x2b, 0x74, 0x6a, 0x7a, + 0x6b, 0x37, 0x46, 0x71, 0x58, 0x0a, 0x78, 0x7a, 0x38, 0x65, 0x63, 0x41, + 0x67, 0x77, 0x6f, 0x4e, 0x7a, 0x46, 0x73, 0x32, 0x31, 0x76, 0x30, 0x49, + 0x4a, 0x79, 0x45, 0x61, 0x76, 0x53, 0x67, 0x57, 0x68, 0x5a, 0x67, 0x68, + 0x65, 0x33, 0x65, 0x4a, 0x4a, 0x67, 0x2b, 0x73, 0x7a, 0x65, 0x50, 0x34, + 0x54, 0x72, 0x6a, 0x54, 0x67, 0x7a, 0x6b, 0x41, 0x70, 0x79, 0x49, 0x2f, + 0x6f, 0x31, 0x7a, 0x43, 0x5a, 0x78, 0x4d, 0x64, 0x46, 0x79, 0x0a, 0x4b, + 0x4a, 0x4c, 0x5a, 0x57, 0x79, 0x4e, 0x74, 0x5a, 0x72, 0x56, 0x74, 0x42, + 0x30, 0x4c, 0x72, 0x70, 0x6a, 0x50, 0x4f, 0x6b, 0x74, 0x76, 0x41, 0x39, + 0x6d, 0x78, 0x6a, 0x65, 0x4d, 0x33, 0x4b, 0x54, 0x6a, 0x32, 0x31, 0x35, + 0x56, 0x4b, 0x62, 0x38, 0x62, 0x34, 0x37, 0x35, 0x6c, 0x52, 0x67, 0x73, + 0x47, 0x59, 0x65, 0x43, 0x61, 0x73, 0x48, 0x2f, 0x6c, 0x53, 0x4a, 0x45, + 0x55, 0x4c, 0x52, 0x0a, 0x39, 0x79, 0x53, 0x36, 0x59, 0x48, 0x67, 0x61, + 0x6d, 0x50, 0x66, 0x4a, 0x45, 0x66, 0x30, 0x57, 0x77, 0x54, 0x55, 0x61, + 0x56, 0x48, 0x58, 0x76, 0x51, 0x39, 0x50, 0x6c, 0x72, 0x6b, 0x37, 0x4f, + 0x35, 0x33, 0x76, 0x44, 0x78, 0x6b, 0x35, 0x68, 0x55, 0x55, 0x75, 0x72, + 0x6d, 0x6b, 0x56, 0x4c, 0x6f, 0x52, 0x39, 0x42, 0x76, 0x55, 0x68, 0x54, + 0x46, 0x58, 0x46, 0x6b, 0x43, 0x34, 0x61, 0x7a, 0x0a, 0x35, 0x53, 0x36, + 0x2b, 0x7a, 0x71, 0x51, 0x62, 0x77, 0x53, 0x6d, 0x45, 0x6f, 0x72, 0x58, + 0x4c, 0x43, 0x43, 0x4e, 0x32, 0x51, 0x79, 0x49, 0x6b, 0x48, 0x78, 0x63, + 0x45, 0x31, 0x47, 0x36, 0x63, 0x78, 0x76, 0x78, 0x2f, 0x4b, 0x32, 0x59, + 0x61, 0x37, 0x49, 0x72, 0x6c, 0x31, 0x73, 0x39, 0x4e, 0x39, 0x57, 0x4d, + 0x4a, 0x74, 0x78, 0x55, 0x35, 0x31, 0x6e, 0x75, 0x73, 0x36, 0x2b, 0x4e, + 0x38, 0x0a, 0x36, 0x55, 0x37, 0x38, 0x64, 0x55, 0x4c, 0x49, 0x37, 0x56, + 0x69, 0x56, 0x44, 0x41, 0x5a, 0x43, 0x6f, 0x70, 0x7a, 0x33, 0x35, 0x48, + 0x43, 0x7a, 0x33, 0x33, 0x4a, 0x76, 0x57, 0x6a, 0x64, 0x41, 0x69, 0x64, + 0x69, 0x46, 0x70, 0x4e, 0x66, 0x78, 0x43, 0x39, 0x35, 0x44, 0x47, 0x64, + 0x52, 0x4b, 0x57, 0x43, 0x79, 0x4d, 0x69, 0x6a, 0x6d, 0x65, 0x76, 0x34, + 0x53, 0x48, 0x38, 0x52, 0x59, 0x37, 0x0a, 0x4e, 0x67, 0x7a, 0x70, 0x30, + 0x37, 0x54, 0x4b, 0x62, 0x42, 0x6c, 0x42, 0x55, 0x67, 0x6d, 0x68, 0x48, + 0x62, 0x42, 0x71, 0x76, 0x34, 0x4c, 0x76, 0x63, 0x46, 0x45, 0x68, 0x4d, + 0x74, 0x77, 0x46, 0x64, 0x6f, 0x7a, 0x4c, 0x39, 0x32, 0x54, 0x6b, 0x41, + 0x31, 0x43, 0x76, 0x6a, 0x4a, 0x46, 0x6e, 0x71, 0x38, 0x58, 0x79, 0x37, + 0x6c, 0x6a, 0x59, 0x33, 0x72, 0x37, 0x33, 0x35, 0x7a, 0x48, 0x50, 0x0a, + 0x62, 0x4d, 0x6b, 0x37, 0x63, 0x63, 0x48, 0x56, 0x69, 0x4c, 0x56, 0x6c, + 0x76, 0x4d, 0x44, 0x6f, 0x46, 0x78, 0x63, 0x48, 0x45, 0x72, 0x56, 0x63, + 0x30, 0x71, 0x73, 0x67, 0x6b, 0x37, 0x54, 0x6d, 0x67, 0x6f, 0x4e, 0x77, + 0x4e, 0x73, 0x58, 0x4e, 0x6f, 0x34, 0x32, 0x74, 0x69, 0x2b, 0x79, 0x6a, + 0x77, 0x55, 0x4f, 0x48, 0x35, 0x6b, 0x50, 0x69, 0x4e, 0x4c, 0x36, 0x56, + 0x69, 0x7a, 0x58, 0x74, 0x0a, 0x42, 0x7a, 0x6e, 0x61, 0x71, 0x42, 0x31, + 0x36, 0x6e, 0x7a, 0x61, 0x65, 0x45, 0x72, 0x41, 0x4d, 0x5a, 0x52, 0x4b, + 0x51, 0x46, 0x57, 0x44, 0x5a, 0x4a, 0x6b, 0x42, 0x45, 0x34, 0x31, 0x5a, + 0x67, 0x70, 0x52, 0x44, 0x55, 0x61, 0x6a, 0x7a, 0x39, 0x51, 0x64, 0x77, + 0x4f, 0x57, 0x6b, 0x65, 0x32, 0x37, 0x35, 0x64, 0x68, 0x64, 0x55, 0x2f, + 0x5a, 0x2f, 0x73, 0x65, 0x79, 0x48, 0x64, 0x54, 0x74, 0x0a, 0x58, 0x55, + 0x6d, 0x7a, 0x71, 0x57, 0x72, 0x4c, 0x5a, 0x6f, 0x51, 0x54, 0x31, 0x56, + 0x79, 0x67, 0x33, 0x4e, 0x39, 0x75, 0x64, 0x77, 0x62, 0x52, 0x63, 0x58, + 0x58, 0x49, 0x56, 0x32, 0x2b, 0x76, 0x44, 0x33, 0x64, 0x62, 0x41, 0x67, + 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x41, + 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, + 0x51, 0x46, 0x0a, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x44, + 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, + 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x30, 0x47, 0x41, + 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x52, 0x55, 0x72, + 0x66, 0x72, 0x48, 0x6b, 0x6c, 0x65, 0x75, 0x79, 0x6a, 0x57, 0x63, 0x4c, + 0x68, 0x4c, 0x37, 0x35, 0x4c, 0x70, 0x64, 0x0a, 0x49, 0x4e, 0x79, 0x55, + 0x56, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, + 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x41, 0x4f, 0x43, + 0x41, 0x67, 0x45, 0x41, 0x4d, 0x4a, 0x6d, 0x64, 0x42, 0x54, 0x4c, 0x49, + 0x58, 0x67, 0x34, 0x37, 0x6d, 0x41, 0x45, 0x36, 0x69, 0x71, 0x54, 0x6e, + 0x42, 0x2f, 0x64, 0x36, 0x2b, 0x4f, 0x65, 0x61, 0x33, 0x31, 0x42, 0x44, + 0x0a, 0x55, 0x35, 0x63, 0x71, 0x50, 0x63, 0x6f, 0x38, 0x52, 0x35, 0x67, + 0x75, 0x34, 0x52, 0x56, 0x37, 0x38, 0x5a, 0x4c, 0x7a, 0x59, 0x64, 0x71, + 0x51, 0x4a, 0x52, 0x5a, 0x6c, 0x77, 0x4a, 0x39, 0x55, 0x58, 0x51, 0x34, + 0x44, 0x4f, 0x31, 0x74, 0x33, 0x41, 0x70, 0x79, 0x45, 0x74, 0x67, 0x32, + 0x59, 0x58, 0x7a, 0x54, 0x64, 0x4f, 0x32, 0x50, 0x43, 0x77, 0x79, 0x69, + 0x42, 0x77, 0x70, 0x77, 0x70, 0x0a, 0x4c, 0x69, 0x6e, 0x69, 0x79, 0x4d, + 0x4d, 0x42, 0x38, 0x6a, 0x50, 0x71, 0x4b, 0x71, 0x72, 0x4d, 0x43, 0x51, + 0x6a, 0x33, 0x5a, 0x57, 0x66, 0x47, 0x7a, 0x64, 0x2f, 0x54, 0x74, 0x69, + 0x75, 0x6e, 0x76, 0x63, 0x7a, 0x52, 0x44, 0x6e, 0x42, 0x66, 0x75, 0x43, + 0x50, 0x52, 0x79, 0x35, 0x46, 0x4f, 0x43, 0x76, 0x54, 0x49, 0x65, 0x75, + 0x58, 0x5a, 0x59, 0x7a, 0x62, 0x42, 0x31, 0x4e, 0x2f, 0x38, 0x0a, 0x49, + 0x70, 0x66, 0x33, 0x59, 0x46, 0x33, 0x71, 0x4b, 0x53, 0x39, 0x59, 0x73, + 0x72, 0x31, 0x59, 0x76, 0x59, 0x32, 0x57, 0x54, 0x78, 0x42, 0x31, 0x76, + 0x30, 0x68, 0x37, 0x50, 0x56, 0x47, 0x48, 0x6f, 0x54, 0x78, 0x30, 0x49, + 0x73, 0x4c, 0x38, 0x42, 0x33, 0x2b, 0x41, 0x33, 0x4d, 0x53, 0x73, 0x2f, + 0x6d, 0x72, 0x42, 0x63, 0x44, 0x43, 0x77, 0x36, 0x59, 0x35, 0x70, 0x34, + 0x69, 0x78, 0x70, 0x0a, 0x67, 0x5a, 0x51, 0x4a, 0x75, 0x74, 0x33, 0x2b, + 0x54, 0x63, 0x43, 0x44, 0x6a, 0x4a, 0x52, 0x59, 0x77, 0x45, 0x59, 0x67, + 0x72, 0x35, 0x77, 0x66, 0x41, 0x76, 0x67, 0x31, 0x56, 0x55, 0x6b, 0x76, + 0x52, 0x74, 0x54, 0x41, 0x38, 0x4b, 0x43, 0x57, 0x41, 0x67, 0x38, 0x7a, + 0x78, 0x58, 0x48, 0x7a, 0x6e, 0x69, 0x4e, 0x39, 0x6c, 0x4c, 0x66, 0x39, + 0x4f, 0x74, 0x4d, 0x4a, 0x67, 0x77, 0x59, 0x68, 0x0a, 0x2f, 0x57, 0x41, + 0x39, 0x72, 0x6a, 0x4c, 0x41, 0x30, 0x75, 0x36, 0x4e, 0x70, 0x76, 0x44, + 0x6e, 0x74, 0x49, 0x4a, 0x38, 0x43, 0x73, 0x78, 0x77, 0x79, 0x58, 0x6d, + 0x41, 0x2b, 0x50, 0x35, 0x4d, 0x39, 0x7a, 0x57, 0x45, 0x47, 0x59, 0x6f, + 0x78, 0x2b, 0x77, 0x72, 0x5a, 0x31, 0x33, 0x2b, 0x62, 0x38, 0x4b, 0x4b, + 0x61, 0x61, 0x38, 0x4d, 0x46, 0x53, 0x75, 0x31, 0x42, 0x59, 0x42, 0x51, + 0x77, 0x0a, 0x30, 0x61, 0x6f, 0x52, 0x51, 0x6d, 0x37, 0x54, 0x49, 0x77, + 0x49, 0x45, 0x43, 0x38, 0x5a, 0x6c, 0x33, 0x64, 0x31, 0x53, 0x64, 0x39, + 0x71, 0x42, 0x61, 0x37, 0x4b, 0x6f, 0x2b, 0x67, 0x45, 0x34, 0x75, 0x5a, + 0x62, 0x71, 0x4b, 0x6d, 0x78, 0x6e, 0x6c, 0x34, 0x6d, 0x55, 0x6e, 0x72, + 0x7a, 0x68, 0x56, 0x4e, 0x58, 0x6b, 0x61, 0x6e, 0x6a, 0x76, 0x53, 0x72, + 0x30, 0x72, 0x6d, 0x6a, 0x31, 0x41, 0x0a, 0x66, 0x73, 0x62, 0x41, 0x64, + 0x64, 0x4a, 0x75, 0x2b, 0x32, 0x67, 0x77, 0x37, 0x4f, 0x79, 0x4c, 0x6e, + 0x66, 0x6c, 0x4a, 0x4e, 0x5a, 0x6f, 0x61, 0x4c, 0x4e, 0x6d, 0x7a, 0x6c, + 0x54, 0x6e, 0x56, 0x48, 0x70, 0x4c, 0x33, 0x70, 0x72, 0x6c, 0x6c, 0x4c, + 0x2b, 0x55, 0x39, 0x62, 0x54, 0x70, 0x49, 0x54, 0x41, 0x6a, 0x63, 0x35, + 0x43, 0x67, 0x53, 0x4b, 0x4c, 0x35, 0x39, 0x4e, 0x56, 0x7a, 0x71, 0x0a, + 0x34, 0x42, 0x5a, 0x2b, 0x45, 0x78, 0x74, 0x71, 0x31, 0x7a, 0x37, 0x58, + 0x6e, 0x76, 0x77, 0x74, 0x64, 0x62, 0x4c, 0x42, 0x46, 0x4e, 0x55, 0x6a, + 0x41, 0x39, 0x74, 0x62, 0x62, 0x77, 0x73, 0x2b, 0x65, 0x43, 0x38, 0x4e, + 0x33, 0x6a, 0x4f, 0x4e, 0x46, 0x72, 0x64, 0x49, 0x35, 0x34, 0x4f, 0x61, + 0x67, 0x51, 0x39, 0x37, 0x77, 0x55, 0x4e, 0x4e, 0x56, 0x51, 0x51, 0x58, + 0x4f, 0x45, 0x70, 0x52, 0x0a, 0x31, 0x56, 0x6d, 0x69, 0x69, 0x58, 0x54, + 0x54, 0x6e, 0x37, 0x34, 0x65, 0x53, 0x39, 0x66, 0x47, 0x62, 0x62, 0x65, + 0x49, 0x4a, 0x47, 0x39, 0x67, 0x6b, 0x61, 0x53, 0x43, 0x68, 0x56, 0x74, + 0x57, 0x51, 0x62, 0x7a, 0x51, 0x52, 0x4b, 0x74, 0x71, 0x45, 0x37, 0x37, + 0x52, 0x4c, 0x46, 0x69, 0x33, 0x45, 0x6a, 0x4e, 0x59, 0x73, 0x6a, 0x64, + 0x6a, 0x33, 0x42, 0x50, 0x31, 0x6c, 0x42, 0x30, 0x2f, 0x0a, 0x51, 0x46, + 0x48, 0x31, 0x54, 0x2f, 0x55, 0x36, 0x37, 0x63, 0x6a, 0x46, 0x36, 0x38, + 0x49, 0x65, 0x48, 0x52, 0x61, 0x56, 0x65, 0x73, 0x64, 0x2b, 0x51, 0x6e, + 0x47, 0x54, 0x62, 0x6b, 0x73, 0x56, 0x74, 0x7a, 0x44, 0x66, 0x71, 0x75, + 0x31, 0x58, 0x68, 0x55, 0x69, 0x73, 0x48, 0x57, 0x72, 0x64, 0x4f, 0x57, + 0x6e, 0x6b, 0x34, 0x58, 0x6c, 0x34, 0x76, 0x73, 0x34, 0x46, 0x76, 0x36, + 0x45, 0x4d, 0x0a, 0x39, 0x34, 0x42, 0x37, 0x49, 0x57, 0x63, 0x6e, 0x4d, + 0x46, 0x6b, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x74, 0x61, 0x61, + 0x74, 0x20, 0x64, 0x65, 0x72, 0x20, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, + 0x61, 0x6e, 0x64, 0x65, 0x6e, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x53, 0x74, 0x61, 0x61, 0x74, + 0x20, 0x64, 0x65, 0x72, 0x20, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, + 0x6e, 0x64, 0x65, 0x6e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x74, 0x61, 0x61, 0x74, + 0x20, 0x64, 0x65, 0x72, 0x20, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, + 0x6e, 0x64, 0x65, 0x6e, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x53, 0x74, 0x61, 0x61, 0x74, 0x20, + 0x64, 0x65, 0x72, 0x20, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, + 0x64, 0x65, 0x6e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x53, 0x74, 0x61, 0x61, 0x74, 0x20, 0x64, 0x65, 0x72, 0x20, + 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x65, 0x6e, 0x20, + 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x31, 0x33, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x66, 0x63, 0x3a, 0x30, 0x36, 0x3a, 0x61, 0x66, 0x3a, 0x37, + 0x62, 0x3a, 0x65, 0x38, 0x3a, 0x31, 0x61, 0x3a, 0x66, 0x31, 0x3a, 0x39, + 0x61, 0x3a, 0x62, 0x34, 0x3a, 0x65, 0x38, 0x3a, 0x64, 0x32, 0x3a, 0x37, + 0x30, 0x3a, 0x31, 0x66, 0x3a, 0x63, 0x30, 0x3a, 0x66, 0x35, 0x3a, 0x62, + 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, 0x36, + 0x3a, 0x65, 0x32, 0x3a, 0x37, 0x65, 0x3a, 0x63, 0x31, 0x3a, 0x34, 0x66, + 0x3a, 0x64, 0x62, 0x3a, 0x38, 0x32, 0x3a, 0x63, 0x31, 0x3a, 0x63, 0x30, + 0x3a, 0x61, 0x36, 0x3a, 0x37, 0x35, 0x3a, 0x62, 0x35, 0x3a, 0x30, 0x35, + 0x3a, 0x62, 0x65, 0x3a, 0x33, 0x64, 0x3a, 0x32, 0x39, 0x3a, 0x62, 0x34, + 0x3a, 0x65, 0x64, 0x3a, 0x64, 0x62, 0x3a, 0x62, 0x62, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x64, 0x3a, 0x32, + 0x34, 0x3a, 0x39, 0x31, 0x3a, 0x34, 0x31, 0x3a, 0x34, 0x63, 0x3a, 0x66, + 0x65, 0x3a, 0x39, 0x35, 0x3a, 0x36, 0x37, 0x3a, 0x34, 0x36, 0x3a, 0x65, + 0x63, 0x3a, 0x34, 0x63, 0x3a, 0x65, 0x66, 0x3a, 0x61, 0x36, 0x3a, 0x63, + 0x66, 0x3a, 0x36, 0x66, 0x3a, 0x37, 0x32, 0x3a, 0x65, 0x32, 0x3a, 0x38, + 0x61, 0x3a, 0x31, 0x33, 0x3a, 0x32, 0x39, 0x3a, 0x34, 0x33, 0x3a, 0x32, + 0x66, 0x3a, 0x39, 0x64, 0x3a, 0x38, 0x61, 0x3a, 0x39, 0x30, 0x3a, 0x37, + 0x61, 0x3a, 0x63, 0x34, 0x3a, 0x63, 0x62, 0x3a, 0x35, 0x64, 0x3a, 0x61, + 0x64, 0x3a, 0x63, 0x31, 0x3a, 0x35, 0x61, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x46, 0x63, 0x44, 0x43, 0x43, 0x41, 0x31, 0x69, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x45, 0x41, 0x4a, 0x69, 0x57, + 0x6a, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, + 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x59, + 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, + 0x45, 0x77, 0x4a, 0x4f, 0x0a, 0x54, 0x44, 0x45, 0x65, 0x4d, 0x42, 0x77, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x56, 0x55, 0x33, 0x52, + 0x68, 0x59, 0x58, 0x51, 0x67, 0x5a, 0x47, 0x56, 0x79, 0x49, 0x45, 0x35, + 0x6c, 0x5a, 0x47, 0x56, 0x79, 0x62, 0x47, 0x46, 0x75, 0x5a, 0x47, 0x56, + 0x75, 0x4d, 0x53, 0x6b, 0x77, 0x4a, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x44, 0x44, 0x43, 0x42, 0x54, 0x64, 0x47, 0x46, 0x68, 0x0a, 0x64, 0x43, + 0x42, 0x6b, 0x5a, 0x58, 0x49, 0x67, 0x54, 0x6d, 0x56, 0x6b, 0x5a, 0x58, + 0x4a, 0x73, 0x59, 0x57, 0x35, 0x6b, 0x5a, 0x57, 0x34, 0x67, 0x52, 0x56, + 0x59, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x54, + 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4d, 0x44, 0x45, 0x79, 0x4d, 0x44, + 0x67, 0x78, 0x4d, 0x54, 0x45, 0x35, 0x4d, 0x6a, 0x6c, 0x61, 0x46, 0x77, + 0x30, 0x79, 0x0a, 0x4d, 0x6a, 0x45, 0x79, 0x4d, 0x44, 0x67, 0x78, 0x4d, + 0x54, 0x45, 0x77, 0x4d, 0x6a, 0x68, 0x61, 0x4d, 0x46, 0x67, 0x78, 0x43, + 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, + 0x6b, 0x35, 0x4d, 0x4d, 0x52, 0x34, 0x77, 0x48, 0x41, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x4b, 0x44, 0x42, 0x56, 0x54, 0x64, 0x47, 0x46, 0x68, 0x64, + 0x43, 0x42, 0x6b, 0x5a, 0x58, 0x49, 0x67, 0x0a, 0x54, 0x6d, 0x56, 0x6b, + 0x5a, 0x58, 0x4a, 0x73, 0x59, 0x57, 0x35, 0x6b, 0x5a, 0x57, 0x34, 0x78, + 0x4b, 0x54, 0x41, 0x6e, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, + 0x49, 0x46, 0x4e, 0x30, 0x59, 0x57, 0x46, 0x30, 0x49, 0x47, 0x52, 0x6c, + 0x63, 0x69, 0x42, 0x4f, 0x5a, 0x57, 0x52, 0x6c, 0x63, 0x6d, 0x78, 0x68, + 0x62, 0x6d, 0x52, 0x6c, 0x62, 0x69, 0x42, 0x46, 0x56, 0x69, 0x42, 0x53, + 0x0a, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x49, 0x49, + 0x43, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, + 0x43, 0x41, 0x67, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x43, 0x43, 0x67, 0x4b, + 0x43, 0x41, 0x67, 0x45, 0x41, 0x34, 0x38, 0x64, 0x2b, 0x69, 0x66, 0x6b, + 0x6b, 0x53, 0x7a, 0x72, 0x53, 0x0a, 0x4d, 0x34, 0x4d, 0x31, 0x4c, 0x47, + 0x6e, 0x73, 0x33, 0x41, 0x6d, 0x6b, 0x34, 0x31, 0x47, 0x6f, 0x4a, 0x53, + 0x74, 0x35, 0x75, 0x41, 0x67, 0x39, 0x34, 0x4a, 0x47, 0x36, 0x68, 0x49, + 0x58, 0x47, 0x68, 0x61, 0x54, 0x4b, 0x35, 0x73, 0x6b, 0x75, 0x55, 0x36, + 0x54, 0x4a, 0x4a, 0x42, 0x37, 0x39, 0x56, 0x57, 0x5a, 0x78, 0x58, 0x53, + 0x7a, 0x46, 0x59, 0x47, 0x67, 0x45, 0x74, 0x39, 0x6e, 0x43, 0x0a, 0x55, + 0x69, 0x59, 0x34, 0x69, 0x4b, 0x54, 0x57, 0x4f, 0x30, 0x43, 0x6d, 0x77, + 0x73, 0x30, 0x2f, 0x7a, 0x5a, 0x69, 0x54, 0x73, 0x31, 0x51, 0x55, 0x57, + 0x4a, 0x5a, 0x56, 0x31, 0x56, 0x44, 0x2b, 0x68, 0x71, 0x32, 0x6b, 0x59, + 0x33, 0x39, 0x63, 0x68, 0x2f, 0x61, 0x4f, 0x35, 0x69, 0x65, 0x53, 0x5a, + 0x78, 0x65, 0x53, 0x41, 0x67, 0x4d, 0x73, 0x33, 0x4e, 0x5a, 0x6d, 0x64, + 0x4f, 0x33, 0x64, 0x0a, 0x5a, 0x2f, 0x2f, 0x42, 0x59, 0x59, 0x31, 0x6a, + 0x54, 0x77, 0x2b, 0x62, 0x62, 0x52, 0x63, 0x77, 0x4a, 0x75, 0x2b, 0x72, + 0x30, 0x68, 0x38, 0x51, 0x6f, 0x50, 0x6e, 0x46, 0x66, 0x78, 0x5a, 0x70, + 0x67, 0x51, 0x4e, 0x48, 0x37, 0x52, 0x35, 0x6f, 0x6a, 0x58, 0x4b, 0x68, + 0x54, 0x62, 0x49, 0x6d, 0x78, 0x72, 0x70, 0x73, 0x58, 0x32, 0x33, 0x57, + 0x72, 0x39, 0x47, 0x78, 0x45, 0x34, 0x36, 0x70, 0x0a, 0x72, 0x66, 0x4e, + 0x65, 0x61, 0x58, 0x55, 0x6d, 0x47, 0x44, 0x35, 0x42, 0x4b, 0x79, 0x46, + 0x2f, 0x37, 0x6f, 0x74, 0x64, 0x42, 0x77, 0x61, 0x64, 0x51, 0x38, 0x51, + 0x70, 0x43, 0x69, 0x76, 0x38, 0x4b, 0x6a, 0x36, 0x47, 0x79, 0x7a, 0x79, + 0x44, 0x4f, 0x76, 0x6e, 0x4a, 0x44, 0x64, 0x72, 0x46, 0x6d, 0x65, 0x4b, + 0x38, 0x65, 0x45, 0x45, 0x7a, 0x64, 0x75, 0x47, 0x2f, 0x4c, 0x31, 0x33, + 0x6c, 0x0a, 0x70, 0x4a, 0x68, 0x51, 0x44, 0x42, 0x58, 0x64, 0x34, 0x50, + 0x71, 0x63, 0x66, 0x7a, 0x68, 0x6f, 0x30, 0x4c, 0x4b, 0x6d, 0x65, 0x71, + 0x66, 0x52, 0x4d, 0x62, 0x31, 0x2b, 0x69, 0x6c, 0x67, 0x6e, 0x51, 0x37, + 0x4f, 0x36, 0x4d, 0x35, 0x48, 0x54, 0x70, 0x35, 0x67, 0x56, 0x58, 0x4a, + 0x72, 0x6d, 0x30, 0x77, 0x39, 0x31, 0x32, 0x66, 0x78, 0x42, 0x6d, 0x4a, + 0x63, 0x2b, 0x71, 0x69, 0x58, 0x62, 0x0a, 0x6a, 0x35, 0x49, 0x75, 0x73, + 0x48, 0x73, 0x4d, 0x58, 0x2f, 0x46, 0x6a, 0x71, 0x54, 0x66, 0x35, 0x6d, + 0x33, 0x56, 0x70, 0x54, 0x43, 0x67, 0x6d, 0x4a, 0x64, 0x72, 0x56, 0x38, + 0x68, 0x4a, 0x77, 0x52, 0x56, 0x58, 0x6a, 0x33, 0x33, 0x4e, 0x65, 0x4e, + 0x2f, 0x55, 0x68, 0x62, 0x4a, 0x43, 0x4f, 0x4e, 0x56, 0x72, 0x4a, 0x30, + 0x79, 0x50, 0x72, 0x30, 0x38, 0x43, 0x2b, 0x65, 0x4b, 0x78, 0x43, 0x0a, + 0x4b, 0x46, 0x68, 0x6d, 0x70, 0x55, 0x5a, 0x74, 0x63, 0x41, 0x4c, 0x58, + 0x45, 0x50, 0x6c, 0x4c, 0x56, 0x50, 0x78, 0x64, 0x68, 0x6b, 0x71, 0x48, + 0x7a, 0x33, 0x2f, 0x4b, 0x52, 0x61, 0x77, 0x52, 0x57, 0x72, 0x55, 0x67, + 0x55, 0x59, 0x30, 0x76, 0x69, 0x45, 0x65, 0x58, 0x4f, 0x63, 0x44, 0x50, + 0x75, 0x73, 0x42, 0x43, 0x41, 0x55, 0x43, 0x5a, 0x53, 0x43, 0x45, 0x4c, + 0x61, 0x36, 0x66, 0x53, 0x0a, 0x2f, 0x5a, 0x62, 0x56, 0x30, 0x62, 0x35, + 0x47, 0x6e, 0x55, 0x6e, 0x67, 0x43, 0x36, 0x61, 0x67, 0x49, 0x6b, 0x34, + 0x34, 0x30, 0x4d, 0x45, 0x38, 0x4d, 0x4c, 0x78, 0x77, 0x6a, 0x79, 0x78, + 0x31, 0x7a, 0x4e, 0x44, 0x46, 0x6a, 0x46, 0x45, 0x37, 0x50, 0x5a, 0x51, + 0x49, 0x5a, 0x43, 0x5a, 0x68, 0x66, 0x62, 0x6e, 0x44, 0x5a, 0x59, 0x38, + 0x55, 0x6e, 0x43, 0x48, 0x51, 0x71, 0x76, 0x30, 0x58, 0x0a, 0x63, 0x67, + 0x4f, 0x50, 0x76, 0x5a, 0x75, 0x4d, 0x35, 0x6c, 0x35, 0x54, 0x6e, 0x72, + 0x6d, 0x64, 0x37, 0x34, 0x4b, 0x37, 0x34, 0x62, 0x7a, 0x69, 0x63, 0x6b, + 0x46, 0x62, 0x49, 0x5a, 0x54, 0x54, 0x52, 0x54, 0x65, 0x55, 0x30, 0x64, + 0x38, 0x4a, 0x4f, 0x56, 0x33, 0x6e, 0x49, 0x36, 0x71, 0x61, 0x48, 0x63, + 0x70, 0x74, 0x71, 0x41, 0x71, 0x47, 0x68, 0x59, 0x71, 0x43, 0x76, 0x6b, + 0x49, 0x48, 0x0a, 0x31, 0x76, 0x49, 0x34, 0x67, 0x6e, 0x50, 0x61, 0x68, + 0x31, 0x76, 0x6c, 0x50, 0x4e, 0x4f, 0x65, 0x50, 0x71, 0x63, 0x37, 0x6e, + 0x76, 0x51, 0x44, 0x73, 0x2f, 0x6e, 0x78, 0x66, 0x52, 0x4e, 0x30, 0x41, + 0x76, 0x2b, 0x37, 0x6f, 0x65, 0x58, 0x36, 0x41, 0x48, 0x6b, 0x63, 0x70, + 0x6d, 0x5a, 0x42, 0x69, 0x46, 0x78, 0x67, 0x56, 0x36, 0x59, 0x75, 0x43, + 0x63, 0x53, 0x36, 0x2f, 0x5a, 0x72, 0x50, 0x0a, 0x70, 0x78, 0x39, 0x41, + 0x77, 0x37, 0x76, 0x4d, 0x57, 0x67, 0x70, 0x56, 0x53, 0x7a, 0x73, 0x34, + 0x64, 0x6c, 0x47, 0x34, 0x59, 0x34, 0x75, 0x45, 0x6c, 0x42, 0x62, 0x6d, + 0x56, 0x76, 0x4d, 0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, 0x43, + 0x4d, 0x45, 0x41, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, + 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, + 0x0a, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, + 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, + 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, + 0x45, 0x46, 0x50, 0x36, 0x72, 0x41, 0x4a, 0x43, 0x59, 0x6e, 0x69, 0x54, + 0x38, 0x71, 0x63, 0x77, 0x61, 0x69, 0x76, 0x73, 0x6e, 0x75, 0x4c, 0x38, + 0x77, 0x62, 0x71, 0x67, 0x37, 0x0a, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, + 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, + 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x41, 0x51, 0x44, 0x50, 0x64, 0x79, + 0x78, 0x75, 0x56, 0x72, 0x35, 0x4f, 0x73, 0x37, 0x61, 0x45, 0x41, 0x4a, + 0x53, 0x72, 0x52, 0x38, 0x6b, 0x4e, 0x30, 0x6e, 0x62, 0x48, 0x68, 0x70, + 0x38, 0x64, 0x42, 0x39, 0x4f, 0x32, 0x74, 0x4c, 0x73, 0x49, 0x0a, 0x65, + 0x4b, 0x39, 0x70, 0x30, 0x67, 0x74, 0x4a, 0x33, 0x6a, 0x50, 0x46, 0x72, + 0x4b, 0x33, 0x43, 0x69, 0x41, 0x4a, 0x39, 0x42, 0x72, 0x63, 0x31, 0x41, + 0x73, 0x46, 0x67, 0x79, 0x62, 0x2f, 0x45, 0x36, 0x4a, 0x54, 0x65, 0x31, + 0x4e, 0x4f, 0x70, 0x45, 0x79, 0x56, 0x61, 0x2f, 0x6d, 0x36, 0x69, 0x72, + 0x6e, 0x30, 0x46, 0x33, 0x48, 0x33, 0x7a, 0x62, 0x50, 0x42, 0x2b, 0x70, + 0x6f, 0x33, 0x75, 0x0a, 0x32, 0x64, 0x66, 0x4f, 0x57, 0x42, 0x66, 0x6f, + 0x71, 0x53, 0x6d, 0x75, 0x63, 0x30, 0x69, 0x48, 0x35, 0x35, 0x76, 0x4b, + 0x62, 0x69, 0x6d, 0x68, 0x5a, 0x46, 0x38, 0x5a, 0x45, 0x2f, 0x65, 0x75, + 0x42, 0x68, 0x44, 0x2f, 0x55, 0x63, 0x61, 0x62, 0x54, 0x56, 0x55, 0x6c, + 0x54, 0x35, 0x4f, 0x5a, 0x45, 0x41, 0x46, 0x54, 0x64, 0x66, 0x45, 0x54, + 0x7a, 0x73, 0x65, 0x6d, 0x51, 0x55, 0x48, 0x53, 0x0a, 0x76, 0x34, 0x69, + 0x6c, 0x66, 0x30, 0x58, 0x38, 0x72, 0x4c, 0x69, 0x6c, 0x74, 0x54, 0x4d, + 0x4d, 0x67, 0x73, 0x54, 0x37, 0x42, 0x2f, 0x5a, 0x71, 0x35, 0x53, 0x57, + 0x45, 0x58, 0x77, 0x62, 0x4b, 0x77, 0x59, 0x59, 0x35, 0x45, 0x64, 0x74, + 0x59, 0x7a, 0x58, 0x63, 0x37, 0x4c, 0x4d, 0x4a, 0x4d, 0x44, 0x31, 0x36, + 0x61, 0x34, 0x2f, 0x43, 0x72, 0x50, 0x6d, 0x45, 0x62, 0x55, 0x43, 0x54, + 0x43, 0x0a, 0x77, 0x50, 0x54, 0x78, 0x47, 0x66, 0x41, 0x52, 0x4b, 0x62, + 0x61, 0x6c, 0x47, 0x41, 0x4b, 0x62, 0x31, 0x32, 0x4e, 0x4d, 0x63, 0x49, + 0x78, 0x48, 0x6f, 0x77, 0x4e, 0x44, 0x58, 0x4c, 0x6c, 0x64, 0x52, 0x71, + 0x41, 0x4e, 0x62, 0x2f, 0x39, 0x5a, 0x6a, 0x72, 0x37, 0x64, 0x6e, 0x33, + 0x4c, 0x44, 0x57, 0x79, 0x76, 0x66, 0x6a, 0x46, 0x76, 0x4f, 0x35, 0x51, + 0x78, 0x47, 0x62, 0x4a, 0x4b, 0x79, 0x0a, 0x43, 0x71, 0x4e, 0x4d, 0x56, + 0x45, 0x49, 0x59, 0x46, 0x52, 0x49, 0x59, 0x76, 0x64, 0x72, 0x38, 0x75, + 0x6e, 0x52, 0x75, 0x2f, 0x38, 0x47, 0x32, 0x6f, 0x47, 0x54, 0x59, 0x71, + 0x56, 0x39, 0x56, 0x72, 0x70, 0x39, 0x63, 0x61, 0x6e, 0x61, 0x57, 0x32, + 0x48, 0x4e, 0x6e, 0x68, 0x2f, 0x74, 0x4e, 0x66, 0x31, 0x7a, 0x75, 0x61, + 0x63, 0x70, 0x7a, 0x45, 0x50, 0x75, 0x4b, 0x71, 0x66, 0x32, 0x65, 0x0a, + 0x76, 0x54, 0x59, 0x34, 0x53, 0x55, 0x6d, 0x48, 0x39, 0x41, 0x34, 0x55, + 0x38, 0x4f, 0x6d, 0x48, 0x75, 0x44, 0x2b, 0x6e, 0x54, 0x33, 0x70, 0x61, + 0x6a, 0x6e, 0x6e, 0x55, 0x6b, 0x2b, 0x53, 0x37, 0x61, 0x46, 0x4b, 0x45, + 0x72, 0x47, 0x7a, 0x70, 0x38, 0x35, 0x68, 0x77, 0x56, 0x58, 0x49, 0x79, + 0x2b, 0x54, 0x53, 0x72, 0x4b, 0x30, 0x6d, 0x31, 0x7a, 0x53, 0x42, 0x69, + 0x35, 0x44, 0x70, 0x36, 0x0a, 0x5a, 0x32, 0x4f, 0x72, 0x6c, 0x74, 0x78, + 0x74, 0x72, 0x70, 0x66, 0x73, 0x2f, 0x4a, 0x39, 0x32, 0x56, 0x6f, 0x67, + 0x75, 0x5a, 0x73, 0x39, 0x62, 0x74, 0x73, 0x6d, 0x6b, 0x73, 0x4e, 0x63, + 0x46, 0x75, 0x75, 0x45, 0x6e, 0x4c, 0x35, 0x4f, 0x37, 0x4a, 0x69, 0x71, + 0x69, 0x6b, 0x37, 0x41, 0x62, 0x38, 0x34, 0x36, 0x2b, 0x48, 0x55, 0x43, + 0x6a, 0x75, 0x54, 0x61, 0x50, 0x50, 0x6f, 0x49, 0x61, 0x0a, 0x47, 0x6c, + 0x36, 0x49, 0x36, 0x6c, 0x44, 0x34, 0x57, 0x65, 0x4b, 0x44, 0x52, 0x69, + 0x6b, 0x4c, 0x34, 0x30, 0x52, 0x63, 0x34, 0x5a, 0x57, 0x32, 0x61, 0x5a, + 0x43, 0x61, 0x46, 0x47, 0x2b, 0x58, 0x72, 0x6f, 0x48, 0x50, 0x61, 0x4f, + 0x2b, 0x5a, 0x6d, 0x72, 0x36, 0x31, 0x35, 0x2b, 0x46, 0x2f, 0x2b, 0x50, + 0x6f, 0x54, 0x52, 0x78, 0x5a, 0x4d, 0x7a, 0x47, 0x30, 0x49, 0x51, 0x4f, + 0x65, 0x4c, 0x0a, 0x65, 0x47, 0x39, 0x51, 0x67, 0x6b, 0x52, 0x51, 0x50, + 0x32, 0x59, 0x47, 0x69, 0x71, 0x74, 0x44, 0x68, 0x46, 0x5a, 0x4b, 0x44, + 0x79, 0x41, 0x74, 0x68, 0x67, 0x37, 0x31, 0x30, 0x74, 0x76, 0x53, 0x65, + 0x6f, 0x70, 0x4c, 0x7a, 0x61, 0x58, 0x6f, 0x54, 0x76, 0x46, 0x65, 0x4a, + 0x69, 0x55, 0x42, 0x57, 0x53, 0x4f, 0x67, 0x66, 0x74, 0x4c, 0x32, 0x66, + 0x69, 0x46, 0x58, 0x31, 0x79, 0x65, 0x38, 0x0a, 0x46, 0x56, 0x64, 0x4d, + 0x70, 0x45, 0x62, 0x42, 0x34, 0x49, 0x4d, 0x65, 0x44, 0x45, 0x78, 0x4e, + 0x48, 0x30, 0x38, 0x47, 0x47, 0x65, 0x4c, 0x35, 0x71, 0x50, 0x51, 0x36, + 0x67, 0x71, 0x47, 0x79, 0x65, 0x55, 0x4e, 0x35, 0x31, 0x71, 0x31, 0x76, + 0x65, 0x69, 0x65, 0x51, 0x41, 0x36, 0x54, 0x71, 0x4a, 0x49, 0x63, 0x2f, + 0x32, 0x62, 0x33, 0x5a, 0x36, 0x66, 0x4a, 0x66, 0x55, 0x45, 0x6b, 0x63, + 0x0a, 0x37, 0x75, 0x7a, 0x58, 0x4c, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x49, 0x64, 0x65, 0x6e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x20, 0x4f, 0x3d, 0x49, + 0x64, 0x65, 0x6e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x53, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x49, + 0x64, 0x65, 0x6e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f, 0x6d, + 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x31, 0x20, 0x4f, 0x3d, 0x49, 0x64, 0x65, 0x6e, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x49, 0x64, 0x65, 0x6e, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x33, + 0x32, 0x39, 0x38, 0x38, 0x32, 0x31, 0x30, 0x33, 0x34, 0x39, 0x34, 0x36, + 0x33, 0x34, 0x32, 0x33, 0x39, 0x30, 0x35, 0x32, 0x30, 0x30, 0x30, 0x33, + 0x38, 0x37, 0x37, 0x37, 0x39, 0x36, 0x38, 0x33, 0x39, 0x34, 0x32, 0x36, + 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x33, 0x3a, 0x33, + 0x65, 0x3a, 0x37, 0x37, 0x3a, 0x37, 0x33, 0x3a, 0x37, 0x35, 0x3a, 0x65, + 0x65, 0x3a, 0x61, 0x30, 0x3a, 0x64, 0x33, 0x3a, 0x65, 0x33, 0x3a, 0x37, + 0x65, 0x3a, 0x34, 0x39, 0x3a, 0x36, 0x33, 0x3a, 0x34, 0x39, 0x3a, 0x35, + 0x39, 0x3a, 0x62, 0x62, 0x3a, 0x63, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x66, 0x3a, 0x37, 0x31, 0x3a, 0x37, 0x65, + 0x3a, 0x61, 0x61, 0x3a, 0x34, 0x61, 0x3a, 0x64, 0x39, 0x3a, 0x34, 0x65, + 0x3a, 0x63, 0x39, 0x3a, 0x35, 0x35, 0x3a, 0x38, 0x34, 0x3a, 0x39, 0x39, + 0x3a, 0x36, 0x30, 0x3a, 0x32, 0x64, 0x3a, 0x34, 0x38, 0x3a, 0x64, 0x65, + 0x3a, 0x35, 0x66, 0x3a, 0x62, 0x63, 0x3a, 0x66, 0x30, 0x3a, 0x33, 0x61, + 0x3a, 0x32, 0x35, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x35, 0x64, 0x3a, 0x35, 0x36, 0x3a, 0x34, 0x39, 0x3a, 0x39, + 0x62, 0x3a, 0x65, 0x34, 0x3a, 0x64, 0x32, 0x3a, 0x65, 0x30, 0x3a, 0x38, + 0x62, 0x3a, 0x63, 0x66, 0x3a, 0x63, 0x61, 0x3a, 0x64, 0x30, 0x3a, 0x38, + 0x61, 0x3a, 0x33, 0x65, 0x3a, 0x33, 0x38, 0x3a, 0x37, 0x32, 0x3a, 0x33, + 0x64, 0x3a, 0x35, 0x30, 0x3a, 0x35, 0x30, 0x3a, 0x33, 0x62, 0x3a, 0x64, + 0x65, 0x3a, 0x37, 0x30, 0x3a, 0x36, 0x39, 0x3a, 0x34, 0x38, 0x3a, 0x65, + 0x34, 0x3a, 0x32, 0x66, 0x3a, 0x35, 0x35, 0x3a, 0x36, 0x30, 0x3a, 0x33, + 0x30, 0x3a, 0x31, 0x39, 0x3a, 0x65, 0x35, 0x3a, 0x32, 0x38, 0x3a, 0x61, + 0x65, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x59, 0x44, + 0x43, 0x43, 0x41, 0x30, 0x69, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, + 0x49, 0x51, 0x43, 0x67, 0x46, 0x43, 0x67, 0x41, 0x41, 0x41, 0x41, 0x55, + 0x55, 0x6a, 0x79, 0x45, 0x53, 0x31, 0x41, 0x41, 0x41, 0x41, 0x41, 0x6a, + 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, + 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x4b, 0x0a, 0x4d, + 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, + 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x53, 0x4d, 0x42, 0x41, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4a, 0x53, 0x57, 0x52, 0x6c, 0x62, + 0x6c, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4d, 0x53, 0x63, 0x77, 0x4a, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x35, 0x4a, 0x5a, + 0x47, 0x56, 0x75, 0x0a, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, + 0x51, 0x32, 0x39, 0x74, 0x62, 0x57, 0x56, 0x79, 0x59, 0x32, 0x6c, 0x68, + 0x62, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, + 0x49, 0x44, 0x45, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x51, 0x77, + 0x4d, 0x54, 0x45, 0x32, 0x4d, 0x54, 0x67, 0x78, 0x4d, 0x6a, 0x49, 0x7a, + 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x51, 0x77, 0x0a, 0x4d, 0x54, 0x45, + 0x32, 0x4d, 0x54, 0x67, 0x78, 0x4d, 0x6a, 0x49, 0x7a, 0x57, 0x6a, 0x42, + 0x4b, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x53, 0x4d, 0x42, 0x41, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4a, 0x53, 0x57, 0x52, + 0x6c, 0x62, 0x6c, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4d, 0x53, 0x63, + 0x77, 0x0a, 0x4a, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, + 0x35, 0x4a, 0x5a, 0x47, 0x56, 0x75, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, + 0x51, 0x67, 0x51, 0x32, 0x39, 0x74, 0x62, 0x57, 0x56, 0x79, 0x59, 0x32, + 0x6c, 0x68, 0x62, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, + 0x4e, 0x42, 0x49, 0x44, 0x45, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, + 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x0a, 0x53, 0x49, 0x62, 0x33, 0x44, + 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, + 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x41, + 0x51, 0x43, 0x6e, 0x55, 0x42, 0x6e, 0x65, 0x50, 0x35, 0x6b, 0x39, 0x31, + 0x44, 0x4e, 0x47, 0x38, 0x57, 0x39, 0x52, 0x59, 0x59, 0x4b, 0x79, 0x71, + 0x55, 0x2b, 0x50, 0x5a, 0x34, 0x6c, 0x64, 0x68, 0x4e, 0x6c, 0x54, 0x0a, + 0x33, 0x51, 0x77, 0x6f, 0x32, 0x64, 0x66, 0x77, 0x2f, 0x36, 0x36, 0x56, + 0x51, 0x33, 0x4b, 0x5a, 0x2b, 0x62, 0x56, 0x64, 0x66, 0x49, 0x72, 0x42, + 0x51, 0x75, 0x45, 0x78, 0x55, 0x48, 0x54, 0x52, 0x67, 0x51, 0x31, 0x38, + 0x7a, 0x5a, 0x73, 0x68, 0x71, 0x30, 0x50, 0x69, 0x72, 0x4b, 0x31, 0x65, + 0x68, 0x6d, 0x37, 0x7a, 0x43, 0x59, 0x6f, 0x66, 0x57, 0x6a, 0x4b, 0x39, + 0x6f, 0x75, 0x75, 0x55, 0x0a, 0x2b, 0x65, 0x68, 0x63, 0x43, 0x75, 0x7a, + 0x2f, 0x6d, 0x4e, 0x4b, 0x76, 0x63, 0x62, 0x4f, 0x30, 0x55, 0x35, 0x39, + 0x4f, 0x68, 0x2b, 0x2b, 0x53, 0x76, 0x4c, 0x33, 0x73, 0x54, 0x7a, 0x49, + 0x77, 0x69, 0x45, 0x73, 0x58, 0x58, 0x6c, 0x66, 0x45, 0x55, 0x38, 0x4c, + 0x32, 0x41, 0x70, 0x65, 0x4e, 0x32, 0x57, 0x49, 0x72, 0x76, 0x79, 0x51, + 0x66, 0x59, 0x6f, 0x33, 0x66, 0x77, 0x37, 0x67, 0x70, 0x0a, 0x53, 0x30, + 0x6c, 0x34, 0x50, 0x4a, 0x4e, 0x67, 0x69, 0x43, 0x4c, 0x38, 0x6d, 0x64, + 0x6f, 0x32, 0x79, 0x4d, 0x4b, 0x69, 0x31, 0x43, 0x78, 0x55, 0x41, 0x47, + 0x63, 0x31, 0x62, 0x6e, 0x4f, 0x2f, 0x41, 0x6c, 0x6a, 0x77, 0x70, 0x4e, + 0x33, 0x6c, 0x73, 0x4b, 0x49, 0x6d, 0x65, 0x73, 0x72, 0x67, 0x4e, 0x71, + 0x55, 0x5a, 0x46, 0x76, 0x58, 0x39, 0x74, 0x2b, 0x2b, 0x75, 0x50, 0x30, + 0x44, 0x31, 0x0a, 0x62, 0x56, 0x6f, 0x45, 0x2f, 0x63, 0x34, 0x30, 0x79, + 0x69, 0x54, 0x63, 0x64, 0x43, 0x4d, 0x62, 0x58, 0x54, 0x4d, 0x54, 0x45, + 0x6c, 0x33, 0x45, 0x41, 0x53, 0x58, 0x32, 0x4d, 0x4e, 0x30, 0x43, 0x58, + 0x5a, 0x2f, 0x67, 0x31, 0x55, 0x65, 0x39, 0x74, 0x4f, 0x73, 0x62, 0x6f, + 0x62, 0x74, 0x4a, 0x53, 0x64, 0x69, 0x66, 0x57, 0x77, 0x4c, 0x7a, 0x69, + 0x75, 0x51, 0x6b, 0x6b, 0x4f, 0x52, 0x69, 0x0a, 0x54, 0x30, 0x2f, 0x42, + 0x72, 0x34, 0x73, 0x4f, 0x64, 0x42, 0x65, 0x6f, 0x30, 0x58, 0x4b, 0x49, + 0x61, 0x6e, 0x6f, 0x42, 0x53, 0x63, 0x79, 0x30, 0x52, 0x6e, 0x6e, 0x47, + 0x46, 0x37, 0x48, 0x61, 0x6d, 0x42, 0x34, 0x48, 0x57, 0x66, 0x70, 0x31, + 0x49, 0x59, 0x56, 0x6c, 0x33, 0x5a, 0x42, 0x57, 0x7a, 0x76, 0x75, 0x72, + 0x70, 0x57, 0x43, 0x64, 0x78, 0x4a, 0x33, 0x35, 0x55, 0x72, 0x43, 0x4c, + 0x0a, 0x76, 0x59, 0x66, 0x35, 0x6a, 0x79, 0x73, 0x6a, 0x43, 0x69, 0x4e, + 0x32, 0x4f, 0x2f, 0x63, 0x7a, 0x34, 0x63, 0x6b, 0x41, 0x38, 0x32, 0x6e, + 0x35, 0x53, 0x36, 0x4c, 0x67, 0x54, 0x72, 0x78, 0x2b, 0x6b, 0x7a, 0x6d, + 0x45, 0x42, 0x2f, 0x64, 0x45, 0x63, 0x48, 0x37, 0x2b, 0x42, 0x31, 0x72, + 0x6c, 0x73, 0x61, 0x7a, 0x52, 0x47, 0x4d, 0x7a, 0x79, 0x4e, 0x65, 0x56, + 0x4a, 0x53, 0x51, 0x6a, 0x4b, 0x0a, 0x56, 0x73, 0x6b, 0x39, 0x2b, 0x77, + 0x38, 0x59, 0x66, 0x59, 0x73, 0x37, 0x77, 0x52, 0x50, 0x43, 0x54, 0x59, + 0x2f, 0x4a, 0x54, 0x77, 0x34, 0x33, 0x36, 0x52, 0x2b, 0x68, 0x44, 0x6d, + 0x72, 0x66, 0x59, 0x69, 0x37, 0x4c, 0x4e, 0x51, 0x5a, 0x52, 0x65, 0x53, + 0x7a, 0x49, 0x4a, 0x54, 0x6a, 0x30, 0x2b, 0x6b, 0x75, 0x6e, 0x69, 0x56, + 0x79, 0x63, 0x30, 0x75, 0x4d, 0x4e, 0x4f, 0x59, 0x5a, 0x4b, 0x0a, 0x64, + 0x48, 0x7a, 0x56, 0x57, 0x59, 0x66, 0x43, 0x50, 0x30, 0x34, 0x4d, 0x58, + 0x46, 0x4c, 0x30, 0x50, 0x66, 0x64, 0x53, 0x67, 0x76, 0x48, 0x71, 0x6f, + 0x36, 0x7a, 0x39, 0x53, 0x54, 0x51, 0x61, 0x4b, 0x50, 0x4e, 0x42, 0x69, + 0x44, 0x6f, 0x54, 0x37, 0x75, 0x6a, 0x65, 0x2f, 0x35, 0x6b, 0x64, 0x58, + 0x37, 0x72, 0x4c, 0x36, 0x42, 0x37, 0x79, 0x75, 0x56, 0x42, 0x67, 0x77, + 0x44, 0x48, 0x54, 0x0a, 0x63, 0x2b, 0x58, 0x76, 0x76, 0x71, 0x44, 0x74, + 0x4d, 0x77, 0x74, 0x30, 0x76, 0x69, 0x41, 0x67, 0x78, 0x47, 0x64, 0x73, + 0x38, 0x41, 0x67, 0x44, 0x65, 0x6c, 0x57, 0x41, 0x66, 0x30, 0x5a, 0x4f, + 0x6c, 0x71, 0x66, 0x30, 0x48, 0x6a, 0x37, 0x68, 0x39, 0x74, 0x67, 0x4a, + 0x34, 0x54, 0x4e, 0x6b, 0x4b, 0x32, 0x50, 0x58, 0x4d, 0x6c, 0x36, 0x66, + 0x2b, 0x63, 0x42, 0x37, 0x44, 0x33, 0x68, 0x76, 0x0a, 0x6c, 0x37, 0x79, + 0x54, 0x6d, 0x76, 0x6d, 0x63, 0x45, 0x70, 0x42, 0x34, 0x65, 0x6f, 0x43, + 0x48, 0x46, 0x64, 0x64, 0x79, 0x64, 0x4a, 0x78, 0x56, 0x64, 0x48, 0x69, + 0x78, 0x75, 0x75, 0x46, 0x75, 0x63, 0x41, 0x53, 0x36, 0x54, 0x36, 0x43, + 0x36, 0x61, 0x4d, 0x4e, 0x37, 0x2f, 0x7a, 0x48, 0x77, 0x63, 0x7a, 0x30, + 0x39, 0x6c, 0x43, 0x71, 0x78, 0x43, 0x30, 0x45, 0x4f, 0x6f, 0x50, 0x35, + 0x4e, 0x0a, 0x69, 0x47, 0x56, 0x72, 0x65, 0x54, 0x4f, 0x30, 0x31, 0x77, + 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, + 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, + 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x44, 0x77, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, + 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x0a, 0x2f, 0x7a, 0x41, 0x64, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x37, + 0x55, 0x51, 0x5a, 0x77, 0x4e, 0x50, 0x77, 0x42, 0x6f, 0x76, 0x75, 0x70, + 0x48, 0x75, 0x2b, 0x51, 0x75, 0x63, 0x6d, 0x56, 0x4d, 0x69, 0x4f, 0x4e, + 0x6e, 0x59, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, 0x0a, + 0x67, 0x67, 0x49, 0x42, 0x41, 0x41, 0x32, 0x75, 0x6b, 0x44, 0x4c, 0x32, + 0x70, 0x6b, 0x74, 0x38, 0x52, 0x48, 0x59, 0x5a, 0x59, 0x52, 0x34, 0x6e, + 0x4b, 0x4d, 0x31, 0x65, 0x56, 0x4f, 0x38, 0x6c, 0x76, 0x4f, 0x4d, 0x49, + 0x6b, 0x50, 0x6b, 0x70, 0x31, 0x36, 0x35, 0x6f, 0x43, 0x4f, 0x47, 0x55, + 0x41, 0x46, 0x6a, 0x76, 0x4c, 0x69, 0x35, 0x2b, 0x55, 0x31, 0x4b, 0x4d, + 0x74, 0x6c, 0x77, 0x48, 0x0a, 0x36, 0x6f, 0x69, 0x36, 0x6d, 0x59, 0x74, + 0x51, 0x6c, 0x4e, 0x65, 0x43, 0x67, 0x4e, 0x39, 0x68, 0x43, 0x51, 0x43, + 0x54, 0x72, 0x51, 0x30, 0x55, 0x35, 0x73, 0x37, 0x42, 0x38, 0x6a, 0x65, + 0x55, 0x65, 0x4c, 0x42, 0x66, 0x6e, 0x4c, 0x4f, 0x69, 0x63, 0x37, 0x69, + 0x50, 0x42, 0x5a, 0x4d, 0x34, 0x7a, 0x59, 0x30, 0x2b, 0x73, 0x4c, 0x6a, + 0x37, 0x77, 0x4d, 0x2b, 0x78, 0x38, 0x75, 0x77, 0x74, 0x0a, 0x4c, 0x52, + 0x76, 0x4d, 0x37, 0x4b, 0x71, 0x61, 0x73, 0x36, 0x70, 0x67, 0x67, 0x68, + 0x73, 0x74, 0x4f, 0x38, 0x4f, 0x45, 0x50, 0x56, 0x65, 0x4b, 0x6c, 0x68, + 0x36, 0x63, 0x64, 0x62, 0x6a, 0x54, 0x4d, 0x4d, 0x31, 0x67, 0x43, 0x49, + 0x4f, 0x51, 0x30, 0x34, 0x35, 0x55, 0x38, 0x55, 0x31, 0x6d, 0x77, 0x46, + 0x31, 0x30, 0x41, 0x30, 0x43, 0x6a, 0x37, 0x6f, 0x56, 0x2b, 0x77, 0x68, + 0x39, 0x33, 0x0a, 0x6e, 0x41, 0x62, 0x6f, 0x77, 0x61, 0x63, 0x59, 0x58, + 0x56, 0x4b, 0x56, 0x37, 0x63, 0x6e, 0x64, 0x4a, 0x5a, 0x35, 0x74, 0x2b, + 0x71, 0x6e, 0x74, 0x6f, 0x7a, 0x6f, 0x30, 0x30, 0x46, 0x6c, 0x37, 0x32, + 0x75, 0x31, 0x51, 0x38, 0x7a, 0x57, 0x2f, 0x37, 0x65, 0x73, 0x55, 0x54, + 0x54, 0x48, 0x48, 0x59, 0x50, 0x54, 0x61, 0x38, 0x59, 0x65, 0x63, 0x34, + 0x6b, 0x6a, 0x69, 0x78, 0x73, 0x55, 0x33, 0x0a, 0x2b, 0x77, 0x59, 0x51, + 0x2b, 0x6e, 0x56, 0x5a, 0x5a, 0x6a, 0x46, 0x48, 0x4b, 0x64, 0x70, 0x32, + 0x6d, 0x68, 0x7a, 0x70, 0x67, 0x71, 0x37, 0x76, 0x6d, 0x72, 0x6c, 0x52, + 0x39, 0x34, 0x67, 0x6a, 0x6d, 0x6d, 0x6d, 0x56, 0x59, 0x6a, 0x7a, 0x6c, + 0x56, 0x59, 0x41, 0x32, 0x31, 0x31, 0x51, 0x43, 0x2f, 0x2f, 0x47, 0x35, + 0x58, 0x63, 0x37, 0x55, 0x49, 0x32, 0x2f, 0x59, 0x52, 0x59, 0x52, 0x4b, + 0x0a, 0x57, 0x32, 0x58, 0x76, 0x69, 0x51, 0x7a, 0x64, 0x46, 0x4b, 0x63, + 0x67, 0x79, 0x78, 0x69, 0x6c, 0x4a, 0x62, 0x51, 0x4e, 0x2b, 0x51, 0x48, + 0x77, 0x6f, 0x74, 0x4c, 0x30, 0x41, 0x4d, 0x68, 0x30, 0x6a, 0x71, 0x45, + 0x71, 0x53, 0x49, 0x35, 0x6c, 0x32, 0x78, 0x50, 0x45, 0x34, 0x69, 0x55, + 0x58, 0x66, 0x65, 0x75, 0x2b, 0x68, 0x31, 0x73, 0x58, 0x49, 0x46, 0x52, + 0x52, 0x6b, 0x30, 0x70, 0x54, 0x0a, 0x41, 0x77, 0x76, 0x73, 0x58, 0x63, + 0x6f, 0x7a, 0x37, 0x57, 0x4c, 0x39, 0x52, 0x63, 0x63, 0x76, 0x57, 0x39, + 0x78, 0x59, 0x6f, 0x49, 0x41, 0x35, 0x35, 0x76, 0x72, 0x58, 0x2f, 0x68, + 0x4d, 0x55, 0x70, 0x75, 0x30, 0x39, 0x6c, 0x45, 0x70, 0x43, 0x64, 0x4e, + 0x54, 0x44, 0x64, 0x31, 0x6c, 0x7a, 0x7a, 0x59, 0x39, 0x47, 0x76, 0x6c, + 0x55, 0x34, 0x37, 0x2f, 0x72, 0x6f, 0x6b, 0x54, 0x4c, 0x71, 0x0a, 0x6c, + 0x31, 0x67, 0x45, 0x49, 0x74, 0x34, 0x34, 0x77, 0x38, 0x79, 0x38, 0x62, + 0x63, 0x6b, 0x7a, 0x4f, 0x6d, 0x6f, 0x4b, 0x61, 0x54, 0x2b, 0x67, 0x79, + 0x4f, 0x70, 0x79, 0x6a, 0x34, 0x78, 0x6a, 0x68, 0x69, 0x4f, 0x39, 0x62, + 0x54, 0x79, 0x57, 0x6e, 0x70, 0x58, 0x67, 0x53, 0x55, 0x79, 0x71, 0x6f, + 0x72, 0x6b, 0x71, 0x47, 0x35, 0x77, 0x32, 0x67, 0x58, 0x6a, 0x74, 0x77, + 0x2b, 0x68, 0x47, 0x0a, 0x34, 0x69, 0x5a, 0x5a, 0x52, 0x48, 0x55, 0x65, + 0x32, 0x58, 0x57, 0x4a, 0x55, 0x63, 0x30, 0x51, 0x68, 0x4a, 0x31, 0x68, + 0x59, 0x4d, 0x74, 0x64, 0x2b, 0x5a, 0x63, 0x69, 0x54, 0x59, 0x36, 0x59, + 0x35, 0x75, 0x4e, 0x2f, 0x39, 0x6c, 0x75, 0x37, 0x72, 0x73, 0x33, 0x4b, + 0x53, 0x6f, 0x46, 0x72, 0x58, 0x67, 0x76, 0x7a, 0x55, 0x65, 0x46, 0x30, + 0x4b, 0x2b, 0x6c, 0x2b, 0x4a, 0x36, 0x66, 0x5a, 0x0a, 0x6d, 0x55, 0x6c, + 0x4f, 0x2b, 0x4b, 0x57, 0x41, 0x32, 0x79, 0x55, 0x50, 0x48, 0x47, 0x4e, + 0x69, 0x69, 0x73, 0x6b, 0x7a, 0x5a, 0x32, 0x73, 0x38, 0x45, 0x49, 0x50, + 0x47, 0x72, 0x64, 0x36, 0x6f, 0x7a, 0x52, 0x61, 0x4f, 0x6a, 0x66, 0x41, + 0x48, 0x4e, 0x33, 0x47, 0x66, 0x38, 0x71, 0x76, 0x38, 0x51, 0x66, 0x58, + 0x42, 0x69, 0x2b, 0x77, 0x41, 0x4e, 0x31, 0x30, 0x4a, 0x35, 0x55, 0x36, + 0x41, 0x0a, 0x37, 0x2f, 0x71, 0x78, 0x58, 0x44, 0x67, 0x47, 0x70, 0x52, + 0x74, 0x4b, 0x34, 0x64, 0x77, 0x34, 0x4c, 0x54, 0x7a, 0x63, 0x71, 0x78, + 0x2b, 0x51, 0x47, 0x74, 0x56, 0x4b, 0x6e, 0x4f, 0x37, 0x52, 0x63, 0x47, + 0x7a, 0x4d, 0x37, 0x76, 0x52, 0x58, 0x2b, 0x42, 0x69, 0x36, 0x68, 0x47, + 0x36, 0x48, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x49, 0x64, 0x65, 0x6e, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, + 0x53, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x20, 0x31, 0x20, 0x4f, 0x3d, 0x49, 0x64, 0x65, 0x6e, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x49, 0x64, 0x65, 0x6e, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, + 0x53, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x20, 0x31, 0x20, 0x4f, 0x3d, 0x49, 0x64, 0x65, 0x6e, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x49, 0x64, 0x65, 0x6e, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x53, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, + 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, + 0x31, 0x33, 0x32, 0x39, 0x38, 0x38, 0x32, 0x31, 0x30, 0x33, 0x34, 0x39, + 0x34, 0x36, 0x33, 0x34, 0x32, 0x33, 0x39, 0x30, 0x35, 0x32, 0x31, 0x39, + 0x37, 0x36, 0x31, 0x35, 0x36, 0x38, 0x34, 0x33, 0x39, 0x33, 0x33, 0x36, + 0x39, 0x38, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x37, + 0x3a, 0x30, 0x36, 0x3a, 0x61, 0x35, 0x3a, 0x62, 0x30, 0x3a, 0x66, 0x63, + 0x3a, 0x38, 0x39, 0x3a, 0x39, 0x64, 0x3a, 0x62, 0x61, 0x3a, 0x66, 0x34, + 0x3a, 0x36, 0x62, 0x3a, 0x38, 0x63, 0x3a, 0x31, 0x61, 0x3a, 0x36, 0x34, + 0x3a, 0x63, 0x64, 0x3a, 0x64, 0x35, 0x3a, 0x62, 0x61, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x61, 0x3a, 0x32, 0x39, 0x3a, + 0x34, 0x31, 0x3a, 0x36, 0x30, 0x3a, 0x37, 0x37, 0x3a, 0x39, 0x38, 0x3a, + 0x33, 0x66, 0x3a, 0x66, 0x34, 0x3a, 0x66, 0x33, 0x3a, 0x65, 0x66, 0x3a, + 0x66, 0x32, 0x3a, 0x33, 0x31, 0x3a, 0x30, 0x35, 0x3a, 0x33, 0x62, 0x3a, + 0x32, 0x65, 0x3a, 0x65, 0x61, 0x3a, 0x36, 0x64, 0x3a, 0x34, 0x64, 0x3a, + 0x34, 0x35, 0x3a, 0x66, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x30, 0x3a, 0x64, 0x30, 0x3a, 0x38, 0x39, + 0x3a, 0x35, 0x61, 0x3a, 0x39, 0x61, 0x3a, 0x34, 0x34, 0x3a, 0x38, 0x61, + 0x3a, 0x32, 0x36, 0x3a, 0x32, 0x30, 0x3a, 0x39, 0x31, 0x3a, 0x36, 0x33, + 0x3a, 0x35, 0x35, 0x3a, 0x32, 0x32, 0x3a, 0x64, 0x31, 0x3a, 0x66, 0x35, + 0x3a, 0x32, 0x30, 0x3a, 0x31, 0x30, 0x3a, 0x62, 0x35, 0x3a, 0x38, 0x36, + 0x3a, 0x37, 0x61, 0x3a, 0x63, 0x61, 0x3a, 0x65, 0x31, 0x3a, 0x32, 0x63, + 0x3a, 0x37, 0x38, 0x3a, 0x65, 0x66, 0x3a, 0x39, 0x35, 0x3a, 0x38, 0x66, + 0x3a, 0x64, 0x34, 0x3a, 0x66, 0x34, 0x3a, 0x33, 0x38, 0x3a, 0x39, 0x66, + 0x3a, 0x32, 0x66, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, + 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, + 0x5a, 0x6a, 0x43, 0x43, 0x41, 0x30, 0x36, 0x67, 0x41, 0x77, 0x49, 0x42, + 0x41, 0x67, 0x49, 0x51, 0x43, 0x67, 0x46, 0x43, 0x67, 0x41, 0x41, 0x41, + 0x41, 0x55, 0x55, 0x6a, 0x7a, 0x30, 0x5a, 0x38, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, + 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x4e, + 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x53, 0x4d, 0x42, 0x41, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4a, 0x53, 0x57, 0x52, + 0x6c, 0x62, 0x6c, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4d, 0x53, 0x6f, + 0x77, 0x4b, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x79, 0x46, + 0x4a, 0x5a, 0x47, 0x56, 0x75, 0x0a, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, + 0x51, 0x67, 0x55, 0x48, 0x56, 0x69, 0x62, 0x47, 0x6c, 0x6a, 0x49, 0x46, + 0x4e, 0x6c, 0x59, 0x33, 0x52, 0x76, 0x63, 0x69, 0x42, 0x53, 0x62, 0x32, + 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x44, 0x45, 0x77, 0x48, 0x68, + 0x63, 0x4e, 0x4d, 0x54, 0x51, 0x77, 0x4d, 0x54, 0x45, 0x32, 0x4d, 0x54, + 0x63, 0x31, 0x4d, 0x7a, 0x4d, 0x79, 0x57, 0x68, 0x63, 0x4e, 0x0a, 0x4d, + 0x7a, 0x51, 0x77, 0x4d, 0x54, 0x45, 0x32, 0x4d, 0x54, 0x63, 0x31, 0x4d, + 0x7a, 0x4d, 0x79, 0x57, 0x6a, 0x42, 0x4e, 0x4d, 0x51, 0x73, 0x77, 0x43, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, + 0x7a, 0x45, 0x53, 0x4d, 0x42, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x68, 0x4d, 0x4a, 0x53, 0x57, 0x52, 0x6c, 0x62, 0x6c, 0x52, 0x79, 0x64, + 0x58, 0x4e, 0x30, 0x0a, 0x4d, 0x53, 0x6f, 0x77, 0x4b, 0x41, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x44, 0x45, 0x79, 0x46, 0x4a, 0x5a, 0x47, 0x56, 0x75, + 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x55, 0x48, 0x56, 0x69, + 0x62, 0x47, 0x6c, 0x6a, 0x49, 0x46, 0x4e, 0x6c, 0x59, 0x33, 0x52, 0x76, + 0x63, 0x69, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, + 0x49, 0x44, 0x45, 0x77, 0x67, 0x67, 0x49, 0x69, 0x0a, 0x4d, 0x41, 0x30, + 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, + 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, + 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51, 0x43, + 0x32, 0x49, 0x70, 0x54, 0x38, 0x70, 0x45, 0x69, 0x76, 0x36, 0x45, 0x64, + 0x72, 0x43, 0x76, 0x73, 0x6e, 0x64, 0x75, 0x54, 0x79, 0x50, 0x34, 0x6f, + 0x37, 0x0a, 0x65, 0x6b, 0x6f, 0x73, 0x4d, 0x53, 0x71, 0x4d, 0x6a, 0x62, + 0x43, 0x70, 0x77, 0x7a, 0x46, 0x72, 0x71, 0x48, 0x64, 0x32, 0x68, 0x43, + 0x61, 0x32, 0x72, 0x49, 0x46, 0x43, 0x44, 0x51, 0x6a, 0x72, 0x56, 0x56, + 0x69, 0x37, 0x65, 0x76, 0x69, 0x38, 0x5a, 0x58, 0x33, 0x79, 0x6f, 0x47, + 0x32, 0x4c, 0x71, 0x45, 0x66, 0x70, 0x59, 0x6e, 0x59, 0x65, 0x45, 0x65, + 0x34, 0x49, 0x46, 0x4e, 0x47, 0x79, 0x0a, 0x52, 0x42, 0x62, 0x30, 0x36, + 0x74, 0x44, 0x36, 0x48, 0x69, 0x39, 0x65, 0x32, 0x38, 0x74, 0x7a, 0x51, + 0x61, 0x36, 0x38, 0x41, 0x4c, 0x42, 0x4b, 0x4b, 0x30, 0x43, 0x79, 0x72, + 0x4f, 0x45, 0x37, 0x53, 0x38, 0x49, 0x74, 0x6e, 0x65, 0x53, 0x68, 0x6d, + 0x2b, 0x77, 0x61, 0x4f, 0x68, 0x37, 0x77, 0x43, 0x4c, 0x50, 0x51, 0x35, + 0x43, 0x51, 0x31, 0x42, 0x35, 0x2b, 0x63, 0x74, 0x4d, 0x6c, 0x53, 0x0a, + 0x62, 0x64, 0x73, 0x48, 0x79, 0x6f, 0x2b, 0x31, 0x57, 0x2f, 0x43, 0x44, + 0x38, 0x30, 0x2f, 0x48, 0x4c, 0x61, 0x58, 0x49, 0x72, 0x63, 0x75, 0x56, + 0x49, 0x4b, 0x51, 0x78, 0x4b, 0x46, 0x64, 0x59, 0x57, 0x75, 0x53, 0x4e, + 0x47, 0x35, 0x71, 0x72, 0x6e, 0x67, 0x30, 0x4d, 0x38, 0x67, 0x6f, 0x7a, + 0x4f, 0x53, 0x49, 0x35, 0x43, 0x70, 0x63, 0x75, 0x38, 0x31, 0x4e, 0x33, + 0x75, 0x55, 0x52, 0x46, 0x0a, 0x2f, 0x59, 0x54, 0x4c, 0x4e, 0x69, 0x43, + 0x42, 0x57, 0x53, 0x32, 0x61, 0x62, 0x32, 0x31, 0x49, 0x53, 0x47, 0x48, + 0x4b, 0x54, 0x4e, 0x39, 0x54, 0x30, 0x61, 0x39, 0x53, 0x76, 0x45, 0x53, + 0x66, 0x71, 0x79, 0x39, 0x72, 0x67, 0x33, 0x4c, 0x76, 0x64, 0x59, 0x44, + 0x61, 0x42, 0x6a, 0x4d, 0x62, 0x58, 0x63, 0x6a, 0x61, 0x59, 0x38, 0x5a, + 0x4e, 0x7a, 0x61, 0x78, 0x6d, 0x4d, 0x63, 0x33, 0x52, 0x0a, 0x33, 0x6a, + 0x36, 0x48, 0x45, 0x44, 0x62, 0x68, 0x75, 0x61, 0x52, 0x36, 0x37, 0x32, + 0x42, 0x51, 0x73, 0x73, 0x76, 0x4b, 0x70, 0x6c, 0x62, 0x67, 0x4e, 0x36, + 0x2b, 0x72, 0x4e, 0x42, 0x4d, 0x35, 0x4a, 0x65, 0x67, 0x35, 0x5a, 0x75, + 0x53, 0x59, 0x65, 0x71, 0x6f, 0x53, 0x6d, 0x4a, 0x78, 0x5a, 0x5a, 0x6f, + 0x59, 0x2b, 0x72, 0x66, 0x47, 0x77, 0x79, 0x6a, 0x34, 0x47, 0x44, 0x33, + 0x76, 0x77, 0x0a, 0x45, 0x55, 0x73, 0x33, 0x6f, 0x45, 0x52, 0x74, 0x65, + 0x38, 0x75, 0x6f, 0x6a, 0x48, 0x48, 0x30, 0x31, 0x62, 0x57, 0x52, 0x4e, + 0x73, 0x7a, 0x77, 0x46, 0x63, 0x59, 0x72, 0x33, 0x6c, 0x45, 0x58, 0x73, + 0x5a, 0x64, 0x4d, 0x55, 0x44, 0x32, 0x78, 0x6c, 0x56, 0x6c, 0x38, 0x42, + 0x58, 0x30, 0x74, 0x49, 0x64, 0x55, 0x41, 0x76, 0x77, 0x46, 0x6e, 0x6f, + 0x6c, 0x35, 0x37, 0x70, 0x6c, 0x7a, 0x79, 0x0a, 0x39, 0x79, 0x4c, 0x78, + 0x6b, 0x41, 0x32, 0x54, 0x32, 0x36, 0x70, 0x45, 0x55, 0x57, 0x62, 0x4d, + 0x66, 0x58, 0x59, 0x44, 0x36, 0x32, 0x71, 0x6f, 0x4b, 0x6a, 0x67, 0x5a, + 0x6c, 0x33, 0x59, 0x4e, 0x61, 0x34, 0x70, 0x68, 0x2b, 0x62, 0x7a, 0x32, + 0x37, 0x6e, 0x62, 0x39, 0x63, 0x43, 0x76, 0x64, 0x4b, 0x54, 0x7a, 0x34, + 0x43, 0x68, 0x35, 0x62, 0x51, 0x68, 0x79, 0x4c, 0x56, 0x69, 0x39, 0x56, + 0x0a, 0x47, 0x78, 0x79, 0x68, 0x4c, 0x72, 0x58, 0x48, 0x46, 0x75, 0x62, + 0x34, 0x71, 0x6a, 0x79, 0x53, 0x6a, 0x6d, 0x6d, 0x32, 0x41, 0x63, 0x47, + 0x31, 0x68, 0x70, 0x32, 0x4a, 0x44, 0x77, 0x73, 0x34, 0x6c, 0x46, 0x54, + 0x6f, 0x36, 0x74, 0x79, 0x65, 0x50, 0x53, 0x57, 0x38, 0x55, 0x79, 0x62, + 0x74, 0x31, 0x61, 0x73, 0x35, 0x71, 0x73, 0x56, 0x41, 0x54, 0x46, 0x53, + 0x72, 0x73, 0x72, 0x54, 0x5a, 0x0a, 0x32, 0x66, 0x6a, 0x58, 0x63, 0x74, + 0x73, 0x63, 0x76, 0x47, 0x32, 0x39, 0x5a, 0x56, 0x2f, 0x76, 0x69, 0x44, + 0x55, 0x71, 0x5a, 0x69, 0x2f, 0x75, 0x39, 0x72, 0x4e, 0x6c, 0x38, 0x44, + 0x4f, 0x4e, 0x66, 0x4a, 0x68, 0x42, 0x61, 0x55, 0x59, 0x50, 0x51, 0x78, + 0x78, 0x70, 0x2b, 0x70, 0x75, 0x31, 0x30, 0x47, 0x46, 0x71, 0x7a, 0x63, + 0x70, 0x4c, 0x32, 0x55, 0x79, 0x51, 0x52, 0x71, 0x73, 0x56, 0x0a, 0x57, + 0x61, 0x46, 0x48, 0x56, 0x43, 0x6b, 0x75, 0x67, 0x79, 0x68, 0x66, 0x48, + 0x4d, 0x4b, 0x69, 0x71, 0x33, 0x49, 0x58, 0x41, 0x41, 0x61, 0x4f, 0x52, + 0x65, 0x79, 0x4c, 0x34, 0x6a, 0x4d, 0x39, 0x66, 0x39, 0x6f, 0x5a, 0x52, + 0x4f, 0x52, 0x69, 0x63, 0x73, 0x50, 0x66, 0x49, 0x73, 0x62, 0x79, 0x56, + 0x74, 0x54, 0x64, 0x58, 0x35, 0x56, 0x79, 0x37, 0x57, 0x31, 0x66, 0x39, + 0x30, 0x67, 0x44, 0x0a, 0x57, 0x2f, 0x33, 0x46, 0x4b, 0x71, 0x44, 0x32, + 0x63, 0x79, 0x4f, 0x45, 0x45, 0x42, 0x73, 0x42, 0x35, 0x77, 0x49, 0x44, + 0x41, 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x4f, + 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, + 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, + 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x0a, 0x42, 0x41, 0x55, + 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, + 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x34, 0x33, 0x48, + 0x67, 0x6e, 0x74, 0x69, 0x6e, 0x51, 0x74, 0x6e, 0x62, 0x63, 0x5a, 0x46, + 0x72, 0x6c, 0x4a, 0x50, 0x72, 0x77, 0x36, 0x50, 0x52, 0x46, 0x4b, 0x4d, + 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, + 0x4e, 0x0a, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, + 0x49, 0x42, 0x41, 0x45, 0x66, 0x36, 0x33, 0x51, 0x71, 0x77, 0x45, 0x5a, + 0x45, 0x34, 0x72, 0x55, 0x31, 0x64, 0x39, 0x2b, 0x55, 0x4f, 0x6c, 0x31, + 0x51, 0x5a, 0x67, 0x6b, 0x69, 0x48, 0x56, 0x49, 0x79, 0x71, 0x5a, 0x4a, + 0x6e, 0x59, 0x57, 0x76, 0x36, 0x49, 0x41, 0x63, 0x56, 0x59, 0x70, 0x5a, + 0x6d, 0x78, 0x49, 0x31, 0x51, 0x6a, 0x0a, 0x74, 0x32, 0x6f, 0x64, 0x49, + 0x46, 0x66, 0x6c, 0x41, 0x57, 0x4a, 0x42, 0x46, 0x39, 0x4d, 0x4a, 0x32, + 0x33, 0x58, 0x4c, 0x62, 0x6c, 0x53, 0x51, 0x64, 0x66, 0x34, 0x61, 0x6e, + 0x34, 0x45, 0x4b, 0x77, 0x74, 0x33, 0x58, 0x39, 0x77, 0x6e, 0x51, 0x57, + 0x33, 0x49, 0x56, 0x35, 0x42, 0x34, 0x4a, 0x61, 0x6a, 0x30, 0x7a, 0x38, + 0x79, 0x47, 0x61, 0x35, 0x68, 0x56, 0x2b, 0x72, 0x56, 0x48, 0x56, 0x0a, + 0x44, 0x52, 0x44, 0x74, 0x66, 0x55, 0x4c, 0x41, 0x6a, 0x2b, 0x37, 0x41, + 0x6d, 0x67, 0x6a, 0x56, 0x51, 0x64, 0x5a, 0x63, 0x44, 0x69, 0x46, 0x70, + 0x62, 0x6f, 0x42, 0x68, 0x44, 0x68, 0x58, 0x41, 0x75, 0x4d, 0x2f, 0x46, + 0x53, 0x52, 0x4a, 0x53, 0x7a, 0x4c, 0x34, 0x36, 0x7a, 0x4e, 0x51, 0x75, + 0x4f, 0x41, 0x58, 0x65, 0x4e, 0x66, 0x30, 0x66, 0x62, 0x37, 0x69, 0x41, + 0x61, 0x4a, 0x67, 0x39, 0x0a, 0x54, 0x61, 0x44, 0x4b, 0x51, 0x47, 0x58, + 0x53, 0x63, 0x33, 0x7a, 0x31, 0x69, 0x39, 0x6b, 0x4b, 0x6c, 0x54, 0x2f, + 0x59, 0x50, 0x79, 0x4e, 0x74, 0x47, 0x74, 0x45, 0x71, 0x4a, 0x42, 0x6e, + 0x5a, 0x68, 0x62, 0x4d, 0x58, 0x37, 0x33, 0x68, 0x75, 0x71, 0x56, 0x6a, + 0x52, 0x49, 0x39, 0x50, 0x48, 0x45, 0x2b, 0x31, 0x79, 0x4a, 0x58, 0x39, + 0x64, 0x73, 0x58, 0x4e, 0x77, 0x30, 0x48, 0x38, 0x47, 0x0a, 0x6c, 0x77, + 0x6d, 0x45, 0x4b, 0x59, 0x42, 0x68, 0x48, 0x66, 0x70, 0x65, 0x2f, 0x33, + 0x4f, 0x73, 0x6f, 0x4f, 0x4f, 0x4a, 0x75, 0x42, 0x78, 0x78, 0x46, 0x63, + 0x62, 0x65, 0x4d, 0x58, 0x38, 0x53, 0x33, 0x4f, 0x46, 0x74, 0x6d, 0x36, + 0x2f, 0x6e, 0x36, 0x4a, 0x39, 0x31, 0x65, 0x45, 0x79, 0x72, 0x52, 0x6a, + 0x75, 0x61, 0x7a, 0x72, 0x38, 0x46, 0x47, 0x46, 0x31, 0x4e, 0x46, 0x54, + 0x77, 0x57, 0x0a, 0x6d, 0x68, 0x6c, 0x51, 0x42, 0x4a, 0x71, 0x79, 0x6d, + 0x6d, 0x39, 0x6c, 0x69, 0x31, 0x4a, 0x66, 0x50, 0x46, 0x67, 0x45, 0x4b, + 0x43, 0x58, 0x41, 0x5a, 0x6d, 0x45, 0x78, 0x66, 0x72, 0x6e, 0x67, 0x64, + 0x62, 0x6b, 0x61, 0x71, 0x49, 0x48, 0x57, 0x63, 0x68, 0x65, 0x7a, 0x78, + 0x51, 0x4d, 0x78, 0x4e, 0x52, 0x46, 0x34, 0x65, 0x4b, 0x4c, 0x67, 0x36, + 0x54, 0x43, 0x4d, 0x66, 0x34, 0x44, 0x66, 0x0a, 0x57, 0x4e, 0x38, 0x38, + 0x75, 0x69, 0x65, 0x57, 0x34, 0x6f, 0x41, 0x30, 0x62, 0x65, 0x4f, 0x59, + 0x30, 0x32, 0x51, 0x6e, 0x72, 0x45, 0x68, 0x2b, 0x4b, 0x48, 0x64, 0x63, + 0x78, 0x69, 0x56, 0x68, 0x4a, 0x66, 0x69, 0x46, 0x44, 0x47, 0x58, 0x36, + 0x78, 0x44, 0x49, 0x76, 0x70, 0x5a, 0x67, 0x46, 0x35, 0x50, 0x67, 0x4c, + 0x5a, 0x78, 0x59, 0x57, 0x78, 0x6f, 0x4b, 0x34, 0x4d, 0x68, 0x6e, 0x35, + 0x0a, 0x2b, 0x62, 0x6c, 0x35, 0x33, 0x42, 0x2f, 0x4e, 0x36, 0x36, 0x2b, + 0x72, 0x44, 0x74, 0x30, 0x62, 0x32, 0x30, 0x58, 0x6b, 0x65, 0x75, 0x63, + 0x43, 0x34, 0x70, 0x56, 0x64, 0x2f, 0x47, 0x6e, 0x77, 0x55, 0x32, 0x6c, + 0x68, 0x6c, 0x58, 0x56, 0x35, 0x43, 0x31, 0x35, 0x56, 0x35, 0x6a, 0x67, + 0x63, 0x6c, 0x4b, 0x6c, 0x5a, 0x4d, 0x35, 0x37, 0x49, 0x63, 0x58, 0x52, + 0x35, 0x66, 0x31, 0x47, 0x4a, 0x0a, 0x74, 0x73, 0x68, 0x71, 0x75, 0x44, + 0x44, 0x49, 0x61, 0x6a, 0x6a, 0x44, 0x62, 0x70, 0x37, 0x68, 0x4e, 0x78, + 0x62, 0x71, 0x42, 0x57, 0x4a, 0x4d, 0x57, 0x78, 0x4a, 0x48, 0x37, 0x61, + 0x65, 0x30, 0x73, 0x31, 0x68, 0x57, 0x78, 0x30, 0x6e, 0x7a, 0x66, 0x78, + 0x4a, 0x6f, 0x43, 0x54, 0x46, 0x78, 0x38, 0x47, 0x33, 0x34, 0x54, 0x6b, + 0x66, 0x37, 0x31, 0x6f, 0x58, 0x75, 0x78, 0x56, 0x68, 0x41, 0x0a, 0x47, + 0x61, 0x51, 0x64, 0x70, 0x2f, 0x6c, 0x4c, 0x51, 0x7a, 0x66, 0x63, 0x61, + 0x46, 0x70, 0x50, 0x7a, 0x2b, 0x76, 0x43, 0x5a, 0x48, 0x54, 0x65, 0x74, + 0x42, 0x58, 0x5a, 0x39, 0x46, 0x52, 0x55, 0x47, 0x69, 0x38, 0x63, 0x31, + 0x35, 0x64, 0x78, 0x56, 0x4a, 0x43, 0x4f, 0x32, 0x53, 0x43, 0x64, 0x55, + 0x79, 0x74, 0x2f, 0x71, 0x34, 0x2f, 0x69, 0x36, 0x6a, 0x43, 0x38, 0x55, + 0x44, 0x66, 0x76, 0x0a, 0x38, 0x55, 0x65, 0x31, 0x66, 0x58, 0x77, 0x73, + 0x42, 0x4f, 0x78, 0x6f, 0x6e, 0x62, 0x52, 0x4a, 0x52, 0x42, 0x44, 0x30, + 0x63, 0x6b, 0x73, 0x63, 0x5a, 0x4f, 0x66, 0x38, 0x35, 0x6d, 0x75, 0x51, + 0x33, 0x57, 0x6c, 0x39, 0x61, 0x66, 0x30, 0x41, 0x56, 0x71, 0x57, 0x33, + 0x72, 0x4c, 0x61, 0x74, 0x74, 0x38, 0x6f, 0x2b, 0x41, 0x65, 0x2b, 0x63, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, + 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x53, 0x65, 0x65, 0x20, 0x77, 0x77, + 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, + 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x2d, 0x74, 0x65, 0x72, 0x6d, + 0x73, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x45, + 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, + 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x20, 0x4f, + 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x53, 0x65, 0x65, 0x20, 0x77, 0x77, + 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, + 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x2d, 0x74, 0x65, 0x72, 0x6d, + 0x73, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x45, + 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, + 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x32, 0x34, 0x36, 0x39, 0x38, + 0x39, 0x33, 0x35, 0x32, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x34, 0x62, 0x3a, 0x65, 0x32, 0x3a, 0x63, 0x39, 0x3a, 0x39, 0x31, 0x3a, + 0x39, 0x36, 0x3a, 0x36, 0x35, 0x3a, 0x30, 0x63, 0x3a, 0x66, 0x34, 0x3a, + 0x30, 0x65, 0x3a, 0x35, 0x61, 0x3a, 0x39, 0x33, 0x3a, 0x39, 0x32, 0x3a, + 0x61, 0x30, 0x3a, 0x30, 0x61, 0x3a, 0x66, 0x65, 0x3a, 0x62, 0x32, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x63, 0x3a, 0x66, + 0x34, 0x3a, 0x32, 0x37, 0x3a, 0x66, 0x64, 0x3a, 0x37, 0x39, 0x3a, 0x30, + 0x63, 0x3a, 0x33, 0x61, 0x3a, 0x64, 0x31, 0x3a, 0x36, 0x36, 0x3a, 0x30, + 0x36, 0x3a, 0x38, 0x64, 0x3a, 0x65, 0x38, 0x3a, 0x31, 0x65, 0x3a, 0x35, + 0x37, 0x3a, 0x65, 0x66, 0x3a, 0x62, 0x62, 0x3a, 0x39, 0x33, 0x3a, 0x32, + 0x32, 0x3a, 0x37, 0x32, 0x3a, 0x64, 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x33, 0x3a, 0x64, 0x66, 0x3a, + 0x35, 0x37, 0x3a, 0x37, 0x34, 0x3a, 0x62, 0x30, 0x3a, 0x33, 0x65, 0x3a, + 0x37, 0x66, 0x3a, 0x65, 0x66, 0x3a, 0x35, 0x66, 0x3a, 0x65, 0x34, 0x3a, + 0x30, 0x64, 0x3a, 0x39, 0x33, 0x3a, 0x31, 0x61, 0x3a, 0x37, 0x62, 0x3a, + 0x65, 0x64, 0x3a, 0x66, 0x31, 0x3a, 0x62, 0x62, 0x3a, 0x32, 0x65, 0x3a, + 0x36, 0x62, 0x3a, 0x34, 0x32, 0x3a, 0x37, 0x33, 0x3a, 0x38, 0x63, 0x3a, + 0x34, 0x65, 0x3a, 0x36, 0x64, 0x3a, 0x33, 0x38, 0x3a, 0x34, 0x31, 0x3a, + 0x31, 0x30, 0x3a, 0x33, 0x64, 0x3a, 0x33, 0x61, 0x3a, 0x61, 0x37, 0x3a, + 0x66, 0x33, 0x3a, 0x33, 0x39, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, + 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, + 0x49, 0x45, 0x50, 0x6a, 0x43, 0x43, 0x41, 0x79, 0x61, 0x67, 0x41, 0x77, + 0x49, 0x42, 0x41, 0x67, 0x49, 0x45, 0x53, 0x6c, 0x4f, 0x4d, 0x4b, 0x44, + 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, + 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x43, 0x42, 0x76, 0x6a, + 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, + 0x4d, 0x43, 0x0a, 0x56, 0x56, 0x4d, 0x78, 0x46, 0x6a, 0x41, 0x55, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, 0x55, 0x56, 0x75, 0x64, + 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, + 0x79, 0x34, 0x78, 0x4b, 0x44, 0x41, 0x6d, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x73, 0x54, 0x48, 0x31, 0x4e, 0x6c, 0x5a, 0x53, 0x42, 0x33, 0x64, + 0x33, 0x63, 0x75, 0x5a, 0x57, 0x35, 0x30, 0x0a, 0x63, 0x6e, 0x56, 0x7a, + 0x64, 0x43, 0x35, 0x75, 0x5a, 0x58, 0x51, 0x76, 0x62, 0x47, 0x56, 0x6e, + 0x59, 0x57, 0x77, 0x74, 0x64, 0x47, 0x56, 0x79, 0x62, 0x58, 0x4d, 0x78, + 0x4f, 0x54, 0x41, 0x33, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, + 0x4d, 0x43, 0x68, 0x6a, 0x4b, 0x53, 0x41, 0x79, 0x4d, 0x44, 0x41, 0x35, + 0x49, 0x45, 0x56, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x73, + 0x0a, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x67, 0x4c, 0x53, 0x42, + 0x6d, 0x62, 0x33, 0x49, 0x67, 0x59, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, + 0x79, 0x61, 0x58, 0x70, 0x6c, 0x5a, 0x43, 0x42, 0x31, 0x63, 0x32, 0x55, + 0x67, 0x62, 0x32, 0x35, 0x73, 0x65, 0x54, 0x45, 0x79, 0x4d, 0x44, 0x41, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x70, 0x52, 0x57, 0x35, + 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x0a, 0x64, 0x43, 0x42, 0x53, 0x62, 0x32, + 0x39, 0x30, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, + 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, + 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x49, 0x43, + 0x30, 0x67, 0x52, 0x7a, 0x49, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x44, + 0x6b, 0x77, 0x4e, 0x7a, 0x41, 0x33, 0x4d, 0x54, 0x63, 0x79, 0x0a, 0x4e, + 0x54, 0x55, 0x30, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x41, 0x78, 0x4d, + 0x6a, 0x41, 0x33, 0x4d, 0x54, 0x63, 0x31, 0x4e, 0x54, 0x55, 0x30, 0x57, + 0x6a, 0x43, 0x42, 0x76, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x46, + 0x6a, 0x41, 0x55, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x44, + 0x55, 0x56, 0x75, 0x0a, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x73, + 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x4b, 0x44, 0x41, 0x6d, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x48, 0x31, 0x4e, 0x6c, + 0x5a, 0x53, 0x42, 0x33, 0x64, 0x33, 0x63, 0x75, 0x5a, 0x57, 0x35, 0x30, + 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x35, 0x75, 0x5a, 0x58, 0x51, 0x76, + 0x62, 0x47, 0x56, 0x6e, 0x59, 0x57, 0x77, 0x74, 0x0a, 0x64, 0x47, 0x56, + 0x79, 0x62, 0x58, 0x4d, 0x78, 0x4f, 0x54, 0x41, 0x33, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x73, 0x54, 0x4d, 0x43, 0x68, 0x6a, 0x4b, 0x53, 0x41, + 0x79, 0x4d, 0x44, 0x41, 0x35, 0x49, 0x45, 0x56, 0x75, 0x64, 0x48, 0x4a, + 0x31, 0x63, 0x33, 0x51, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, + 0x67, 0x4c, 0x53, 0x42, 0x6d, 0x62, 0x33, 0x49, 0x67, 0x59, 0x58, 0x56, + 0x30, 0x0a, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x70, 0x6c, 0x5a, 0x43, + 0x42, 0x31, 0x63, 0x32, 0x55, 0x67, 0x62, 0x32, 0x35, 0x73, 0x65, 0x54, + 0x45, 0x79, 0x4d, 0x44, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, + 0x4d, 0x70, 0x52, 0x57, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, + 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, + 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x0a, 0x59, 0x58, 0x52, 0x70, 0x62, + 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, + 0x58, 0x52, 0x35, 0x49, 0x43, 0x30, 0x67, 0x52, 0x7a, 0x49, 0x77, 0x67, + 0x67, 0x45, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, + 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, + 0x34, 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x0a, + 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x43, 0x36, 0x68, 0x4c, 0x5a, 0x79, + 0x32, 0x35, 0x34, 0x4d, 0x61, 0x2b, 0x4b, 0x5a, 0x36, 0x54, 0x41, 0x42, + 0x70, 0x33, 0x62, 0x71, 0x4d, 0x72, 0x69, 0x56, 0x51, 0x52, 0x72, 0x4a, + 0x32, 0x6d, 0x46, 0x4f, 0x57, 0x48, 0x4c, 0x50, 0x2f, 0x76, 0x61, 0x43, + 0x65, 0x62, 0x39, 0x7a, 0x59, 0x51, 0x59, 0x4b, 0x70, 0x53, 0x66, 0x59, + 0x73, 0x31, 0x2f, 0x54, 0x0a, 0x52, 0x55, 0x34, 0x63, 0x63, 0x74, 0x5a, + 0x4f, 0x4d, 0x76, 0x4a, 0x79, 0x69, 0x67, 0x2f, 0x33, 0x67, 0x78, 0x6e, + 0x51, 0x61, 0x6f, 0x43, 0x41, 0x41, 0x45, 0x55, 0x65, 0x73, 0x4d, 0x66, + 0x6e, 0x6d, 0x72, 0x38, 0x53, 0x56, 0x79, 0x63, 0x63, 0x6f, 0x32, 0x67, + 0x76, 0x43, 0x6f, 0x65, 0x39, 0x61, 0x6d, 0x73, 0x4f, 0x58, 0x6d, 0x58, + 0x7a, 0x48, 0x48, 0x66, 0x56, 0x31, 0x49, 0x57, 0x4e, 0x0a, 0x63, 0x43, + 0x47, 0x30, 0x73, 0x7a, 0x4c, 0x6e, 0x69, 0x36, 0x4c, 0x56, 0x68, 0x6a, + 0x6b, 0x43, 0x73, 0x62, 0x6a, 0x53, 0x52, 0x38, 0x37, 0x6b, 0x79, 0x55, + 0x6e, 0x45, 0x4f, 0x36, 0x66, 0x65, 0x2b, 0x31, 0x52, 0x39, 0x56, 0x37, + 0x37, 0x77, 0x36, 0x47, 0x37, 0x43, 0x65, 0x62, 0x49, 0x36, 0x43, 0x31, + 0x58, 0x69, 0x55, 0x4a, 0x67, 0x57, 0x4d, 0x68, 0x4e, 0x63, 0x4c, 0x33, + 0x68, 0x57, 0x0a, 0x77, 0x63, 0x4b, 0x55, 0x73, 0x2f, 0x4a, 0x61, 0x35, + 0x43, 0x65, 0x61, 0x6e, 0x79, 0x54, 0x58, 0x78, 0x75, 0x7a, 0x51, 0x6d, + 0x79, 0x57, 0x43, 0x34, 0x38, 0x7a, 0x43, 0x78, 0x45, 0x58, 0x46, 0x6a, + 0x4a, 0x64, 0x36, 0x42, 0x6d, 0x73, 0x71, 0x45, 0x5a, 0x2b, 0x70, 0x43, + 0x6d, 0x35, 0x49, 0x4f, 0x32, 0x2f, 0x62, 0x31, 0x42, 0x45, 0x5a, 0x51, + 0x76, 0x65, 0x50, 0x42, 0x37, 0x2f, 0x31, 0x0a, 0x55, 0x31, 0x2b, 0x63, + 0x50, 0x76, 0x51, 0x58, 0x4c, 0x4f, 0x5a, 0x70, 0x72, 0x45, 0x34, 0x79, + 0x54, 0x47, 0x4a, 0x33, 0x36, 0x72, 0x66, 0x6f, 0x35, 0x62, 0x73, 0x30, + 0x76, 0x42, 0x6d, 0x4c, 0x72, 0x70, 0x78, 0x52, 0x35, 0x37, 0x64, 0x2b, + 0x74, 0x56, 0x4f, 0x78, 0x4d, 0x79, 0x4c, 0x6c, 0x62, 0x63, 0x39, 0x77, + 0x50, 0x42, 0x72, 0x36, 0x34, 0x70, 0x74, 0x6e, 0x74, 0x6f, 0x50, 0x30, + 0x0a, 0x6a, 0x61, 0x57, 0x76, 0x59, 0x6b, 0x78, 0x4e, 0x34, 0x46, 0x69, + 0x73, 0x5a, 0x44, 0x51, 0x53, 0x41, 0x2f, 0x69, 0x32, 0x6a, 0x5a, 0x52, + 0x6a, 0x4a, 0x4b, 0x52, 0x78, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, + 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, + 0x42, 0x42, 0x6a, 0x41, 0x50, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, + 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, + 0x48, 0x2f, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, + 0x51, 0x57, 0x42, 0x42, 0x52, 0x71, 0x63, 0x69, 0x5a, 0x36, 0x30, 0x42, + 0x37, 0x76, 0x66, 0x65, 0x63, 0x37, 0x61, 0x56, 0x48, 0x55, 0x62, 0x49, + 0x32, 0x66, 0x6b, 0x42, 0x4a, 0x6d, 0x71, 0x7a, 0x41, 0x4e, 0x0a, 0x42, + 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, + 0x51, 0x73, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x65, + 0x5a, 0x38, 0x64, 0x6c, 0x73, 0x61, 0x32, 0x65, 0x54, 0x38, 0x69, 0x6a, + 0x59, 0x66, 0x54, 0x68, 0x77, 0x4d, 0x45, 0x59, 0x47, 0x70, 0x72, 0x6d, + 0x69, 0x35, 0x5a, 0x69, 0x58, 0x4d, 0x52, 0x72, 0x45, 0x50, 0x52, 0x39, + 0x52, 0x50, 0x2f, 0x0a, 0x6a, 0x54, 0x6b, 0x72, 0x77, 0x50, 0x4b, 0x39, + 0x54, 0x33, 0x43, 0x4d, 0x71, 0x53, 0x2f, 0x71, 0x46, 0x38, 0x51, 0x4c, + 0x56, 0x4a, 0x37, 0x55, 0x47, 0x35, 0x61, 0x59, 0x4d, 0x7a, 0x79, 0x6f, + 0x72, 0x57, 0x4b, 0x69, 0x41, 0x48, 0x61, 0x72, 0x57, 0x57, 0x6c, 0x75, + 0x42, 0x68, 0x31, 0x2b, 0x78, 0x4c, 0x6c, 0x45, 0x6a, 0x5a, 0x69, 0x76, + 0x45, 0x74, 0x52, 0x68, 0x32, 0x77, 0x6f, 0x5a, 0x0a, 0x52, 0x6b, 0x66, + 0x7a, 0x36, 0x2f, 0x64, 0x6a, 0x77, 0x55, 0x41, 0x46, 0x51, 0x4b, 0x58, + 0x53, 0x74, 0x2f, 0x53, 0x31, 0x6d, 0x6a, 0x61, 0x2f, 0x71, 0x59, 0x68, + 0x32, 0x69, 0x41, 0x52, 0x56, 0x42, 0x43, 0x75, 0x63, 0x68, 0x33, 0x38, + 0x61, 0x4e, 0x7a, 0x78, 0x2b, 0x4c, 0x61, 0x55, 0x61, 0x32, 0x4e, 0x53, + 0x4a, 0x58, 0x73, 0x71, 0x39, 0x72, 0x44, 0x31, 0x73, 0x32, 0x47, 0x32, + 0x76, 0x0a, 0x31, 0x66, 0x4e, 0x32, 0x44, 0x38, 0x30, 0x37, 0x69, 0x44, + 0x67, 0x69, 0x6e, 0x57, 0x79, 0x54, 0x6d, 0x73, 0x51, 0x39, 0x76, 0x34, + 0x49, 0x62, 0x5a, 0x54, 0x2b, 0x6d, 0x44, 0x31, 0x32, 0x71, 0x2f, 0x4f, + 0x57, 0x79, 0x46, 0x63, 0x71, 0x31, 0x72, 0x63, 0x61, 0x38, 0x50, 0x64, + 0x43, 0x45, 0x36, 0x4f, 0x6f, 0x47, 0x63, 0x72, 0x42, 0x4e, 0x4f, 0x54, + 0x4a, 0x34, 0x76, 0x7a, 0x34, 0x52, 0x0a, 0x6e, 0x41, 0x75, 0x6b, 0x6e, + 0x5a, 0x6f, 0x68, 0x38, 0x2f, 0x43, 0x62, 0x43, 0x7a, 0x42, 0x34, 0x32, + 0x38, 0x48, 0x63, 0x68, 0x30, 0x50, 0x2b, 0x76, 0x47, 0x4f, 0x61, 0x79, + 0x73, 0x58, 0x43, 0x48, 0x4d, 0x6e, 0x48, 0x6a, 0x66, 0x38, 0x37, 0x45, + 0x6c, 0x67, 0x49, 0x35, 0x72, 0x59, 0x39, 0x37, 0x48, 0x6f, 0x73, 0x54, + 0x76, 0x75, 0x44, 0x6c, 0x73, 0x34, 0x4d, 0x50, 0x47, 0x6d, 0x48, 0x0a, + 0x56, 0x48, 0x4f, 0x6b, 0x63, 0x38, 0x4b, 0x54, 0x2f, 0x31, 0x45, 0x51, + 0x72, 0x42, 0x56, 0x55, 0x41, 0x64, 0x6a, 0x38, 0x42, 0x62, 0x47, 0x4a, + 0x6f, 0x58, 0x39, 0x30, 0x67, 0x35, 0x70, 0x4a, 0x31, 0x39, 0x78, 0x4f, + 0x65, 0x34, 0x70, 0x49, 0x62, 0x34, 0x74, 0x46, 0x39, 0x67, 0x3d, 0x3d, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x45, 0x43, 0x31, 0x20, + 0x4f, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x53, 0x65, 0x65, 0x20, 0x77, + 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, + 0x65, 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x2d, 0x74, 0x65, 0x72, + 0x6d, 0x73, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, + 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, + 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x45, 0x43, 0x31, + 0x20, 0x4f, 0x3d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x53, 0x65, 0x65, 0x20, + 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x6e, 0x65, 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x2d, 0x74, 0x65, + 0x72, 0x6d, 0x73, 0x2f, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x31, 0x32, + 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, + 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x45, 0x43, 0x31, 0x22, 0x0a, 0x23, + 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x35, 0x31, 0x35, + 0x34, 0x33, 0x31, 0x32, 0x34, 0x34, 0x38, 0x31, 0x39, 0x33, 0x30, 0x36, + 0x34, 0x39, 0x31, 0x31, 0x34, 0x31, 0x31, 0x36, 0x31, 0x33, 0x33, 0x33, + 0x36, 0x39, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x36, + 0x3a, 0x37, 0x65, 0x3a, 0x31, 0x64, 0x3a, 0x66, 0x30, 0x3a, 0x35, 0x38, + 0x3a, 0x63, 0x35, 0x3a, 0x34, 0x39, 0x3a, 0x36, 0x63, 0x3a, 0x32, 0x34, + 0x3a, 0x33, 0x62, 0x3a, 0x33, 0x64, 0x3a, 0x65, 0x64, 0x3a, 0x39, 0x38, + 0x3a, 0x31, 0x38, 0x3a, 0x65, 0x64, 0x3a, 0x62, 0x63, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x30, 0x3a, 0x64, 0x38, 0x3a, + 0x30, 0x36, 0x3a, 0x34, 0x30, 0x3a, 0x64, 0x66, 0x3a, 0x39, 0x62, 0x3a, + 0x32, 0x35, 0x3a, 0x66, 0x35, 0x3a, 0x31, 0x32, 0x3a, 0x32, 0x35, 0x3a, + 0x33, 0x61, 0x3a, 0x31, 0x31, 0x3a, 0x65, 0x61, 0x3a, 0x66, 0x37, 0x3a, + 0x35, 0x39, 0x3a, 0x38, 0x61, 0x3a, 0x65, 0x62, 0x3a, 0x31, 0x34, 0x3a, + 0x62, 0x35, 0x3a, 0x34, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x32, 0x3a, 0x65, 0x64, 0x3a, 0x30, 0x65, + 0x3a, 0x62, 0x32, 0x3a, 0x38, 0x63, 0x3a, 0x31, 0x34, 0x3a, 0x64, 0x61, + 0x3a, 0x34, 0x35, 0x3a, 0x31, 0x36, 0x3a, 0x35, 0x63, 0x3a, 0x35, 0x36, + 0x3a, 0x36, 0x37, 0x3a, 0x39, 0x31, 0x3a, 0x37, 0x30, 0x3a, 0x30, 0x64, + 0x3a, 0x36, 0x34, 0x3a, 0x35, 0x31, 0x3a, 0x64, 0x37, 0x3a, 0x66, 0x62, + 0x3a, 0x35, 0x36, 0x3a, 0x66, 0x30, 0x3a, 0x62, 0x32, 0x3a, 0x61, 0x62, + 0x3a, 0x31, 0x64, 0x3a, 0x33, 0x62, 0x3a, 0x38, 0x65, 0x3a, 0x62, 0x30, + 0x3a, 0x37, 0x30, 0x3a, 0x65, 0x35, 0x3a, 0x36, 0x65, 0x3a, 0x64, 0x66, + 0x3a, 0x66, 0x35, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, + 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, + 0x2b, 0x54, 0x43, 0x43, 0x41, 0x6f, 0x43, 0x67, 0x41, 0x77, 0x49, 0x42, + 0x41, 0x67, 0x49, 0x4e, 0x41, 0x4b, 0x61, 0x4c, 0x65, 0x53, 0x6b, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x55, 0x4e, 0x43, 0x52, 0x2b, 0x54, 0x41, 0x4b, + 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, + 0x41, 0x7a, 0x43, 0x42, 0x76, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, + 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, + 0x78, 0x46, 0x6a, 0x41, 0x55, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, + 0x54, 0x44, 0x55, 0x56, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, + 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x4b, 0x44, 0x41, + 0x6d, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x48, 0x31, 0x4e, + 0x6c, 0x5a, 0x53, 0x42, 0x33, 0x0a, 0x64, 0x33, 0x63, 0x75, 0x5a, 0x57, + 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x43, 0x35, 0x75, 0x5a, 0x58, + 0x51, 0x76, 0x62, 0x47, 0x56, 0x6e, 0x59, 0x57, 0x77, 0x74, 0x64, 0x47, + 0x56, 0x79, 0x62, 0x58, 0x4d, 0x78, 0x4f, 0x54, 0x41, 0x33, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x4d, 0x43, 0x68, 0x6a, 0x4b, 0x53, + 0x41, 0x79, 0x4d, 0x44, 0x45, 0x79, 0x49, 0x45, 0x56, 0x75, 0x0a, 0x64, + 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x73, 0x49, 0x45, 0x6c, 0x75, 0x59, + 0x79, 0x34, 0x67, 0x4c, 0x53, 0x42, 0x6d, 0x62, 0x33, 0x49, 0x67, 0x59, + 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x70, 0x6c, 0x5a, + 0x43, 0x42, 0x31, 0x63, 0x32, 0x55, 0x67, 0x62, 0x32, 0x35, 0x73, 0x65, + 0x54, 0x45, 0x7a, 0x4d, 0x44, 0x45, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, + 0x78, 0x4d, 0x71, 0x0a, 0x52, 0x57, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, + 0x64, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x6c, + 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, + 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, + 0x61, 0x58, 0x52, 0x35, 0x49, 0x43, 0x30, 0x67, 0x52, 0x55, 0x4d, 0x78, + 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x79, 0x0a, 0x4d, 0x54, 0x49, + 0x78, 0x4f, 0x44, 0x45, 0x31, 0x4d, 0x6a, 0x55, 0x7a, 0x4e, 0x6c, 0x6f, + 0x58, 0x44, 0x54, 0x4d, 0x33, 0x4d, 0x54, 0x49, 0x78, 0x4f, 0x44, 0x45, + 0x31, 0x4e, 0x54, 0x55, 0x7a, 0x4e, 0x6c, 0x6f, 0x77, 0x67, 0x62, 0x38, + 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, + 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x52, 0x59, 0x77, 0x46, 0x41, 0x59, + 0x44, 0x0a, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x31, 0x46, 0x62, 0x6e, + 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4c, 0x43, 0x42, 0x4a, 0x62, 0x6d, + 0x4d, 0x75, 0x4d, 0x53, 0x67, 0x77, 0x4a, 0x67, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4c, 0x45, 0x78, 0x39, 0x54, 0x5a, 0x57, 0x55, 0x67, 0x64, 0x33, + 0x64, 0x33, 0x4c, 0x6d, 0x56, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, + 0x51, 0x75, 0x62, 0x6d, 0x56, 0x30, 0x0a, 0x4c, 0x32, 0x78, 0x6c, 0x5a, + 0x32, 0x46, 0x73, 0x4c, 0x58, 0x52, 0x6c, 0x63, 0x6d, 0x31, 0x7a, 0x4d, + 0x54, 0x6b, 0x77, 0x4e, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, + 0x7a, 0x41, 0x6f, 0x59, 0x79, 0x6b, 0x67, 0x4d, 0x6a, 0x41, 0x78, 0x4d, + 0x69, 0x42, 0x46, 0x62, 0x6e, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x4c, + 0x43, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x49, 0x43, 0x30, 0x67, 0x0a, + 0x5a, 0x6d, 0x39, 0x79, 0x49, 0x47, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, + 0x63, 0x6d, 0x6c, 0x36, 0x5a, 0x57, 0x51, 0x67, 0x64, 0x58, 0x4e, 0x6c, + 0x49, 0x47, 0x39, 0x75, 0x62, 0x48, 0x6b, 0x78, 0x4d, 0x7a, 0x41, 0x78, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x4b, 0x6b, 0x56, 0x75, + 0x64, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x55, 0x6d, 0x39, 0x76, + 0x64, 0x43, 0x42, 0x44, 0x0a, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, + 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, + 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x53, 0x41, + 0x74, 0x49, 0x45, 0x56, 0x44, 0x4d, 0x54, 0x42, 0x32, 0x4d, 0x42, 0x41, + 0x47, 0x42, 0x79, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, 0x45, + 0x47, 0x42, 0x53, 0x75, 0x42, 0x42, 0x41, 0x41, 0x69, 0x0a, 0x41, 0x32, + 0x49, 0x41, 0x42, 0x49, 0x51, 0x54, 0x79, 0x64, 0x43, 0x36, 0x62, 0x55, + 0x46, 0x37, 0x34, 0x6d, 0x7a, 0x51, 0x36, 0x31, 0x56, 0x66, 0x5a, 0x67, + 0x49, 0x61, 0x4a, 0x50, 0x52, 0x62, 0x69, 0x57, 0x6c, 0x48, 0x34, 0x37, + 0x6a, 0x43, 0x66, 0x66, 0x48, 0x79, 0x41, 0x73, 0x57, 0x66, 0x6f, 0x50, + 0x5a, 0x62, 0x31, 0x59, 0x73, 0x47, 0x47, 0x59, 0x5a, 0x50, 0x55, 0x78, + 0x42, 0x74, 0x0a, 0x42, 0x79, 0x51, 0x6e, 0x6f, 0x61, 0x44, 0x34, 0x31, + 0x55, 0x63, 0x5a, 0x59, 0x55, 0x78, 0x39, 0x79, 0x70, 0x4d, 0x6e, 0x36, + 0x6e, 0x51, 0x4d, 0x37, 0x32, 0x2b, 0x57, 0x43, 0x66, 0x35, 0x6a, 0x37, + 0x48, 0x42, 0x64, 0x4e, 0x71, 0x31, 0x6e, 0x64, 0x36, 0x37, 0x4a, 0x6e, + 0x58, 0x78, 0x56, 0x52, 0x44, 0x71, 0x69, 0x59, 0x31, 0x45, 0x66, 0x39, + 0x65, 0x4e, 0x69, 0x31, 0x4b, 0x6c, 0x48, 0x0a, 0x42, 0x7a, 0x37, 0x4d, + 0x49, 0x4b, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, + 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, + 0x41, 0x67, 0x45, 0x47, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, + 0x41, 0x66, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, + 0x0a, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4c, 0x64, 0x6a, 0x35, 0x78, 0x72, + 0x64, 0x6a, 0x65, 0x6b, 0x49, 0x70, 0x6c, 0x57, 0x44, 0x70, 0x4f, 0x42, + 0x71, 0x55, 0x45, 0x46, 0x6c, 0x45, 0x55, 0x4a, 0x4a, 0x4d, 0x41, 0x6f, + 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, + 0x44, 0x41, 0x32, 0x63, 0x41, 0x4d, 0x47, 0x51, 0x43, 0x4d, 0x47, 0x46, + 0x35, 0x32, 0x4f, 0x56, 0x43, 0x0a, 0x52, 0x39, 0x38, 0x63, 0x72, 0x6c, + 0x4f, 0x5a, 0x46, 0x37, 0x5a, 0x76, 0x48, 0x48, 0x33, 0x68, 0x76, 0x78, + 0x47, 0x55, 0x30, 0x51, 0x4f, 0x49, 0x64, 0x65, 0x53, 0x4e, 0x69, 0x61, + 0x53, 0x4b, 0x64, 0x30, 0x62, 0x65, 0x62, 0x57, 0x48, 0x76, 0x41, 0x76, + 0x58, 0x37, 0x74, 0x64, 0x2f, 0x4d, 0x2f, 0x6b, 0x37, 0x2f, 0x2f, 0x71, + 0x6e, 0x6d, 0x70, 0x77, 0x49, 0x77, 0x57, 0x35, 0x6e, 0x58, 0x0a, 0x68, + 0x54, 0x63, 0x47, 0x74, 0x58, 0x73, 0x49, 0x2f, 0x65, 0x73, 0x6e, 0x69, + 0x30, 0x71, 0x55, 0x2b, 0x65, 0x48, 0x36, 0x70, 0x34, 0x34, 0x6d, 0x43, + 0x4f, 0x68, 0x38, 0x6b, 0x6d, 0x68, 0x74, 0x63, 0x39, 0x68, 0x76, 0x4a, + 0x71, 0x77, 0x68, 0x41, 0x72, 0x69, 0x5a, 0x74, 0x79, 0x5a, 0x42, 0x57, + 0x79, 0x56, 0x67, 0x72, 0x74, 0x42, 0x49, 0x47, 0x75, 0x34, 0x47, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x46, 0x43, 0x41, 0x20, 0x45, 0x56, 0x20, + 0x52, 0x4f, 0x4f, 0x54, 0x20, 0x4f, 0x3d, 0x43, 0x68, 0x69, 0x6e, 0x61, + 0x20, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x69, 0x61, 0x6c, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, + 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x43, 0x46, 0x43, 0x41, 0x20, 0x45, 0x56, 0x20, 0x52, 0x4f, 0x4f, + 0x54, 0x20, 0x4f, 0x3d, 0x43, 0x68, 0x69, 0x6e, 0x61, 0x20, 0x46, 0x69, + 0x6e, 0x61, 0x6e, 0x63, 0x69, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x46, 0x43, 0x41, 0x20, 0x45, + 0x56, 0x20, 0x52, 0x4f, 0x4f, 0x54, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x34, 0x30, 0x37, 0x35, 0x35, 0x35, + 0x32, 0x38, 0x36, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, + 0x34, 0x3a, 0x65, 0x31, 0x3a, 0x62, 0x36, 0x3a, 0x65, 0x64, 0x3a, 0x32, + 0x36, 0x3a, 0x37, 0x61, 0x3a, 0x37, 0x61, 0x3a, 0x34, 0x34, 0x3a, 0x33, + 0x30, 0x3a, 0x33, 0x33, 0x3a, 0x39, 0x34, 0x3a, 0x61, 0x62, 0x3a, 0x37, + 0x62, 0x3a, 0x32, 0x37, 0x3a, 0x38, 0x31, 0x3a, 0x33, 0x30, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x32, 0x3a, 0x62, 0x38, + 0x3a, 0x32, 0x39, 0x3a, 0x34, 0x62, 0x3a, 0x35, 0x35, 0x3a, 0x38, 0x34, + 0x3a, 0x61, 0x62, 0x3a, 0x36, 0x62, 0x3a, 0x35, 0x38, 0x3a, 0x63, 0x32, + 0x3a, 0x39, 0x30, 0x3a, 0x34, 0x36, 0x3a, 0x36, 0x63, 0x3a, 0x61, 0x63, + 0x3a, 0x33, 0x66, 0x3a, 0x62, 0x38, 0x3a, 0x33, 0x39, 0x3a, 0x38, 0x66, + 0x3a, 0x38, 0x34, 0x3a, 0x38, 0x33, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x63, 0x3a, 0x63, 0x33, 0x3a, 0x64, + 0x37, 0x3a, 0x38, 0x65, 0x3a, 0x34, 0x65, 0x3a, 0x31, 0x64, 0x3a, 0x35, + 0x65, 0x3a, 0x34, 0x35, 0x3a, 0x35, 0x34, 0x3a, 0x37, 0x61, 0x3a, 0x30, + 0x34, 0x3a, 0x65, 0x36, 0x3a, 0x38, 0x37, 0x3a, 0x33, 0x65, 0x3a, 0x36, + 0x34, 0x3a, 0x66, 0x39, 0x3a, 0x30, 0x63, 0x3a, 0x66, 0x39, 0x3a, 0x35, + 0x33, 0x3a, 0x36, 0x64, 0x3a, 0x31, 0x63, 0x3a, 0x63, 0x63, 0x3a, 0x32, + 0x65, 0x3a, 0x66, 0x38, 0x3a, 0x30, 0x30, 0x3a, 0x66, 0x33, 0x3a, 0x35, + 0x35, 0x3a, 0x63, 0x34, 0x3a, 0x63, 0x35, 0x3a, 0x66, 0x64, 0x3a, 0x37, + 0x30, 0x3a, 0x66, 0x64, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x46, 0x6a, 0x54, 0x43, 0x43, 0x41, 0x33, 0x57, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x45, 0x47, 0x45, 0x72, 0x4d, 0x31, 0x6a, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, + 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x57, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, + 0x44, 0x0a, 0x54, 0x6a, 0x45, 0x77, 0x4d, 0x43, 0x34, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x67, 0x77, 0x6e, 0x51, 0x32, 0x68, 0x70, 0x62, 0x6d, + 0x45, 0x67, 0x52, 0x6d, 0x6c, 0x75, 0x59, 0x57, 0x35, 0x6a, 0x61, 0x57, + 0x46, 0x73, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, + 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, + 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x0a, 0x61, 0x58, 0x52, 0x35, 0x4d, + 0x52, 0x55, 0x77, 0x45, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, + 0x41, 0x78, 0x44, 0x52, 0x6b, 0x4e, 0x42, 0x49, 0x45, 0x56, 0x57, 0x49, + 0x46, 0x4a, 0x50, 0x54, 0x31, 0x51, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, + 0x54, 0x49, 0x77, 0x4f, 0x44, 0x41, 0x34, 0x4d, 0x44, 0x4d, 0x77, 0x4e, + 0x7a, 0x41, 0x78, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x6b, 0x78, 0x0a, + 0x4d, 0x6a, 0x4d, 0x78, 0x4d, 0x44, 0x4d, 0x77, 0x4e, 0x7a, 0x41, 0x78, + 0x57, 0x6a, 0x42, 0x57, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x44, 0x54, 0x6a, 0x45, 0x77, + 0x4d, 0x43, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x6e, + 0x51, 0x32, 0x68, 0x70, 0x62, 0x6d, 0x45, 0x67, 0x52, 0x6d, 0x6c, 0x75, + 0x59, 0x57, 0x35, 0x6a, 0x0a, 0x61, 0x57, 0x46, 0x73, 0x49, 0x45, 0x4e, + 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, + 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, + 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x52, 0x55, 0x77, 0x45, 0x77, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x41, 0x78, 0x44, 0x52, 0x6b, 0x4e, + 0x42, 0x49, 0x45, 0x56, 0x57, 0x49, 0x46, 0x4a, 0x50, 0x0a, 0x54, 0x31, + 0x51, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, + 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, + 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, + 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51, 0x44, 0x58, 0x58, 0x57, + 0x76, 0x4e, 0x45, 0x44, 0x38, 0x66, 0x42, 0x56, 0x6e, 0x56, 0x42, 0x55, + 0x30, 0x33, 0x0a, 0x73, 0x51, 0x37, 0x73, 0x6d, 0x43, 0x75, 0x4f, 0x46, + 0x52, 0x33, 0x36, 0x6b, 0x30, 0x73, 0x58, 0x67, 0x69, 0x46, 0x78, 0x45, + 0x46, 0x4c, 0x58, 0x55, 0x57, 0x52, 0x77, 0x46, 0x73, 0x4a, 0x56, 0x61, + 0x55, 0x32, 0x4f, 0x46, 0x57, 0x32, 0x66, 0x76, 0x77, 0x77, 0x62, 0x77, + 0x75, 0x43, 0x6a, 0x5a, 0x39, 0x59, 0x4d, 0x72, 0x4d, 0x38, 0x69, 0x72, + 0x71, 0x39, 0x33, 0x56, 0x43, 0x70, 0x4c, 0x0a, 0x54, 0x49, 0x70, 0x54, + 0x55, 0x6e, 0x72, 0x44, 0x37, 0x69, 0x37, 0x65, 0x73, 0x33, 0x45, 0x6c, + 0x77, 0x65, 0x6c, 0x64, 0x50, 0x65, 0x36, 0x68, 0x4c, 0x36, 0x50, 0x33, + 0x4b, 0x6a, 0x7a, 0x4a, 0x49, 0x78, 0x31, 0x71, 0x71, 0x78, 0x32, 0x68, + 0x70, 0x2f, 0x48, 0x7a, 0x37, 0x4b, 0x44, 0x56, 0x52, 0x4d, 0x38, 0x56, + 0x7a, 0x33, 0x49, 0x76, 0x48, 0x57, 0x4f, 0x58, 0x36, 0x4a, 0x6e, 0x35, + 0x0a, 0x2f, 0x5a, 0x4f, 0x6b, 0x56, 0x49, 0x42, 0x4d, 0x55, 0x74, 0x52, + 0x53, 0x71, 0x79, 0x35, 0x4a, 0x33, 0x35, 0x44, 0x4e, 0x75, 0x46, 0x2b, + 0x2b, 0x50, 0x39, 0x36, 0x68, 0x79, 0x6b, 0x30, 0x67, 0x31, 0x43, 0x58, + 0x6f, 0x68, 0x43, 0x6c, 0x54, 0x74, 0x37, 0x47, 0x49, 0x48, 0x2f, 0x2f, + 0x36, 0x32, 0x70, 0x43, 0x66, 0x43, 0x71, 0x6b, 0x74, 0x51, 0x54, 0x2b, + 0x78, 0x38, 0x52, 0x67, 0x70, 0x0a, 0x37, 0x68, 0x5a, 0x5a, 0x4c, 0x44, + 0x52, 0x4a, 0x47, 0x71, 0x67, 0x47, 0x31, 0x36, 0x69, 0x49, 0x30, 0x67, + 0x4e, 0x79, 0x65, 0x6a, 0x4c, 0x69, 0x36, 0x6d, 0x68, 0x4e, 0x62, 0x69, + 0x79, 0x57, 0x5a, 0x58, 0x76, 0x4b, 0x57, 0x66, 0x72, 0x79, 0x34, 0x74, + 0x33, 0x75, 0x4d, 0x43, 0x7a, 0x37, 0x7a, 0x45, 0x61, 0x73, 0x78, 0x47, + 0x50, 0x72, 0x62, 0x33, 0x38, 0x32, 0x4b, 0x7a, 0x52, 0x7a, 0x0a, 0x45, + 0x70, 0x52, 0x2f, 0x33, 0x38, 0x77, 0x6d, 0x6e, 0x76, 0x46, 0x79, 0x58, + 0x56, 0x42, 0x6c, 0x57, 0x59, 0x39, 0x70, 0x73, 0x34, 0x64, 0x65, 0x4d, + 0x6d, 0x2f, 0x44, 0x47, 0x49, 0x71, 0x31, 0x6c, 0x59, 0x2b, 0x77, 0x65, + 0x6a, 0x66, 0x65, 0x57, 0x6b, 0x55, 0x37, 0x78, 0x7a, 0x62, 0x68, 0x37, + 0x32, 0x66, 0x52, 0x4f, 0x64, 0x4f, 0x58, 0x57, 0x33, 0x4e, 0x69, 0x47, + 0x55, 0x67, 0x74, 0x0a, 0x68, 0x78, 0x77, 0x47, 0x2b, 0x33, 0x53, 0x59, + 0x49, 0x45, 0x6c, 0x7a, 0x38, 0x41, 0x58, 0x53, 0x47, 0x37, 0x47, 0x67, + 0x6f, 0x37, 0x63, 0x62, 0x63, 0x4e, 0x4f, 0x49, 0x61, 0x62, 0x6c, 0x61, + 0x31, 0x6a, 0x6a, 0x30, 0x59, 0x74, 0x77, 0x6c, 0x69, 0x33, 0x69, 0x2f, + 0x2b, 0x4f, 0x68, 0x2b, 0x75, 0x46, 0x7a, 0x4a, 0x6c, 0x55, 0x39, 0x66, + 0x70, 0x79, 0x32, 0x35, 0x49, 0x47, 0x76, 0x50, 0x0a, 0x61, 0x39, 0x33, + 0x31, 0x44, 0x66, 0x53, 0x43, 0x74, 0x2f, 0x53, 0x79, 0x5a, 0x69, 0x34, + 0x51, 0x4b, 0x50, 0x61, 0x58, 0x57, 0x6e, 0x75, 0x57, 0x46, 0x6f, 0x38, + 0x42, 0x47, 0x53, 0x31, 0x73, 0x62, 0x6e, 0x38, 0x35, 0x57, 0x41, 0x5a, + 0x6b, 0x67, 0x77, 0x47, 0x44, 0x67, 0x38, 0x4e, 0x4e, 0x6b, 0x74, 0x30, + 0x79, 0x78, 0x6f, 0x65, 0x6b, 0x4e, 0x2b, 0x6b, 0x57, 0x7a, 0x71, 0x6f, + 0x74, 0x0a, 0x61, 0x4b, 0x38, 0x4b, 0x67, 0x57, 0x55, 0x36, 0x63, 0x4d, + 0x47, 0x62, 0x72, 0x55, 0x31, 0x74, 0x56, 0x4d, 0x6f, 0x71, 0x4c, 0x55, + 0x75, 0x46, 0x47, 0x37, 0x4f, 0x41, 0x35, 0x6e, 0x42, 0x46, 0x44, 0x57, + 0x74, 0x65, 0x4e, 0x66, 0x42, 0x2f, 0x4f, 0x37, 0x69, 0x63, 0x35, 0x41, + 0x52, 0x77, 0x69, 0x52, 0x49, 0x6c, 0x6b, 0x39, 0x6f, 0x4b, 0x6d, 0x53, + 0x4a, 0x67, 0x61, 0x6d, 0x4e, 0x67, 0x0a, 0x54, 0x6e, 0x59, 0x47, 0x6d, + 0x45, 0x36, 0x39, 0x67, 0x36, 0x30, 0x64, 0x57, 0x49, 0x6f, 0x6c, 0x68, + 0x64, 0x4c, 0x48, 0x5a, 0x52, 0x34, 0x74, 0x6a, 0x73, 0x62, 0x66, 0x74, + 0x73, 0x62, 0x68, 0x66, 0x34, 0x6f, 0x45, 0x49, 0x52, 0x55, 0x70, 0x64, + 0x50, 0x41, 0x2b, 0x6e, 0x4a, 0x43, 0x64, 0x44, 0x43, 0x37, 0x78, 0x69, + 0x6a, 0x35, 0x61, 0x71, 0x67, 0x77, 0x4a, 0x48, 0x73, 0x66, 0x56, 0x0a, + 0x50, 0x4b, 0x50, 0x74, 0x6c, 0x38, 0x4d, 0x65, 0x4e, 0x50, 0x6f, 0x34, + 0x2b, 0x51, 0x67, 0x4f, 0x34, 0x38, 0x42, 0x64, 0x4b, 0x34, 0x50, 0x52, + 0x56, 0x6d, 0x72, 0x4a, 0x74, 0x71, 0x68, 0x55, 0x55, 0x79, 0x35, 0x34, + 0x4d, 0x6d, 0x63, 0x39, 0x67, 0x6e, 0x39, 0x30, 0x30, 0x50, 0x76, 0x68, + 0x74, 0x67, 0x56, 0x67, 0x75, 0x58, 0x44, 0x62, 0x6a, 0x67, 0x76, 0x35, + 0x45, 0x31, 0x68, 0x76, 0x0a, 0x63, 0x57, 0x41, 0x51, 0x55, 0x68, 0x43, + 0x35, 0x77, 0x55, 0x45, 0x4a, 0x37, 0x33, 0x49, 0x66, 0x5a, 0x7a, 0x46, + 0x34, 0x2f, 0x35, 0x59, 0x46, 0x6a, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, + 0x42, 0x6f, 0x32, 0x4d, 0x77, 0x59, 0x54, 0x41, 0x66, 0x42, 0x67, 0x4e, + 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x54, + 0x6a, 0x2f, 0x69, 0x33, 0x39, 0x4b, 0x4e, 0x41, 0x4c, 0x0a, 0x74, 0x62, + 0x71, 0x32, 0x6f, 0x73, 0x53, 0x2f, 0x42, 0x71, 0x6f, 0x46, 0x6a, 0x4a, + 0x50, 0x37, 0x4c, 0x7a, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, + 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, + 0x48, 0x2f, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, + 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, + 0x41, 0x64, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, + 0x67, 0x51, 0x55, 0x34, 0x2f, 0x34, 0x74, 0x2f, 0x53, 0x6a, 0x51, 0x43, + 0x37, 0x57, 0x36, 0x74, 0x71, 0x4c, 0x45, 0x76, 0x77, 0x61, 0x71, 0x42, + 0x59, 0x79, 0x54, 0x2b, 0x79, 0x38, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, + 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x42, 0x0a, 0x41, 0x43, 0x58, 0x47, + 0x75, 0x6d, 0x76, 0x72, 0x68, 0x38, 0x76, 0x65, 0x67, 0x6a, 0x6d, 0x57, + 0x50, 0x66, 0x42, 0x45, 0x70, 0x32, 0x75, 0x45, 0x63, 0x77, 0x50, 0x65, + 0x6e, 0x53, 0x74, 0x50, 0x75, 0x69, 0x42, 0x2f, 0x76, 0x48, 0x69, 0x79, + 0x7a, 0x35, 0x65, 0x77, 0x47, 0x35, 0x7a, 0x7a, 0x31, 0x33, 0x6b, 0x75, + 0x39, 0x55, 0x69, 0x32, 0x30, 0x76, 0x73, 0x58, 0x69, 0x4f, 0x62, 0x54, + 0x0a, 0x65, 0x6a, 0x2f, 0x74, 0x55, 0x78, 0x50, 0x51, 0x34, 0x69, 0x39, + 0x71, 0x65, 0x63, 0x73, 0x41, 0x49, 0x79, 0x6a, 0x6d, 0x48, 0x6a, 0x64, + 0x58, 0x4e, 0x59, 0x6d, 0x45, 0x77, 0x6e, 0x5a, 0x50, 0x4e, 0x44, 0x61, + 0x74, 0x5a, 0x38, 0x50, 0x4f, 0x51, 0x51, 0x61, 0x49, 0x78, 0x66, 0x66, + 0x75, 0x32, 0x42, 0x71, 0x34, 0x31, 0x67, 0x74, 0x2f, 0x55, 0x50, 0x2b, + 0x54, 0x71, 0x68, 0x64, 0x4c, 0x0a, 0x6a, 0x4f, 0x7a, 0x74, 0x55, 0x6d, + 0x43, 0x79, 0x70, 0x41, 0x62, 0x71, 0x54, 0x75, 0x76, 0x30, 0x61, 0x78, + 0x6e, 0x39, 0x36, 0x2f, 0x55, 0x61, 0x34, 0x43, 0x55, 0x71, 0x6d, 0x74, + 0x7a, 0x48, 0x51, 0x54, 0x62, 0x33, 0x79, 0x48, 0x51, 0x46, 0x68, 0x44, + 0x6d, 0x56, 0x4f, 0x64, 0x59, 0x4c, 0x4f, 0x36, 0x51, 0x6e, 0x2b, 0x67, + 0x6a, 0x59, 0x58, 0x42, 0x37, 0x34, 0x42, 0x47, 0x42, 0x53, 0x0a, 0x45, + 0x53, 0x67, 0x6f, 0x41, 0x2f, 0x2f, 0x76, 0x55, 0x32, 0x59, 0x41, 0x70, + 0x55, 0x6f, 0x30, 0x46, 0x6d, 0x5a, 0x38, 0x2f, 0x51, 0x6d, 0x6b, 0x72, + 0x70, 0x35, 0x6e, 0x47, 0x6d, 0x39, 0x42, 0x43, 0x32, 0x73, 0x47, 0x45, + 0x35, 0x75, 0x50, 0x68, 0x6e, 0x45, 0x46, 0x74, 0x43, 0x2b, 0x4e, 0x69, + 0x57, 0x59, 0x7a, 0x4b, 0x58, 0x5a, 0x55, 0x6d, 0x68, 0x48, 0x34, 0x4a, + 0x2f, 0x71, 0x79, 0x0a, 0x50, 0x35, 0x48, 0x67, 0x7a, 0x67, 0x30, 0x62, + 0x38, 0x7a, 0x41, 0x61, 0x72, 0x62, 0x38, 0x69, 0x58, 0x52, 0x76, 0x54, + 0x76, 0x79, 0x55, 0x46, 0x54, 0x65, 0x47, 0x53, 0x47, 0x6e, 0x2b, 0x5a, + 0x6e, 0x7a, 0x78, 0x45, 0x6b, 0x38, 0x72, 0x55, 0x51, 0x45, 0x6c, 0x73, + 0x67, 0x49, 0x66, 0x58, 0x42, 0x44, 0x72, 0x44, 0x4d, 0x6c, 0x49, 0x31, + 0x44, 0x6c, 0x62, 0x34, 0x70, 0x64, 0x31, 0x39, 0x0a, 0x78, 0x49, 0x73, + 0x4e, 0x45, 0x52, 0x39, 0x54, 0x79, 0x78, 0x36, 0x79, 0x46, 0x37, 0x5a, + 0x6f, 0x64, 0x31, 0x72, 0x67, 0x31, 0x4d, 0x76, 0x49, 0x42, 0x36, 0x37, + 0x31, 0x4f, 0x69, 0x36, 0x4f, 0x4e, 0x37, 0x66, 0x51, 0x41, 0x55, 0x74, + 0x44, 0x4b, 0x58, 0x65, 0x4d, 0x4f, 0x5a, 0x65, 0x50, 0x67, 0x6c, 0x72, + 0x34, 0x55, 0x65, 0x57, 0x4a, 0x6f, 0x42, 0x6a, 0x6e, 0x61, 0x48, 0x39, + 0x64, 0x0a, 0x43, 0x69, 0x37, 0x37, 0x6f, 0x30, 0x63, 0x4f, 0x50, 0x61, + 0x59, 0x6a, 0x65, 0x73, 0x59, 0x42, 0x78, 0x34, 0x2f, 0x49, 0x58, 0x72, + 0x39, 0x74, 0x67, 0x46, 0x61, 0x2b, 0x69, 0x69, 0x53, 0x36, 0x4d, 0x2b, + 0x71, 0x66, 0x34, 0x54, 0x49, 0x52, 0x6e, 0x76, 0x48, 0x53, 0x54, 0x34, + 0x44, 0x32, 0x47, 0x30, 0x43, 0x76, 0x4f, 0x4a, 0x34, 0x52, 0x55, 0x48, + 0x6c, 0x7a, 0x45, 0x68, 0x4c, 0x4e, 0x0a, 0x35, 0x6d, 0x79, 0x64, 0x4c, + 0x49, 0x68, 0x79, 0x50, 0x44, 0x43, 0x42, 0x42, 0x70, 0x45, 0x69, 0x36, + 0x6c, 0x6d, 0x74, 0x32, 0x68, 0x6b, 0x75, 0x49, 0x73, 0x4b, 0x4e, 0x75, + 0x59, 0x79, 0x48, 0x34, 0x47, 0x61, 0x38, 0x63, 0x79, 0x4e, 0x66, 0x49, + 0x57, 0x52, 0x6a, 0x67, 0x45, 0x6a, 0x31, 0x6f, 0x44, 0x77, 0x59, 0x50, + 0x5a, 0x54, 0x49, 0x53, 0x45, 0x45, 0x64, 0x51, 0x4c, 0x70, 0x65, 0x0a, + 0x2f, 0x76, 0x35, 0x57, 0x4f, 0x61, 0x48, 0x49, 0x7a, 0x31, 0x36, 0x65, + 0x47, 0x57, 0x52, 0x47, 0x45, 0x4e, 0x6f, 0x58, 0x6b, 0x62, 0x63, 0x46, + 0x67, 0x4b, 0x79, 0x4c, 0x6d, 0x5a, 0x4a, 0x39, 0x35, 0x36, 0x4c, 0x59, + 0x42, 0x77, 0x73, 0x32, 0x4a, 0x2b, 0x64, 0x49, 0x65, 0x57, 0x43, 0x4b, + 0x77, 0x39, 0x63, 0x54, 0x58, 0x50, 0x68, 0x79, 0x51, 0x4e, 0x39, 0x4b, + 0x79, 0x38, 0x2b, 0x5a, 0x0a, 0x41, 0x41, 0x6f, 0x41, 0x43, 0x78, 0x47, + 0x56, 0x32, 0x6c, 0x5a, 0x46, 0x41, 0x34, 0x67, 0x4b, 0x6e, 0x32, 0x66, + 0x51, 0x31, 0x58, 0x6d, 0x78, 0x71, 0x49, 0x31, 0x41, 0x62, 0x51, 0x33, + 0x43, 0x65, 0x6b, 0x44, 0x36, 0x38, 0x31, 0x39, 0x6b, 0x52, 0x35, 0x4c, + 0x4c, 0x55, 0x37, 0x6d, 0x37, 0x57, 0x63, 0x35, 0x50, 0x2f, 0x64, 0x41, + 0x56, 0x55, 0x77, 0x48, 0x59, 0x33, 0x2b, 0x76, 0x5a, 0x0a, 0x35, 0x6e, + 0x62, 0x76, 0x30, 0x43, 0x4f, 0x37, 0x4f, 0x36, 0x6c, 0x35, 0x73, 0x39, + 0x55, 0x43, 0x4b, 0x63, 0x32, 0x4a, 0x6f, 0x35, 0x59, 0x50, 0x53, 0x6a, + 0x58, 0x6e, 0x54, 0x6b, 0x4c, 0x41, 0x64, 0x63, 0x30, 0x48, 0x7a, 0x2b, + 0x59, 0x73, 0x36, 0x33, 0x73, 0x75, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, + 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x6e, 0x6f, 0x6d, 0x69, 0x73, 0x20, 0x2d, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x6e, 0x6f, 0x6d, 0x69, 0x73, 0x20, 0x4f, 0x55, 0x3d, + 0x30, 0x30, 0x30, 0x32, 0x20, 0x34, 0x33, 0x33, 0x39, 0x39, 0x38, 0x39, + 0x30, 0x33, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x6f, + 0x6d, 0x69, 0x73, 0x20, 0x2d, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x20, 0x4f, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x6f, 0x6d, + 0x69, 0x73, 0x20, 0x4f, 0x55, 0x3d, 0x30, 0x30, 0x30, 0x32, 0x20, 0x34, + 0x33, 0x33, 0x39, 0x39, 0x38, 0x39, 0x30, 0x33, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x6e, 0x6f, 0x6d, 0x69, 0x73, 0x20, 0x2d, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x31, 0x34, 0x3a, 0x30, 0x61, 0x3a, 0x66, 0x64, 0x3a, 0x38, 0x64, 0x3a, + 0x61, 0x38, 0x3a, 0x32, 0x38, 0x3a, 0x62, 0x35, 0x3a, 0x33, 0x38, 0x3a, + 0x36, 0x39, 0x3a, 0x64, 0x62, 0x3a, 0x35, 0x36, 0x3a, 0x37, 0x65, 0x3a, + 0x36, 0x31, 0x3a, 0x32, 0x32, 0x3a, 0x30, 0x33, 0x3a, 0x33, 0x66, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x64, 0x3a, 0x37, + 0x30, 0x3a, 0x62, 0x62, 0x3a, 0x30, 0x31, 0x3a, 0x61, 0x35, 0x3a, 0x61, + 0x34, 0x3a, 0x61, 0x30, 0x3a, 0x31, 0x38, 0x3a, 0x31, 0x31, 0x3a, 0x32, + 0x65, 0x3a, 0x66, 0x37, 0x3a, 0x31, 0x63, 0x3a, 0x30, 0x31, 0x3a, 0x62, + 0x39, 0x3a, 0x33, 0x32, 0x3a, 0x63, 0x35, 0x3a, 0x33, 0x34, 0x3a, 0x65, + 0x37, 0x3a, 0x38, 0x38, 0x3a, 0x61, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x61, 0x3a, 0x39, 0x39, 0x3a, + 0x66, 0x35, 0x3a, 0x62, 0x63, 0x3a, 0x31, 0x31, 0x3a, 0x37, 0x34, 0x3a, + 0x62, 0x37, 0x3a, 0x33, 0x63, 0x3a, 0x62, 0x62, 0x3a, 0x31, 0x64, 0x3a, + 0x36, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x38, 0x34, 0x3a, 0x65, 0x30, 0x3a, + 0x31, 0x63, 0x3a, 0x33, 0x34, 0x3a, 0x65, 0x35, 0x3a, 0x31, 0x63, 0x3a, + 0x63, 0x62, 0x3a, 0x33, 0x39, 0x3a, 0x37, 0x38, 0x3a, 0x64, 0x61, 0x3a, + 0x31, 0x32, 0x3a, 0x35, 0x66, 0x3a, 0x30, 0x65, 0x3a, 0x33, 0x33, 0x3a, + 0x32, 0x36, 0x3a, 0x38, 0x38, 0x3a, 0x38, 0x33, 0x3a, 0x62, 0x66, 0x3a, + 0x34, 0x31, 0x3a, 0x35, 0x38, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, + 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, + 0x49, 0x46, 0x6b, 0x6a, 0x43, 0x43, 0x41, 0x33, 0x71, 0x67, 0x41, 0x77, + 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x73, 0x46, 0x41, 0x44, 0x42, 0x61, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x47, 0x55, 0x6a, + 0x45, 0x54, 0x0a, 0x4d, 0x42, 0x45, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x68, 0x4d, 0x4b, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x75, 0x62, + 0x32, 0x31, 0x70, 0x63, 0x7a, 0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x4f, 0x4d, 0x44, 0x41, 0x77, 0x4d, + 0x69, 0x41, 0x30, 0x4d, 0x7a, 0x4d, 0x35, 0x4f, 0x54, 0x67, 0x35, 0x4d, + 0x44, 0x4d, 0x78, 0x48, 0x54, 0x41, 0x62, 0x0a, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x4d, 0x54, 0x46, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, + 0x62, 0x6d, 0x39, 0x74, 0x61, 0x58, 0x4d, 0x67, 0x4c, 0x53, 0x42, 0x53, + 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x42, 0x34, 0x58, + 0x44, 0x54, 0x45, 0x7a, 0x4d, 0x54, 0x41, 0x79, 0x4d, 0x54, 0x41, 0x35, + 0x4d, 0x54, 0x63, 0x78, 0x4f, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x4d, 0x7a, + 0x0a, 0x4d, 0x54, 0x41, 0x79, 0x4d, 0x54, 0x41, 0x35, 0x4d, 0x54, 0x63, + 0x78, 0x4f, 0x46, 0x6f, 0x77, 0x57, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x6c, 0x49, + 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, + 0x54, 0x43, 0x6b, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x62, 0x6d, 0x39, + 0x74, 0x61, 0x58, 0x4d, 0x78, 0x0a, 0x46, 0x7a, 0x41, 0x56, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x44, 0x6a, 0x41, 0x77, 0x4d, 0x44, + 0x49, 0x67, 0x4e, 0x44, 0x4d, 0x7a, 0x4f, 0x54, 0x6b, 0x34, 0x4f, 0x54, + 0x41, 0x7a, 0x4d, 0x52, 0x30, 0x77, 0x47, 0x77, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x44, 0x45, 0x78, 0x52, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, + 0x35, 0x76, 0x62, 0x57, 0x6c, 0x7a, 0x49, 0x43, 0x30, 0x67, 0x0a, 0x55, + 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x54, 0x43, 0x43, 0x41, + 0x69, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, + 0x67, 0x49, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x67, 0x6f, 0x43, 0x67, + 0x67, 0x49, 0x42, 0x41, 0x4e, 0x54, 0x4d, 0x43, 0x51, 0x6f, 0x73, 0x50, + 0x35, 0x4c, 0x32, 0x0a, 0x66, 0x78, 0x53, 0x65, 0x43, 0x35, 0x79, 0x61, + 0x61, 0x68, 0x31, 0x41, 0x4d, 0x47, 0x54, 0x39, 0x71, 0x74, 0x38, 0x4f, + 0x48, 0x67, 0x5a, 0x62, 0x6e, 0x31, 0x43, 0x46, 0x36, 0x73, 0x32, 0x4e, + 0x71, 0x30, 0x4e, 0x6e, 0x33, 0x72, 0x44, 0x36, 0x66, 0x6f, 0x43, 0x57, + 0x6e, 0x6f, 0x52, 0x34, 0x6b, 0x6b, 0x6a, 0x57, 0x34, 0x7a, 0x6e, 0x75, + 0x7a, 0x75, 0x52, 0x5a, 0x57, 0x4a, 0x66, 0x6c, 0x0a, 0x4c, 0x69, 0x65, + 0x59, 0x36, 0x70, 0x4f, 0x6f, 0x64, 0x35, 0x74, 0x4b, 0x38, 0x4f, 0x39, + 0x30, 0x67, 0x43, 0x33, 0x72, 0x4d, 0x42, 0x2b, 0x31, 0x32, 0x63, 0x65, + 0x41, 0x6e, 0x47, 0x49, 0x6e, 0x6b, 0x59, 0x6a, 0x77, 0x53, 0x6f, 0x6e, + 0x64, 0x33, 0x49, 0x6a, 0x6d, 0x46, 0x50, 0x6e, 0x56, 0x41, 0x79, 0x2f, + 0x2f, 0x6c, 0x64, 0x75, 0x39, 0x6e, 0x2b, 0x77, 0x73, 0x2b, 0x68, 0x51, + 0x56, 0x0a, 0x57, 0x5a, 0x55, 0x4b, 0x78, 0x6b, 0x64, 0x38, 0x61, 0x52, + 0x69, 0x35, 0x70, 0x77, 0x50, 0x35, 0x79, 0x6e, 0x61, 0x70, 0x7a, 0x38, + 0x64, 0x76, 0x74, 0x46, 0x34, 0x46, 0x2f, 0x75, 0x37, 0x42, 0x55, 0x72, + 0x4a, 0x31, 0x4d, 0x6f, 0x66, 0x73, 0x37, 0x53, 0x6c, 0x6d, 0x4f, 0x2f, + 0x4e, 0x4b, 0x46, 0x6f, 0x4c, 0x32, 0x31, 0x70, 0x72, 0x62, 0x63, 0x70, + 0x6a, 0x70, 0x33, 0x76, 0x44, 0x46, 0x0a, 0x54, 0x4b, 0x57, 0x72, 0x74, + 0x65, 0x6f, 0x42, 0x34, 0x6f, 0x77, 0x75, 0x5a, 0x48, 0x39, 0x6b, 0x62, + 0x2f, 0x32, 0x6a, 0x4a, 0x5a, 0x4f, 0x4c, 0x79, 0x4b, 0x49, 0x4f, 0x53, + 0x59, 0x30, 0x30, 0x38, 0x42, 0x2f, 0x73, 0x57, 0x45, 0x55, 0x75, 0x4e, + 0x4b, 0x71, 0x45, 0x55, 0x4c, 0x33, 0x6e, 0x73, 0x6b, 0x6f, 0x54, 0x75, + 0x4c, 0x41, 0x50, 0x72, 0x6a, 0x68, 0x64, 0x73, 0x4b, 0x6b, 0x62, 0x0a, + 0x35, 0x6e, 0x50, 0x4a, 0x57, 0x71, 0x48, 0x5a, 0x5a, 0x6b, 0x43, 0x71, + 0x71, 0x55, 0x32, 0x6d, 0x4e, 0x41, 0x4b, 0x74, 0x68, 0x48, 0x36, 0x79, + 0x49, 0x38, 0x48, 0x37, 0x4b, 0x73, 0x5a, 0x6e, 0x39, 0x44, 0x53, 0x32, + 0x73, 0x4a, 0x56, 0x71, 0x4d, 0x30, 0x39, 0x78, 0x52, 0x4c, 0x57, 0x74, + 0x77, 0x48, 0x6b, 0x7a, 0x69, 0x4f, 0x43, 0x2f, 0x37, 0x61, 0x4f, 0x67, + 0x46, 0x4c, 0x53, 0x63, 0x0a, 0x43, 0x62, 0x41, 0x4b, 0x34, 0x32, 0x43, + 0x2b, 0x2b, 0x50, 0x68, 0x6d, 0x69, 0x4d, 0x31, 0x62, 0x38, 0x58, 0x63, + 0x46, 0x34, 0x4c, 0x56, 0x7a, 0x62, 0x73, 0x46, 0x39, 0x52, 0x69, 0x36, + 0x4f, 0x53, 0x79, 0x65, 0x6d, 0x7a, 0x54, 0x55, 0x4b, 0x2f, 0x65, 0x56, + 0x4e, 0x66, 0x61, 0x6f, 0x71, 0x6f, 0x79, 0x6e, 0x48, 0x57, 0x6d, 0x67, + 0x45, 0x36, 0x4f, 0x58, 0x57, 0x6b, 0x36, 0x52, 0x69, 0x0a, 0x77, 0x73, + 0x58, 0x6d, 0x39, 0x45, 0x2f, 0x47, 0x2b, 0x5a, 0x38, 0x61, 0x6a, 0x59, + 0x4a, 0x4a, 0x47, 0x59, 0x72, 0x4b, 0x57, 0x55, 0x4d, 0x36, 0x36, 0x41, + 0x30, 0x79, 0x77, 0x66, 0x52, 0x4d, 0x45, 0x77, 0x4e, 0x76, 0x62, 0x71, + 0x59, 0x2f, 0x6b, 0x58, 0x50, 0x4c, 0x79, 0x6e, 0x4e, 0x76, 0x45, 0x69, + 0x43, 0x4c, 0x37, 0x73, 0x43, 0x43, 0x65, 0x4e, 0x35, 0x4c, 0x4c, 0x73, + 0x4a, 0x4a, 0x0a, 0x77, 0x78, 0x33, 0x74, 0x46, 0x76, 0x59, 0x6b, 0x39, + 0x43, 0x63, 0x62, 0x58, 0x46, 0x63, 0x78, 0x33, 0x46, 0x58, 0x75, 0x71, + 0x42, 0x35, 0x76, 0x62, 0x4b, 0x7a, 0x69, 0x52, 0x63, 0x78, 0x58, 0x56, + 0x34, 0x70, 0x31, 0x56, 0x78, 0x6e, 0x67, 0x74, 0x56, 0x69, 0x5a, 0x53, + 0x54, 0x59, 0x78, 0x50, 0x44, 0x4d, 0x42, 0x62, 0x52, 0x5a, 0x4b, 0x7a, + 0x62, 0x67, 0x71, 0x67, 0x34, 0x53, 0x47, 0x0a, 0x6d, 0x2f, 0x6c, 0x67, + 0x30, 0x68, 0x39, 0x74, 0x6b, 0x51, 0x50, 0x54, 0x59, 0x4b, 0x62, 0x56, + 0x50, 0x5a, 0x72, 0x64, 0x64, 0x35, 0x41, 0x39, 0x4e, 0x61, 0x53, 0x66, + 0x44, 0x31, 0x37, 0x31, 0x55, 0x6b, 0x52, 0x70, 0x75, 0x63, 0x43, 0x36, + 0x33, 0x4d, 0x39, 0x39, 0x33, 0x33, 0x7a, 0x5a, 0x78, 0x4b, 0x79, 0x47, + 0x49, 0x6a, 0x4b, 0x38, 0x65, 0x32, 0x75, 0x52, 0x37, 0x33, 0x72, 0x34, + 0x0a, 0x46, 0x32, 0x69, 0x77, 0x34, 0x6c, 0x4e, 0x56, 0x59, 0x43, 0x32, + 0x76, 0x50, 0x73, 0x4b, 0x44, 0x32, 0x4e, 0x6b, 0x4a, 0x4b, 0x2f, 0x44, + 0x41, 0x5a, 0x4e, 0x75, 0x48, 0x69, 0x35, 0x48, 0x4d, 0x6b, 0x65, 0x73, + 0x45, 0x2f, 0x58, 0x61, 0x30, 0x6c, 0x5a, 0x72, 0x6d, 0x46, 0x41, 0x59, + 0x62, 0x31, 0x54, 0x51, 0x64, 0x76, 0x74, 0x6a, 0x2f, 0x64, 0x42, 0x78, + 0x54, 0x68, 0x5a, 0x6e, 0x67, 0x0a, 0x57, 0x56, 0x4a, 0x4b, 0x59, 0x65, + 0x32, 0x49, 0x6e, 0x6d, 0x74, 0x4a, 0x69, 0x55, 0x5a, 0x2b, 0x49, 0x46, + 0x72, 0x5a, 0x35, 0x30, 0x72, 0x6c, 0x61, 0x75, 0x37, 0x53, 0x5a, 0x52, + 0x46, 0x44, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x59, 0x7a, + 0x42, 0x68, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, + 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x0a, 0x42, + 0x6a, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, + 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, + 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, + 0x42, 0x54, 0x76, 0x6b, 0x55, 0x7a, 0x31, 0x70, 0x63, 0x4d, 0x77, 0x36, + 0x43, 0x38, 0x49, 0x36, 0x74, 0x4e, 0x78, 0x49, 0x71, 0x53, 0x53, 0x61, + 0x48, 0x68, 0x30, 0x0a, 0x32, 0x54, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x54, 0x76, + 0x6b, 0x55, 0x7a, 0x31, 0x70, 0x63, 0x4d, 0x77, 0x36, 0x43, 0x38, 0x49, + 0x36, 0x74, 0x4e, 0x78, 0x49, 0x71, 0x53, 0x53, 0x61, 0x48, 0x68, 0x30, + 0x32, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, + 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x0a, 0x41, 0x41, 0x4f, + 0x43, 0x41, 0x67, 0x45, 0x41, 0x66, 0x6a, 0x31, 0x55, 0x32, 0x69, 0x4a, + 0x64, 0x47, 0x6c, 0x67, 0x2b, 0x4f, 0x31, 0x51, 0x6e, 0x75, 0x72, 0x72, + 0x4d, 0x79, 0x4f, 0x4d, 0x61, 0x61, 0x75, 0x6f, 0x2b, 0x2b, 0x52, 0x4c, + 0x72, 0x56, 0x6c, 0x38, 0x39, 0x55, 0x4d, 0x37, 0x67, 0x36, 0x6b, 0x67, + 0x6d, 0x4a, 0x73, 0x39, 0x35, 0x56, 0x6e, 0x36, 0x52, 0x48, 0x4a, 0x6b, + 0x2f, 0x0a, 0x30, 0x4b, 0x47, 0x52, 0x48, 0x43, 0x77, 0x50, 0x54, 0x35, + 0x69, 0x56, 0x57, 0x56, 0x4f, 0x39, 0x30, 0x43, 0x4c, 0x59, 0x69, 0x46, + 0x32, 0x63, 0x4e, 0x2f, 0x7a, 0x37, 0x5a, 0x4d, 0x46, 0x34, 0x6a, 0x49, + 0x75, 0x61, 0x59, 0x41, 0x6e, 0x71, 0x31, 0x66, 0x6f, 0x68, 0x58, 0x39, + 0x42, 0x30, 0x5a, 0x65, 0x64, 0x51, 0x78, 0x62, 0x38, 0x75, 0x75, 0x51, + 0x73, 0x4c, 0x72, 0x62, 0x57, 0x77, 0x0a, 0x46, 0x36, 0x59, 0x53, 0x6a, + 0x4e, 0x52, 0x69, 0x65, 0x4f, 0x70, 0x57, 0x61, 0x75, 0x77, 0x4b, 0x30, + 0x6b, 0x44, 0x44, 0x50, 0x41, 0x55, 0x77, 0x50, 0x6b, 0x32, 0x55, 0x74, + 0x35, 0x39, 0x4b, 0x41, 0x39, 0x4e, 0x39, 0x4a, 0x30, 0x75, 0x32, 0x2f, + 0x6b, 0x54, 0x4f, 0x2b, 0x68, 0x6b, 0x7a, 0x47, 0x6d, 0x32, 0x6b, 0x51, + 0x74, 0x48, 0x64, 0x7a, 0x4d, 0x6a, 0x49, 0x31, 0x78, 0x5a, 0x53, 0x0a, + 0x67, 0x30, 0x38, 0x31, 0x6c, 0x4c, 0x4d, 0x53, 0x56, 0x58, 0x33, 0x6c, + 0x34, 0x6b, 0x4c, 0x72, 0x35, 0x4a, 0x79, 0x54, 0x43, 0x63, 0x42, 0x4d, + 0x57, 0x77, 0x65, 0x72, 0x78, 0x32, 0x30, 0x52, 0x6f, 0x46, 0x41, 0x58, + 0x6c, 0x43, 0x4f, 0x6f, 0x74, 0x51, 0x71, 0x53, 0x44, 0x37, 0x4a, 0x36, + 0x77, 0x57, 0x41, 0x73, 0x4f, 0x4d, 0x77, 0x61, 0x70, 0x6c, 0x76, 0x2f, + 0x38, 0x67, 0x7a, 0x6a, 0x0a, 0x71, 0x68, 0x38, 0x63, 0x33, 0x4c, 0x69, + 0x67, 0x6b, 0x79, 0x66, 0x65, 0x59, 0x2b, 0x4e, 0x2f, 0x49, 0x5a, 0x38, + 0x36, 0x35, 0x5a, 0x37, 0x36, 0x34, 0x42, 0x4e, 0x71, 0x64, 0x65, 0x75, + 0x57, 0x58, 0x47, 0x4b, 0x52, 0x6c, 0x49, 0x35, 0x6e, 0x55, 0x37, 0x61, + 0x4a, 0x2b, 0x42, 0x49, 0x4a, 0x79, 0x32, 0x39, 0x53, 0x57, 0x77, 0x4e, + 0x79, 0x68, 0x6c, 0x43, 0x56, 0x43, 0x4e, 0x53, 0x4e, 0x0a, 0x68, 0x34, + 0x59, 0x56, 0x48, 0x35, 0x55, 0x6b, 0x32, 0x4b, 0x52, 0x76, 0x6d, 0x73, + 0x36, 0x6b, 0x6e, 0x5a, 0x74, 0x74, 0x30, 0x72, 0x4a, 0x32, 0x42, 0x6f, + 0x62, 0x47, 0x56, 0x67, 0x6a, 0x46, 0x36, 0x77, 0x6e, 0x61, 0x4e, 0x73, + 0x49, 0x62, 0x57, 0x30, 0x47, 0x2b, 0x59, 0x53, 0x72, 0x6a, 0x63, 0x4f, + 0x61, 0x34, 0x70, 0x76, 0x69, 0x32, 0x57, 0x73, 0x53, 0x39, 0x49, 0x66, + 0x66, 0x2f, 0x0a, 0x71, 0x6c, 0x2b, 0x68, 0x62, 0x48, 0x59, 0x35, 0x5a, + 0x74, 0x62, 0x71, 0x54, 0x46, 0x58, 0x68, 0x41, 0x44, 0x4f, 0x62, 0x45, + 0x35, 0x68, 0x6a, 0x79, 0x57, 0x2f, 0x51, 0x41, 0x53, 0x41, 0x4a, 0x4e, + 0x31, 0x4c, 0x6e, 0x44, 0x45, 0x38, 0x2b, 0x7a, 0x62, 0x7a, 0x31, 0x58, + 0x35, 0x59, 0x6e, 0x70, 0x79, 0x41, 0x43, 0x6c, 0x65, 0x41, 0x75, 0x36, + 0x41, 0x64, 0x42, 0x42, 0x52, 0x38, 0x56, 0x0a, 0x62, 0x74, 0x61, 0x77, + 0x35, 0x42, 0x6e, 0x67, 0x44, 0x77, 0x4b, 0x54, 0x41, 0x43, 0x64, 0x79, + 0x78, 0x59, 0x76, 0x52, 0x56, 0x42, 0x39, 0x64, 0x53, 0x73, 0x4e, 0x41, + 0x6c, 0x33, 0x35, 0x56, 0x70, 0x6e, 0x7a, 0x42, 0x4d, 0x77, 0x51, 0x55, + 0x41, 0x52, 0x31, 0x4a, 0x49, 0x47, 0x6b, 0x4c, 0x47, 0x5a, 0x4f, 0x64, + 0x62, 0x6c, 0x67, 0x69, 0x39, 0x30, 0x41, 0x4d, 0x52, 0x67, 0x77, 0x6a, + 0x0a, 0x59, 0x2f, 0x4d, 0x35, 0x30, 0x6e, 0x39, 0x32, 0x55, 0x61, 0x66, + 0x30, 0x79, 0x4b, 0x48, 0x78, 0x44, 0x48, 0x59, 0x69, 0x49, 0x30, 0x5a, + 0x53, 0x4b, 0x53, 0x33, 0x69, 0x6f, 0x30, 0x45, 0x48, 0x56, 0x6d, 0x6d, + 0x59, 0x30, 0x67, 0x55, 0x4a, 0x76, 0x47, 0x6e, 0x48, 0x57, 0x6d, 0x48, + 0x4e, 0x6a, 0x34, 0x46, 0x67, 0x46, 0x55, 0x32, 0x41, 0x33, 0x5a, 0x44, + 0x69, 0x66, 0x63, 0x52, 0x51, 0x0a, 0x38, 0x6f, 0x77, 0x37, 0x62, 0x6b, + 0x72, 0x48, 0x78, 0x75, 0x61, 0x41, 0x4b, 0x7a, 0x79, 0x42, 0x76, 0x42, + 0x47, 0x41, 0x46, 0x68, 0x41, 0x6e, 0x31, 0x2f, 0x44, 0x4e, 0x50, 0x33, + 0x6e, 0x4d, 0x63, 0x79, 0x72, 0x44, 0x66, 0x6c, 0x4f, 0x52, 0x31, 0x6d, + 0x37, 0x34, 0x39, 0x66, 0x50, 0x48, 0x30, 0x46, 0x46, 0x4e, 0x6a, 0x6b, + 0x75, 0x6c, 0x57, 0x2b, 0x59, 0x5a, 0x46, 0x7a, 0x76, 0x57, 0x0a, 0x67, + 0x51, 0x6e, 0x63, 0x49, 0x74, 0x7a, 0x75, 0x6a, 0x72, 0x6e, 0x45, 0x6a, + 0x31, 0x50, 0x68, 0x5a, 0x37, 0x73, 0x7a, 0x75, 0x49, 0x67, 0x56, 0x52, + 0x73, 0x2f, 0x74, 0x61, 0x54, 0x58, 0x2f, 0x64, 0x51, 0x31, 0x47, 0x38, + 0x38, 0x35, 0x78, 0x34, 0x63, 0x56, 0x72, 0x68, 0x6b, 0x49, 0x47, 0x75, + 0x55, 0x45, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x4f, 0x49, 0x53, 0x54, + 0x45, 0x20, 0x57, 0x49, 0x53, 0x65, 0x4b, 0x65, 0x79, 0x20, 0x47, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x42, + 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x57, 0x49, 0x53, 0x65, 0x4b, 0x65, + 0x79, 0x20, 0x4f, 0x55, 0x3d, 0x4f, 0x49, 0x53, 0x54, 0x45, 0x20, 0x46, + 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x45, 0x6e, + 0x64, 0x6f, 0x72, 0x73, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x4f, 0x49, 0x53, + 0x54, 0x45, 0x20, 0x57, 0x49, 0x53, 0x65, 0x4b, 0x65, 0x79, 0x20, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, + 0x42, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x57, 0x49, 0x53, 0x65, 0x4b, + 0x65, 0x79, 0x20, 0x4f, 0x55, 0x3d, 0x4f, 0x49, 0x53, 0x54, 0x45, 0x20, + 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x45, + 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x4f, 0x49, 0x53, 0x54, 0x45, 0x20, + 0x57, 0x49, 0x53, 0x65, 0x4b, 0x65, 0x79, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x42, 0x20, 0x43, + 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x31, 0x35, 0x37, 0x37, 0x36, 0x38, 0x35, 0x39, 0x35, 0x36, 0x31, + 0x36, 0x35, 0x38, 0x38, 0x34, 0x31, 0x34, 0x34, 0x32, 0x32, 0x31, 0x35, + 0x39, 0x32, 0x37, 0x38, 0x39, 0x36, 0x36, 0x37, 0x35, 0x30, 0x37, 0x35, + 0x37, 0x35, 0x36, 0x38, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x61, 0x34, 0x3a, 0x65, 0x62, 0x3a, 0x62, 0x39, 0x3a, 0x36, 0x31, 0x3a, + 0x32, 0x38, 0x3a, 0x32, 0x65, 0x3a, 0x62, 0x37, 0x3a, 0x32, 0x66, 0x3a, + 0x39, 0x38, 0x3a, 0x62, 0x30, 0x3a, 0x33, 0x35, 0x3a, 0x32, 0x36, 0x3a, + 0x39, 0x30, 0x3a, 0x39, 0x39, 0x3a, 0x35, 0x31, 0x3a, 0x31, 0x64, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x66, 0x3a, 0x66, + 0x39, 0x3a, 0x34, 0x30, 0x3a, 0x37, 0x36, 0x3a, 0x31, 0x38, 0x3a, 0x64, + 0x33, 0x3a, 0x64, 0x37, 0x3a, 0x36, 0x61, 0x3a, 0x34, 0x62, 0x3a, 0x39, + 0x38, 0x3a, 0x66, 0x30, 0x3a, 0x61, 0x38, 0x3a, 0x33, 0x35, 0x3a, 0x39, + 0x65, 0x3a, 0x30, 0x63, 0x3a, 0x66, 0x64, 0x3a, 0x32, 0x37, 0x3a, 0x61, + 0x63, 0x3a, 0x63, 0x63, 0x3a, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x62, 0x3a, 0x39, 0x63, 0x3a, + 0x30, 0x38, 0x3a, 0x65, 0x38, 0x3a, 0x36, 0x65, 0x3a, 0x62, 0x30, 0x3a, + 0x66, 0x37, 0x3a, 0x36, 0x37, 0x3a, 0x63, 0x66, 0x3a, 0x61, 0x64, 0x3a, + 0x36, 0x35, 0x3a, 0x63, 0x64, 0x3a, 0x39, 0x38, 0x3a, 0x62, 0x36, 0x3a, + 0x32, 0x31, 0x3a, 0x34, 0x39, 0x3a, 0x65, 0x35, 0x3a, 0x34, 0x39, 0x3a, + 0x34, 0x61, 0x3a, 0x36, 0x37, 0x3a, 0x66, 0x35, 0x3a, 0x38, 0x34, 0x3a, + 0x35, 0x65, 0x3a, 0x37, 0x62, 0x3a, 0x64, 0x31, 0x3a, 0x65, 0x64, 0x3a, + 0x30, 0x31, 0x3a, 0x39, 0x66, 0x3a, 0x32, 0x37, 0x3a, 0x62, 0x38, 0x3a, + 0x36, 0x62, 0x3a, 0x64, 0x36, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, + 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, + 0x49, 0x44, 0x74, 0x54, 0x43, 0x43, 0x41, 0x70, 0x32, 0x67, 0x41, 0x77, + 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x64, 0x72, 0x45, 0x67, 0x55, 0x6e, + 0x54, 0x77, 0x68, 0x59, 0x64, 0x47, 0x73, 0x2f, 0x67, 0x6a, 0x47, 0x76, + 0x62, 0x43, 0x77, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, + 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, + 0x42, 0x74, 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x44, 0x53, 0x44, 0x45, 0x51, 0x4d, + 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x48, 0x56, + 0x30, 0x6c, 0x54, 0x5a, 0x55, 0x74, 0x6c, 0x65, 0x54, 0x45, 0x69, 0x4d, + 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x5a, 0x54, + 0x30, 0x6c, 0x54, 0x56, 0x45, 0x55, 0x67, 0x0a, 0x52, 0x6d, 0x39, 0x31, + 0x62, 0x6d, 0x52, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x46, + 0x62, 0x6d, 0x52, 0x76, 0x63, 0x6e, 0x4e, 0x6c, 0x5a, 0x44, 0x45, 0x6f, + 0x4d, 0x43, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x66, + 0x54, 0x30, 0x6c, 0x54, 0x56, 0x45, 0x55, 0x67, 0x56, 0x30, 0x6c, 0x54, + 0x5a, 0x55, 0x74, 0x6c, 0x65, 0x53, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, + 0x0a, 0x59, 0x57, 0x77, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, + 0x48, 0x51, 0x69, 0x42, 0x44, 0x51, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, + 0x78, 0x4e, 0x44, 0x45, 0x79, 0x4d, 0x44, 0x45, 0x78, 0x4e, 0x54, 0x41, + 0x77, 0x4d, 0x7a, 0x4a, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4f, 0x54, 0x45, + 0x79, 0x4d, 0x44, 0x45, 0x78, 0x4e, 0x54, 0x45, 0x77, 0x4d, 0x7a, 0x46, + 0x61, 0x4d, 0x47, 0x30, 0x78, 0x0a, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x4e, 0x49, 0x4d, 0x52, + 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, + 0x64, 0x58, 0x53, 0x56, 0x4e, 0x6c, 0x53, 0x32, 0x56, 0x35, 0x4d, 0x53, + 0x49, 0x77, 0x49, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, + 0x6c, 0x50, 0x53, 0x56, 0x4e, 0x55, 0x52, 0x53, 0x42, 0x47, 0x0a, 0x62, + 0x33, 0x56, 0x75, 0x5a, 0x47, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, + 0x45, 0x56, 0x75, 0x5a, 0x47, 0x39, 0x79, 0x63, 0x32, 0x56, 0x6b, 0x4d, + 0x53, 0x67, 0x77, 0x4a, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, + 0x78, 0x39, 0x50, 0x53, 0x56, 0x4e, 0x55, 0x52, 0x53, 0x42, 0x58, 0x53, + 0x56, 0x4e, 0x6c, 0x53, 0x32, 0x56, 0x35, 0x49, 0x45, 0x64, 0x73, 0x62, + 0x32, 0x4a, 0x68, 0x0a, 0x62, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, + 0x49, 0x45, 0x64, 0x43, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x49, 0x49, 0x42, + 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, + 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, + 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, + 0x41, 0x51, 0x45, 0x41, 0x32, 0x42, 0x65, 0x33, 0x0a, 0x48, 0x45, 0x6f, + 0x6b, 0x4b, 0x74, 0x61, 0x58, 0x73, 0x63, 0x72, 0x69, 0x48, 0x76, 0x74, + 0x39, 0x4f, 0x4f, 0x2b, 0x59, 0x39, 0x62, 0x49, 0x35, 0x6d, 0x45, 0x34, + 0x6e, 0x75, 0x42, 0x46, 0x64, 0x65, 0x39, 0x49, 0x6c, 0x6c, 0x49, 0x69, + 0x43, 0x46, 0x53, 0x5a, 0x71, 0x47, 0x7a, 0x47, 0x37, 0x71, 0x46, 0x73, + 0x68, 0x49, 0x53, 0x76, 0x59, 0x44, 0x30, 0x36, 0x66, 0x57, 0x76, 0x47, + 0x78, 0x0a, 0x57, 0x75, 0x52, 0x35, 0x31, 0x6a, 0x49, 0x6a, 0x4b, 0x2b, + 0x46, 0x54, 0x7a, 0x4a, 0x6c, 0x46, 0x58, 0x48, 0x74, 0x50, 0x72, 0x62, + 0x79, 0x2f, 0x68, 0x30, 0x6f, 0x4c, 0x53, 0x35, 0x64, 0x61, 0x71, 0x50, + 0x5a, 0x49, 0x37, 0x48, 0x31, 0x37, 0x44, 0x63, 0x30, 0x68, 0x42, 0x74, + 0x2b, 0x65, 0x46, 0x66, 0x31, 0x42, 0x69, 0x6b, 0x69, 0x33, 0x49, 0x50, + 0x53, 0x68, 0x65, 0x68, 0x74, 0x58, 0x0a, 0x31, 0x46, 0x31, 0x51, 0x2f, + 0x37, 0x70, 0x6e, 0x32, 0x43, 0x4f, 0x5a, 0x48, 0x38, 0x67, 0x2f, 0x34, + 0x39, 0x37, 0x2f, 0x62, 0x31, 0x74, 0x33, 0x73, 0x57, 0x74, 0x75, 0x75, + 0x4d, 0x6c, 0x6b, 0x39, 0x2b, 0x48, 0x4b, 0x51, 0x55, 0x59, 0x4f, 0x4b, + 0x58, 0x48, 0x51, 0x75, 0x53, 0x50, 0x38, 0x79, 0x59, 0x46, 0x66, 0x54, + 0x76, 0x64, 0x76, 0x33, 0x37, 0x2b, 0x45, 0x72, 0x58, 0x4e, 0x6b, 0x0a, + 0x75, 0x37, 0x64, 0x43, 0x6a, 0x6d, 0x6e, 0x32, 0x31, 0x48, 0x59, 0x64, + 0x66, 0x70, 0x32, 0x6e, 0x75, 0x46, 0x65, 0x4b, 0x55, 0x57, 0x64, 0x79, + 0x31, 0x39, 0x53, 0x6f, 0x75, 0x4a, 0x56, 0x55, 0x51, 0x48, 0x4d, 0x44, + 0x39, 0x75, 0x72, 0x30, 0x36, 0x2f, 0x34, 0x6f, 0x51, 0x6e, 0x63, 0x2f, + 0x6e, 0x53, 0x4d, 0x62, 0x73, 0x72, 0x59, 0x39, 0x67, 0x42, 0x51, 0x48, + 0x54, 0x43, 0x35, 0x50, 0x0a, 0x39, 0x39, 0x55, 0x4b, 0x46, 0x67, 0x32, + 0x39, 0x5a, 0x6b, 0x4d, 0x33, 0x66, 0x69, 0x4e, 0x44, 0x65, 0x63, 0x4e, + 0x41, 0x68, 0x76, 0x56, 0x4d, 0x4b, 0x64, 0x71, 0x4f, 0x6d, 0x71, 0x30, + 0x4e, 0x70, 0x51, 0x53, 0x48, 0x69, 0x42, 0x36, 0x46, 0x34, 0x2b, 0x6c, + 0x54, 0x31, 0x5a, 0x76, 0x49, 0x69, 0x77, 0x4e, 0x6a, 0x65, 0x4f, 0x76, + 0x67, 0x47, 0x55, 0x70, 0x75, 0x75, 0x79, 0x39, 0x72, 0x0a, 0x4d, 0x32, + 0x52, 0x59, 0x6b, 0x36, 0x31, 0x70, 0x76, 0x34, 0x38, 0x62, 0x37, 0x34, + 0x4a, 0x49, 0x78, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x31, + 0x45, 0x77, 0x54, 0x7a, 0x41, 0x4c, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, + 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x59, 0x59, 0x77, 0x44, 0x77, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, + 0x55, 0x77, 0x0a, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x64, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x4e, + 0x51, 0x2f, 0x49, 0x4e, 0x6d, 0x4e, 0x65, 0x34, 0x71, 0x50, 0x73, 0x2b, + 0x54, 0x74, 0x6d, 0x46, 0x63, 0x35, 0x52, 0x55, 0x75, 0x4f, 0x52, 0x6d, + 0x6a, 0x30, 0x77, 0x45, 0x41, 0x59, 0x4a, 0x4b, 0x77, 0x59, 0x42, 0x42, + 0x41, 0x47, 0x43, 0x4e, 0x78, 0x55, 0x42, 0x0a, 0x42, 0x41, 0x4d, 0x43, + 0x41, 0x51, 0x41, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, + 0x67, 0x67, 0x45, 0x42, 0x41, 0x45, 0x42, 0x4d, 0x2b, 0x34, 0x65, 0x79, + 0x6d, 0x59, 0x47, 0x51, 0x66, 0x70, 0x33, 0x46, 0x73, 0x4c, 0x41, 0x6d, + 0x7a, 0x59, 0x68, 0x37, 0x4b, 0x7a, 0x4b, 0x4e, 0x62, 0x72, 0x67, 0x68, + 0x0a, 0x63, 0x56, 0x69, 0x58, 0x66, 0x61, 0x34, 0x33, 0x46, 0x4b, 0x38, + 0x2b, 0x35, 0x2f, 0x65, 0x61, 0x34, 0x6e, 0x33, 0x32, 0x63, 0x5a, 0x69, + 0x5a, 0x42, 0x4b, 0x70, 0x44, 0x64, 0x48, 0x69, 0x6a, 0x34, 0x30, 0x6c, + 0x68, 0x50, 0x6e, 0x4f, 0x4d, 0x54, 0x5a, 0x54, 0x67, 0x2b, 0x58, 0x48, + 0x45, 0x74, 0x68, 0x59, 0x4f, 0x55, 0x33, 0x67, 0x66, 0x31, 0x71, 0x4b, + 0x48, 0x4c, 0x77, 0x49, 0x35, 0x0a, 0x67, 0x53, 0x6b, 0x38, 0x72, 0x78, + 0x57, 0x59, 0x49, 0x54, 0x44, 0x2b, 0x4b, 0x4a, 0x41, 0x41, 0x6a, 0x4e, + 0x48, 0x68, 0x79, 0x2f, 0x70, 0x65, 0x79, 0x50, 0x33, 0x34, 0x45, 0x45, + 0x59, 0x37, 0x6f, 0x6e, 0x68, 0x43, 0x6b, 0x52, 0x64, 0x30, 0x56, 0x51, + 0x72, 0x65, 0x55, 0x47, 0x64, 0x4e, 0x5a, 0x74, 0x47, 0x6e, 0x2f, 0x2f, + 0x33, 0x5a, 0x77, 0x4c, 0x57, 0x6f, 0x6f, 0x34, 0x72, 0x4f, 0x0a, 0x5a, + 0x76, 0x55, 0x50, 0x51, 0x38, 0x32, 0x6e, 0x4b, 0x31, 0x64, 0x37, 0x59, + 0x30, 0x5a, 0x71, 0x71, 0x69, 0x35, 0x53, 0x32, 0x50, 0x54, 0x74, 0x34, + 0x57, 0x32, 0x74, 0x4b, 0x5a, 0x42, 0x34, 0x53, 0x4c, 0x72, 0x68, 0x49, + 0x36, 0x71, 0x6a, 0x69, 0x65, 0x79, 0x31, 0x71, 0x35, 0x62, 0x41, 0x74, + 0x45, 0x75, 0x69, 0x48, 0x5a, 0x65, 0x65, 0x65, 0x76, 0x4a, 0x75, 0x51, + 0x48, 0x48, 0x66, 0x0a, 0x61, 0x50, 0x46, 0x6c, 0x54, 0x63, 0x35, 0x38, + 0x42, 0x64, 0x39, 0x54, 0x5a, 0x61, 0x6d, 0x6c, 0x38, 0x4c, 0x47, 0x58, + 0x42, 0x48, 0x41, 0x56, 0x52, 0x67, 0x4f, 0x59, 0x31, 0x4e, 0x4b, 0x2f, + 0x56, 0x4c, 0x53, 0x67, 0x57, 0x48, 0x31, 0x53, 0x62, 0x39, 0x70, 0x57, + 0x4a, 0x6d, 0x4c, 0x55, 0x32, 0x4e, 0x75, 0x4a, 0x4d, 0x57, 0x38, 0x63, + 0x38, 0x43, 0x4c, 0x43, 0x30, 0x32, 0x49, 0x63, 0x0a, 0x4e, 0x63, 0x31, + 0x4d, 0x61, 0x52, 0x56, 0x55, 0x47, 0x70, 0x43, 0x59, 0x33, 0x75, 0x73, + 0x65, 0x58, 0x38, 0x70, 0x33, 0x78, 0x38, 0x75, 0x4f, 0x50, 0x55, 0x4e, + 0x70, 0x6e, 0x4a, 0x70, 0x59, 0x30, 0x43, 0x51, 0x37, 0x33, 0x78, 0x74, + 0x41, 0x6c, 0x6e, 0x34, 0x31, 0x72, 0x59, 0x48, 0x48, 0x54, 0x6e, 0x47, + 0x36, 0x69, 0x42, 0x4d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x5a, + 0x41, 0x46, 0x49, 0x52, 0x20, 0x52, 0x4f, 0x4f, 0x54, 0x20, 0x43, 0x41, + 0x32, 0x20, 0x4f, 0x3d, 0x4b, 0x72, 0x61, 0x6a, 0x6f, 0x77, 0x61, 0x20, + 0x49, 0x7a, 0x62, 0x61, 0x20, 0x52, 0x6f, 0x7a, 0x6c, 0x69, 0x63, 0x7a, + 0x65, 0x6e, 0x69, 0x6f, 0x77, 0x61, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x0a, + 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x53, 0x5a, 0x41, 0x46, 0x49, 0x52, 0x20, 0x52, 0x4f, 0x4f, + 0x54, 0x20, 0x43, 0x41, 0x32, 0x20, 0x4f, 0x3d, 0x4b, 0x72, 0x61, 0x6a, + 0x6f, 0x77, 0x61, 0x20, 0x49, 0x7a, 0x62, 0x61, 0x20, 0x52, 0x6f, 0x7a, + 0x6c, 0x69, 0x63, 0x7a, 0x65, 0x6e, 0x69, 0x6f, 0x77, 0x61, 0x20, 0x53, + 0x2e, 0x41, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x53, 0x5a, 0x41, 0x46, 0x49, 0x52, 0x20, 0x52, 0x4f, 0x4f, + 0x54, 0x20, 0x43, 0x41, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x33, 0x35, 0x37, 0x30, 0x34, 0x33, 0x30, + 0x33, 0x34, 0x37, 0x36, 0x37, 0x31, 0x38, 0x36, 0x39, 0x31, 0x34, 0x32, + 0x31, 0x37, 0x32, 0x37, 0x37, 0x33, 0x34, 0x34, 0x35, 0x38, 0x37, 0x33, + 0x38, 0x36, 0x37, 0x34, 0x33, 0x33, 0x37, 0x37, 0x35, 0x35, 0x38, 0x32, + 0x39, 0x36, 0x32, 0x39, 0x32, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x31, 0x31, 0x3a, 0x36, 0x34, 0x3a, 0x63, 0x31, 0x3a, 0x38, 0x39, + 0x3a, 0x62, 0x30, 0x3a, 0x32, 0x34, 0x3a, 0x62, 0x31, 0x3a, 0x38, 0x63, + 0x3a, 0x62, 0x31, 0x3a, 0x30, 0x37, 0x3a, 0x37, 0x65, 0x3a, 0x38, 0x39, + 0x3a, 0x39, 0x65, 0x3a, 0x35, 0x31, 0x3a, 0x39, 0x65, 0x3a, 0x39, 0x39, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x32, 0x3a, + 0x35, 0x32, 0x3a, 0x66, 0x61, 0x3a, 0x39, 0x35, 0x3a, 0x33, 0x66, 0x3a, + 0x65, 0x64, 0x3a, 0x64, 0x62, 0x3a, 0x32, 0x34, 0x3a, 0x36, 0x30, 0x3a, + 0x62, 0x64, 0x3a, 0x36, 0x65, 0x3a, 0x32, 0x38, 0x3a, 0x66, 0x33, 0x3a, + 0x39, 0x63, 0x3a, 0x63, 0x63, 0x3a, 0x63, 0x66, 0x3a, 0x35, 0x65, 0x3a, + 0x62, 0x33, 0x3a, 0x33, 0x66, 0x3a, 0x64, 0x65, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x31, 0x3a, 0x33, 0x33, + 0x3a, 0x39, 0x64, 0x3a, 0x33, 0x33, 0x3a, 0x32, 0x38, 0x3a, 0x31, 0x61, + 0x3a, 0x30, 0x62, 0x3a, 0x35, 0x36, 0x3a, 0x65, 0x35, 0x3a, 0x35, 0x37, + 0x3a, 0x64, 0x33, 0x3a, 0x64, 0x33, 0x3a, 0x32, 0x62, 0x3a, 0x31, 0x63, + 0x3a, 0x65, 0x37, 0x3a, 0x66, 0x39, 0x3a, 0x33, 0x36, 0x3a, 0x37, 0x65, + 0x3a, 0x62, 0x30, 0x3a, 0x39, 0x34, 0x3a, 0x62, 0x64, 0x3a, 0x35, 0x66, + 0x3a, 0x61, 0x37, 0x3a, 0x32, 0x61, 0x3a, 0x37, 0x65, 0x3a, 0x35, 0x30, + 0x3a, 0x30, 0x34, 0x3a, 0x63, 0x38, 0x3a, 0x64, 0x65, 0x3a, 0x64, 0x37, + 0x3a, 0x63, 0x61, 0x3a, 0x66, 0x65, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x44, 0x63, 0x6a, 0x43, 0x43, 0x41, 0x6c, 0x71, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x50, 0x6f, 0x70, 0x64, 0x42, + 0x2b, 0x78, 0x56, 0x30, 0x6a, 0x4c, 0x56, 0x74, 0x2b, 0x4f, 0x32, 0x58, + 0x77, 0x48, 0x72, 0x4c, 0x64, 0x7a, 0x6b, 0x31, 0x75, 0x51, 0x77, 0x44, + 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, + 0x51, 0x45, 0x4c, 0x0a, 0x42, 0x51, 0x41, 0x77, 0x55, 0x54, 0x45, 0x4c, + 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, + 0x55, 0x45, 0x77, 0x78, 0x4b, 0x44, 0x41, 0x6d, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x6f, 0x4d, 0x48, 0x30, 0x74, 0x79, 0x59, 0x57, 0x70, 0x76, + 0x64, 0x32, 0x45, 0x67, 0x53, 0x58, 0x70, 0x69, 0x59, 0x53, 0x42, 0x53, + 0x62, 0x33, 0x70, 0x73, 0x61, 0x57, 0x4e, 0x36, 0x0a, 0x5a, 0x57, 0x35, + 0x70, 0x62, 0x33, 0x64, 0x68, 0x49, 0x46, 0x4d, 0x75, 0x51, 0x53, 0x34, + 0x78, 0x47, 0x44, 0x41, 0x57, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, + 0x4d, 0x44, 0x31, 0x4e, 0x61, 0x51, 0x55, 0x5a, 0x4a, 0x55, 0x69, 0x42, + 0x53, 0x54, 0x30, 0x39, 0x55, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x6a, 0x41, + 0x65, 0x46, 0x77, 0x30, 0x78, 0x4e, 0x54, 0x45, 0x77, 0x4d, 0x54, 0x6b, + 0x77, 0x0a, 0x4e, 0x7a, 0x51, 0x7a, 0x4d, 0x7a, 0x42, 0x61, 0x46, 0x77, + 0x30, 0x7a, 0x4e, 0x54, 0x45, 0x77, 0x4d, 0x54, 0x6b, 0x77, 0x4e, 0x7a, + 0x51, 0x7a, 0x4d, 0x7a, 0x42, 0x61, 0x4d, 0x46, 0x45, 0x78, 0x43, 0x7a, + 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, + 0x42, 0x4d, 0x4d, 0x53, 0x67, 0x77, 0x4a, 0x67, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4b, 0x44, 0x42, 0x39, 0x4c, 0x0a, 0x63, 0x6d, 0x46, 0x71, 0x62, + 0x33, 0x64, 0x68, 0x49, 0x45, 0x6c, 0x36, 0x59, 0x6d, 0x45, 0x67, 0x55, + 0x6d, 0x39, 0x36, 0x62, 0x47, 0x6c, 0x6a, 0x65, 0x6d, 0x56, 0x75, 0x61, + 0x57, 0x39, 0x33, 0x59, 0x53, 0x42, 0x54, 0x4c, 0x6b, 0x45, 0x75, 0x4d, + 0x52, 0x67, 0x77, 0x46, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, + 0x41, 0x39, 0x54, 0x57, 0x6b, 0x46, 0x47, 0x53, 0x56, 0x49, 0x67, 0x0a, + 0x55, 0x6b, 0x39, 0x50, 0x56, 0x43, 0x42, 0x44, 0x51, 0x54, 0x49, 0x77, + 0x67, 0x67, 0x45, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, + 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, + 0x41, 0x34, 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, + 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x43, 0x33, 0x76, 0x44, 0x35, 0x51, + 0x71, 0x45, 0x76, 0x4e, 0x0a, 0x51, 0x4c, 0x58, 0x4f, 0x59, 0x65, 0x65, + 0x57, 0x79, 0x72, 0x53, 0x68, 0x32, 0x67, 0x77, 0x69, 0x73, 0x50, 0x71, + 0x31, 0x65, 0x33, 0x59, 0x41, 0x64, 0x34, 0x77, 0x4c, 0x7a, 0x33, 0x32, + 0x6f, 0x68, 0x73, 0x77, 0x6d, 0x55, 0x65, 0x51, 0x67, 0x50, 0x59, 0x55, + 0x4d, 0x31, 0x6c, 0x6a, 0x6a, 0x35, 0x2f, 0x51, 0x71, 0x47, 0x4a, 0x33, + 0x61, 0x30, 0x61, 0x34, 0x6d, 0x37, 0x75, 0x74, 0x54, 0x0a, 0x33, 0x50, + 0x53, 0x51, 0x31, 0x68, 0x4e, 0x4b, 0x44, 0x4a, 0x41, 0x38, 0x77, 0x2f, + 0x54, 0x61, 0x30, 0x6f, 0x34, 0x4e, 0x6b, 0x6a, 0x72, 0x63, 0x73, 0x62, + 0x48, 0x2f, 0x4f, 0x4e, 0x37, 0x44, 0x75, 0x69, 0x31, 0x66, 0x67, 0x4c, + 0x6b, 0x43, 0x76, 0x55, 0x71, 0x64, 0x47, 0x77, 0x2b, 0x30, 0x77, 0x38, + 0x4c, 0x42, 0x5a, 0x77, 0x50, 0x64, 0x33, 0x42, 0x75, 0x63, 0x50, 0x62, + 0x4f, 0x77, 0x0a, 0x33, 0x67, 0x41, 0x65, 0x71, 0x44, 0x52, 0x48, 0x75, + 0x35, 0x72, 0x72, 0x2f, 0x67, 0x73, 0x55, 0x76, 0x54, 0x61, 0x45, 0x32, + 0x67, 0x30, 0x67, 0x76, 0x2f, 0x70, 0x62, 0x79, 0x36, 0x6b, 0x57, 0x49, + 0x4b, 0x30, 0x35, 0x59, 0x4f, 0x34, 0x76, 0x64, 0x62, 0x62, 0x6e, 0x6c, + 0x35, 0x7a, 0x35, 0x50, 0x76, 0x31, 0x2b, 0x54, 0x57, 0x39, 0x4e, 0x4c, + 0x2b, 0x2b, 0x49, 0x44, 0x57, 0x72, 0x36, 0x0a, 0x33, 0x66, 0x45, 0x39, + 0x62, 0x69, 0x43, 0x6c, 0x6f, 0x42, 0x4b, 0x30, 0x54, 0x58, 0x43, 0x35, + 0x7a, 0x74, 0x64, 0x79, 0x4f, 0x34, 0x6d, 0x54, 0x70, 0x34, 0x43, 0x45, + 0x48, 0x43, 0x64, 0x4a, 0x63, 0x6b, 0x6d, 0x31, 0x2f, 0x7a, 0x75, 0x56, + 0x6e, 0x73, 0x48, 0x4d, 0x79, 0x41, 0x48, 0x73, 0x36, 0x41, 0x36, 0x4b, + 0x43, 0x70, 0x62, 0x6e, 0x73, 0x36, 0x61, 0x48, 0x35, 0x64, 0x62, 0x35, + 0x0a, 0x42, 0x53, 0x73, 0x4e, 0x6c, 0x30, 0x42, 0x77, 0x50, 0x4c, 0x71, + 0x73, 0x64, 0x56, 0x71, 0x63, 0x31, 0x55, 0x32, 0x64, 0x41, 0x67, 0x72, + 0x53, 0x53, 0x35, 0x74, 0x6d, 0x53, 0x30, 0x59, 0x48, 0x46, 0x32, 0x57, + 0x74, 0x6e, 0x32, 0x79, 0x49, 0x41, 0x4e, 0x77, 0x69, 0x69, 0x65, 0x44, + 0x68, 0x5a, 0x4e, 0x52, 0x6e, 0x76, 0x44, 0x46, 0x35, 0x59, 0x54, 0x79, + 0x37, 0x79, 0x6b, 0x48, 0x4e, 0x0a, 0x58, 0x47, 0x6f, 0x41, 0x79, 0x44, + 0x77, 0x34, 0x6a, 0x6c, 0x69, 0x76, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, + 0x47, 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, + 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, + 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x0a, 0x41, + 0x67, 0x45, 0x47, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, + 0x67, 0x51, 0x57, 0x42, 0x42, 0x51, 0x75, 0x46, 0x71, 0x6c, 0x4b, 0x47, + 0x4c, 0x58, 0x4c, 0x7a, 0x50, 0x56, 0x76, 0x55, 0x50, 0x4d, 0x6a, 0x58, + 0x2f, 0x68, 0x64, 0x35, 0x36, 0x7a, 0x77, 0x79, 0x44, 0x41, 0x4e, 0x42, + 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, + 0x51, 0x73, 0x46, 0x0a, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, + 0x74, 0x58, 0x50, 0x34, 0x41, 0x39, 0x78, 0x5a, 0x57, 0x78, 0x31, 0x32, + 0x36, 0x61, 0x4d, 0x71, 0x65, 0x35, 0x41, 0x6f, 0x73, 0x6b, 0x33, 0x41, + 0x4d, 0x30, 0x2b, 0x71, 0x6d, 0x72, 0x48, 0x55, 0x75, 0x4f, 0x51, 0x6e, + 0x2f, 0x36, 0x6d, 0x57, 0x6d, 0x63, 0x35, 0x47, 0x34, 0x47, 0x31, 0x38, + 0x54, 0x4b, 0x49, 0x34, 0x70, 0x41, 0x5a, 0x77, 0x0a, 0x38, 0x50, 0x52, + 0x42, 0x45, 0x65, 0x77, 0x2f, 0x52, 0x34, 0x30, 0x2f, 0x63, 0x6f, 0x66, + 0x35, 0x4f, 0x2f, 0x32, 0x6b, 0x62, 0x79, 0x74, 0x54, 0x41, 0x4f, 0x44, + 0x2f, 0x4f, 0x62, 0x6c, 0x71, 0x42, 0x77, 0x37, 0x72, 0x48, 0x52, 0x7a, + 0x32, 0x6f, 0x6e, 0x4b, 0x51, 0x79, 0x34, 0x49, 0x39, 0x45, 0x59, 0x4b, + 0x4c, 0x30, 0x72, 0x75, 0x66, 0x4b, 0x71, 0x38, 0x68, 0x35, 0x6d, 0x4f, + 0x47, 0x0a, 0x6e, 0x58, 0x6b, 0x5a, 0x37, 0x2f, 0x65, 0x37, 0x44, 0x44, + 0x57, 0x51, 0x77, 0x34, 0x72, 0x74, 0x54, 0x77, 0x2f, 0x31, 0x7a, 0x42, + 0x4c, 0x5a, 0x70, 0x44, 0x36, 0x37, 0x6f, 0x50, 0x77, 0x67, 0x6c, 0x56, + 0x39, 0x50, 0x4a, 0x69, 0x38, 0x52, 0x49, 0x34, 0x4e, 0x4f, 0x64, 0x51, + 0x63, 0x50, 0x76, 0x35, 0x76, 0x52, 0x74, 0x42, 0x33, 0x70, 0x45, 0x41, + 0x54, 0x2b, 0x79, 0x6d, 0x43, 0x50, 0x0a, 0x6f, 0x6b, 0x79, 0x34, 0x72, + 0x63, 0x2f, 0x68, 0x6b, 0x41, 0x2f, 0x4e, 0x72, 0x67, 0x72, 0x48, 0x58, + 0x58, 0x75, 0x33, 0x55, 0x4e, 0x4c, 0x55, 0x59, 0x66, 0x72, 0x56, 0x46, + 0x64, 0x76, 0x58, 0x6e, 0x34, 0x64, 0x52, 0x56, 0x4f, 0x75, 0x6c, 0x34, + 0x2b, 0x76, 0x4a, 0x68, 0x61, 0x41, 0x6c, 0x49, 0x44, 0x66, 0x37, 0x6a, + 0x73, 0x34, 0x4d, 0x4e, 0x49, 0x54, 0x68, 0x50, 0x49, 0x47, 0x79, 0x0a, + 0x64, 0x30, 0x35, 0x44, 0x70, 0x59, 0x68, 0x66, 0x68, 0x6d, 0x65, 0x68, + 0x50, 0x65, 0x61, 0x30, 0x58, 0x47, 0x47, 0x32, 0x50, 0x74, 0x76, 0x2b, + 0x74, 0x79, 0x6a, 0x46, 0x6f, 0x67, 0x65, 0x75, 0x74, 0x63, 0x72, 0x4b, + 0x6a, 0x53, 0x6f, 0x53, 0x37, 0x35, 0x66, 0x74, 0x77, 0x6a, 0x43, 0x6b, + 0x79, 0x53, 0x70, 0x36, 0x2b, 0x2f, 0x4e, 0x4e, 0x49, 0x78, 0x75, 0x5a, + 0x4d, 0x7a, 0x53, 0x67, 0x0a, 0x4c, 0x76, 0x57, 0x70, 0x43, 0x7a, 0x2f, + 0x55, 0x58, 0x65, 0x48, 0x50, 0x68, 0x4a, 0x2f, 0x69, 0x47, 0x63, 0x4a, + 0x66, 0x69, 0x74, 0x59, 0x67, 0x48, 0x75, 0x4e, 0x7a, 0x74, 0x77, 0x3d, + 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x43, 0x41, 0x20, 0x32, 0x20, 0x4f, 0x3d, + 0x55, 0x6e, 0x69, 0x7a, 0x65, 0x74, 0x6f, 0x20, 0x54, 0x65, 0x63, 0x68, + 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x20, 0x53, 0x2e, 0x41, + 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, + 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x65, 0x64, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x20, 0x43, 0x41, 0x20, 0x32, 0x20, 0x4f, 0x3d, 0x55, 0x6e, 0x69, 0x7a, + 0x65, 0x74, 0x6f, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, + 0x67, 0x69, 0x65, 0x73, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x20, 0x4f, 0x55, + 0x3d, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, + 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x43, 0x41, 0x20, 0x32, 0x22, 0x0a, 0x23, + 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x34, 0x34, 0x39, + 0x37, 0x39, 0x39, 0x30, 0x30, 0x30, 0x31, 0x37, 0x32, 0x30, 0x34, 0x33, + 0x38, 0x33, 0x30, 0x39, 0x39, 0x34, 0x36, 0x33, 0x37, 0x36, 0x34, 0x33, + 0x35, 0x37, 0x35, 0x31, 0x32, 0x35, 0x39, 0x36, 0x39, 0x36, 0x39, 0x0a, + 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x64, 0x3a, 0x34, 0x36, + 0x3a, 0x39, 0x65, 0x3a, 0x64, 0x39, 0x3a, 0x32, 0x35, 0x3a, 0x36, 0x64, + 0x3a, 0x30, 0x38, 0x3a, 0x32, 0x33, 0x3a, 0x35, 0x62, 0x3a, 0x35, 0x65, + 0x3a, 0x37, 0x34, 0x3a, 0x37, 0x64, 0x3a, 0x31, 0x65, 0x3a, 0x32, 0x37, + 0x3a, 0x64, 0x62, 0x3a, 0x66, 0x32, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x64, 0x33, 0x3a, 0x64, 0x64, 0x3a, 0x34, 0x38, 0x3a, + 0x33, 0x65, 0x3a, 0x32, 0x62, 0x3a, 0x62, 0x66, 0x3a, 0x34, 0x63, 0x3a, + 0x30, 0x35, 0x3a, 0x65, 0x38, 0x3a, 0x61, 0x66, 0x3a, 0x31, 0x30, 0x3a, + 0x66, 0x35, 0x3a, 0x66, 0x61, 0x3a, 0x37, 0x36, 0x3a, 0x32, 0x36, 0x3a, + 0x63, 0x66, 0x3a, 0x64, 0x33, 0x3a, 0x64, 0x63, 0x3a, 0x33, 0x30, 0x3a, + 0x39, 0x32, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x62, 0x36, 0x3a, 0x37, 0x36, 0x3a, 0x66, 0x32, 0x3a, 0x65, 0x64, + 0x3a, 0x64, 0x61, 0x3a, 0x65, 0x38, 0x3a, 0x37, 0x37, 0x3a, 0x35, 0x63, + 0x3a, 0x64, 0x33, 0x3a, 0x36, 0x63, 0x3a, 0x62, 0x30, 0x3a, 0x66, 0x36, + 0x3a, 0x33, 0x63, 0x3a, 0x64, 0x31, 0x3a, 0x64, 0x34, 0x3a, 0x36, 0x30, + 0x3a, 0x33, 0x39, 0x3a, 0x36, 0x31, 0x3a, 0x66, 0x34, 0x3a, 0x39, 0x65, + 0x3a, 0x36, 0x32, 0x3a, 0x36, 0x35, 0x3a, 0x62, 0x61, 0x3a, 0x30, 0x31, + 0x3a, 0x33, 0x61, 0x3a, 0x32, 0x66, 0x3a, 0x30, 0x33, 0x3a, 0x30, 0x37, + 0x3a, 0x62, 0x36, 0x3a, 0x64, 0x30, 0x3a, 0x62, 0x38, 0x3a, 0x30, 0x34, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x30, 0x6a, 0x43, + 0x43, 0x41, 0x37, 0x71, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x51, 0x49, 0x64, 0x62, 0x51, 0x53, 0x6b, 0x38, 0x6c, 0x44, 0x38, 0x6b, + 0x79, 0x4e, 0x2f, 0x79, 0x71, 0x58, 0x68, 0x4b, 0x4e, 0x36, 0x54, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, + 0x42, 0x41, 0x51, 0x30, 0x46, 0x41, 0x44, 0x43, 0x42, 0x0a, 0x67, 0x44, + 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, + 0x4d, 0x43, 0x55, 0x45, 0x77, 0x78, 0x49, 0x6a, 0x41, 0x67, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x47, 0x56, 0x56, 0x75, 0x61, 0x58, + 0x70, 0x6c, 0x64, 0x47, 0x38, 0x67, 0x56, 0x47, 0x56, 0x6a, 0x61, 0x47, + 0x35, 0x76, 0x62, 0x47, 0x39, 0x6e, 0x61, 0x57, 0x56, 0x7a, 0x49, 0x46, + 0x4d, 0x75, 0x0a, 0x51, 0x53, 0x34, 0x78, 0x4a, 0x7a, 0x41, 0x6c, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x48, 0x6b, 0x4e, 0x6c, 0x63, + 0x6e, 0x52, 0x31, 0x62, 0x53, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, + 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, + 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, + 0x54, 0x45, 0x6b, 0x4d, 0x43, 0x49, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, + 0x41, 0x78, 0x4d, 0x62, 0x51, 0x32, 0x56, 0x79, 0x64, 0x48, 0x56, 0x74, + 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x5a, 0x57, 0x51, 0x67, + 0x54, 0x6d, 0x56, 0x30, 0x64, 0x32, 0x39, 0x79, 0x61, 0x79, 0x42, 0x44, + 0x51, 0x53, 0x41, 0x79, 0x4d, 0x43, 0x49, 0x59, 0x44, 0x7a, 0x49, 0x77, + 0x4d, 0x54, 0x45, 0x78, 0x4d, 0x44, 0x41, 0x32, 0x4d, 0x44, 0x67, 0x7a, + 0x0a, 0x4f, 0x54, 0x55, 0x32, 0x57, 0x68, 0x67, 0x50, 0x4d, 0x6a, 0x41, + 0x30, 0x4e, 0x6a, 0x45, 0x77, 0x4d, 0x44, 0x59, 0x77, 0x4f, 0x44, 0x4d, + 0x35, 0x4e, 0x54, 0x5a, 0x61, 0x4d, 0x49, 0x47, 0x41, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, + 0x51, 0x54, 0x44, 0x45, 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x68, 0x4d, 0x5a, 0x0a, 0x56, 0x57, 0x35, 0x70, 0x65, 0x6d, + 0x56, 0x30, 0x62, 0x79, 0x42, 0x55, 0x5a, 0x57, 0x4e, 0x6f, 0x62, 0x6d, + 0x39, 0x73, 0x62, 0x32, 0x64, 0x70, 0x5a, 0x58, 0x4d, 0x67, 0x55, 0x79, + 0x35, 0x42, 0x4c, 0x6a, 0x45, 0x6e, 0x4d, 0x43, 0x55, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x78, 0x4d, 0x65, 0x51, 0x32, 0x56, 0x79, 0x64, 0x48, + 0x56, 0x74, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x0a, 0x5a, + 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, + 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, + 0x53, 0x51, 0x77, 0x49, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, + 0x78, 0x74, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x64, 0x57, 0x30, 0x67, 0x56, + 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x6c, 0x5a, 0x43, 0x42, 0x4f, 0x5a, + 0x58, 0x52, 0x33, 0x0a, 0x62, 0x33, 0x4a, 0x72, 0x49, 0x45, 0x4e, 0x42, + 0x49, 0x44, 0x49, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, + 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, + 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, + 0x67, 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51, 0x43, 0x39, + 0x2b, 0x58, 0x6a, 0x34, 0x35, 0x74, 0x57, 0x41, 0x0a, 0x44, 0x47, 0x53, + 0x64, 0x68, 0x68, 0x75, 0x57, 0x5a, 0x47, 0x63, 0x2f, 0x49, 0x6a, 0x6f, + 0x65, 0x64, 0x51, 0x46, 0x39, 0x37, 0x2f, 0x74, 0x63, 0x5a, 0x34, 0x7a, + 0x4a, 0x7a, 0x46, 0x78, 0x72, 0x71, 0x5a, 0x48, 0x6d, 0x75, 0x55, 0x4c, + 0x6c, 0x49, 0x45, 0x75, 0x62, 0x32, 0x70, 0x74, 0x37, 0x75, 0x5a, 0x6c, + 0x64, 0x32, 0x5a, 0x75, 0x41, 0x53, 0x39, 0x65, 0x45, 0x51, 0x43, 0x73, + 0x6e, 0x0a, 0x30, 0x2b, 0x69, 0x36, 0x4d, 0x4c, 0x73, 0x2b, 0x43, 0x52, + 0x71, 0x6e, 0x53, 0x5a, 0x58, 0x76, 0x4b, 0x30, 0x41, 0x6b, 0x77, 0x70, + 0x66, 0x48, 0x70, 0x2b, 0x36, 0x62, 0x4a, 0x65, 0x2b, 0x6f, 0x43, 0x67, + 0x43, 0x58, 0x68, 0x56, 0x71, 0x71, 0x6e, 0x64, 0x77, 0x70, 0x79, 0x65, + 0x49, 0x31, 0x42, 0x2b, 0x74, 0x77, 0x54, 0x55, 0x72, 0x57, 0x77, 0x62, + 0x4e, 0x57, 0x75, 0x4b, 0x46, 0x42, 0x0a, 0x4f, 0x4a, 0x76, 0x52, 0x2b, + 0x7a, 0x46, 0x2f, 0x6a, 0x2b, 0x42, 0x66, 0x34, 0x62, 0x45, 0x2f, 0x44, + 0x34, 0x34, 0x57, 0x53, 0x57, 0x44, 0x58, 0x42, 0x6f, 0x30, 0x59, 0x2b, + 0x61, 0x6f, 0x6d, 0x45, 0x4b, 0x73, 0x71, 0x30, 0x39, 0x44, 0x52, 0x5a, + 0x34, 0x30, 0x62, 0x52, 0x72, 0x35, 0x48, 0x4d, 0x4e, 0x55, 0x75, 0x63, + 0x74, 0x48, 0x46, 0x59, 0x39, 0x72, 0x6e, 0x59, 0x33, 0x6c, 0x45, 0x0a, + 0x66, 0x6b, 0x74, 0x6a, 0x4a, 0x49, 0x6d, 0x47, 0x4c, 0x6a, 0x51, 0x2f, + 0x4b, 0x55, 0x78, 0x53, 0x69, 0x79, 0x71, 0x6e, 0x77, 0x4f, 0x4b, 0x52, + 0x4b, 0x49, 0x6d, 0x35, 0x77, 0x46, 0x76, 0x35, 0x48, 0x64, 0x6e, 0x6e, + 0x4a, 0x36, 0x33, 0x2f, 0x6d, 0x67, 0x4b, 0x58, 0x77, 0x63, 0x5a, 0x51, + 0x6b, 0x70, 0x73, 0x43, 0x4c, 0x4c, 0x32, 0x70, 0x75, 0x54, 0x52, 0x5a, + 0x43, 0x72, 0x2b, 0x45, 0x0a, 0x53, 0x76, 0x2f, 0x66, 0x2f, 0x72, 0x4f, + 0x66, 0x36, 0x39, 0x6d, 0x65, 0x34, 0x4a, 0x67, 0x6a, 0x37, 0x4b, 0x5a, + 0x72, 0x64, 0x78, 0x59, 0x71, 0x32, 0x38, 0x79, 0x74, 0x4f, 0x78, 0x79, + 0x6b, 0x68, 0x39, 0x78, 0x47, 0x63, 0x31, 0x34, 0x5a, 0x59, 0x6d, 0x68, + 0x46, 0x56, 0x2b, 0x53, 0x51, 0x67, 0x6b, 0x4b, 0x37, 0x51, 0x74, 0x62, + 0x77, 0x59, 0x65, 0x44, 0x42, 0x6f, 0x7a, 0x31, 0x6d, 0x0a, 0x6f, 0x31, + 0x33, 0x30, 0x47, 0x4f, 0x36, 0x49, 0x79, 0x59, 0x30, 0x58, 0x52, 0x53, + 0x6d, 0x5a, 0x4d, 0x6e, 0x55, 0x43, 0x4d, 0x65, 0x34, 0x70, 0x4a, 0x73, + 0x68, 0x72, 0x41, 0x75, 0x61, 0x31, 0x59, 0x6b, 0x56, 0x2f, 0x4e, 0x78, + 0x56, 0x61, 0x49, 0x32, 0x69, 0x4a, 0x31, 0x44, 0x37, 0x65, 0x54, 0x69, + 0x65, 0x77, 0x38, 0x45, 0x41, 0x4d, 0x76, 0x45, 0x30, 0x58, 0x79, 0x30, + 0x32, 0x69, 0x0a, 0x73, 0x78, 0x37, 0x51, 0x42, 0x6c, 0x72, 0x64, 0x39, + 0x70, 0x50, 0x50, 0x56, 0x33, 0x57, 0x5a, 0x39, 0x66, 0x71, 0x47, 0x47, + 0x6d, 0x64, 0x34, 0x73, 0x37, 0x2b, 0x57, 0x2f, 0x6a, 0x54, 0x63, 0x76, + 0x65, 0x64, 0x53, 0x56, 0x75, 0x57, 0x7a, 0x35, 0x58, 0x56, 0x37, 0x31, + 0x30, 0x47, 0x52, 0x42, 0x64, 0x78, 0x64, 0x61, 0x65, 0x4f, 0x56, 0x44, + 0x55, 0x4f, 0x35, 0x2f, 0x49, 0x4f, 0x57, 0x0a, 0x4f, 0x5a, 0x56, 0x37, + 0x62, 0x49, 0x42, 0x61, 0x54, 0x78, 0x4e, 0x79, 0x78, 0x74, 0x64, 0x39, + 0x4b, 0x58, 0x70, 0x45, 0x75, 0x6c, 0x4b, 0x6b, 0x4b, 0x74, 0x56, 0x42, + 0x52, 0x67, 0x6b, 0x67, 0x2f, 0x69, 0x4b, 0x67, 0x74, 0x6c, 0x73, 0x77, + 0x6a, 0x62, 0x79, 0x4a, 0x44, 0x4e, 0x58, 0x58, 0x63, 0x50, 0x69, 0x48, + 0x55, 0x76, 0x33, 0x61, 0x37, 0x36, 0x78, 0x52, 0x4c, 0x67, 0x65, 0x7a, + 0x0a, 0x54, 0x76, 0x37, 0x51, 0x43, 0x64, 0x70, 0x77, 0x37, 0x35, 0x6a, + 0x36, 0x56, 0x75, 0x5a, 0x74, 0x32, 0x37, 0x56, 0x58, 0x53, 0x39, 0x7a, + 0x6c, 0x4c, 0x43, 0x55, 0x56, 0x79, 0x4a, 0x34, 0x75, 0x65, 0x45, 0x37, + 0x34, 0x32, 0x70, 0x79, 0x65, 0x68, 0x69, 0x7a, 0x4b, 0x56, 0x2f, 0x4d, + 0x61, 0x35, 0x63, 0x69, 0x53, 0x69, 0x78, 0x71, 0x43, 0x6c, 0x6e, 0x72, + 0x44, 0x76, 0x46, 0x41, 0x53, 0x0a, 0x61, 0x64, 0x67, 0x4f, 0x57, 0x6b, + 0x61, 0x4c, 0x4f, 0x75, 0x73, 0x6d, 0x2b, 0x69, 0x50, 0x4a, 0x74, 0x72, + 0x43, 0x42, 0x76, 0x6b, 0x49, 0x41, 0x70, 0x50, 0x6a, 0x57, 0x2f, 0x6a, + 0x41, 0x75, 0x78, 0x39, 0x4a, 0x47, 0x39, 0x75, 0x57, 0x4f, 0x64, 0x66, + 0x33, 0x79, 0x7a, 0x4c, 0x6e, 0x51, 0x68, 0x31, 0x76, 0x4d, 0x42, 0x68, + 0x42, 0x67, 0x75, 0x34, 0x4d, 0x31, 0x74, 0x31, 0x35, 0x6e, 0x0a, 0x33, + 0x6b, 0x66, 0x73, 0x6d, 0x55, 0x6a, 0x78, 0x70, 0x4b, 0x45, 0x56, 0x2f, + 0x71, 0x32, 0x4d, 0x59, 0x6f, 0x34, 0x35, 0x56, 0x55, 0x38, 0x35, 0x46, + 0x72, 0x6d, 0x78, 0x59, 0x35, 0x33, 0x2f, 0x74, 0x77, 0x49, 0x44, 0x41, + 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x50, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, + 0x54, 0x41, 0x44, 0x0a, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x42, 0x30, 0x47, + 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x53, 0x32, + 0x6f, 0x56, 0x51, 0x35, 0x41, 0x73, 0x4f, 0x67, 0x50, 0x34, 0x36, 0x4b, + 0x76, 0x50, 0x72, 0x55, 0x2b, 0x42, 0x79, 0x6d, 0x30, 0x54, 0x6f, 0x4f, + 0x2f, 0x54, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, + 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x0a, 0x41, 0x51, 0x59, + 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, + 0x4e, 0x41, 0x51, 0x45, 0x4e, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, + 0x42, 0x41, 0x48, 0x47, 0x6c, 0x44, 0x73, 0x37, 0x6b, 0x36, 0x62, 0x38, + 0x2f, 0x4f, 0x4e, 0x57, 0x4a, 0x57, 0x73, 0x51, 0x43, 0x59, 0x66, 0x74, + 0x4d, 0x78, 0x52, 0x51, 0x58, 0x4c, 0x59, 0x74, 0x50, 0x55, 0x32, 0x73, + 0x51, 0x0a, 0x46, 0x2f, 0x78, 0x6c, 0x68, 0x4d, 0x63, 0x51, 0x53, 0x5a, + 0x44, 0x65, 0x32, 0x38, 0x63, 0x6d, 0x6b, 0x34, 0x67, 0x6d, 0x62, 0x33, + 0x44, 0x57, 0x41, 0x6c, 0x34, 0x35, 0x6f, 0x50, 0x65, 0x50, 0x71, 0x35, + 0x61, 0x31, 0x70, 0x52, 0x4e, 0x63, 0x67, 0x52, 0x52, 0x74, 0x44, 0x6f, + 0x47, 0x43, 0x45, 0x52, 0x75, 0x4b, 0x54, 0x73, 0x5a, 0x50, 0x70, 0x64, + 0x31, 0x69, 0x48, 0x6b, 0x54, 0x66, 0x0a, 0x43, 0x56, 0x6e, 0x30, 0x57, + 0x33, 0x63, 0x4c, 0x4e, 0x2b, 0x6d, 0x4c, 0x49, 0x4d, 0x62, 0x34, 0x43, + 0x6b, 0x34, 0x75, 0x57, 0x42, 0x7a, 0x72, 0x4d, 0x39, 0x44, 0x50, 0x68, + 0x6d, 0x44, 0x4a, 0x32, 0x76, 0x75, 0x41, 0x4c, 0x35, 0x35, 0x4d, 0x59, + 0x49, 0x52, 0x34, 0x50, 0x53, 0x46, 0x6b, 0x31, 0x76, 0x74, 0x42, 0x48, + 0x78, 0x67, 0x50, 0x35, 0x38, 0x6c, 0x31, 0x63, 0x62, 0x32, 0x39, 0x0a, + 0x58, 0x4e, 0x34, 0x30, 0x68, 0x7a, 0x35, 0x42, 0x73, 0x41, 0x37, 0x32, + 0x75, 0x64, 0x59, 0x2f, 0x43, 0x52, 0x4f, 0x57, 0x46, 0x43, 0x2f, 0x65, + 0x6d, 0x68, 0x31, 0x61, 0x75, 0x56, 0x62, 0x4f, 0x4e, 0x54, 0x71, 0x77, + 0x58, 0x33, 0x42, 0x4e, 0x58, 0x75, 0x4d, 0x70, 0x38, 0x53, 0x4d, 0x6f, + 0x63, 0x6c, 0x6d, 0x32, 0x71, 0x38, 0x4b, 0x4d, 0x5a, 0x69, 0x59, 0x63, + 0x64, 0x79, 0x77, 0x6d, 0x0a, 0x64, 0x6a, 0x57, 0x4c, 0x4b, 0x4b, 0x64, + 0x70, 0x6f, 0x50, 0x6b, 0x37, 0x39, 0x53, 0x50, 0x64, 0x68, 0x52, 0x42, + 0x30, 0x79, 0x5a, 0x41, 0x44, 0x56, 0x70, 0x48, 0x6e, 0x72, 0x37, 0x70, + 0x48, 0x31, 0x42, 0x4b, 0x58, 0x45, 0x53, 0x4c, 0x6a, 0x6f, 0x6b, 0x6d, + 0x55, 0x62, 0x4f, 0x65, 0x33, 0x6c, 0x45, 0x75, 0x36, 0x4c, 0x61, 0x54, + 0x61, 0x4d, 0x34, 0x74, 0x4d, 0x70, 0x6b, 0x54, 0x2f, 0x0a, 0x57, 0x6a, + 0x7a, 0x47, 0x48, 0x57, 0x54, 0x59, 0x74, 0x54, 0x48, 0x6b, 0x70, 0x6a, + 0x78, 0x36, 0x71, 0x46, 0x63, 0x4c, 0x32, 0x2b, 0x31, 0x68, 0x47, 0x73, + 0x76, 0x78, 0x7a, 0x6e, 0x4e, 0x33, 0x59, 0x36, 0x53, 0x48, 0x62, 0x30, + 0x78, 0x52, 0x4f, 0x4e, 0x62, 0x6b, 0x58, 0x38, 0x65, 0x66, 0x74, 0x6f, + 0x45, 0x71, 0x35, 0x49, 0x56, 0x49, 0x65, 0x56, 0x68, 0x65, 0x4f, 0x2f, + 0x6a, 0x62, 0x0a, 0x41, 0x6f, 0x4a, 0x6e, 0x77, 0x54, 0x6e, 0x62, 0x77, + 0x33, 0x52, 0x4c, 0x50, 0x54, 0x59, 0x65, 0x2b, 0x53, 0x6d, 0x54, 0x69, + 0x47, 0x68, 0x62, 0x71, 0x45, 0x51, 0x5a, 0x49, 0x66, 0x43, 0x6e, 0x36, + 0x49, 0x45, 0x4e, 0x4c, 0x4f, 0x69, 0x54, 0x4e, 0x72, 0x51, 0x33, 0x73, + 0x73, 0x71, 0x77, 0x47, 0x79, 0x5a, 0x36, 0x6d, 0x69, 0x55, 0x66, 0x6d, + 0x70, 0x71, 0x41, 0x6e, 0x6b, 0x73, 0x71, 0x0a, 0x50, 0x2f, 0x75, 0x6a, + 0x6d, 0x76, 0x35, 0x7a, 0x4d, 0x6e, 0x48, 0x43, 0x6e, 0x73, 0x5a, 0x79, + 0x34, 0x59, 0x70, 0x6f, 0x4a, 0x2f, 0x48, 0x6b, 0x44, 0x37, 0x54, 0x45, + 0x54, 0x4b, 0x56, 0x68, 0x6b, 0x2f, 0x69, 0x58, 0x45, 0x41, 0x63, 0x71, + 0x4d, 0x43, 0x57, 0x70, 0x75, 0x63, 0x68, 0x78, 0x75, 0x4f, 0x39, 0x6f, + 0x7a, 0x43, 0x31, 0x2b, 0x39, 0x65, 0x42, 0x2b, 0x44, 0x34, 0x4b, 0x6f, + 0x0a, 0x62, 0x37, 0x61, 0x36, 0x62, 0x49, 0x4e, 0x44, 0x64, 0x38, 0x32, + 0x4b, 0x6b, 0x68, 0x65, 0x68, 0x6e, 0x6c, 0x74, 0x34, 0x46, 0x6a, 0x31, + 0x46, 0x34, 0x6a, 0x4e, 0x79, 0x33, 0x65, 0x46, 0x6d, 0x79, 0x70, 0x6e, + 0x54, 0x79, 0x63, 0x55, 0x6d, 0x2f, 0x51, 0x31, 0x6f, 0x42, 0x45, 0x61, + 0x75, 0x74, 0x74, 0x6d, 0x62, 0x6a, 0x4c, 0x34, 0x5a, 0x76, 0x72, 0x48, + 0x47, 0x38, 0x68, 0x6e, 0x6a, 0x0a, 0x58, 0x41, 0x4c, 0x4b, 0x4c, 0x4e, + 0x68, 0x76, 0x53, 0x67, 0x66, 0x5a, 0x79, 0x54, 0x58, 0x61, 0x51, 0x48, + 0x58, 0x79, 0x78, 0x4b, 0x63, 0x5a, 0x62, 0x35, 0x35, 0x43, 0x45, 0x4a, + 0x68, 0x31, 0x35, 0x70, 0x57, 0x4c, 0x59, 0x4c, 0x7a, 0x74, 0x78, 0x52, + 0x4c, 0x58, 0x69, 0x73, 0x37, 0x56, 0x6d, 0x46, 0x78, 0x57, 0x6c, 0x67, + 0x50, 0x46, 0x37, 0x6e, 0x63, 0x47, 0x4e, 0x66, 0x2f, 0x50, 0x0a, 0x35, + 0x4f, 0x34, 0x2f, 0x45, 0x32, 0x48, 0x75, 0x32, 0x39, 0x6f, 0x74, 0x68, + 0x66, 0x44, 0x4e, 0x72, 0x70, 0x32, 0x79, 0x47, 0x41, 0x6c, 0x46, 0x77, + 0x35, 0x4b, 0x68, 0x63, 0x68, 0x66, 0x38, 0x52, 0x37, 0x61, 0x67, 0x43, + 0x79, 0x7a, 0x78, 0x78, 0x4e, 0x35, 0x44, 0x61, 0x41, 0x68, 0x71, 0x58, + 0x7a, 0x76, 0x77, 0x64, 0x6d, 0x50, 0x37, 0x7a, 0x41, 0x59, 0x73, 0x70, + 0x73, 0x62, 0x69, 0x0a, 0x44, 0x72, 0x57, 0x35, 0x76, 0x69, 0x53, 0x50, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, + 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, + 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x35, + 0x20, 0x4f, 0x3d, 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, + 0x41, 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, + 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x2e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, + 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, + 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x35, + 0x20, 0x4f, 0x3d, 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, + 0x41, 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, + 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x2e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, + 0x61, 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, + 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, + 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x35, 0x22, 0x0a, 0x23, 0x20, + 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x30, 0x0a, 0x23, 0x20, + 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x61, 0x3a, 0x66, 0x66, 0x3a, 0x65, + 0x32, 0x3a, 0x64, 0x62, 0x3a, 0x30, 0x33, 0x3a, 0x64, 0x39, 0x3a, 0x63, + 0x62, 0x3a, 0x34, 0x62, 0x3a, 0x65, 0x39, 0x3a, 0x30, 0x66, 0x3a, 0x61, + 0x64, 0x3a, 0x38, 0x34, 0x3a, 0x66, 0x64, 0x3a, 0x37, 0x62, 0x3a, 0x31, + 0x38, 0x3a, 0x63, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x30, 0x31, 0x3a, 0x30, 0x63, 0x3a, 0x30, 0x36, 0x3a, 0x39, 0x35, + 0x3a, 0x61, 0x36, 0x3a, 0x39, 0x38, 0x3a, 0x31, 0x39, 0x3a, 0x31, 0x34, + 0x3a, 0x66, 0x66, 0x3a, 0x62, 0x66, 0x3a, 0x35, 0x66, 0x3a, 0x63, 0x36, + 0x3a, 0x62, 0x30, 0x3a, 0x62, 0x36, 0x3a, 0x39, 0x35, 0x3a, 0x65, 0x61, + 0x3a, 0x32, 0x39, 0x3a, 0x65, 0x39, 0x3a, 0x31, 0x32, 0x3a, 0x61, 0x36, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, + 0x30, 0x3a, 0x34, 0x30, 0x3a, 0x39, 0x32, 0x3a, 0x39, 0x61, 0x3a, 0x30, + 0x32, 0x3a, 0x63, 0x65, 0x3a, 0x35, 0x33, 0x3a, 0x62, 0x34, 0x3a, 0x61, + 0x63, 0x3a, 0x66, 0x34, 0x3a, 0x66, 0x32, 0x3a, 0x66, 0x66, 0x3a, 0x63, + 0x36, 0x3a, 0x39, 0x38, 0x3a, 0x31, 0x63, 0x3a, 0x65, 0x34, 0x3a, 0x34, + 0x39, 0x3a, 0x36, 0x66, 0x3a, 0x37, 0x35, 0x3a, 0x35, 0x65, 0x3a, 0x36, + 0x64, 0x3a, 0x34, 0x35, 0x3a, 0x66, 0x65, 0x3a, 0x30, 0x62, 0x3a, 0x32, + 0x61, 0x3a, 0x36, 0x39, 0x3a, 0x32, 0x62, 0x3a, 0x63, 0x64, 0x3a, 0x35, + 0x32, 0x3a, 0x35, 0x32, 0x3a, 0x33, 0x66, 0x3a, 0x33, 0x36, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x47, 0x43, 0x7a, 0x43, 0x43, 0x41, + 0x2f, 0x4f, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, + 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, + 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x43, 0x42, 0x70, + 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x68, 0x4d, 0x43, 0x52, 0x31, 0x49, 0x78, 0x0a, 0x44, 0x7a, 0x41, 0x4e, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x42, 0x6b, 0x46, 0x30, + 0x61, 0x47, 0x56, 0x75, 0x63, 0x7a, 0x46, 0x45, 0x4d, 0x45, 0x49, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x37, 0x53, 0x47, 0x56, 0x73, + 0x62, 0x47, 0x56, 0x75, 0x61, 0x57, 0x4d, 0x67, 0x51, 0x57, 0x4e, 0x68, + 0x5a, 0x47, 0x56, 0x74, 0x61, 0x57, 0x4d, 0x67, 0x59, 0x57, 0x35, 0x6b, + 0x0a, 0x49, 0x46, 0x4a, 0x6c, 0x63, 0x32, 0x56, 0x68, 0x63, 0x6d, 0x4e, + 0x6f, 0x49, 0x45, 0x6c, 0x75, 0x63, 0x33, 0x52, 0x70, 0x64, 0x48, 0x56, + 0x30, 0x61, 0x57, 0x39, 0x75, 0x63, 0x79, 0x42, 0x44, 0x5a, 0x58, 0x4a, + 0x30, 0x4c, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, + 0x70, 0x64, 0x48, 0x6b, 0x78, 0x51, 0x44, 0x41, 0x2b, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x4d, 0x54, 0x0a, 0x4e, 0x30, 0x68, 0x6c, 0x62, 0x47, + 0x78, 0x6c, 0x62, 0x6d, 0x6c, 0x6a, 0x49, 0x45, 0x46, 0x6a, 0x59, 0x57, + 0x52, 0x6c, 0x62, 0x57, 0x6c, 0x6a, 0x49, 0x47, 0x46, 0x75, 0x5a, 0x43, + 0x42, 0x53, 0x5a, 0x58, 0x4e, 0x6c, 0x59, 0x58, 0x4a, 0x6a, 0x61, 0x43, + 0x42, 0x4a, 0x62, 0x6e, 0x4e, 0x30, 0x61, 0x58, 0x52, 0x31, 0x64, 0x47, + 0x6c, 0x76, 0x62, 0x6e, 0x4d, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x0a, 0x64, + 0x45, 0x4e, 0x42, 0x49, 0x44, 0x49, 0x77, 0x4d, 0x54, 0x55, 0x77, 0x48, + 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x55, 0x77, 0x4e, 0x7a, 0x41, 0x33, 0x4d, + 0x54, 0x41, 0x78, 0x4d, 0x54, 0x49, 0x78, 0x57, 0x68, 0x63, 0x4e, 0x4e, + 0x44, 0x41, 0x77, 0x4e, 0x6a, 0x4d, 0x77, 0x4d, 0x54, 0x41, 0x78, 0x4d, + 0x54, 0x49, 0x78, 0x57, 0x6a, 0x43, 0x42, 0x70, 0x6a, 0x45, 0x4c, 0x4d, + 0x41, 0x6b, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, + 0x52, 0x31, 0x49, 0x78, 0x44, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x63, 0x54, 0x42, 0x6b, 0x46, 0x30, 0x61, 0x47, 0x56, 0x75, + 0x63, 0x7a, 0x46, 0x45, 0x4d, 0x45, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x68, 0x4d, 0x37, 0x53, 0x47, 0x56, 0x73, 0x62, 0x47, 0x56, 0x75, + 0x61, 0x57, 0x4d, 0x67, 0x51, 0x57, 0x4e, 0x68, 0x0a, 0x5a, 0x47, 0x56, + 0x74, 0x61, 0x57, 0x4d, 0x67, 0x59, 0x57, 0x35, 0x6b, 0x49, 0x46, 0x4a, + 0x6c, 0x63, 0x32, 0x56, 0x68, 0x63, 0x6d, 0x4e, 0x6f, 0x49, 0x45, 0x6c, + 0x75, 0x63, 0x33, 0x52, 0x70, 0x64, 0x48, 0x56, 0x30, 0x61, 0x57, 0x39, + 0x75, 0x63, 0x79, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x4c, 0x69, 0x42, + 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, + 0x78, 0x0a, 0x51, 0x44, 0x41, 0x2b, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x4d, 0x54, 0x4e, 0x30, 0x68, 0x6c, 0x62, 0x47, 0x78, 0x6c, 0x62, 0x6d, + 0x6c, 0x6a, 0x49, 0x45, 0x46, 0x6a, 0x59, 0x57, 0x52, 0x6c, 0x62, 0x57, + 0x6c, 0x6a, 0x49, 0x47, 0x46, 0x75, 0x5a, 0x43, 0x42, 0x53, 0x5a, 0x58, + 0x4e, 0x6c, 0x59, 0x58, 0x4a, 0x6a, 0x61, 0x43, 0x42, 0x4a, 0x62, 0x6e, + 0x4e, 0x30, 0x61, 0x58, 0x52, 0x31, 0x0a, 0x64, 0x47, 0x6c, 0x76, 0x62, + 0x6e, 0x4d, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x45, 0x4e, 0x42, 0x49, + 0x44, 0x49, 0x77, 0x4d, 0x54, 0x55, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, + 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, + 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, + 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x0a, + 0x41, 0x51, 0x44, 0x43, 0x2b, 0x4b, 0x6b, 0x2f, 0x47, 0x34, 0x6e, 0x38, + 0x50, 0x44, 0x77, 0x45, 0x58, 0x54, 0x32, 0x51, 0x4e, 0x72, 0x43, 0x52, + 0x4f, 0x6e, 0x6b, 0x38, 0x5a, 0x6c, 0x72, 0x76, 0x62, 0x54, 0x6b, 0x42, + 0x53, 0x52, 0x71, 0x30, 0x74, 0x38, 0x39, 0x2f, 0x54, 0x53, 0x4e, 0x54, + 0x74, 0x35, 0x41, 0x41, 0x34, 0x78, 0x4d, 0x71, 0x4b, 0x4b, 0x59, 0x78, + 0x38, 0x5a, 0x45, 0x41, 0x0a, 0x34, 0x79, 0x6a, 0x73, 0x72, 0x69, 0x46, + 0x42, 0x7a, 0x68, 0x2f, 0x61, 0x2f, 0x58, 0x30, 0x53, 0x57, 0x77, 0x47, + 0x44, 0x44, 0x37, 0x6d, 0x77, 0x58, 0x35, 0x6e, 0x68, 0x38, 0x68, 0x4b, + 0x44, 0x67, 0x45, 0x30, 0x47, 0x50, 0x74, 0x2b, 0x73, 0x72, 0x2b, 0x65, + 0x68, 0x69, 0x47, 0x73, 0x78, 0x72, 0x2f, 0x43, 0x4c, 0x30, 0x42, 0x67, + 0x7a, 0x75, 0x4e, 0x74, 0x46, 0x61, 0x6a, 0x54, 0x30, 0x0a, 0x41, 0x6f, + 0x41, 0x6b, 0x4b, 0x41, 0x6f, 0x43, 0x46, 0x5a, 0x56, 0x65, 0x64, 0x69, + 0x6f, 0x4e, 0x6d, 0x54, 0x6f, 0x55, 0x57, 0x2f, 0x62, 0x4c, 0x79, 0x31, + 0x4f, 0x38, 0x45, 0x30, 0x30, 0x42, 0x69, 0x44, 0x65, 0x55, 0x4a, 0x52, + 0x74, 0x43, 0x76, 0x43, 0x4c, 0x59, 0x6a, 0x71, 0x4f, 0x57, 0x58, 0x6a, + 0x72, 0x5a, 0x4d, 0x74, 0x73, 0x2b, 0x36, 0x50, 0x41, 0x51, 0x5a, 0x65, + 0x31, 0x30, 0x0a, 0x34, 0x53, 0x2b, 0x6e, 0x66, 0x4b, 0x38, 0x6e, 0x4e, + 0x4c, 0x73, 0x70, 0x66, 0x5a, 0x75, 0x32, 0x7a, 0x77, 0x6e, 0x49, 0x35, + 0x64, 0x4d, 0x4b, 0x2f, 0x49, 0x68, 0x6c, 0x5a, 0x58, 0x51, 0x4b, 0x33, + 0x48, 0x4d, 0x63, 0x58, 0x4d, 0x31, 0x41, 0x73, 0x52, 0x7a, 0x55, 0x74, + 0x6f, 0x53, 0x4d, 0x54, 0x46, 0x44, 0x50, 0x61, 0x49, 0x36, 0x6f, 0x57, + 0x61, 0x37, 0x43, 0x4a, 0x30, 0x36, 0x43, 0x0a, 0x6f, 0x6a, 0x58, 0x64, + 0x46, 0x50, 0x51, 0x66, 0x2f, 0x37, 0x4a, 0x33, 0x31, 0x59, 0x63, 0x76, + 0x71, 0x6d, 0x35, 0x39, 0x4a, 0x43, 0x66, 0x6e, 0x78, 0x73, 0x73, 0x6d, + 0x35, 0x75, 0x58, 0x2b, 0x5a, 0x77, 0x64, 0x6a, 0x32, 0x45, 0x55, 0x4e, + 0x33, 0x54, 0x70, 0x5a, 0x5a, 0x54, 0x6c, 0x59, 0x65, 0x70, 0x4b, 0x5a, + 0x63, 0x6a, 0x32, 0x63, 0x68, 0x46, 0x36, 0x49, 0x49, 0x62, 0x6a, 0x56, + 0x0a, 0x39, 0x43, 0x7a, 0x38, 0x32, 0x58, 0x42, 0x53, 0x54, 0x33, 0x69, + 0x34, 0x76, 0x54, 0x77, 0x72, 0x69, 0x35, 0x57, 0x59, 0x39, 0x62, 0x50, + 0x52, 0x61, 0x4d, 0x38, 0x67, 0x46, 0x48, 0x35, 0x4d, 0x58, 0x46, 0x2f, + 0x6e, 0x69, 0x2b, 0x58, 0x31, 0x4e, 0x59, 0x45, 0x5a, 0x4e, 0x39, 0x63, + 0x52, 0x43, 0x4c, 0x64, 0x6d, 0x76, 0x74, 0x4e, 0x4b, 0x7a, 0x6f, 0x4e, + 0x58, 0x41, 0x44, 0x72, 0x44, 0x0a, 0x67, 0x66, 0x67, 0x58, 0x79, 0x35, + 0x49, 0x32, 0x58, 0x64, 0x47, 0x6a, 0x32, 0x48, 0x55, 0x62, 0x34, 0x59, + 0x73, 0x6e, 0x36, 0x6e, 0x70, 0x49, 0x51, 0x66, 0x31, 0x46, 0x47, 0x51, + 0x61, 0x74, 0x4a, 0x35, 0x6c, 0x4f, 0x77, 0x58, 0x42, 0x48, 0x33, 0x62, + 0x57, 0x66, 0x67, 0x56, 0x4d, 0x53, 0x35, 0x62, 0x47, 0x4d, 0x53, 0x46, + 0x30, 0x78, 0x51, 0x78, 0x66, 0x6a, 0x6a, 0x4d, 0x5a, 0x36, 0x0a, 0x59, + 0x35, 0x5a, 0x4c, 0x4b, 0x54, 0x42, 0x4f, 0x68, 0x45, 0x35, 0x69, 0x47, + 0x56, 0x34, 0x38, 0x7a, 0x70, 0x65, 0x51, 0x70, 0x58, 0x38, 0x42, 0x36, + 0x35, 0x33, 0x67, 0x2b, 0x49, 0x75, 0x4a, 0x33, 0x53, 0x57, 0x59, 0x50, + 0x5a, 0x4b, 0x32, 0x66, 0x75, 0x2f, 0x5a, 0x38, 0x56, 0x46, 0x52, 0x66, + 0x53, 0x30, 0x6d, 0x79, 0x47, 0x6c, 0x5a, 0x59, 0x65, 0x43, 0x73, 0x61, + 0x72, 0x67, 0x71, 0x0a, 0x4e, 0x68, 0x45, 0x45, 0x65, 0x6c, 0x43, 0x39, + 0x4d, 0x6f, 0x53, 0x2b, 0x4c, 0x39, 0x78, 0x79, 0x31, 0x64, 0x63, 0x64, + 0x46, 0x6b, 0x66, 0x6b, 0x52, 0x32, 0x59, 0x67, 0x50, 0x2f, 0x53, 0x57, + 0x78, 0x61, 0x2b, 0x4f, 0x41, 0x58, 0x71, 0x6c, 0x44, 0x33, 0x70, 0x6b, + 0x39, 0x51, 0x30, 0x59, 0x68, 0x39, 0x6d, 0x75, 0x69, 0x4e, 0x58, 0x36, + 0x68, 0x4d, 0x45, 0x36, 0x77, 0x47, 0x6b, 0x6f, 0x0a, 0x4c, 0x66, 0x49, + 0x4e, 0x61, 0x46, 0x47, 0x71, 0x34, 0x36, 0x56, 0x33, 0x78, 0x71, 0x53, + 0x51, 0x44, 0x71, 0x45, 0x33, 0x69, 0x7a, 0x45, 0x6a, 0x52, 0x38, 0x45, + 0x4a, 0x43, 0x4f, 0x74, 0x75, 0x39, 0x33, 0x69, 0x62, 0x31, 0x34, 0x4c, + 0x38, 0x68, 0x43, 0x43, 0x5a, 0x53, 0x52, 0x6d, 0x32, 0x45, 0x6b, 0x61, + 0x78, 0x2b, 0x30, 0x56, 0x56, 0x46, 0x71, 0x6d, 0x6a, 0x5a, 0x61, 0x79, + 0x63, 0x0a, 0x42, 0x77, 0x2f, 0x71, 0x61, 0x39, 0x77, 0x66, 0x4c, 0x67, + 0x5a, 0x79, 0x37, 0x49, 0x61, 0x49, 0x45, 0x75, 0x51, 0x74, 0x32, 0x31, + 0x38, 0x46, 0x4c, 0x2b, 0x54, 0x77, 0x41, 0x39, 0x4d, 0x6d, 0x4d, 0x2b, + 0x65, 0x41, 0x77, 0x73, 0x31, 0x43, 0x6f, 0x52, 0x63, 0x30, 0x43, 0x77, + 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, + 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x52, 0x4d, 0x42, 0x41, + 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, + 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, + 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x64, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x63, + 0x52, 0x56, 0x6e, 0x79, 0x4d, 0x6a, 0x4a, 0x76, 0x58, 0x56, 0x64, 0x0a, + 0x63, 0x74, 0x41, 0x34, 0x47, 0x47, 0x71, 0x64, 0x38, 0x33, 0x45, 0x6b, + 0x56, 0x41, 0x73, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, + 0x67, 0x67, 0x49, 0x42, 0x41, 0x48, 0x57, 0x37, 0x62, 0x56, 0x52, 0x4c, + 0x71, 0x68, 0x42, 0x59, 0x52, 0x6a, 0x54, 0x79, 0x59, 0x74, 0x63, 0x57, + 0x4e, 0x6c, 0x30, 0x49, 0x0a, 0x58, 0x74, 0x56, 0x73, 0x79, 0x49, 0x65, + 0x39, 0x74, 0x43, 0x35, 0x47, 0x38, 0x6a, 0x48, 0x34, 0x66, 0x4f, 0x70, + 0x43, 0x74, 0x5a, 0x4d, 0x57, 0x56, 0x64, 0x79, 0x68, 0x44, 0x42, 0x4b, + 0x67, 0x32, 0x6d, 0x46, 0x2b, 0x44, 0x31, 0x68, 0x59, 0x63, 0x32, 0x52, + 0x79, 0x78, 0x2b, 0x68, 0x46, 0x6a, 0x74, 0x79, 0x70, 0x38, 0x69, 0x59, + 0x2f, 0x78, 0x6e, 0x6d, 0x4d, 0x73, 0x56, 0x4d, 0x49, 0x0a, 0x4d, 0x34, + 0x47, 0x77, 0x56, 0x68, 0x4f, 0x2b, 0x35, 0x6c, 0x46, 0x63, 0x32, 0x4a, + 0x73, 0x4b, 0x54, 0x30, 0x75, 0x63, 0x56, 0x6c, 0x4d, 0x43, 0x36, 0x55, + 0x2f, 0x32, 0x44, 0x57, 0x44, 0x71, 0x54, 0x55, 0x4a, 0x56, 0x36, 0x48, + 0x77, 0x62, 0x49, 0x53, 0x48, 0x54, 0x47, 0x7a, 0x72, 0x4d, 0x64, 0x2f, + 0x4b, 0x34, 0x6b, 0x50, 0x46, 0x6f, 0x78, 0x2f, 0x6c, 0x61, 0x2f, 0x76, + 0x6f, 0x74, 0x0a, 0x39, 0x4c, 0x2f, 0x4a, 0x39, 0x55, 0x55, 0x62, 0x7a, + 0x6a, 0x67, 0x51, 0x4b, 0x6a, 0x65, 0x4b, 0x65, 0x61, 0x4f, 0x30, 0x34, + 0x77, 0x6c, 0x73, 0x68, 0x59, 0x61, 0x54, 0x2f, 0x34, 0x6d, 0x57, 0x4a, + 0x33, 0x69, 0x42, 0x6a, 0x32, 0x66, 0x6a, 0x52, 0x6e, 0x52, 0x55, 0x6a, + 0x74, 0x6b, 0x4e, 0x61, 0x65, 0x4a, 0x4b, 0x39, 0x45, 0x31, 0x30, 0x41, + 0x2f, 0x2b, 0x79, 0x64, 0x2b, 0x32, 0x56, 0x0a, 0x5a, 0x35, 0x66, 0x6b, + 0x73, 0x63, 0x57, 0x72, 0x76, 0x32, 0x6f, 0x6a, 0x36, 0x4e, 0x53, 0x55, + 0x34, 0x6b, 0x51, 0x6f, 0x59, 0x73, 0x52, 0x4c, 0x34, 0x76, 0x44, 0x59, + 0x34, 0x69, 0x6c, 0x72, 0x47, 0x6e, 0x42, 0x2b, 0x4a, 0x47, 0x47, 0x54, + 0x65, 0x30, 0x38, 0x44, 0x4d, 0x69, 0x55, 0x4e, 0x52, 0x53, 0x51, 0x72, + 0x6c, 0x72, 0x52, 0x47, 0x61, 0x72, 0x39, 0x4b, 0x43, 0x2f, 0x65, 0x61, + 0x0a, 0x6a, 0x38, 0x47, 0x73, 0x47, 0x73, 0x56, 0x6e, 0x38, 0x32, 0x38, + 0x30, 0x30, 0x76, 0x70, 0x7a, 0x59, 0x34, 0x7a, 0x76, 0x46, 0x72, 0x43, + 0x6f, 0x70, 0x45, 0x59, 0x71, 0x2b, 0x4f, 0x73, 0x53, 0x37, 0x48, 0x4b, + 0x30, 0x37, 0x2f, 0x67, 0x72, 0x66, 0x6f, 0x78, 0x53, 0x77, 0x49, 0x75, + 0x45, 0x56, 0x50, 0x6b, 0x76, 0x50, 0x75, 0x4e, 0x56, 0x71, 0x4e, 0x78, + 0x6d, 0x73, 0x64, 0x6e, 0x68, 0x0a, 0x58, 0x39, 0x69, 0x7a, 0x6a, 0x46, + 0x6b, 0x30, 0x57, 0x61, 0x53, 0x72, 0x54, 0x32, 0x79, 0x37, 0x48, 0x78, + 0x6a, 0x62, 0x64, 0x61, 0x76, 0x59, 0x79, 0x35, 0x4c, 0x4e, 0x6c, 0x44, + 0x68, 0x68, 0x44, 0x67, 0x63, 0x47, 0x48, 0x30, 0x74, 0x47, 0x45, 0x50, + 0x45, 0x56, 0x76, 0x6f, 0x32, 0x46, 0x58, 0x44, 0x74, 0x4b, 0x4b, 0x34, + 0x46, 0x35, 0x44, 0x37, 0x52, 0x70, 0x6e, 0x30, 0x6c, 0x51, 0x0a, 0x6c, + 0x30, 0x33, 0x33, 0x44, 0x6c, 0x5a, 0x64, 0x77, 0x4a, 0x56, 0x71, 0x77, + 0x6a, 0x62, 0x44, 0x47, 0x32, 0x6a, 0x4a, 0x39, 0x53, 0x72, 0x63, 0x52, + 0x35, 0x71, 0x2b, 0x73, 0x73, 0x37, 0x46, 0x4a, 0x65, 0x6a, 0x36, 0x41, + 0x37, 0x6e, 0x61, 0x2b, 0x52, 0x5a, 0x75, 0x6b, 0x59, 0x54, 0x31, 0x48, + 0x43, 0x6a, 0x49, 0x2f, 0x43, 0x62, 0x4d, 0x31, 0x78, 0x79, 0x51, 0x56, + 0x71, 0x64, 0x66, 0x0a, 0x62, 0x7a, 0x6f, 0x45, 0x76, 0x4d, 0x31, 0x34, + 0x69, 0x51, 0x75, 0x4f, 0x44, 0x79, 0x2b, 0x6a, 0x71, 0x6b, 0x2b, 0x69, + 0x47, 0x78, 0x49, 0x39, 0x46, 0x67, 0x68, 0x41, 0x44, 0x2f, 0x46, 0x47, + 0x54, 0x4e, 0x65, 0x71, 0x65, 0x77, 0x6a, 0x42, 0x43, 0x76, 0x56, 0x74, + 0x4a, 0x39, 0x34, 0x43, 0x6a, 0x38, 0x72, 0x44, 0x74, 0x53, 0x76, 0x4b, + 0x36, 0x65, 0x76, 0x49, 0x49, 0x56, 0x4d, 0x34, 0x0a, 0x70, 0x63, 0x77, + 0x37, 0x32, 0x48, 0x63, 0x33, 0x4d, 0x4b, 0x4a, 0x50, 0x32, 0x57, 0x2f, + 0x52, 0x38, 0x6b, 0x43, 0x74, 0x51, 0x58, 0x6f, 0x58, 0x78, 0x64, 0x5a, + 0x4b, 0x4e, 0x59, 0x6d, 0x33, 0x51, 0x64, 0x56, 0x38, 0x68, 0x6e, 0x39, + 0x56, 0x54, 0x59, 0x4e, 0x4b, 0x70, 0x58, 0x4d, 0x67, 0x77, 0x44, 0x71, + 0x76, 0x6b, 0x50, 0x47, 0x61, 0x4a, 0x49, 0x37, 0x5a, 0x6a, 0x6e, 0x48, + 0x4b, 0x0a, 0x65, 0x37, 0x69, 0x47, 0x32, 0x72, 0x4b, 0x50, 0x6d, 0x54, + 0x34, 0x64, 0x45, 0x77, 0x30, 0x53, 0x45, 0x65, 0x37, 0x55, 0x71, 0x2f, + 0x44, 0x70, 0x46, 0x58, 0x59, 0x43, 0x35, 0x4f, 0x44, 0x66, 0x71, 0x69, + 0x41, 0x65, 0x57, 0x32, 0x47, 0x46, 0x5a, 0x45, 0x43, 0x70, 0x6b, 0x4a, + 0x63, 0x4e, 0x72, 0x56, 0x50, 0x53, 0x57, 0x68, 0x32, 0x48, 0x61, 0x67, + 0x43, 0x58, 0x5a, 0x57, 0x4b, 0x30, 0x0a, 0x76, 0x6d, 0x39, 0x71, 0x70, + 0x2f, 0x55, 0x73, 0x51, 0x75, 0x30, 0x79, 0x72, 0x62, 0x59, 0x68, 0x6e, + 0x72, 0x36, 0x38, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x48, 0x65, 0x6c, 0x6c, + 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, + 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x35, 0x20, 0x4f, 0x3d, 0x48, 0x65, + 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, + 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65, 0x72, 0x74, 0x2e, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, + 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, + 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, + 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x45, 0x43, 0x43, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x35, 0x20, + 0x4f, 0x3d, 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, + 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, + 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65, + 0x72, 0x74, 0x2e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, + 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, + 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, + 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x45, 0x43, 0x43, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x35, 0x22, + 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x30, + 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x31, 0x3a, 0x65, + 0x35, 0x3a, 0x62, 0x34, 0x3a, 0x31, 0x37, 0x3a, 0x65, 0x62, 0x3a, 0x63, + 0x32, 0x3a, 0x66, 0x35, 0x3a, 0x65, 0x31, 0x3a, 0x34, 0x62, 0x3a, 0x30, + 0x64, 0x3a, 0x34, 0x31, 0x3a, 0x37, 0x62, 0x3a, 0x34, 0x39, 0x3a, 0x39, + 0x32, 0x3a, 0x66, 0x65, 0x3a, 0x65, 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x66, 0x3a, 0x66, 0x31, 0x3a, 0x37, 0x31, + 0x3a, 0x38, 0x64, 0x3a, 0x39, 0x32, 0x3a, 0x64, 0x35, 0x3a, 0x39, 0x61, + 0x3a, 0x66, 0x33, 0x3a, 0x37, 0x64, 0x3a, 0x37, 0x34, 0x3a, 0x39, 0x37, + 0x3a, 0x62, 0x34, 0x3a, 0x62, 0x63, 0x3a, 0x36, 0x66, 0x3a, 0x38, 0x34, + 0x3a, 0x36, 0x38, 0x3a, 0x30, 0x62, 0x3a, 0x62, 0x61, 0x3a, 0x62, 0x36, + 0x3a, 0x36, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x34, 0x34, 0x3a, 0x62, 0x35, 0x3a, 0x34, 0x35, 0x3a, 0x61, + 0x61, 0x3a, 0x38, 0x61, 0x3a, 0x32, 0x35, 0x3a, 0x65, 0x36, 0x3a, 0x35, + 0x61, 0x3a, 0x37, 0x33, 0x3a, 0x63, 0x61, 0x3a, 0x31, 0x35, 0x3a, 0x64, + 0x63, 0x3a, 0x32, 0x37, 0x3a, 0x66, 0x63, 0x3a, 0x33, 0x36, 0x3a, 0x64, + 0x32, 0x3a, 0x34, 0x63, 0x3a, 0x31, 0x63, 0x3a, 0x62, 0x39, 0x3a, 0x39, + 0x35, 0x3a, 0x33, 0x61, 0x3a, 0x30, 0x36, 0x3a, 0x36, 0x35, 0x3a, 0x33, + 0x39, 0x3a, 0x62, 0x31, 0x3a, 0x31, 0x35, 0x3a, 0x38, 0x32, 0x3a, 0x64, + 0x63, 0x3a, 0x34, 0x38, 0x3a, 0x37, 0x62, 0x3a, 0x34, 0x38, 0x3a, 0x33, + 0x33, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x77, 0x7a, + 0x43, 0x43, 0x41, 0x6b, 0x71, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, + 0x49, 0x42, 0x41, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, + 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x6a, 0x43, 0x42, 0x71, 0x6a, + 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, + 0x4d, 0x43, 0x52, 0x31, 0x49, 0x78, 0x44, 0x7a, 0x41, 0x4e, 0x0a, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, 0x42, 0x6b, 0x46, 0x30, 0x61, + 0x47, 0x56, 0x75, 0x63, 0x7a, 0x46, 0x45, 0x4d, 0x45, 0x49, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x37, 0x53, 0x47, 0x56, 0x73, 0x62, + 0x47, 0x56, 0x75, 0x61, 0x57, 0x4d, 0x67, 0x51, 0x57, 0x4e, 0x68, 0x5a, + 0x47, 0x56, 0x74, 0x61, 0x57, 0x4d, 0x67, 0x59, 0x57, 0x35, 0x6b, 0x49, + 0x46, 0x4a, 0x6c, 0x0a, 0x63, 0x32, 0x56, 0x68, 0x63, 0x6d, 0x4e, 0x6f, + 0x49, 0x45, 0x6c, 0x75, 0x63, 0x33, 0x52, 0x70, 0x64, 0x48, 0x56, 0x30, + 0x61, 0x57, 0x39, 0x75, 0x63, 0x79, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, + 0x4c, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, + 0x64, 0x48, 0x6b, 0x78, 0x52, 0x44, 0x42, 0x43, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x4d, 0x54, 0x4f, 0x30, 0x68, 0x6c, 0x0a, 0x62, 0x47, 0x78, + 0x6c, 0x62, 0x6d, 0x6c, 0x6a, 0x49, 0x45, 0x46, 0x6a, 0x59, 0x57, 0x52, + 0x6c, 0x62, 0x57, 0x6c, 0x6a, 0x49, 0x47, 0x46, 0x75, 0x5a, 0x43, 0x42, + 0x53, 0x5a, 0x58, 0x4e, 0x6c, 0x59, 0x58, 0x4a, 0x6a, 0x61, 0x43, 0x42, + 0x4a, 0x62, 0x6e, 0x4e, 0x30, 0x61, 0x58, 0x52, 0x31, 0x64, 0x47, 0x6c, + 0x76, 0x62, 0x6e, 0x4d, 0x67, 0x52, 0x55, 0x4e, 0x44, 0x49, 0x46, 0x4a, + 0x76, 0x0a, 0x62, 0x33, 0x52, 0x44, 0x51, 0x53, 0x41, 0x79, 0x4d, 0x44, + 0x45, 0x31, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x31, 0x4d, 0x44, + 0x63, 0x77, 0x4e, 0x7a, 0x45, 0x77, 0x4d, 0x7a, 0x63, 0x78, 0x4d, 0x6c, + 0x6f, 0x58, 0x44, 0x54, 0x51, 0x77, 0x4d, 0x44, 0x59, 0x7a, 0x4d, 0x44, + 0x45, 0x77, 0x4d, 0x7a, 0x63, 0x78, 0x4d, 0x6c, 0x6f, 0x77, 0x67, 0x61, + 0x6f, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x59, 0x54, 0x41, 0x6b, 0x64, 0x53, 0x4d, 0x51, 0x38, 0x77, 0x44, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x45, 0x77, 0x5a, 0x42, 0x64, + 0x47, 0x68, 0x6c, 0x62, 0x6e, 0x4d, 0x78, 0x52, 0x44, 0x42, 0x43, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x4f, 0x30, 0x68, 0x6c, 0x62, + 0x47, 0x78, 0x6c, 0x62, 0x6d, 0x6c, 0x6a, 0x49, 0x45, 0x46, 0x6a, 0x0a, + 0x59, 0x57, 0x52, 0x6c, 0x62, 0x57, 0x6c, 0x6a, 0x49, 0x47, 0x46, 0x75, + 0x5a, 0x43, 0x42, 0x53, 0x5a, 0x58, 0x4e, 0x6c, 0x59, 0x58, 0x4a, 0x6a, + 0x61, 0x43, 0x42, 0x4a, 0x62, 0x6e, 0x4e, 0x30, 0x61, 0x58, 0x52, 0x31, + 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6e, 0x4d, 0x67, 0x51, 0x32, 0x56, 0x79, + 0x64, 0x43, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, + 0x61, 0x58, 0x52, 0x35, 0x0a, 0x4d, 0x55, 0x51, 0x77, 0x51, 0x67, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x7a, 0x74, 0x49, 0x5a, 0x57, 0x78, + 0x73, 0x5a, 0x57, 0x35, 0x70, 0x59, 0x79, 0x42, 0x42, 0x59, 0x32, 0x46, + 0x6b, 0x5a, 0x57, 0x31, 0x70, 0x59, 0x79, 0x42, 0x68, 0x62, 0x6d, 0x51, + 0x67, 0x55, 0x6d, 0x56, 0x7a, 0x5a, 0x57, 0x46, 0x79, 0x59, 0x32, 0x67, + 0x67, 0x53, 0x57, 0x35, 0x7a, 0x64, 0x47, 0x6c, 0x30, 0x0a, 0x64, 0x58, + 0x52, 0x70, 0x62, 0x32, 0x35, 0x7a, 0x49, 0x45, 0x56, 0x44, 0x51, 0x79, + 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x51, 0x30, 0x45, 0x67, 0x4d, 0x6a, + 0x41, 0x78, 0x4e, 0x54, 0x42, 0x32, 0x4d, 0x42, 0x41, 0x47, 0x42, 0x79, + 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x42, 0x53, + 0x75, 0x42, 0x42, 0x41, 0x41, 0x69, 0x41, 0x32, 0x49, 0x41, 0x42, 0x4a, + 0x4b, 0x67, 0x0a, 0x51, 0x65, 0x68, 0x4c, 0x67, 0x6f, 0x52, 0x63, 0x34, + 0x76, 0x67, 0x78, 0x45, 0x5a, 0x6d, 0x47, 0x5a, 0x45, 0x34, 0x4a, 0x4a, + 0x53, 0x2b, 0x64, 0x51, 0x53, 0x38, 0x4b, 0x72, 0x6a, 0x56, 0x50, 0x64, + 0x4a, 0x57, 0x79, 0x55, 0x57, 0x52, 0x72, 0x6a, 0x57, 0x76, 0x6d, 0x50, + 0x33, 0x43, 0x56, 0x38, 0x41, 0x56, 0x45, 0x52, 0x36, 0x5a, 0x79, 0x4f, + 0x46, 0x42, 0x32, 0x6c, 0x51, 0x4a, 0x61, 0x0a, 0x6a, 0x71, 0x34, 0x6f, + 0x6e, 0x76, 0x6b, 0x74, 0x54, 0x70, 0x6e, 0x76, 0x4c, 0x45, 0x68, 0x76, + 0x54, 0x43, 0x55, 0x70, 0x36, 0x4e, 0x46, 0x78, 0x57, 0x39, 0x38, 0x64, + 0x77, 0x58, 0x55, 0x33, 0x74, 0x4e, 0x66, 0x36, 0x65, 0x33, 0x70, 0x43, + 0x6e, 0x47, 0x6f, 0x4b, 0x56, 0x6c, 0x70, 0x38, 0x61, 0x51, 0x75, 0x71, + 0x67, 0x41, 0x6b, 0x6b, 0x62, 0x48, 0x37, 0x42, 0x52, 0x71, 0x4e, 0x43, + 0x0a, 0x4d, 0x45, 0x41, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, + 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, + 0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, + 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, + 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, + 0x45, 0x46, 0x4c, 0x51, 0x69, 0x0a, 0x43, 0x34, 0x4b, 0x5a, 0x4a, 0x41, + 0x45, 0x4f, 0x6e, 0x4c, 0x76, 0x6b, 0x44, 0x76, 0x32, 0x2f, 0x2b, 0x35, + 0x63, 0x67, 0x6b, 0x35, 0x6b, 0x71, 0x4d, 0x41, 0x6f, 0x47, 0x43, 0x43, + 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x32, + 0x63, 0x41, 0x4d, 0x47, 0x51, 0x43, 0x4d, 0x47, 0x66, 0x4f, 0x46, 0x6d, + 0x49, 0x34, 0x6f, 0x71, 0x78, 0x69, 0x52, 0x61, 0x65, 0x70, 0x0a, 0x6c, + 0x53, 0x54, 0x41, 0x47, 0x69, 0x65, 0x63, 0x4d, 0x6a, 0x76, 0x41, 0x77, + 0x4e, 0x57, 0x36, 0x71, 0x65, 0x66, 0x34, 0x42, 0x45, 0x4e, 0x54, 0x68, + 0x65, 0x35, 0x53, 0x49, 0x64, 0x36, 0x64, 0x39, 0x53, 0x57, 0x44, 0x50, + 0x70, 0x35, 0x59, 0x53, 0x79, 0x2f, 0x58, 0x5a, 0x78, 0x4d, 0x4f, 0x49, + 0x51, 0x49, 0x77, 0x42, 0x65, 0x46, 0x31, 0x41, 0x64, 0x35, 0x6f, 0x37, + 0x53, 0x6f, 0x66, 0x0a, 0x54, 0x55, 0x77, 0x4a, 0x43, 0x41, 0x33, 0x73, + 0x53, 0x36, 0x31, 0x6b, 0x46, 0x79, 0x6a, 0x6e, 0x64, 0x63, 0x35, 0x46, + 0x5a, 0x58, 0x49, 0x68, 0x46, 0x38, 0x73, 0x69, 0x51, 0x51, 0x36, 0x4d, + 0x45, 0x35, 0x67, 0x34, 0x6d, 0x6c, 0x52, 0x74, 0x6d, 0x38, 0x72, 0x69, + 0x66, 0x4f, 0x6f, 0x43, 0x57, 0x43, 0x4b, 0x52, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, + 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x49, 0x53, 0x52, 0x47, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x58, + 0x31, 0x20, 0x4f, 0x3d, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, + 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x52, 0x65, + 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x49, 0x53, 0x52, 0x47, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x58, 0x31, 0x20, 0x4f, 0x3d, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x65, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, + 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x49, 0x53, 0x52, 0x47, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x58, + 0x31, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x31, 0x37, 0x32, 0x38, 0x38, 0x36, 0x39, 0x32, 0x38, 0x36, 0x36, + 0x39, 0x37, 0x39, 0x30, 0x34, 0x37, 0x36, 0x30, 0x36, 0x34, 0x36, 0x37, + 0x30, 0x32, 0x34, 0x33, 0x35, 0x30, 0x34, 0x31, 0x36, 0x39, 0x30, 0x36, + 0x31, 0x31, 0x32, 0x30, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x30, 0x63, 0x3a, 0x64, 0x32, 0x3a, 0x66, 0x39, 0x3a, 0x65, 0x30, 0x3a, + 0x64, 0x61, 0x3a, 0x31, 0x37, 0x3a, 0x37, 0x33, 0x3a, 0x65, 0x39, 0x3a, + 0x65, 0x64, 0x3a, 0x38, 0x36, 0x3a, 0x34, 0x64, 0x3a, 0x61, 0x35, 0x3a, + 0x65, 0x33, 0x3a, 0x37, 0x30, 0x3a, 0x65, 0x37, 0x3a, 0x34, 0x65, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x61, 0x3a, 0x62, + 0x64, 0x3a, 0x32, 0x61, 0x3a, 0x37, 0x39, 0x3a, 0x61, 0x31, 0x3a, 0x30, + 0x37, 0x3a, 0x36, 0x61, 0x3a, 0x33, 0x31, 0x3a, 0x66, 0x32, 0x3a, 0x31, + 0x64, 0x3a, 0x32, 0x35, 0x3a, 0x33, 0x36, 0x3a, 0x33, 0x35, 0x3a, 0x63, + 0x62, 0x3a, 0x30, 0x33, 0x3a, 0x39, 0x64, 0x3a, 0x34, 0x33, 0x3a, 0x32, + 0x39, 0x3a, 0x61, 0x35, 0x3a, 0x65, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x36, 0x3a, 0x62, 0x63, 0x3a, + 0x65, 0x63, 0x3a, 0x30, 0x36, 0x3a, 0x32, 0x36, 0x3a, 0x34, 0x39, 0x3a, + 0x37, 0x36, 0x3a, 0x66, 0x33, 0x3a, 0x37, 0x34, 0x3a, 0x36, 0x30, 0x3a, + 0x37, 0x37, 0x3a, 0x39, 0x61, 0x3a, 0x63, 0x66, 0x3a, 0x32, 0x38, 0x3a, + 0x63, 0x35, 0x3a, 0x61, 0x37, 0x3a, 0x63, 0x66, 0x3a, 0x65, 0x38, 0x3a, + 0x61, 0x33, 0x3a, 0x63, 0x30, 0x3a, 0x61, 0x61, 0x3a, 0x65, 0x31, 0x3a, + 0x31, 0x61, 0x3a, 0x38, 0x66, 0x3a, 0x66, 0x63, 0x3a, 0x65, 0x65, 0x3a, + 0x30, 0x35, 0x3a, 0x63, 0x30, 0x3a, 0x62, 0x64, 0x3a, 0x64, 0x66, 0x3a, + 0x30, 0x38, 0x3a, 0x63, 0x36, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, + 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, + 0x49, 0x46, 0x61, 0x7a, 0x43, 0x43, 0x41, 0x31, 0x4f, 0x67, 0x41, 0x77, + 0x49, 0x42, 0x41, 0x67, 0x49, 0x52, 0x41, 0x49, 0x49, 0x51, 0x7a, 0x37, + 0x44, 0x53, 0x51, 0x4f, 0x4e, 0x5a, 0x52, 0x47, 0x50, 0x67, 0x75, 0x32, + 0x4f, 0x43, 0x69, 0x77, 0x41, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, + 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, + 0x41, 0x77, 0x0a, 0x54, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x4b, + 0x54, 0x41, 0x6e, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x49, + 0x45, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x79, 0x62, 0x6d, 0x56, 0x30, 0x49, + 0x46, 0x4e, 0x6c, 0x59, 0x33, 0x56, 0x79, 0x61, 0x58, 0x52, 0x35, 0x49, + 0x46, 0x4a, 0x6c, 0x63, 0x32, 0x56, 0x68, 0x0a, 0x63, 0x6d, 0x4e, 0x6f, + 0x49, 0x45, 0x64, 0x79, 0x62, 0x33, 0x56, 0x77, 0x4d, 0x52, 0x55, 0x77, + 0x45, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x77, 0x78, 0x4a, + 0x55, 0x31, 0x4a, 0x48, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, + 0x57, 0x44, 0x45, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x55, 0x77, + 0x4e, 0x6a, 0x41, 0x30, 0x4d, 0x54, 0x45, 0x77, 0x4e, 0x44, 0x4d, 0x34, + 0x0a, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x55, 0x77, 0x4e, 0x6a, 0x41, + 0x30, 0x4d, 0x54, 0x45, 0x77, 0x4e, 0x44, 0x4d, 0x34, 0x57, 0x6a, 0x42, + 0x50, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x70, 0x4d, 0x43, 0x63, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x67, 0x53, 0x57, 0x35, + 0x30, 0x5a, 0x58, 0x4a, 0x75, 0x0a, 0x5a, 0x58, 0x51, 0x67, 0x55, 0x32, + 0x56, 0x6a, 0x64, 0x58, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x55, 0x6d, + 0x56, 0x7a, 0x5a, 0x57, 0x46, 0x79, 0x59, 0x32, 0x67, 0x67, 0x52, 0x33, + 0x4a, 0x76, 0x64, 0x58, 0x41, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x44, 0x45, 0x6c, 0x54, 0x55, 0x6b, + 0x63, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x59, 0x0a, 0x4d, + 0x54, 0x43, 0x43, 0x41, 0x69, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, + 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, + 0x67, 0x6f, 0x43, 0x67, 0x67, 0x49, 0x42, 0x41, 0x4b, 0x33, 0x6f, 0x4a, + 0x48, 0x50, 0x30, 0x46, 0x44, 0x66, 0x7a, 0x6d, 0x35, 0x34, 0x72, 0x56, + 0x79, 0x67, 0x63, 0x0a, 0x68, 0x37, 0x37, 0x63, 0x74, 0x39, 0x38, 0x34, + 0x6b, 0x49, 0x78, 0x75, 0x50, 0x4f, 0x5a, 0x58, 0x6f, 0x48, 0x6a, 0x33, + 0x64, 0x63, 0x4b, 0x69, 0x2f, 0x76, 0x56, 0x71, 0x62, 0x76, 0x59, 0x41, + 0x54, 0x79, 0x6a, 0x62, 0x33, 0x6d, 0x69, 0x47, 0x62, 0x45, 0x53, 0x54, + 0x74, 0x72, 0x46, 0x6a, 0x2f, 0x52, 0x51, 0x53, 0x61, 0x37, 0x38, 0x66, + 0x30, 0x75, 0x6f, 0x78, 0x6d, 0x79, 0x46, 0x2b, 0x0a, 0x30, 0x54, 0x4d, + 0x38, 0x75, 0x6b, 0x6a, 0x31, 0x33, 0x58, 0x6e, 0x66, 0x73, 0x37, 0x6a, + 0x2f, 0x45, 0x76, 0x45, 0x68, 0x6d, 0x6b, 0x76, 0x42, 0x69, 0x6f, 0x5a, + 0x78, 0x61, 0x55, 0x70, 0x6d, 0x5a, 0x6d, 0x79, 0x50, 0x66, 0x6a, 0x78, + 0x77, 0x76, 0x36, 0x30, 0x70, 0x49, 0x67, 0x62, 0x7a, 0x35, 0x4d, 0x44, + 0x6d, 0x67, 0x4b, 0x37, 0x69, 0x53, 0x34, 0x2b, 0x33, 0x6d, 0x58, 0x36, + 0x55, 0x0a, 0x41, 0x35, 0x2f, 0x54, 0x52, 0x35, 0x64, 0x38, 0x6d, 0x55, + 0x67, 0x6a, 0x55, 0x2b, 0x67, 0x34, 0x72, 0x6b, 0x38, 0x4b, 0x62, 0x34, + 0x4d, 0x75, 0x30, 0x55, 0x6c, 0x58, 0x6a, 0x49, 0x42, 0x30, 0x74, 0x74, + 0x6f, 0x76, 0x30, 0x44, 0x69, 0x4e, 0x65, 0x77, 0x4e, 0x77, 0x49, 0x52, + 0x74, 0x31, 0x38, 0x6a, 0x41, 0x38, 0x2b, 0x6f, 0x2b, 0x75, 0x33, 0x64, + 0x70, 0x6a, 0x71, 0x2b, 0x73, 0x57, 0x0a, 0x54, 0x38, 0x4b, 0x4f, 0x45, + 0x55, 0x74, 0x2b, 0x7a, 0x77, 0x76, 0x6f, 0x2f, 0x37, 0x56, 0x33, 0x4c, + 0x76, 0x53, 0x79, 0x65, 0x30, 0x72, 0x67, 0x54, 0x42, 0x49, 0x6c, 0x44, + 0x48, 0x43, 0x4e, 0x41, 0x79, 0x6d, 0x67, 0x34, 0x56, 0x4d, 0x6b, 0x37, + 0x42, 0x50, 0x5a, 0x37, 0x68, 0x6d, 0x2f, 0x45, 0x4c, 0x4e, 0x4b, 0x6a, + 0x44, 0x2b, 0x4a, 0x6f, 0x32, 0x46, 0x52, 0x33, 0x71, 0x79, 0x48, 0x0a, + 0x42, 0x35, 0x54, 0x30, 0x59, 0x33, 0x48, 0x73, 0x4c, 0x75, 0x4a, 0x76, + 0x57, 0x35, 0x69, 0x42, 0x34, 0x59, 0x6c, 0x63, 0x4e, 0x48, 0x6c, 0x73, + 0x64, 0x75, 0x38, 0x37, 0x6b, 0x47, 0x4a, 0x35, 0x35, 0x74, 0x75, 0x6b, + 0x6d, 0x69, 0x38, 0x6d, 0x78, 0x64, 0x41, 0x51, 0x34, 0x51, 0x37, 0x65, + 0x32, 0x52, 0x43, 0x4f, 0x46, 0x76, 0x75, 0x33, 0x39, 0x36, 0x6a, 0x33, + 0x78, 0x2b, 0x55, 0x43, 0x0a, 0x42, 0x35, 0x69, 0x50, 0x4e, 0x67, 0x69, + 0x56, 0x35, 0x2b, 0x49, 0x33, 0x6c, 0x67, 0x30, 0x32, 0x64, 0x5a, 0x37, + 0x37, 0x44, 0x6e, 0x4b, 0x78, 0x48, 0x5a, 0x75, 0x38, 0x41, 0x2f, 0x6c, + 0x4a, 0x42, 0x64, 0x69, 0x42, 0x33, 0x51, 0x57, 0x30, 0x4b, 0x74, 0x5a, + 0x42, 0x36, 0x61, 0x77, 0x42, 0x64, 0x70, 0x55, 0x4b, 0x44, 0x39, 0x6a, + 0x66, 0x31, 0x62, 0x30, 0x53, 0x48, 0x7a, 0x55, 0x76, 0x0a, 0x4b, 0x42, + 0x64, 0x73, 0x30, 0x70, 0x6a, 0x42, 0x71, 0x41, 0x6c, 0x6b, 0x64, 0x32, + 0x35, 0x48, 0x4e, 0x37, 0x72, 0x4f, 0x72, 0x46, 0x6c, 0x65, 0x61, 0x4a, + 0x31, 0x2f, 0x63, 0x74, 0x61, 0x4a, 0x78, 0x51, 0x5a, 0x42, 0x4b, 0x54, + 0x35, 0x5a, 0x50, 0x74, 0x30, 0x6d, 0x39, 0x53, 0x54, 0x4a, 0x45, 0x61, + 0x64, 0x61, 0x6f, 0x30, 0x78, 0x41, 0x48, 0x30, 0x61, 0x68, 0x6d, 0x62, + 0x57, 0x6e, 0x0a, 0x4f, 0x6c, 0x46, 0x75, 0x68, 0x6a, 0x75, 0x65, 0x66, + 0x58, 0x4b, 0x6e, 0x45, 0x67, 0x56, 0x34, 0x57, 0x65, 0x30, 0x2b, 0x55, + 0x58, 0x67, 0x56, 0x43, 0x77, 0x4f, 0x50, 0x6a, 0x64, 0x41, 0x76, 0x42, + 0x62, 0x49, 0x2b, 0x65, 0x30, 0x6f, 0x63, 0x53, 0x33, 0x4d, 0x46, 0x45, + 0x76, 0x7a, 0x47, 0x36, 0x75, 0x42, 0x51, 0x45, 0x33, 0x78, 0x44, 0x6b, + 0x33, 0x53, 0x7a, 0x79, 0x6e, 0x54, 0x6e, 0x0a, 0x6a, 0x68, 0x38, 0x42, + 0x43, 0x4e, 0x41, 0x77, 0x31, 0x46, 0x74, 0x78, 0x4e, 0x72, 0x51, 0x48, + 0x75, 0x73, 0x45, 0x77, 0x4d, 0x46, 0x78, 0x49, 0x74, 0x34, 0x49, 0x37, + 0x6d, 0x4b, 0x5a, 0x39, 0x59, 0x49, 0x71, 0x69, 0x6f, 0x79, 0x6d, 0x43, + 0x7a, 0x4c, 0x71, 0x39, 0x67, 0x77, 0x51, 0x62, 0x6f, 0x6f, 0x4d, 0x44, + 0x51, 0x61, 0x48, 0x57, 0x42, 0x66, 0x45, 0x62, 0x77, 0x72, 0x62, 0x77, + 0x0a, 0x71, 0x48, 0x79, 0x47, 0x4f, 0x30, 0x61, 0x6f, 0x53, 0x43, 0x71, + 0x49, 0x33, 0x48, 0x61, 0x61, 0x64, 0x72, 0x38, 0x66, 0x61, 0x71, 0x55, + 0x39, 0x47, 0x59, 0x2f, 0x72, 0x4f, 0x50, 0x4e, 0x6b, 0x33, 0x73, 0x67, + 0x72, 0x44, 0x51, 0x6f, 0x6f, 0x2f, 0x2f, 0x66, 0x62, 0x34, 0x68, 0x56, + 0x43, 0x31, 0x43, 0x4c, 0x51, 0x4a, 0x31, 0x33, 0x68, 0x65, 0x66, 0x34, + 0x59, 0x35, 0x33, 0x43, 0x49, 0x0a, 0x72, 0x55, 0x37, 0x6d, 0x32, 0x59, + 0x73, 0x36, 0x78, 0x74, 0x30, 0x6e, 0x55, 0x57, 0x37, 0x2f, 0x76, 0x47, + 0x54, 0x31, 0x4d, 0x30, 0x4e, 0x50, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, + 0x47, 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, + 0x49, 0x42, 0x42, 0x6a, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, + 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, + 0x51, 0x48, 0x2f, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, + 0x67, 0x51, 0x57, 0x42, 0x42, 0x52, 0x35, 0x74, 0x46, 0x6e, 0x6d, 0x65, + 0x37, 0x62, 0x6c, 0x35, 0x41, 0x46, 0x7a, 0x67, 0x41, 0x69, 0x49, 0x79, + 0x42, 0x70, 0x59, 0x39, 0x75, 0x6d, 0x62, 0x62, 0x6a, 0x41, 0x4e, 0x42, + 0x67, 0x6b, 0x71, 0x0a, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x73, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, + 0x56, 0x52, 0x39, 0x59, 0x71, 0x62, 0x79, 0x79, 0x71, 0x46, 0x44, 0x51, + 0x44, 0x4c, 0x48, 0x59, 0x47, 0x6d, 0x6b, 0x67, 0x4a, 0x79, 0x6b, 0x49, + 0x72, 0x47, 0x46, 0x31, 0x58, 0x49, 0x70, 0x75, 0x2b, 0x49, 0x4c, 0x6c, + 0x61, 0x53, 0x2f, 0x56, 0x39, 0x6c, 0x5a, 0x4c, 0x0a, 0x75, 0x62, 0x68, + 0x7a, 0x45, 0x46, 0x6e, 0x54, 0x49, 0x5a, 0x64, 0x2b, 0x35, 0x30, 0x78, + 0x78, 0x2b, 0x37, 0x4c, 0x53, 0x59, 0x4b, 0x30, 0x35, 0x71, 0x41, 0x76, + 0x71, 0x46, 0x79, 0x46, 0x57, 0x68, 0x66, 0x46, 0x51, 0x44, 0x6c, 0x6e, + 0x72, 0x7a, 0x75, 0x42, 0x5a, 0x36, 0x62, 0x72, 0x4a, 0x46, 0x65, 0x2b, + 0x47, 0x6e, 0x59, 0x2b, 0x45, 0x67, 0x50, 0x62, 0x6b, 0x36, 0x5a, 0x47, + 0x51, 0x0a, 0x33, 0x42, 0x65, 0x62, 0x59, 0x68, 0x74, 0x46, 0x38, 0x47, + 0x61, 0x56, 0x30, 0x6e, 0x78, 0x76, 0x77, 0x75, 0x6f, 0x37, 0x37, 0x78, + 0x2f, 0x50, 0x79, 0x39, 0x61, 0x75, 0x4a, 0x2f, 0x47, 0x70, 0x73, 0x4d, + 0x69, 0x75, 0x2f, 0x58, 0x31, 0x2b, 0x6d, 0x76, 0x6f, 0x69, 0x42, 0x4f, + 0x76, 0x2f, 0x32, 0x58, 0x2f, 0x71, 0x6b, 0x53, 0x73, 0x69, 0x73, 0x52, + 0x63, 0x4f, 0x6a, 0x2f, 0x4b, 0x4b, 0x0a, 0x4e, 0x46, 0x74, 0x59, 0x32, + 0x50, 0x77, 0x42, 0x79, 0x56, 0x53, 0x35, 0x75, 0x43, 0x62, 0x4d, 0x69, + 0x6f, 0x67, 0x7a, 0x69, 0x55, 0x77, 0x74, 0x68, 0x44, 0x79, 0x43, 0x33, + 0x2b, 0x36, 0x57, 0x56, 0x77, 0x57, 0x36, 0x4c, 0x4c, 0x76, 0x33, 0x78, + 0x4c, 0x66, 0x48, 0x54, 0x6a, 0x75, 0x43, 0x76, 0x6a, 0x48, 0x49, 0x49, + 0x6e, 0x4e, 0x7a, 0x6b, 0x74, 0x48, 0x43, 0x67, 0x4b, 0x51, 0x35, 0x0a, + 0x4f, 0x52, 0x41, 0x7a, 0x49, 0x34, 0x4a, 0x4d, 0x50, 0x4a, 0x2b, 0x47, + 0x73, 0x6c, 0x57, 0x59, 0x48, 0x62, 0x34, 0x70, 0x68, 0x6f, 0x77, 0x69, + 0x6d, 0x35, 0x37, 0x69, 0x61, 0x7a, 0x74, 0x58, 0x4f, 0x6f, 0x4a, 0x77, + 0x54, 0x64, 0x77, 0x4a, 0x78, 0x34, 0x6e, 0x4c, 0x43, 0x67, 0x64, 0x4e, + 0x62, 0x4f, 0x68, 0x64, 0x6a, 0x73, 0x6e, 0x76, 0x7a, 0x71, 0x76, 0x48, + 0x75, 0x37, 0x55, 0x72, 0x0a, 0x54, 0x6b, 0x58, 0x57, 0x53, 0x74, 0x41, + 0x6d, 0x7a, 0x4f, 0x56, 0x79, 0x79, 0x67, 0x68, 0x71, 0x70, 0x5a, 0x58, + 0x6a, 0x46, 0x61, 0x48, 0x33, 0x70, 0x4f, 0x33, 0x4a, 0x4c, 0x46, 0x2b, + 0x6c, 0x2b, 0x2f, 0x2b, 0x73, 0x4b, 0x41, 0x49, 0x75, 0x76, 0x74, 0x64, + 0x37, 0x75, 0x2b, 0x4e, 0x78, 0x65, 0x35, 0x41, 0x57, 0x30, 0x77, 0x64, + 0x65, 0x52, 0x6c, 0x4e, 0x38, 0x4e, 0x77, 0x64, 0x43, 0x0a, 0x6a, 0x4e, + 0x50, 0x45, 0x6c, 0x70, 0x7a, 0x56, 0x6d, 0x62, 0x55, 0x71, 0x34, 0x4a, + 0x55, 0x61, 0x67, 0x45, 0x69, 0x75, 0x54, 0x44, 0x6b, 0x48, 0x7a, 0x73, + 0x78, 0x48, 0x70, 0x46, 0x4b, 0x56, 0x4b, 0x37, 0x71, 0x34, 0x2b, 0x36, + 0x33, 0x53, 0x4d, 0x31, 0x4e, 0x39, 0x35, 0x52, 0x31, 0x4e, 0x62, 0x64, + 0x57, 0x68, 0x73, 0x63, 0x64, 0x43, 0x62, 0x2b, 0x5a, 0x41, 0x4a, 0x7a, + 0x56, 0x63, 0x0a, 0x6f, 0x79, 0x69, 0x33, 0x42, 0x34, 0x33, 0x6e, 0x6a, + 0x54, 0x4f, 0x51, 0x35, 0x79, 0x4f, 0x66, 0x2b, 0x31, 0x43, 0x63, 0x65, + 0x57, 0x78, 0x47, 0x31, 0x62, 0x51, 0x56, 0x73, 0x35, 0x5a, 0x75, 0x66, + 0x70, 0x73, 0x4d, 0x6c, 0x6a, 0x71, 0x34, 0x55, 0x69, 0x30, 0x2f, 0x31, + 0x6c, 0x76, 0x68, 0x2b, 0x77, 0x6a, 0x43, 0x68, 0x50, 0x34, 0x6b, 0x71, + 0x4b, 0x4f, 0x4a, 0x32, 0x71, 0x78, 0x71, 0x0a, 0x34, 0x52, 0x67, 0x71, + 0x73, 0x61, 0x68, 0x44, 0x59, 0x56, 0x76, 0x54, 0x48, 0x39, 0x77, 0x37, + 0x6a, 0x58, 0x62, 0x79, 0x4c, 0x65, 0x69, 0x4e, 0x64, 0x64, 0x38, 0x58, + 0x4d, 0x32, 0x77, 0x39, 0x55, 0x2f, 0x74, 0x37, 0x79, 0x30, 0x46, 0x66, + 0x2f, 0x39, 0x79, 0x69, 0x30, 0x47, 0x45, 0x34, 0x34, 0x5a, 0x61, 0x34, + 0x72, 0x46, 0x32, 0x4c, 0x4e, 0x39, 0x64, 0x31, 0x31, 0x54, 0x50, 0x41, + 0x0a, 0x6d, 0x52, 0x47, 0x75, 0x6e, 0x55, 0x48, 0x42, 0x63, 0x6e, 0x57, + 0x45, 0x76, 0x67, 0x4a, 0x42, 0x51, 0x6c, 0x39, 0x6e, 0x4a, 0x45, 0x69, + 0x55, 0x30, 0x5a, 0x73, 0x6e, 0x76, 0x67, 0x63, 0x2f, 0x75, 0x62, 0x68, + 0x50, 0x67, 0x58, 0x52, 0x52, 0x34, 0x58, 0x71, 0x33, 0x37, 0x5a, 0x30, + 0x6a, 0x34, 0x72, 0x37, 0x67, 0x31, 0x53, 0x67, 0x45, 0x45, 0x7a, 0x77, + 0x78, 0x41, 0x35, 0x37, 0x64, 0x0a, 0x65, 0x6d, 0x79, 0x50, 0x78, 0x67, + 0x63, 0x59, 0x78, 0x6e, 0x2f, 0x65, 0x52, 0x34, 0x34, 0x2f, 0x4b, 0x4a, + 0x34, 0x45, 0x42, 0x73, 0x2b, 0x6c, 0x56, 0x44, 0x52, 0x33, 0x76, 0x65, + 0x79, 0x4a, 0x6d, 0x2b, 0x6b, 0x58, 0x51, 0x39, 0x39, 0x62, 0x32, 0x31, + 0x2f, 0x2b, 0x6a, 0x68, 0x35, 0x58, 0x6f, 0x73, 0x31, 0x41, 0x6e, 0x58, + 0x35, 0x69, 0x49, 0x74, 0x72, 0x65, 0x47, 0x43, 0x63, 0x3d, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, + 0x4f, 0x3d, 0x46, 0x4e, 0x4d, 0x54, 0x2d, 0x52, 0x43, 0x4d, 0x20, 0x4f, + 0x55, 0x3d, 0x41, 0x43, 0x20, 0x52, 0x41, 0x49, 0x5a, 0x20, 0x46, 0x4e, + 0x4d, 0x54, 0x2d, 0x52, 0x43, 0x4d, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x4f, 0x3d, 0x46, 0x4e, 0x4d, 0x54, + 0x2d, 0x52, 0x43, 0x4d, 0x20, 0x4f, 0x55, 0x3d, 0x41, 0x43, 0x20, 0x52, + 0x41, 0x49, 0x5a, 0x20, 0x46, 0x4e, 0x4d, 0x54, 0x2d, 0x52, 0x43, 0x4d, + 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, + 0x43, 0x20, 0x52, 0x41, 0x49, 0x5a, 0x20, 0x46, 0x4e, 0x4d, 0x54, 0x2d, + 0x52, 0x43, 0x4d, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x34, 0x38, 0x35, 0x38, 0x37, 0x36, 0x33, 0x30, 0x38, + 0x32, 0x30, 0x36, 0x34, 0x34, 0x38, 0x38, 0x30, 0x34, 0x37, 0x30, 0x31, + 0x35, 0x35, 0x34, 0x36, 0x38, 0x32, 0x37, 0x36, 0x30, 0x35, 0x35, 0x34, + 0x37, 0x35, 0x39, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, + 0x32, 0x3a, 0x30, 0x39, 0x3a, 0x30, 0x34, 0x3a, 0x62, 0x34, 0x3a, 0x64, + 0x33, 0x3a, 0x62, 0x64, 0x3a, 0x64, 0x31, 0x3a, 0x61, 0x30, 0x3a, 0x31, + 0x34, 0x3a, 0x66, 0x64, 0x3a, 0x31, 0x61, 0x3a, 0x64, 0x32, 0x3a, 0x34, + 0x37, 0x3a, 0x63, 0x34, 0x3a, 0x35, 0x37, 0x3a, 0x31, 0x64, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x63, 0x3a, 0x35, 0x30, + 0x3a, 0x33, 0x35, 0x3a, 0x30, 0x37, 0x3a, 0x62, 0x32, 0x3a, 0x31, 0x35, + 0x3a, 0x63, 0x34, 0x3a, 0x39, 0x35, 0x3a, 0x36, 0x32, 0x3a, 0x31, 0x39, + 0x3a, 0x65, 0x32, 0x3a, 0x61, 0x38, 0x3a, 0x39, 0x61, 0x3a, 0x35, 0x62, + 0x3a, 0x34, 0x32, 0x3a, 0x39, 0x39, 0x3a, 0x32, 0x63, 0x3a, 0x34, 0x63, + 0x3a, 0x32, 0x63, 0x3a, 0x32, 0x30, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x62, 0x3a, 0x63, 0x35, 0x3a, 0x35, + 0x37, 0x3a, 0x30, 0x63, 0x3a, 0x32, 0x39, 0x3a, 0x30, 0x31, 0x3a, 0x38, + 0x63, 0x3a, 0x34, 0x64, 0x3a, 0x36, 0x37, 0x3a, 0x62, 0x31, 0x3a, 0x61, + 0x61, 0x3a, 0x31, 0x32, 0x3a, 0x37, 0x62, 0x3a, 0x61, 0x66, 0x3a, 0x31, + 0x32, 0x3a, 0x66, 0x37, 0x3a, 0x30, 0x33, 0x3a, 0x62, 0x34, 0x3a, 0x36, + 0x31, 0x3a, 0x31, 0x65, 0x3a, 0x62, 0x63, 0x3a, 0x31, 0x37, 0x3a, 0x62, + 0x37, 0x3a, 0x64, 0x61, 0x3a, 0x62, 0x35, 0x3a, 0x35, 0x37, 0x3a, 0x33, + 0x38, 0x3a, 0x39, 0x34, 0x3a, 0x31, 0x37, 0x3a, 0x39, 0x62, 0x3a, 0x39, + 0x33, 0x3a, 0x66, 0x61, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x46, 0x67, 0x7a, 0x43, 0x43, 0x41, 0x32, 0x75, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x50, 0x58, 0x5a, 0x4f, 0x4e, 0x4d, 0x47, 0x63, + 0x32, 0x79, 0x41, 0x59, 0x64, 0x47, 0x73, 0x64, 0x55, 0x68, 0x47, 0x6b, + 0x48, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x4d, 0x44, 0x73, + 0x78, 0x0a, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x59, 0x54, 0x41, 0x6b, 0x56, 0x54, 0x4d, 0x52, 0x45, 0x77, 0x44, 0x77, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, 0x68, 0x47, 0x54, 0x6b, + 0x31, 0x55, 0x4c, 0x56, 0x4a, 0x44, 0x54, 0x54, 0x45, 0x5a, 0x4d, 0x42, + 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x77, 0x77, 0x51, 0x51, 0x55, + 0x4d, 0x67, 0x55, 0x6b, 0x46, 0x4a, 0x0a, 0x57, 0x69, 0x42, 0x47, 0x54, + 0x6b, 0x31, 0x55, 0x4c, 0x56, 0x4a, 0x44, 0x54, 0x54, 0x41, 0x65, 0x46, + 0x77, 0x30, 0x77, 0x4f, 0x44, 0x45, 0x77, 0x4d, 0x6a, 0x6b, 0x78, 0x4e, + 0x54, 0x55, 0x35, 0x4e, 0x54, 0x5a, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4d, + 0x44, 0x41, 0x78, 0x4d, 0x44, 0x45, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, + 0x44, 0x42, 0x61, 0x4d, 0x44, 0x73, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x0a, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x56, 0x54, + 0x4d, 0x52, 0x45, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, + 0x44, 0x41, 0x68, 0x47, 0x54, 0x6b, 0x31, 0x55, 0x4c, 0x56, 0x4a, 0x44, + 0x54, 0x54, 0x45, 0x5a, 0x4d, 0x42, 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x77, 0x77, 0x51, 0x51, 0x55, 0x4d, 0x67, 0x55, 0x6b, 0x46, 0x4a, + 0x57, 0x69, 0x42, 0x47, 0x0a, 0x54, 0x6b, 0x31, 0x55, 0x4c, 0x56, 0x4a, + 0x44, 0x54, 0x54, 0x43, 0x43, 0x41, 0x69, 0x49, 0x77, 0x44, 0x51, 0x59, + 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, + 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x50, 0x41, 0x44, 0x43, + 0x43, 0x41, 0x67, 0x6f, 0x43, 0x67, 0x67, 0x49, 0x42, 0x41, 0x4c, 0x70, + 0x78, 0x67, 0x48, 0x70, 0x4d, 0x68, 0x6d, 0x35, 0x2f, 0x0a, 0x79, 0x42, + 0x4e, 0x74, 0x77, 0x4d, 0x5a, 0x39, 0x48, 0x41, 0x43, 0x58, 0x6a, 0x79, + 0x77, 0x4d, 0x49, 0x37, 0x73, 0x51, 0x6d, 0x6b, 0x43, 0x70, 0x47, 0x72, + 0x65, 0x48, 0x69, 0x50, 0x69, 0x62, 0x56, 0x6d, 0x72, 0x37, 0x35, 0x6e, + 0x75, 0x4f, 0x69, 0x35, 0x4b, 0x4f, 0x70, 0x79, 0x56, 0x64, 0x57, 0x52, + 0x48, 0x62, 0x4e, 0x69, 0x36, 0x33, 0x55, 0x52, 0x63, 0x66, 0x71, 0x51, + 0x67, 0x66, 0x0a, 0x42, 0x42, 0x63, 0x6b, 0x57, 0x4b, 0x6f, 0x33, 0x53, + 0x68, 0x6a, 0x66, 0x35, 0x54, 0x6e, 0x55, 0x56, 0x2f, 0x33, 0x58, 0x77, + 0x53, 0x79, 0x52, 0x41, 0x5a, 0x48, 0x69, 0x49, 0x74, 0x51, 0x44, 0x77, + 0x46, 0x6a, 0x38, 0x64, 0x30, 0x66, 0x73, 0x6a, 0x7a, 0x35, 0x30, 0x51, + 0x37, 0x71, 0x73, 0x4e, 0x49, 0x31, 0x4e, 0x4f, 0x48, 0x5a, 0x6e, 0x6a, + 0x72, 0x44, 0x49, 0x62, 0x7a, 0x41, 0x7a, 0x0a, 0x57, 0x48, 0x46, 0x63, + 0x74, 0x50, 0x56, 0x72, 0x62, 0x74, 0x51, 0x42, 0x55, 0x4c, 0x67, 0x54, + 0x66, 0x6d, 0x78, 0x4b, 0x6f, 0x30, 0x6e, 0x52, 0x49, 0x42, 0x6e, 0x75, + 0x76, 0x4d, 0x41, 0x70, 0x47, 0x47, 0x57, 0x6e, 0x33, 0x76, 0x37, 0x76, + 0x33, 0x51, 0x71, 0x51, 0x49, 0x65, 0x63, 0x61, 0x5a, 0x35, 0x4a, 0x43, + 0x45, 0x4a, 0x68, 0x66, 0x54, 0x7a, 0x43, 0x38, 0x50, 0x68, 0x78, 0x46, + 0x0a, 0x74, 0x42, 0x44, 0x58, 0x61, 0x45, 0x41, 0x55, 0x77, 0x45, 0x44, + 0x36, 0x35, 0x33, 0x63, 0x58, 0x65, 0x75, 0x59, 0x4c, 0x6a, 0x32, 0x56, + 0x62, 0x50, 0x4e, 0x6d, 0x61, 0x55, 0x74, 0x75, 0x31, 0x76, 0x5a, 0x35, + 0x47, 0x7a, 0x7a, 0x33, 0x72, 0x6b, 0x51, 0x55, 0x43, 0x77, 0x4a, 0x61, + 0x79, 0x64, 0x6b, 0x78, 0x4e, 0x45, 0x4a, 0x59, 0x37, 0x6b, 0x76, 0x71, + 0x63, 0x66, 0x77, 0x2b, 0x5a, 0x0a, 0x33, 0x37, 0x34, 0x6a, 0x4e, 0x55, + 0x55, 0x65, 0x41, 0x6c, 0x7a, 0x2b, 0x74, 0x61, 0x69, 0x62, 0x6d, 0x53, + 0x58, 0x61, 0x58, 0x76, 0x4d, 0x69, 0x77, 0x7a, 0x6e, 0x31, 0x35, 0x43, + 0x6f, 0x75, 0x30, 0x38, 0x59, 0x66, 0x78, 0x47, 0x79, 0x71, 0x78, 0x52, + 0x78, 0x71, 0x41, 0x51, 0x56, 0x4b, 0x4c, 0x39, 0x4c, 0x46, 0x77, 0x61, + 0x67, 0x30, 0x4a, 0x6c, 0x31, 0x6d, 0x70, 0x64, 0x49, 0x43, 0x0a, 0x49, + 0x66, 0x6b, 0x59, 0x74, 0x77, 0x62, 0x31, 0x54, 0x70, 0x6c, 0x76, 0x71, + 0x4b, 0x74, 0x4d, 0x55, 0x65, 0x6a, 0x50, 0x55, 0x42, 0x6a, 0x46, 0x64, + 0x38, 0x67, 0x35, 0x43, 0x53, 0x78, 0x4a, 0x6b, 0x6a, 0x4b, 0x5a, 0x71, + 0x4c, 0x73, 0x58, 0x46, 0x33, 0x6d, 0x77, 0x57, 0x73, 0x58, 0x6d, 0x6f, + 0x38, 0x52, 0x5a, 0x5a, 0x55, 0x63, 0x31, 0x67, 0x31, 0x36, 0x70, 0x36, + 0x44, 0x55, 0x4c, 0x0a, 0x6d, 0x62, 0x76, 0x6b, 0x7a, 0x53, 0x44, 0x47, + 0x6d, 0x30, 0x6f, 0x47, 0x4f, 0x62, 0x56, 0x6f, 0x2f, 0x43, 0x4b, 0x36, + 0x37, 0x6c, 0x57, 0x4d, 0x4b, 0x30, 0x37, 0x71, 0x38, 0x37, 0x48, 0x6a, + 0x2f, 0x4c, 0x61, 0x5a, 0x6d, 0x74, 0x56, 0x43, 0x2b, 0x6e, 0x46, 0x4e, + 0x43, 0x4d, 0x2b, 0x48, 0x48, 0x6d, 0x70, 0x78, 0x66, 0x66, 0x6e, 0x54, + 0x74, 0x4f, 0x6d, 0x6c, 0x63, 0x59, 0x46, 0x37, 0x0a, 0x77, 0x6b, 0x35, + 0x48, 0x6c, 0x71, 0x58, 0x32, 0x64, 0x6f, 0x57, 0x6a, 0x4b, 0x49, 0x2f, + 0x70, 0x67, 0x47, 0x36, 0x42, 0x55, 0x36, 0x56, 0x74, 0x58, 0x37, 0x68, + 0x49, 0x2b, 0x63, 0x4c, 0x35, 0x4e, 0x71, 0x59, 0x75, 0x53, 0x66, 0x2b, + 0x34, 0x6c, 0x73, 0x4b, 0x4d, 0x42, 0x37, 0x4f, 0x62, 0x69, 0x46, 0x6a, + 0x38, 0x36, 0x78, 0x73, 0x63, 0x33, 0x69, 0x31, 0x77, 0x34, 0x70, 0x65, + 0x53, 0x0a, 0x4d, 0x4b, 0x47, 0x4a, 0x34, 0x37, 0x78, 0x56, 0x71, 0x43, + 0x66, 0x57, 0x53, 0x2b, 0x32, 0x51, 0x72, 0x59, 0x76, 0x36, 0x59, 0x79, + 0x56, 0x5a, 0x4c, 0x61, 0x67, 0x31, 0x33, 0x63, 0x71, 0x58, 0x4d, 0x37, + 0x7a, 0x6c, 0x7a, 0x63, 0x65, 0x64, 0x30, 0x65, 0x7a, 0x76, 0x58, 0x67, + 0x35, 0x4b, 0x6b, 0x41, 0x59, 0x6d, 0x59, 0x36, 0x32, 0x35, 0x32, 0x54, + 0x55, 0x74, 0x42, 0x37, 0x70, 0x32, 0x0a, 0x5a, 0x53, 0x79, 0x73, 0x56, + 0x34, 0x39, 0x39, 0x39, 0x41, 0x65, 0x55, 0x31, 0x34, 0x45, 0x43, 0x6c, + 0x6c, 0x32, 0x6a, 0x42, 0x30, 0x6e, 0x56, 0x65, 0x74, 0x42, 0x58, 0x2b, + 0x52, 0x76, 0x6e, 0x55, 0x30, 0x5a, 0x31, 0x71, 0x72, 0x42, 0x35, 0x51, + 0x73, 0x74, 0x6f, 0x63, 0x51, 0x6a, 0x70, 0x59, 0x4c, 0x30, 0x35, 0x61, + 0x63, 0x37, 0x30, 0x72, 0x38, 0x4e, 0x57, 0x51, 0x4d, 0x65, 0x74, 0x0a, + 0x55, 0x71, 0x49, 0x4a, 0x35, 0x47, 0x2b, 0x47, 0x52, 0x34, 0x6f, 0x66, + 0x36, 0x79, 0x67, 0x6e, 0x58, 0x59, 0x4d, 0x67, 0x72, 0x77, 0x54, 0x4a, + 0x62, 0x46, 0x61, 0x61, 0x69, 0x30, 0x62, 0x31, 0x41, 0x67, 0x4d, 0x42, + 0x41, 0x41, 0x47, 0x6a, 0x67, 0x59, 0x4d, 0x77, 0x67, 0x59, 0x41, 0x77, + 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, + 0x42, 0x41, 0x55, 0x77, 0x0a, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, + 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, + 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x48, 0x51, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x50, 0x64, + 0x39, 0x78, 0x66, 0x33, 0x45, 0x36, 0x4a, 0x6f, 0x62, 0x64, 0x32, 0x53, + 0x6e, 0x39, 0x52, 0x32, 0x67, 0x7a, 0x4c, 0x2b, 0x48, 0x0a, 0x59, 0x4a, + 0x70, 0x74, 0x4d, 0x44, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x49, 0x41, + 0x51, 0x33, 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x77, 0x59, 0x45, 0x56, 0x52, + 0x30, 0x67, 0x41, 0x44, 0x41, 0x72, 0x4d, 0x43, 0x6b, 0x47, 0x43, 0x43, + 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x77, 0x49, 0x42, 0x46, 0x68, + 0x31, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69, 0x38, 0x76, 0x64, 0x33, + 0x64, 0x33, 0x0a, 0x4c, 0x6d, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x75, 0x5a, + 0x6d, 0x35, 0x74, 0x64, 0x43, 0x35, 0x6c, 0x63, 0x79, 0x39, 0x6b, 0x63, + 0x47, 0x4e, 0x7a, 0x4c, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, + 0x41, 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, 0x42, 0x35, 0x42, 0x4b, 0x33, + 0x2f, 0x4d, 0x6a, 0x54, 0x76, 0x44, 0x44, 0x0a, 0x6e, 0x46, 0x46, 0x6c, + 0x6d, 0x35, 0x77, 0x69, 0x6f, 0x6f, 0x6f, 0x4d, 0x68, 0x66, 0x4e, 0x7a, + 0x4b, 0x57, 0x74, 0x4e, 0x2f, 0x67, 0x48, 0x69, 0x71, 0x51, 0x78, 0x6a, + 0x41, 0x62, 0x38, 0x45, 0x5a, 0x36, 0x57, 0x64, 0x6d, 0x46, 0x2f, 0x39, + 0x41, 0x52, 0x50, 0x36, 0x37, 0x4a, 0x70, 0x69, 0x36, 0x59, 0x62, 0x2b, + 0x74, 0x6d, 0x4c, 0x53, 0x62, 0x6b, 0x79, 0x55, 0x2b, 0x38, 0x42, 0x31, + 0x0a, 0x52, 0x58, 0x78, 0x6c, 0x44, 0x50, 0x69, 0x79, 0x4e, 0x38, 0x2b, + 0x73, 0x44, 0x38, 0x2b, 0x4e, 0x62, 0x2f, 0x6b, 0x5a, 0x39, 0x34, 0x2f, + 0x73, 0x48, 0x76, 0x4a, 0x77, 0x6e, 0x76, 0x44, 0x4b, 0x75, 0x4f, 0x2b, + 0x33, 0x2f, 0x33, 0x59, 0x33, 0x64, 0x6c, 0x76, 0x32, 0x62, 0x6f, 0x6a, + 0x7a, 0x72, 0x32, 0x49, 0x79, 0x49, 0x70, 0x4d, 0x4e, 0x4f, 0x6d, 0x71, + 0x4f, 0x46, 0x47, 0x59, 0x4d, 0x0a, 0x4c, 0x56, 0x4e, 0x30, 0x56, 0x32, + 0x55, 0x65, 0x31, 0x62, 0x4c, 0x64, 0x49, 0x34, 0x45, 0x37, 0x70, 0x57, + 0x59, 0x6a, 0x4a, 0x32, 0x63, 0x4a, 0x6a, 0x2b, 0x46, 0x33, 0x71, 0x6b, + 0x50, 0x4e, 0x5a, 0x56, 0x45, 0x49, 0x37, 0x56, 0x46, 0x59, 0x2f, 0x75, + 0x59, 0x35, 0x2b, 0x63, 0x74, 0x48, 0x68, 0x4b, 0x51, 0x56, 0x38, 0x58, + 0x61, 0x37, 0x70, 0x4f, 0x36, 0x6b, 0x4f, 0x38, 0x52, 0x66, 0x0a, 0x37, + 0x37, 0x49, 0x7a, 0x6c, 0x68, 0x45, 0x59, 0x74, 0x38, 0x6c, 0x6c, 0x76, + 0x68, 0x6a, 0x68, 0x6f, 0x36, 0x54, 0x63, 0x2b, 0x68, 0x6a, 0x35, 0x30, + 0x37, 0x77, 0x54, 0x6d, 0x7a, 0x6c, 0x36, 0x4e, 0x4c, 0x72, 0x54, 0x51, + 0x66, 0x76, 0x36, 0x4d, 0x6f, 0x6f, 0x71, 0x74, 0x79, 0x75, 0x47, 0x43, + 0x32, 0x6d, 0x44, 0x4f, 0x4c, 0x37, 0x4e, 0x69, 0x69, 0x34, 0x4c, 0x63, + 0x4b, 0x32, 0x4e, 0x0a, 0x4a, 0x70, 0x4c, 0x75, 0x48, 0x76, 0x55, 0x42, + 0x4b, 0x77, 0x72, 0x5a, 0x31, 0x70, 0x65, 0x62, 0x62, 0x75, 0x43, 0x6f, + 0x47, 0x52, 0x77, 0x36, 0x49, 0x59, 0x73, 0x4d, 0x48, 0x6b, 0x43, 0x74, + 0x41, 0x2b, 0x66, 0x64, 0x5a, 0x6e, 0x37, 0x31, 0x75, 0x53, 0x41, 0x4e, + 0x41, 0x2b, 0x69, 0x57, 0x2b, 0x59, 0x4a, 0x46, 0x31, 0x44, 0x6e, 0x67, + 0x6f, 0x41, 0x42, 0x64, 0x31, 0x35, 0x6a, 0x6d, 0x0a, 0x66, 0x5a, 0x35, + 0x6e, 0x63, 0x38, 0x4f, 0x61, 0x4b, 0x76, 0x65, 0x72, 0x69, 0x36, 0x45, + 0x36, 0x46, 0x4f, 0x38, 0x30, 0x76, 0x46, 0x49, 0x4f, 0x69, 0x5a, 0x69, + 0x61, 0x42, 0x45, 0x43, 0x45, 0x48, 0x58, 0x35, 0x46, 0x61, 0x5a, 0x4e, + 0x58, 0x7a, 0x75, 0x76, 0x4f, 0x2b, 0x46, 0x42, 0x38, 0x54, 0x78, 0x78, + 0x75, 0x42, 0x45, 0x4f, 0x62, 0x2b, 0x64, 0x59, 0x37, 0x49, 0x78, 0x6a, + 0x70, 0x0a, 0x36, 0x6f, 0x37, 0x52, 0x54, 0x55, 0x61, 0x4e, 0x38, 0x54, + 0x76, 0x6b, 0x61, 0x73, 0x71, 0x36, 0x2b, 0x79, 0x4f, 0x33, 0x6d, 0x2f, + 0x71, 0x5a, 0x41, 0x53, 0x6c, 0x61, 0x57, 0x46, 0x6f, 0x74, 0x34, 0x2f, + 0x6e, 0x55, 0x62, 0x51, 0x34, 0x6d, 0x72, 0x63, 0x46, 0x75, 0x4e, 0x4c, + 0x77, 0x79, 0x2b, 0x41, 0x77, 0x46, 0x2b, 0x6d, 0x57, 0x6a, 0x32, 0x7a, + 0x73, 0x33, 0x67, 0x79, 0x4c, 0x70, 0x0a, 0x31, 0x74, 0x78, 0x79, 0x4d, + 0x2f, 0x31, 0x64, 0x38, 0x69, 0x43, 0x39, 0x64, 0x6a, 0x77, 0x6a, 0x32, + 0x69, 0x6a, 0x33, 0x2b, 0x52, 0x76, 0x72, 0x57, 0x57, 0x54, 0x56, 0x33, + 0x46, 0x39, 0x79, 0x66, 0x69, 0x44, 0x38, 0x7a, 0x59, 0x6d, 0x31, 0x6b, + 0x47, 0x64, 0x4e, 0x59, 0x6e, 0x6f, 0x2f, 0x54, 0x71, 0x30, 0x64, 0x77, + 0x7a, 0x6e, 0x2b, 0x65, 0x76, 0x51, 0x6f, 0x46, 0x74, 0x39, 0x42, 0x0a, + 0x39, 0x6b, 0x69, 0x41, 0x42, 0x64, 0x63, 0x50, 0x55, 0x58, 0x6d, 0x73, + 0x45, 0x4b, 0x76, 0x55, 0x37, 0x41, 0x4e, 0x6d, 0x35, 0x6d, 0x71, 0x77, + 0x75, 0x6a, 0x47, 0x53, 0x51, 0x6b, 0x42, 0x71, 0x76, 0x6a, 0x72, 0x54, + 0x63, 0x75, 0x46, 0x71, 0x4e, 0x31, 0x57, 0x38, 0x72, 0x42, 0x32, 0x56, + 0x74, 0x32, 0x6c, 0x68, 0x38, 0x6b, 0x4f, 0x52, 0x64, 0x4f, 0x61, 0x67, + 0x30, 0x77, 0x6f, 0x6b, 0x0a, 0x52, 0x71, 0x45, 0x49, 0x72, 0x39, 0x62, + 0x61, 0x52, 0x52, 0x6d, 0x57, 0x31, 0x46, 0x4d, 0x64, 0x57, 0x34, 0x52, + 0x35, 0x38, 0x4d, 0x44, 0x33, 0x52, 0x2b, 0x2b, 0x4c, 0x6a, 0x38, 0x55, + 0x47, 0x72, 0x70, 0x31, 0x4d, 0x59, 0x70, 0x33, 0x2f, 0x52, 0x67, 0x54, + 0x34, 0x30, 0x38, 0x6d, 0x32, 0x45, 0x43, 0x56, 0x41, 0x64, 0x66, 0x34, + 0x57, 0x71, 0x73, 0x6c, 0x4b, 0x59, 0x49, 0x59, 0x76, 0x0a, 0x75, 0x75, + 0x38, 0x77, 0x64, 0x2b, 0x52, 0x55, 0x34, 0x72, 0x69, 0x45, 0x6d, 0x56, + 0x69, 0x41, 0x71, 0x68, 0x4f, 0x4c, 0x55, 0x54, 0x70, 0x50, 0x53, 0x50, + 0x61, 0x4c, 0x74, 0x72, 0x4d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, + 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, + 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x20, 0x31, 0x20, 0x4f, 0x3d, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, + 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x20, 0x4f, 0x3d, 0x41, 0x6d, + 0x61, 0x7a, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x22, 0x0a, 0x23, 0x20, 0x53, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x34, 0x33, 0x32, 0x36, + 0x36, 0x39, 0x37, 0x38, 0x39, 0x31, 0x36, 0x36, 0x35, 0x35, 0x38, 0x35, + 0x36, 0x38, 0x37, 0x38, 0x30, 0x33, 0x34, 0x37, 0x31, 0x32, 0x33, 0x31, + 0x37, 0x32, 0x33, 0x30, 0x30, 0x35, 0x34, 0x35, 0x33, 0x38, 0x33, 0x36, + 0x39, 0x39, 0x39, 0x34, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x34, 0x33, 0x3a, 0x63, 0x36, 0x3a, 0x62, 0x66, 0x3a, 0x61, 0x65, 0x3a, + 0x65, 0x63, 0x3a, 0x66, 0x65, 0x3a, 0x61, 0x64, 0x3a, 0x32, 0x66, 0x3a, + 0x31, 0x38, 0x3a, 0x63, 0x36, 0x3a, 0x38, 0x38, 0x3a, 0x36, 0x38, 0x3a, + 0x33, 0x30, 0x3a, 0x66, 0x63, 0x3a, 0x63, 0x38, 0x3a, 0x65, 0x36, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x64, 0x3a, 0x61, + 0x37, 0x3a, 0x66, 0x39, 0x3a, 0x36, 0x35, 0x3a, 0x65, 0x63, 0x3a, 0x35, + 0x65, 0x3a, 0x66, 0x63, 0x3a, 0x33, 0x37, 0x3a, 0x39, 0x31, 0x3a, 0x30, + 0x66, 0x3a, 0x31, 0x63, 0x3a, 0x36, 0x65, 0x3a, 0x35, 0x39, 0x3a, 0x66, + 0x64, 0x3a, 0x63, 0x31, 0x3a, 0x63, 0x63, 0x3a, 0x36, 0x61, 0x3a, 0x36, + 0x65, 0x3a, 0x64, 0x65, 0x3a, 0x31, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x65, 0x3a, 0x63, 0x64, 0x3a, + 0x65, 0x36, 0x3a, 0x38, 0x38, 0x3a, 0x34, 0x66, 0x3a, 0x33, 0x64, 0x3a, + 0x38, 0x37, 0x3a, 0x62, 0x31, 0x3a, 0x31, 0x32, 0x3a, 0x35, 0x62, 0x3a, + 0x61, 0x33, 0x3a, 0x31, 0x61, 0x3a, 0x63, 0x33, 0x3a, 0x66, 0x63, 0x3a, + 0x62, 0x31, 0x3a, 0x33, 0x64, 0x3a, 0x37, 0x30, 0x3a, 0x31, 0x36, 0x3a, + 0x64, 0x65, 0x3a, 0x37, 0x66, 0x3a, 0x35, 0x37, 0x3a, 0x63, 0x63, 0x3a, + 0x39, 0x30, 0x3a, 0x34, 0x66, 0x3a, 0x65, 0x31, 0x3a, 0x63, 0x62, 0x3a, + 0x39, 0x37, 0x3a, 0x63, 0x36, 0x3a, 0x61, 0x65, 0x3a, 0x39, 0x38, 0x3a, + 0x31, 0x39, 0x3a, 0x36, 0x65, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, + 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, + 0x49, 0x44, 0x51, 0x54, 0x43, 0x43, 0x41, 0x69, 0x6d, 0x67, 0x41, 0x77, + 0x49, 0x42, 0x41, 0x67, 0x49, 0x54, 0x42, 0x6d, 0x79, 0x66, 0x7a, 0x35, + 0x6d, 0x2f, 0x6a, 0x41, 0x6f, 0x35, 0x34, 0x76, 0x42, 0x34, 0x69, 0x6b, + 0x50, 0x6d, 0x6c, 0x6a, 0x5a, 0x62, 0x79, 0x6a, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x73, 0x46, 0x0a, 0x41, 0x44, 0x41, 0x35, 0x4d, 0x51, 0x73, 0x77, 0x43, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, + 0x7a, 0x45, 0x50, 0x4d, 0x41, 0x30, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x68, 0x4d, 0x47, 0x51, 0x57, 0x31, 0x68, 0x65, 0x6d, 0x39, 0x75, 0x4d, + 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, + 0x78, 0x42, 0x42, 0x62, 0x57, 0x46, 0x36, 0x0a, 0x62, 0x32, 0x34, 0x67, + 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x53, 0x41, 0x78, + 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x31, 0x4d, 0x44, 0x55, 0x79, + 0x4e, 0x6a, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, + 0x44, 0x54, 0x4d, 0x34, 0x4d, 0x44, 0x45, 0x78, 0x4e, 0x7a, 0x41, 0x77, + 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x77, 0x4f, 0x54, 0x45, 0x4c, + 0x0a, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x56, 0x56, 0x4d, 0x78, 0x44, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x54, 0x42, 0x6b, 0x46, 0x74, 0x59, 0x58, 0x70, + 0x76, 0x62, 0x6a, 0x45, 0x5a, 0x4d, 0x42, 0x63, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x41, 0x78, 0x4d, 0x51, 0x51, 0x57, 0x31, 0x68, 0x65, 0x6d, 0x39, + 0x75, 0x49, 0x46, 0x4a, 0x76, 0x0a, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, + 0x45, 0x67, 0x4d, 0x54, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, 0x51, + 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, + 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, + 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, 0x67, 0x67, 0x45, 0x42, 0x41, 0x4c, + 0x4a, 0x34, 0x67, 0x48, 0x48, 0x4b, 0x65, 0x4e, 0x58, 0x6a, 0x0a, 0x63, + 0x61, 0x39, 0x48, 0x67, 0x46, 0x42, 0x30, 0x66, 0x57, 0x37, 0x59, 0x31, + 0x34, 0x68, 0x32, 0x39, 0x4a, 0x6c, 0x6f, 0x39, 0x31, 0x67, 0x68, 0x59, + 0x50, 0x6c, 0x30, 0x68, 0x41, 0x45, 0x76, 0x72, 0x41, 0x49, 0x74, 0x68, + 0x74, 0x4f, 0x67, 0x51, 0x33, 0x70, 0x4f, 0x73, 0x71, 0x54, 0x51, 0x4e, + 0x72, 0x6f, 0x42, 0x76, 0x6f, 0x33, 0x62, 0x53, 0x4d, 0x67, 0x48, 0x46, + 0x7a, 0x5a, 0x4d, 0x0a, 0x39, 0x4f, 0x36, 0x49, 0x49, 0x38, 0x63, 0x2b, + 0x36, 0x7a, 0x66, 0x31, 0x74, 0x52, 0x6e, 0x34, 0x53, 0x57, 0x69, 0x77, + 0x33, 0x74, 0x65, 0x35, 0x64, 0x6a, 0x67, 0x64, 0x59, 0x5a, 0x36, 0x6b, + 0x2f, 0x6f, 0x49, 0x32, 0x70, 0x65, 0x56, 0x4b, 0x56, 0x75, 0x52, 0x46, + 0x34, 0x66, 0x6e, 0x39, 0x74, 0x42, 0x62, 0x36, 0x64, 0x4e, 0x71, 0x63, + 0x6d, 0x7a, 0x55, 0x35, 0x4c, 0x2f, 0x71, 0x77, 0x0a, 0x49, 0x46, 0x41, + 0x47, 0x62, 0x48, 0x72, 0x51, 0x67, 0x4c, 0x4b, 0x6d, 0x2b, 0x61, 0x2f, + 0x73, 0x52, 0x78, 0x6d, 0x50, 0x55, 0x44, 0x67, 0x48, 0x33, 0x4b, 0x4b, + 0x48, 0x4f, 0x56, 0x6a, 0x34, 0x75, 0x74, 0x57, 0x70, 0x2b, 0x55, 0x68, + 0x6e, 0x4d, 0x4a, 0x62, 0x75, 0x6c, 0x48, 0x68, 0x65, 0x62, 0x34, 0x6d, + 0x6a, 0x55, 0x63, 0x41, 0x77, 0x68, 0x6d, 0x61, 0x68, 0x52, 0x57, 0x61, + 0x36, 0x0a, 0x56, 0x4f, 0x75, 0x6a, 0x77, 0x35, 0x48, 0x35, 0x53, 0x4e, + 0x7a, 0x2f, 0x30, 0x65, 0x67, 0x77, 0x4c, 0x58, 0x30, 0x74, 0x64, 0x48, + 0x41, 0x31, 0x31, 0x34, 0x67, 0x6b, 0x39, 0x35, 0x37, 0x45, 0x57, 0x57, + 0x36, 0x37, 0x63, 0x34, 0x63, 0x58, 0x38, 0x6a, 0x4a, 0x47, 0x4b, 0x4c, + 0x68, 0x44, 0x2b, 0x72, 0x63, 0x64, 0x71, 0x73, 0x71, 0x30, 0x38, 0x70, + 0x38, 0x6b, 0x44, 0x69, 0x31, 0x4c, 0x0a, 0x39, 0x33, 0x46, 0x63, 0x58, + 0x6d, 0x6e, 0x2f, 0x36, 0x70, 0x55, 0x43, 0x79, 0x7a, 0x69, 0x4b, 0x72, + 0x6c, 0x41, 0x34, 0x62, 0x39, 0x76, 0x37, 0x4c, 0x57, 0x49, 0x62, 0x78, + 0x63, 0x63, 0x65, 0x56, 0x4f, 0x46, 0x33, 0x34, 0x47, 0x66, 0x49, 0x44, + 0x35, 0x79, 0x48, 0x49, 0x39, 0x59, 0x2f, 0x51, 0x43, 0x42, 0x2f, 0x49, + 0x49, 0x44, 0x45, 0x67, 0x45, 0x77, 0x2b, 0x4f, 0x79, 0x51, 0x6d, 0x0a, + 0x6a, 0x67, 0x53, 0x75, 0x62, 0x4a, 0x72, 0x49, 0x71, 0x67, 0x30, 0x43, + 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77, + 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, + 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f, + 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, + 0x42, 0x41, 0x4d, 0x43, 0x0a, 0x41, 0x59, 0x59, 0x77, 0x48, 0x51, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x49, 0x51, + 0x59, 0x7a, 0x49, 0x55, 0x30, 0x37, 0x4c, 0x77, 0x4d, 0x6c, 0x4a, 0x51, + 0x75, 0x43, 0x46, 0x6d, 0x63, 0x78, 0x37, 0x49, 0x51, 0x54, 0x67, 0x6f, + 0x49, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x0a, 0x41, 0x34, + 0x49, 0x42, 0x41, 0x51, 0x43, 0x59, 0x38, 0x6a, 0x64, 0x61, 0x51, 0x5a, + 0x43, 0x68, 0x47, 0x73, 0x56, 0x32, 0x55, 0x53, 0x67, 0x67, 0x4e, 0x69, + 0x4d, 0x4f, 0x72, 0x75, 0x59, 0x6f, 0x75, 0x36, 0x72, 0x34, 0x6c, 0x4b, + 0x35, 0x49, 0x70, 0x44, 0x42, 0x2f, 0x47, 0x2f, 0x77, 0x6b, 0x6a, 0x55, + 0x75, 0x30, 0x79, 0x4b, 0x47, 0x58, 0x39, 0x72, 0x62, 0x78, 0x65, 0x6e, + 0x44, 0x49, 0x0a, 0x55, 0x35, 0x50, 0x4d, 0x43, 0x43, 0x6a, 0x6a, 0x6d, + 0x43, 0x58, 0x50, 0x49, 0x36, 0x54, 0x35, 0x33, 0x69, 0x48, 0x54, 0x66, + 0x49, 0x55, 0x4a, 0x72, 0x55, 0x36, 0x61, 0x64, 0x54, 0x72, 0x43, 0x43, + 0x32, 0x71, 0x4a, 0x65, 0x48, 0x5a, 0x45, 0x52, 0x78, 0x68, 0x6c, 0x62, + 0x49, 0x31, 0x42, 0x6a, 0x6a, 0x74, 0x2f, 0x6d, 0x73, 0x76, 0x30, 0x74, + 0x61, 0x64, 0x51, 0x31, 0x77, 0x55, 0x73, 0x0a, 0x4e, 0x2b, 0x67, 0x44, + 0x53, 0x36, 0x33, 0x70, 0x59, 0x61, 0x41, 0x43, 0x62, 0x76, 0x58, 0x79, + 0x38, 0x4d, 0x57, 0x79, 0x37, 0x56, 0x75, 0x33, 0x33, 0x50, 0x71, 0x55, + 0x58, 0x48, 0x65, 0x65, 0x45, 0x36, 0x56, 0x2f, 0x55, 0x71, 0x32, 0x56, + 0x38, 0x76, 0x69, 0x54, 0x4f, 0x39, 0x36, 0x4c, 0x58, 0x46, 0x76, 0x4b, + 0x57, 0x6c, 0x4a, 0x62, 0x59, 0x4b, 0x38, 0x55, 0x39, 0x30, 0x76, 0x76, + 0x0a, 0x6f, 0x2f, 0x75, 0x66, 0x51, 0x4a, 0x56, 0x74, 0x4d, 0x56, 0x54, + 0x38, 0x51, 0x74, 0x50, 0x48, 0x52, 0x68, 0x38, 0x6a, 0x72, 0x64, 0x6b, + 0x50, 0x53, 0x48, 0x43, 0x61, 0x32, 0x58, 0x56, 0x34, 0x63, 0x64, 0x46, + 0x79, 0x51, 0x7a, 0x52, 0x31, 0x62, 0x6c, 0x64, 0x5a, 0x77, 0x67, 0x4a, + 0x63, 0x4a, 0x6d, 0x41, 0x70, 0x7a, 0x79, 0x4d, 0x5a, 0x46, 0x6f, 0x36, + 0x49, 0x51, 0x36, 0x58, 0x55, 0x0a, 0x35, 0x4d, 0x73, 0x49, 0x2b, 0x79, + 0x4d, 0x52, 0x51, 0x2b, 0x68, 0x44, 0x4b, 0x58, 0x4a, 0x69, 0x6f, 0x61, + 0x6c, 0x64, 0x58, 0x67, 0x6a, 0x55, 0x6b, 0x4b, 0x36, 0x34, 0x32, 0x4d, + 0x34, 0x55, 0x77, 0x74, 0x42, 0x56, 0x38, 0x6f, 0x62, 0x32, 0x78, 0x4a, + 0x4e, 0x44, 0x64, 0x32, 0x5a, 0x68, 0x77, 0x4c, 0x6e, 0x6f, 0x51, 0x64, + 0x65, 0x58, 0x65, 0x47, 0x41, 0x44, 0x62, 0x6b, 0x70, 0x79, 0x0a, 0x72, + 0x71, 0x58, 0x52, 0x66, 0x62, 0x6f, 0x51, 0x6e, 0x6f, 0x5a, 0x73, 0x47, + 0x34, 0x71, 0x35, 0x57, 0x54, 0x50, 0x34, 0x36, 0x38, 0x53, 0x51, 0x76, + 0x76, 0x47, 0x35, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x6d, 0x61, 0x7a, + 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, + 0x20, 0x4f, 0x3d, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x0a, 0x23, 0x20, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x20, 0x32, 0x20, 0x4f, 0x3d, 0x41, 0x6d, 0x61, 0x7a, 0x6f, + 0x6e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x20, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x34, 0x33, 0x32, 0x36, 0x36, 0x39, 0x38, + 0x32, 0x38, 0x38, 0x35, 0x39, 0x36, 0x33, 0x35, 0x35, 0x31, 0x38, 0x31, + 0x38, 0x33, 0x34, 0x39, 0x31, 0x36, 0x30, 0x36, 0x35, 0x38, 0x39, 0x32, + 0x35, 0x30, 0x30, 0x36, 0x39, 0x37, 0x30, 0x36, 0x35, 0x33, 0x32, 0x33, + 0x39, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x38, 0x3a, + 0x65, 0x35, 0x3a, 0x38, 0x64, 0x3a, 0x63, 0x65, 0x3a, 0x61, 0x38, 0x3a, + 0x34, 0x32, 0x3a, 0x65, 0x32, 0x3a, 0x37, 0x61, 0x3a, 0x63, 0x30, 0x3a, + 0x32, 0x61, 0x3a, 0x35, 0x63, 0x3a, 0x37, 0x63, 0x3a, 0x39, 0x65, 0x3a, + 0x32, 0x36, 0x3a, 0x62, 0x66, 0x3a, 0x36, 0x36, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x61, 0x3a, 0x38, 0x63, 0x3a, 0x65, + 0x66, 0x3a, 0x34, 0x35, 0x3a, 0x64, 0x37, 0x3a, 0x61, 0x36, 0x3a, 0x39, + 0x38, 0x3a, 0x35, 0x39, 0x3a, 0x37, 0x36, 0x3a, 0x37, 0x61, 0x3a, 0x38, + 0x63, 0x3a, 0x38, 0x62, 0x3a, 0x34, 0x34, 0x3a, 0x39, 0x36, 0x3a, 0x62, + 0x35, 0x3a, 0x37, 0x38, 0x3a, 0x63, 0x66, 0x3a, 0x34, 0x37, 0x3a, 0x34, + 0x62, 0x3a, 0x31, 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, + 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x31, 0x62, 0x3a, 0x61, 0x35, 0x3a, 0x62, 0x32, 0x3a, + 0x61, 0x61, 0x3a, 0x38, 0x63, 0x3a, 0x36, 0x35, 0x3a, 0x34, 0x30, 0x3a, + 0x31, 0x61, 0x3a, 0x38, 0x32, 0x3a, 0x39, 0x36, 0x3a, 0x30, 0x31, 0x3a, + 0x31, 0x38, 0x3a, 0x66, 0x38, 0x3a, 0x30, 0x62, 0x3a, 0x65, 0x63, 0x3a, + 0x34, 0x66, 0x3a, 0x36, 0x32, 0x3a, 0x33, 0x30, 0x3a, 0x34, 0x64, 0x3a, + 0x38, 0x33, 0x3a, 0x63, 0x65, 0x3a, 0x63, 0x34, 0x3a, 0x37, 0x31, 0x3a, + 0x33, 0x61, 0x3a, 0x31, 0x39, 0x3a, 0x63, 0x33, 0x3a, 0x39, 0x63, 0x3a, + 0x30, 0x31, 0x3a, 0x31, 0x65, 0x3a, 0x61, 0x34, 0x3a, 0x36, 0x64, 0x3a, + 0x62, 0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, + 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x51, + 0x54, 0x43, 0x43, 0x41, 0x79, 0x6d, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, + 0x67, 0x49, 0x54, 0x42, 0x6d, 0x79, 0x66, 0x30, 0x70, 0x59, 0x31, 0x68, + 0x70, 0x38, 0x4b, 0x44, 0x2b, 0x57, 0x47, 0x65, 0x50, 0x68, 0x62, 0x4a, + 0x72, 0x75, 0x4b, 0x4e, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x77, 0x46, 0x0a, + 0x41, 0x44, 0x41, 0x35, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x50, + 0x4d, 0x41, 0x30, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x47, + 0x51, 0x57, 0x31, 0x68, 0x65, 0x6d, 0x39, 0x75, 0x4d, 0x52, 0x6b, 0x77, + 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x42, 0x42, + 0x62, 0x57, 0x46, 0x36, 0x0a, 0x62, 0x32, 0x34, 0x67, 0x55, 0x6d, 0x39, + 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x53, 0x41, 0x79, 0x4d, 0x42, 0x34, + 0x58, 0x44, 0x54, 0x45, 0x31, 0x4d, 0x44, 0x55, 0x79, 0x4e, 0x6a, 0x41, + 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x51, + 0x77, 0x4d, 0x44, 0x55, 0x79, 0x4e, 0x6a, 0x41, 0x77, 0x4d, 0x44, 0x41, + 0x77, 0x4d, 0x46, 0x6f, 0x77, 0x4f, 0x54, 0x45, 0x4c, 0x0a, 0x4d, 0x41, + 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, + 0x4d, 0x78, 0x44, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x6f, 0x54, 0x42, 0x6b, 0x46, 0x74, 0x59, 0x58, 0x70, 0x76, 0x62, 0x6a, + 0x45, 0x5a, 0x4d, 0x42, 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, + 0x4d, 0x51, 0x51, 0x57, 0x31, 0x68, 0x65, 0x6d, 0x39, 0x75, 0x49, 0x46, + 0x4a, 0x76, 0x0a, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4d, + 0x6a, 0x43, 0x43, 0x41, 0x69, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, + 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, + 0x67, 0x6f, 0x43, 0x67, 0x67, 0x49, 0x42, 0x41, 0x4b, 0x32, 0x57, 0x6e, + 0x79, 0x32, 0x63, 0x53, 0x6b, 0x78, 0x4b, 0x0a, 0x67, 0x58, 0x6c, 0x52, + 0x6d, 0x65, 0x79, 0x4b, 0x79, 0x32, 0x74, 0x67, 0x55, 0x52, 0x4f, 0x38, + 0x54, 0x57, 0x30, 0x47, 0x2f, 0x4c, 0x41, 0x49, 0x6a, 0x64, 0x30, 0x5a, + 0x45, 0x47, 0x72, 0x48, 0x4a, 0x67, 0x77, 0x31, 0x32, 0x4d, 0x42, 0x76, + 0x49, 0x49, 0x54, 0x70, 0x6c, 0x4c, 0x47, 0x62, 0x68, 0x51, 0x50, 0x44, + 0x57, 0x39, 0x74, 0x4b, 0x36, 0x4d, 0x6a, 0x34, 0x6b, 0x48, 0x62, 0x5a, + 0x0a, 0x57, 0x30, 0x2f, 0x6a, 0x54, 0x4f, 0x67, 0x47, 0x4e, 0x6b, 0x33, + 0x4d, 0x6d, 0x71, 0x77, 0x39, 0x44, 0x4a, 0x41, 0x72, 0x6b, 0x74, 0x51, + 0x47, 0x47, 0x57, 0x43, 0x73, 0x4e, 0x30, 0x52, 0x35, 0x68, 0x59, 0x47, + 0x43, 0x72, 0x56, 0x6f, 0x33, 0x34, 0x41, 0x33, 0x4d, 0x6e, 0x61, 0x5a, + 0x4d, 0x55, 0x6e, 0x62, 0x71, 0x51, 0x35, 0x32, 0x33, 0x42, 0x4e, 0x46, + 0x51, 0x39, 0x6c, 0x58, 0x67, 0x0a, 0x31, 0x64, 0x4b, 0x6d, 0x53, 0x59, + 0x58, 0x70, 0x4e, 0x2b, 0x6e, 0x4b, 0x66, 0x71, 0x35, 0x63, 0x6c, 0x55, + 0x31, 0x49, 0x6d, 0x6a, 0x2b, 0x75, 0x49, 0x46, 0x70, 0x74, 0x69, 0x4a, + 0x58, 0x5a, 0x4e, 0x4c, 0x68, 0x53, 0x47, 0x6b, 0x4f, 0x51, 0x73, 0x4c, + 0x39, 0x73, 0x42, 0x62, 0x6d, 0x32, 0x65, 0x4c, 0x66, 0x71, 0x30, 0x4f, + 0x51, 0x36, 0x50, 0x42, 0x4a, 0x54, 0x59, 0x76, 0x39, 0x4b, 0x0a, 0x38, + 0x6e, 0x75, 0x2b, 0x4e, 0x51, 0x57, 0x70, 0x45, 0x6a, 0x54, 0x6a, 0x38, + 0x32, 0x52, 0x30, 0x59, 0x69, 0x77, 0x39, 0x41, 0x45, 0x6c, 0x61, 0x4b, + 0x50, 0x34, 0x79, 0x52, 0x4c, 0x75, 0x48, 0x33, 0x57, 0x55, 0x6e, 0x41, + 0x6e, 0x45, 0x37, 0x32, 0x6b, 0x72, 0x33, 0x48, 0x39, 0x72, 0x4e, 0x39, + 0x79, 0x46, 0x56, 0x6b, 0x45, 0x38, 0x50, 0x37, 0x4b, 0x36, 0x43, 0x34, + 0x5a, 0x39, 0x72, 0x0a, 0x32, 0x55, 0x58, 0x54, 0x75, 0x2f, 0x42, 0x66, + 0x68, 0x2b, 0x30, 0x38, 0x4c, 0x44, 0x6d, 0x47, 0x32, 0x6a, 0x2f, 0x65, + 0x37, 0x48, 0x4a, 0x56, 0x36, 0x33, 0x6d, 0x6a, 0x72, 0x64, 0x76, 0x64, + 0x66, 0x4c, 0x43, 0x36, 0x48, 0x4d, 0x37, 0x38, 0x33, 0x6b, 0x38, 0x31, + 0x64, 0x73, 0x38, 0x50, 0x2b, 0x48, 0x67, 0x66, 0x61, 0x6a, 0x5a, 0x52, + 0x52, 0x69, 0x64, 0x68, 0x57, 0x2b, 0x6d, 0x65, 0x0a, 0x7a, 0x2f, 0x43, + 0x69, 0x56, 0x58, 0x31, 0x38, 0x4a, 0x59, 0x70, 0x76, 0x4c, 0x37, 0x54, + 0x46, 0x7a, 0x34, 0x51, 0x75, 0x4b, 0x2f, 0x30, 0x4e, 0x55, 0x52, 0x42, + 0x73, 0x2b, 0x31, 0x38, 0x62, 0x76, 0x42, 0x74, 0x2b, 0x78, 0x61, 0x34, + 0x37, 0x6d, 0x41, 0x45, 0x78, 0x6b, 0x76, 0x38, 0x4c, 0x56, 0x2f, 0x53, + 0x61, 0x73, 0x72, 0x6c, 0x58, 0x36, 0x61, 0x76, 0x76, 0x44, 0x58, 0x62, + 0x52, 0x0a, 0x38, 0x4f, 0x37, 0x30, 0x7a, 0x6f, 0x61, 0x6e, 0x34, 0x47, + 0x37, 0x70, 0x74, 0x47, 0x6d, 0x68, 0x33, 0x32, 0x6e, 0x32, 0x4d, 0x38, + 0x5a, 0x70, 0x4c, 0x70, 0x63, 0x54, 0x6e, 0x71, 0x57, 0x48, 0x73, 0x46, + 0x63, 0x51, 0x67, 0x54, 0x66, 0x4a, 0x55, 0x37, 0x4f, 0x37, 0x66, 0x2f, + 0x61, 0x53, 0x30, 0x5a, 0x7a, 0x51, 0x47, 0x50, 0x53, 0x53, 0x62, 0x74, + 0x71, 0x44, 0x54, 0x36, 0x5a, 0x6a, 0x0a, 0x6d, 0x55, 0x79, 0x6c, 0x2b, + 0x31, 0x37, 0x76, 0x49, 0x57, 0x52, 0x36, 0x49, 0x46, 0x39, 0x73, 0x5a, + 0x49, 0x55, 0x56, 0x79, 0x7a, 0x66, 0x70, 0x59, 0x67, 0x77, 0x4c, 0x4b, + 0x68, 0x62, 0x63, 0x41, 0x53, 0x34, 0x79, 0x32, 0x6a, 0x35, 0x4c, 0x39, + 0x5a, 0x34, 0x36, 0x39, 0x68, 0x64, 0x41, 0x6c, 0x4f, 0x2b, 0x65, 0x6b, + 0x51, 0x69, 0x47, 0x2b, 0x72, 0x35, 0x6a, 0x71, 0x46, 0x6f, 0x7a, 0x0a, + 0x37, 0x4d, 0x74, 0x30, 0x51, 0x35, 0x58, 0x35, 0x62, 0x47, 0x6c, 0x53, + 0x4e, 0x73, 0x63, 0x70, 0x62, 0x2f, 0x78, 0x56, 0x41, 0x31, 0x77, 0x66, + 0x2b, 0x35, 0x2b, 0x39, 0x52, 0x2b, 0x76, 0x6e, 0x53, 0x55, 0x65, 0x56, + 0x43, 0x30, 0x36, 0x4a, 0x49, 0x67, 0x6c, 0x4a, 0x34, 0x50, 0x56, 0x68, + 0x48, 0x76, 0x47, 0x2f, 0x4c, 0x6f, 0x70, 0x79, 0x62, 0x6f, 0x42, 0x5a, + 0x2f, 0x31, 0x63, 0x36, 0x0a, 0x2b, 0x58, 0x55, 0x79, 0x6f, 0x30, 0x35, + 0x66, 0x37, 0x4f, 0x30, 0x6f, 0x59, 0x74, 0x6c, 0x4e, 0x63, 0x2f, 0x4c, + 0x4d, 0x67, 0x52, 0x64, 0x67, 0x37, 0x63, 0x33, 0x72, 0x33, 0x4e, 0x75, + 0x6e, 0x79, 0x73, 0x56, 0x2b, 0x41, 0x72, 0x33, 0x79, 0x56, 0x41, 0x68, + 0x55, 0x2f, 0x62, 0x51, 0x74, 0x43, 0x53, 0x77, 0x58, 0x56, 0x45, 0x71, + 0x59, 0x30, 0x56, 0x54, 0x68, 0x55, 0x57, 0x63, 0x49, 0x0a, 0x30, 0x75, + 0x31, 0x75, 0x66, 0x6d, 0x38, 0x2f, 0x30, 0x69, 0x32, 0x42, 0x57, 0x53, + 0x6c, 0x6d, 0x79, 0x35, 0x41, 0x35, 0x6c, 0x52, 0x45, 0x65, 0x64, 0x43, + 0x66, 0x2b, 0x33, 0x65, 0x75, 0x76, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, + 0x47, 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, + 0x4d, 0x42, 0x0a, 0x41, 0x66, 0x38, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, + 0x67, 0x47, 0x47, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, + 0x67, 0x51, 0x57, 0x42, 0x42, 0x53, 0x77, 0x44, 0x50, 0x42, 0x4d, 0x4d, + 0x50, 0x51, 0x46, 0x57, 0x41, 0x4a, 0x49, 0x2f, 0x54, 0x50, 0x6c, 0x55, + 0x71, 0x39, 0x4c, 0x68, 0x4f, 0x4e, 0x6d, 0x0a, 0x55, 0x6a, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x77, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, + 0x71, 0x71, 0x69, 0x41, 0x6a, 0x77, 0x35, 0x34, 0x6f, 0x2b, 0x43, 0x69, + 0x31, 0x4d, 0x33, 0x6d, 0x39, 0x5a, 0x68, 0x36, 0x4f, 0x2b, 0x6f, 0x41, + 0x41, 0x37, 0x43, 0x58, 0x44, 0x70, 0x4f, 0x38, 0x57, 0x71, 0x6a, 0x32, + 0x0a, 0x4c, 0x49, 0x78, 0x79, 0x68, 0x36, 0x6d, 0x78, 0x2f, 0x48, 0x39, + 0x7a, 0x2f, 0x57, 0x4e, 0x78, 0x65, 0x4b, 0x57, 0x48, 0x57, 0x63, 0x38, + 0x77, 0x34, 0x51, 0x30, 0x51, 0x73, 0x68, 0x4e, 0x61, 0x62, 0x59, 0x4c, + 0x31, 0x61, 0x75, 0x61, 0x41, 0x6e, 0x36, 0x41, 0x46, 0x43, 0x32, 0x6a, + 0x6b, 0x52, 0x32, 0x76, 0x48, 0x61, 0x74, 0x2b, 0x32, 0x2f, 0x58, 0x63, + 0x79, 0x63, 0x75, 0x55, 0x59, 0x0a, 0x2b, 0x67, 0x6e, 0x30, 0x6f, 0x4a, + 0x4d, 0x73, 0x58, 0x64, 0x4b, 0x4d, 0x64, 0x59, 0x56, 0x32, 0x5a, 0x5a, + 0x41, 0x4d, 0x41, 0x33, 0x6d, 0x33, 0x4d, 0x53, 0x4e, 0x6a, 0x72, 0x58, + 0x69, 0x44, 0x43, 0x59, 0x5a, 0x6f, 0x68, 0x4d, 0x72, 0x2f, 0x2b, 0x63, + 0x38, 0x6d, 0x6d, 0x70, 0x4a, 0x35, 0x35, 0x38, 0x31, 0x4c, 0x78, 0x65, + 0x64, 0x68, 0x70, 0x78, 0x66, 0x4c, 0x38, 0x36, 0x6b, 0x53, 0x0a, 0x6b, + 0x35, 0x4e, 0x72, 0x70, 0x2b, 0x67, 0x76, 0x55, 0x35, 0x4c, 0x45, 0x59, + 0x46, 0x69, 0x77, 0x7a, 0x41, 0x4a, 0x52, 0x47, 0x46, 0x75, 0x46, 0x6a, + 0x57, 0x4a, 0x5a, 0x59, 0x37, 0x61, 0x74, 0x74, 0x4e, 0x36, 0x61, 0x2b, + 0x79, 0x62, 0x33, 0x41, 0x43, 0x66, 0x41, 0x58, 0x56, 0x55, 0x33, 0x64, + 0x4a, 0x6e, 0x4a, 0x55, 0x48, 0x2f, 0x6a, 0x57, 0x53, 0x35, 0x45, 0x34, + 0x79, 0x77, 0x6c, 0x0a, 0x37, 0x75, 0x78, 0x4d, 0x4d, 0x6e, 0x65, 0x30, + 0x6e, 0x78, 0x72, 0x70, 0x53, 0x31, 0x30, 0x67, 0x78, 0x64, 0x72, 0x39, + 0x48, 0x49, 0x63, 0x57, 0x78, 0x6b, 0x50, 0x6f, 0x31, 0x4c, 0x73, 0x6d, + 0x6d, 0x6b, 0x56, 0x77, 0x58, 0x71, 0x6b, 0x4c, 0x4e, 0x31, 0x50, 0x69, + 0x52, 0x6e, 0x73, 0x6e, 0x2f, 0x65, 0x42, 0x47, 0x38, 0x6f, 0x6d, 0x33, + 0x7a, 0x45, 0x4b, 0x32, 0x79, 0x79, 0x67, 0x6d, 0x0a, 0x62, 0x74, 0x6d, + 0x6c, 0x79, 0x54, 0x72, 0x49, 0x51, 0x52, 0x4e, 0x67, 0x39, 0x31, 0x43, + 0x4d, 0x46, 0x61, 0x36, 0x79, 0x62, 0x52, 0x6f, 0x56, 0x47, 0x6c, 0x64, + 0x34, 0x35, 0x70, 0x49, 0x71, 0x32, 0x57, 0x57, 0x51, 0x67, 0x6a, 0x39, + 0x73, 0x41, 0x71, 0x2b, 0x75, 0x45, 0x6a, 0x6f, 0x6e, 0x6c, 0x6a, 0x59, + 0x45, 0x31, 0x78, 0x32, 0x69, 0x67, 0x47, 0x4f, 0x70, 0x6d, 0x2f, 0x48, + 0x6c, 0x0a, 0x75, 0x72, 0x52, 0x38, 0x46, 0x4c, 0x42, 0x4f, 0x79, 0x62, + 0x45, 0x66, 0x64, 0x46, 0x38, 0x34, 0x39, 0x6c, 0x48, 0x71, 0x6d, 0x2f, + 0x6f, 0x73, 0x6f, 0x68, 0x48, 0x55, 0x71, 0x53, 0x30, 0x6e, 0x47, 0x6b, + 0x57, 0x78, 0x72, 0x37, 0x4a, 0x4f, 0x63, 0x51, 0x33, 0x41, 0x57, 0x45, + 0x62, 0x57, 0x61, 0x51, 0x62, 0x4c, 0x55, 0x38, 0x75, 0x7a, 0x2f, 0x6d, + 0x74, 0x42, 0x7a, 0x55, 0x46, 0x2b, 0x0a, 0x66, 0x55, 0x77, 0x50, 0x66, + 0x48, 0x4a, 0x35, 0x65, 0x6c, 0x6e, 0x4e, 0x58, 0x6b, 0x6f, 0x4f, 0x72, + 0x4a, 0x75, 0x70, 0x6d, 0x48, 0x4e, 0x35, 0x66, 0x4c, 0x54, 0x30, 0x7a, + 0x4c, 0x6d, 0x34, 0x42, 0x77, 0x79, 0x79, 0x64, 0x46, 0x79, 0x34, 0x78, + 0x32, 0x2b, 0x49, 0x6f, 0x5a, 0x43, 0x6e, 0x39, 0x4b, 0x72, 0x35, 0x76, + 0x32, 0x63, 0x36, 0x39, 0x42, 0x6f, 0x56, 0x59, 0x68, 0x36, 0x33, 0x0a, + 0x6e, 0x37, 0x34, 0x39, 0x73, 0x53, 0x6d, 0x76, 0x5a, 0x36, 0x45, 0x53, + 0x38, 0x6c, 0x67, 0x51, 0x47, 0x56, 0x4d, 0x44, 0x4d, 0x42, 0x75, 0x34, + 0x47, 0x6f, 0x6e, 0x32, 0x6e, 0x4c, 0x32, 0x58, 0x41, 0x34, 0x36, 0x6a, + 0x43, 0x66, 0x4d, 0x64, 0x69, 0x79, 0x48, 0x78, 0x74, 0x4e, 0x2f, 0x6b, + 0x48, 0x4e, 0x47, 0x66, 0x5a, 0x51, 0x49, 0x47, 0x36, 0x6c, 0x7a, 0x57, + 0x45, 0x37, 0x4f, 0x45, 0x0a, 0x37, 0x36, 0x4b, 0x6c, 0x58, 0x49, 0x78, + 0x33, 0x4b, 0x61, 0x64, 0x6f, 0x77, 0x47, 0x75, 0x75, 0x51, 0x4e, 0x4b, + 0x6f, 0x74, 0x4f, 0x72, 0x4e, 0x38, 0x49, 0x31, 0x4c, 0x4f, 0x4a, 0x77, + 0x5a, 0x6d, 0x68, 0x73, 0x6f, 0x56, 0x4c, 0x69, 0x4a, 0x6b, 0x4f, 0x2f, + 0x4b, 0x64, 0x59, 0x45, 0x2b, 0x48, 0x76, 0x4a, 0x6b, 0x4a, 0x4d, 0x63, + 0x59, 0x72, 0x30, 0x37, 0x2f, 0x52, 0x35, 0x34, 0x48, 0x0a, 0x39, 0x6a, + 0x56, 0x6c, 0x70, 0x4e, 0x4d, 0x4b, 0x56, 0x76, 0x2f, 0x31, 0x46, 0x32, + 0x52, 0x73, 0x37, 0x36, 0x67, 0x69, 0x4a, 0x55, 0x6d, 0x54, 0x74, 0x74, + 0x38, 0x41, 0x46, 0x39, 0x70, 0x59, 0x66, 0x6c, 0x33, 0x75, 0x78, 0x52, + 0x75, 0x77, 0x30, 0x64, 0x46, 0x66, 0x49, 0x52, 0x44, 0x48, 0x2b, 0x66, + 0x4f, 0x36, 0x41, 0x67, 0x6f, 0x6e, 0x42, 0x38, 0x58, 0x78, 0x31, 0x73, + 0x66, 0x54, 0x0a, 0x34, 0x50, 0x73, 0x4a, 0x59, 0x47, 0x77, 0x3d, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, 0x20, 0x4f, 0x3d, 0x41, + 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x6d, 0x61, 0x7a, + 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, + 0x20, 0x4f, 0x3d, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x0a, 0x23, 0x20, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x41, 0x6d, 0x61, 0x7a, + 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, + 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, + 0x31, 0x34, 0x33, 0x32, 0x36, 0x36, 0x39, 0x38, 0x36, 0x36, 0x39, 0x39, + 0x30, 0x39, 0x30, 0x37, 0x36, 0x36, 0x32, 0x39, 0x34, 0x37, 0x30, 0x30, + 0x36, 0x33, 0x35, 0x33, 0x38, 0x31, 0x32, 0x33, 0x30, 0x39, 0x33, 0x34, + 0x37, 0x38, 0x38, 0x36, 0x36, 0x35, 0x39, 0x33, 0x30, 0x0a, 0x23, 0x20, + 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x30, 0x3a, 0x64, 0x34, 0x3a, 0x65, + 0x66, 0x3a, 0x30, 0x62, 0x3a, 0x66, 0x37, 0x3a, 0x62, 0x35, 0x3a, 0x64, + 0x38, 0x3a, 0x34, 0x39, 0x3a, 0x39, 0x35, 0x3a, 0x32, 0x61, 0x3a, 0x65, + 0x63, 0x3a, 0x66, 0x35, 0x3a, 0x63, 0x34, 0x3a, 0x66, 0x63, 0x3a, 0x38, + 0x31, 0x3a, 0x38, 0x37, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x30, 0x64, 0x3a, 0x34, 0x34, 0x3a, 0x64, 0x64, 0x3a, 0x38, 0x63, + 0x3a, 0x33, 0x63, 0x3a, 0x38, 0x63, 0x3a, 0x31, 0x61, 0x3a, 0x31, 0x61, + 0x3a, 0x35, 0x38, 0x3a, 0x37, 0x35, 0x3a, 0x36, 0x34, 0x3a, 0x38, 0x31, + 0x3a, 0x65, 0x39, 0x3a, 0x30, 0x66, 0x3a, 0x32, 0x65, 0x3a, 0x32, 0x61, + 0x3a, 0x66, 0x66, 0x3a, 0x62, 0x33, 0x3a, 0x64, 0x32, 0x3a, 0x36, 0x65, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, + 0x38, 0x3a, 0x63, 0x65, 0x3a, 0x36, 0x63, 0x3a, 0x66, 0x65, 0x3a, 0x37, + 0x62, 0x3a, 0x66, 0x31, 0x3a, 0x34, 0x65, 0x3a, 0x36, 0x30, 0x3a, 0x62, + 0x32, 0x3a, 0x65, 0x33, 0x3a, 0x34, 0x37, 0x3a, 0x62, 0x38, 0x3a, 0x64, + 0x66, 0x3a, 0x65, 0x38, 0x3a, 0x36, 0x38, 0x3a, 0x63, 0x62, 0x3a, 0x33, + 0x31, 0x3a, 0x64, 0x30, 0x3a, 0x32, 0x65, 0x3a, 0x62, 0x62, 0x3a, 0x33, + 0x61, 0x3a, 0x64, 0x61, 0x3a, 0x32, 0x37, 0x3a, 0x31, 0x35, 0x3a, 0x36, + 0x39, 0x3a, 0x66, 0x35, 0x3a, 0x30, 0x33, 0x3a, 0x34, 0x33, 0x3a, 0x62, + 0x34, 0x3a, 0x36, 0x64, 0x3a, 0x62, 0x33, 0x3a, 0x61, 0x34, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x42, 0x74, 0x6a, 0x43, 0x43, 0x41, + 0x56, 0x75, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x54, 0x42, + 0x6d, 0x79, 0x66, 0x31, 0x58, 0x53, 0x58, 0x4e, 0x6d, 0x59, 0x2f, 0x4f, + 0x77, 0x75, 0x61, 0x32, 0x65, 0x69, 0x65, 0x64, 0x67, 0x50, 0x79, 0x53, + 0x6a, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, + 0x51, 0x51, 0x44, 0x41, 0x6a, 0x41, 0x35, 0x0a, 0x4d, 0x51, 0x73, 0x77, + 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, + 0x55, 0x7a, 0x45, 0x50, 0x4d, 0x41, 0x30, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x68, 0x4d, 0x47, 0x51, 0x57, 0x31, 0x68, 0x65, 0x6d, 0x39, 0x75, + 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, + 0x45, 0x78, 0x42, 0x42, 0x62, 0x57, 0x46, 0x36, 0x62, 0x32, 0x34, 0x67, + 0x0a, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x53, 0x41, + 0x7a, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x31, 0x4d, 0x44, 0x55, + 0x79, 0x4e, 0x6a, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, + 0x58, 0x44, 0x54, 0x51, 0x77, 0x4d, 0x44, 0x55, 0x79, 0x4e, 0x6a, 0x41, + 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x77, 0x4f, 0x54, 0x45, + 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, + 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x44, 0x7a, 0x41, 0x4e, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x42, 0x6b, 0x46, 0x74, 0x59, 0x58, + 0x70, 0x76, 0x62, 0x6a, 0x45, 0x5a, 0x4d, 0x42, 0x63, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x41, 0x78, 0x4d, 0x51, 0x51, 0x57, 0x31, 0x68, 0x65, 0x6d, + 0x39, 0x75, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x0a, 0x51, + 0x30, 0x45, 0x67, 0x4d, 0x7a, 0x42, 0x5a, 0x4d, 0x42, 0x4d, 0x47, 0x42, + 0x79, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x43, + 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x77, 0x45, 0x48, 0x41, + 0x30, 0x49, 0x41, 0x42, 0x43, 0x6d, 0x58, 0x70, 0x38, 0x5a, 0x42, 0x66, + 0x38, 0x41, 0x4e, 0x6d, 0x2b, 0x67, 0x42, 0x47, 0x31, 0x62, 0x47, 0x38, + 0x6c, 0x4b, 0x6c, 0x0a, 0x75, 0x69, 0x32, 0x79, 0x45, 0x75, 0x6a, 0x53, + 0x4c, 0x74, 0x66, 0x36, 0x79, 0x63, 0x58, 0x59, 0x71, 0x6d, 0x30, 0x66, + 0x63, 0x34, 0x45, 0x37, 0x4f, 0x35, 0x68, 0x72, 0x4f, 0x58, 0x77, 0x7a, + 0x70, 0x63, 0x56, 0x4f, 0x68, 0x6f, 0x36, 0x41, 0x46, 0x32, 0x68, 0x69, + 0x52, 0x56, 0x64, 0x39, 0x52, 0x46, 0x67, 0x64, 0x73, 0x7a, 0x66, 0x6c, + 0x5a, 0x77, 0x6a, 0x72, 0x5a, 0x74, 0x36, 0x6a, 0x0a, 0x51, 0x6a, 0x42, + 0x41, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, + 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, + 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, + 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x47, 0x47, 0x4d, 0x42, 0x30, + 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x53, + 0x72, 0x0a, 0x74, 0x74, 0x76, 0x58, 0x42, 0x70, 0x34, 0x33, 0x72, 0x44, + 0x43, 0x47, 0x42, 0x35, 0x46, 0x77, 0x78, 0x35, 0x7a, 0x45, 0x47, 0x62, + 0x46, 0x34, 0x77, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, + 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x67, 0x4e, 0x4a, 0x41, 0x44, + 0x42, 0x47, 0x41, 0x69, 0x45, 0x41, 0x34, 0x49, 0x57, 0x53, 0x6f, 0x78, + 0x65, 0x33, 0x6a, 0x66, 0x6b, 0x72, 0x0a, 0x42, 0x71, 0x57, 0x54, 0x72, + 0x42, 0x71, 0x59, 0x61, 0x47, 0x46, 0x79, 0x2b, 0x75, 0x47, 0x68, 0x30, + 0x50, 0x73, 0x63, 0x65, 0x47, 0x43, 0x6d, 0x51, 0x35, 0x6e, 0x46, 0x75, + 0x4d, 0x51, 0x43, 0x49, 0x51, 0x43, 0x63, 0x41, 0x75, 0x2f, 0x78, 0x6c, + 0x4a, 0x79, 0x7a, 0x6c, 0x76, 0x6e, 0x72, 0x78, 0x69, 0x72, 0x34, 0x74, + 0x69, 0x7a, 0x2b, 0x4f, 0x70, 0x41, 0x55, 0x46, 0x74, 0x65, 0x4d, 0x0a, + 0x59, 0x79, 0x52, 0x49, 0x48, 0x4e, 0x38, 0x77, 0x66, 0x64, 0x56, 0x6f, + 0x4f, 0x77, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x41, 0x6d, 0x61, + 0x7a, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, + 0x34, 0x20, 0x4f, 0x3d, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x0a, 0x23, + 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x34, 0x20, 0x4f, 0x3d, 0x41, 0x6d, 0x61, 0x7a, + 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x34, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x34, 0x33, 0x32, 0x36, 0x36, 0x39, + 0x38, 0x39, 0x37, 0x35, 0x38, 0x30, 0x38, 0x30, 0x37, 0x36, 0x33, 0x39, + 0x37, 0x34, 0x31, 0x30, 0x35, 0x32, 0x30, 0x30, 0x36, 0x33, 0x30, 0x37, + 0x36, 0x33, 0x38, 0x37, 0x37, 0x38, 0x34, 0x39, 0x32, 0x38, 0x34, 0x38, + 0x37, 0x38, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x39, + 0x3a, 0x62, 0x63, 0x3a, 0x32, 0x37, 0x3a, 0x64, 0x35, 0x3a, 0x65, 0x62, + 0x3a, 0x31, 0x37, 0x3a, 0x38, 0x64, 0x3a, 0x30, 0x36, 0x3a, 0x36, 0x61, + 0x3a, 0x36, 0x39, 0x3a, 0x64, 0x35, 0x3a, 0x66, 0x64, 0x3a, 0x38, 0x39, + 0x3a, 0x34, 0x37, 0x3a, 0x62, 0x34, 0x3a, 0x63, 0x64, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x66, 0x36, 0x3a, 0x31, 0x30, 0x3a, + 0x38, 0x34, 0x3a, 0x30, 0x37, 0x3a, 0x64, 0x36, 0x3a, 0x66, 0x38, 0x3a, + 0x62, 0x62, 0x3a, 0x36, 0x37, 0x3a, 0x39, 0x38, 0x3a, 0x30, 0x63, 0x3a, + 0x63, 0x32, 0x3a, 0x65, 0x32, 0x3a, 0x34, 0x34, 0x3a, 0x63, 0x32, 0x3a, + 0x65, 0x62, 0x3a, 0x61, 0x65, 0x3a, 0x31, 0x63, 0x3a, 0x65, 0x66, 0x3a, + 0x36, 0x33, 0x3a, 0x62, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x33, 0x3a, 0x35, 0x64, 0x3a, 0x32, 0x38, + 0x3a, 0x34, 0x31, 0x3a, 0x39, 0x65, 0x3a, 0x64, 0x30, 0x3a, 0x32, 0x30, + 0x3a, 0x32, 0x35, 0x3a, 0x63, 0x66, 0x3a, 0x61, 0x36, 0x3a, 0x39, 0x30, + 0x3a, 0x33, 0x38, 0x3a, 0x63, 0x64, 0x3a, 0x36, 0x32, 0x3a, 0x33, 0x39, + 0x3a, 0x36, 0x32, 0x3a, 0x34, 0x35, 0x3a, 0x38, 0x64, 0x3a, 0x61, 0x35, + 0x3a, 0x63, 0x36, 0x3a, 0x39, 0x35, 0x3a, 0x66, 0x62, 0x3a, 0x64, 0x65, + 0x3a, 0x61, 0x33, 0x3a, 0x63, 0x32, 0x3a, 0x32, 0x62, 0x3a, 0x30, 0x62, + 0x3a, 0x66, 0x62, 0x3a, 0x32, 0x35, 0x3a, 0x38, 0x39, 0x3a, 0x37, 0x30, + 0x3a, 0x39, 0x32, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, + 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x42, + 0x38, 0x6a, 0x43, 0x43, 0x41, 0x58, 0x69, 0x67, 0x41, 0x77, 0x49, 0x42, + 0x41, 0x67, 0x49, 0x54, 0x42, 0x6d, 0x79, 0x66, 0x31, 0x38, 0x47, 0x37, + 0x45, 0x45, 0x77, 0x70, 0x51, 0x2b, 0x56, 0x78, 0x65, 0x33, 0x73, 0x73, + 0x79, 0x42, 0x72, 0x42, 0x44, 0x6a, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, + 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x7a, 0x41, 0x35, + 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x50, 0x4d, 0x41, 0x30, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x47, 0x51, 0x57, 0x31, + 0x68, 0x65, 0x6d, 0x39, 0x75, 0x4d, 0x52, 0x6b, 0x77, 0x46, 0x77, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x42, 0x42, 0x62, 0x57, 0x46, + 0x36, 0x62, 0x32, 0x34, 0x67, 0x0a, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, + 0x42, 0x44, 0x51, 0x53, 0x41, 0x30, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, + 0x45, 0x31, 0x4d, 0x44, 0x55, 0x79, 0x4e, 0x6a, 0x41, 0x77, 0x4d, 0x44, + 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x51, 0x77, 0x4d, 0x44, + 0x55, 0x79, 0x4e, 0x6a, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x46, + 0x6f, 0x77, 0x4f, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x0a, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x44, + 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x42, + 0x6b, 0x46, 0x74, 0x59, 0x58, 0x70, 0x76, 0x62, 0x6a, 0x45, 0x5a, 0x4d, + 0x42, 0x63, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x51, 0x51, + 0x57, 0x31, 0x68, 0x65, 0x6d, 0x39, 0x75, 0x49, 0x46, 0x4a, 0x76, 0x62, + 0x33, 0x51, 0x67, 0x0a, 0x51, 0x30, 0x45, 0x67, 0x4e, 0x44, 0x42, 0x32, + 0x4d, 0x42, 0x41, 0x47, 0x42, 0x79, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, + 0x41, 0x67, 0x45, 0x47, 0x42, 0x53, 0x75, 0x42, 0x42, 0x41, 0x41, 0x69, + 0x41, 0x32, 0x49, 0x41, 0x42, 0x4e, 0x4b, 0x72, 0x69, 0x6a, 0x64, 0x50, + 0x6f, 0x31, 0x4d, 0x4e, 0x2f, 0x73, 0x47, 0x4b, 0x65, 0x30, 0x75, 0x6f, + 0x65, 0x30, 0x5a, 0x4c, 0x59, 0x37, 0x42, 0x69, 0x0a, 0x39, 0x69, 0x30, + 0x62, 0x32, 0x77, 0x68, 0x78, 0x49, 0x64, 0x49, 0x41, 0x36, 0x47, 0x4f, + 0x39, 0x6d, 0x69, 0x66, 0x37, 0x38, 0x44, 0x6c, 0x75, 0x58, 0x65, 0x6f, + 0x39, 0x70, 0x63, 0x6d, 0x42, 0x71, 0x71, 0x4e, 0x62, 0x49, 0x4a, 0x68, + 0x46, 0x58, 0x52, 0x62, 0x62, 0x2f, 0x65, 0x67, 0x51, 0x62, 0x65, 0x4f, + 0x63, 0x34, 0x4f, 0x4f, 0x39, 0x58, 0x34, 0x52, 0x69, 0x38, 0x33, 0x42, + 0x6b, 0x0a, 0x4d, 0x36, 0x44, 0x4c, 0x4a, 0x43, 0x39, 0x77, 0x75, 0x6f, + 0x69, 0x68, 0x4b, 0x71, 0x42, 0x31, 0x2b, 0x49, 0x47, 0x75, 0x59, 0x67, + 0x62, 0x45, 0x67, 0x64, 0x73, 0x35, 0x62, 0x69, 0x6d, 0x77, 0x48, 0x76, + 0x6f, 0x75, 0x58, 0x4b, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77, 0x44, 0x77, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, + 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x0a, 0x2f, 0x7a, 0x41, 0x4f, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, + 0x41, 0x4d, 0x43, 0x41, 0x59, 0x59, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4e, 0x50, 0x73, 0x78, + 0x7a, 0x70, 0x6c, 0x62, 0x73, 0x7a, 0x68, 0x32, 0x6e, 0x61, 0x61, 0x56, + 0x76, 0x75, 0x63, 0x38, 0x34, 0x5a, 0x74, 0x56, 0x2b, 0x57, 0x42, 0x0a, + 0x4d, 0x41, 0x6f, 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, + 0x42, 0x41, 0x4d, 0x44, 0x41, 0x32, 0x67, 0x41, 0x4d, 0x47, 0x55, 0x43, + 0x4d, 0x44, 0x71, 0x4c, 0x49, 0x66, 0x47, 0x39, 0x66, 0x68, 0x47, 0x74, + 0x30, 0x4f, 0x39, 0x59, 0x6c, 0x69, 0x2f, 0x57, 0x36, 0x35, 0x31, 0x2b, + 0x6b, 0x49, 0x30, 0x72, 0x7a, 0x32, 0x5a, 0x56, 0x77, 0x79, 0x7a, 0x6a, + 0x4b, 0x4b, 0x6c, 0x77, 0x0a, 0x43, 0x6b, 0x63, 0x4f, 0x38, 0x44, 0x64, + 0x5a, 0x45, 0x76, 0x38, 0x74, 0x6d, 0x5a, 0x51, 0x6f, 0x54, 0x69, 0x70, + 0x50, 0x4e, 0x55, 0x30, 0x7a, 0x57, 0x67, 0x49, 0x78, 0x41, 0x4f, 0x70, + 0x31, 0x41, 0x45, 0x34, 0x37, 0x78, 0x44, 0x71, 0x55, 0x45, 0x70, 0x48, + 0x4a, 0x57, 0x45, 0x61, 0x64, 0x49, 0x52, 0x4e, 0x79, 0x70, 0x34, 0x69, + 0x63, 0x69, 0x75, 0x52, 0x4d, 0x53, 0x74, 0x75, 0x57, 0x0a, 0x31, 0x4b, + 0x79, 0x4c, 0x61, 0x32, 0x74, 0x4a, 0x45, 0x6c, 0x4d, 0x7a, 0x72, 0x64, + 0x66, 0x6b, 0x76, 0x69, 0x54, 0x38, 0x74, 0x51, 0x70, 0x32, 0x31, 0x4b, + 0x57, 0x38, 0x45, 0x41, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, + 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x4c, + 0x75, 0x78, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x32, 0x20, 0x4f, 0x3d, + 0x4c, 0x75, 0x78, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x2e, 0x41, + 0x2e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x4c, 0x75, 0x78, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x32, 0x20, 0x4f, 0x3d, 0x4c, 0x75, 0x78, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x4c, 0x75, 0x78, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x35, 0x39, 0x39, 0x31, 0x34, 0x33, 0x33, 0x38, 0x32, + 0x32, 0x35, 0x37, 0x33, 0x34, 0x31, 0x34, 0x37, 0x31, 0x32, 0x33, 0x39, + 0x34, 0x31, 0x30, 0x35, 0x38, 0x33, 0x37, 0x36, 0x37, 0x38, 0x38, 0x31, + 0x31, 0x30, 0x33, 0x30, 0x35, 0x38, 0x32, 0x32, 0x34, 0x38, 0x39, 0x35, + 0x32, 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x32, + 0x3a, 0x65, 0x31, 0x3a, 0x30, 0x39, 0x3a, 0x30, 0x30, 0x3a, 0x36, 0x31, + 0x3a, 0x61, 0x66, 0x3a, 0x66, 0x37, 0x3a, 0x66, 0x31, 0x3a, 0x39, 0x31, + 0x3a, 0x36, 0x66, 0x3a, 0x63, 0x34, 0x3a, 0x61, 0x64, 0x3a, 0x38, 0x64, + 0x3a, 0x35, 0x65, 0x3a, 0x33, 0x62, 0x3a, 0x37, 0x63, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x65, 0x3a, 0x30, 0x65, 0x3a, + 0x35, 0x36, 0x3a, 0x31, 0x39, 0x3a, 0x30, 0x61, 0x3a, 0x64, 0x31, 0x3a, + 0x38, 0x62, 0x3a, 0x32, 0x35, 0x3a, 0x39, 0x38, 0x3a, 0x62, 0x32, 0x3a, + 0x30, 0x34, 0x3a, 0x34, 0x34, 0x3a, 0x66, 0x66, 0x3a, 0x36, 0x36, 0x3a, + 0x38, 0x61, 0x3a, 0x30, 0x34, 0x3a, 0x31, 0x37, 0x3a, 0x39, 0x39, 0x3a, + 0x35, 0x66, 0x3a, 0x33, 0x66, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x34, 0x3a, 0x34, 0x35, 0x3a, 0x35, 0x66, + 0x3a, 0x37, 0x31, 0x3a, 0x32, 0x39, 0x3a, 0x63, 0x32, 0x3a, 0x30, 0x62, + 0x3a, 0x31, 0x34, 0x3a, 0x34, 0x37, 0x3a, 0x63, 0x34, 0x3a, 0x31, 0x38, + 0x3a, 0x66, 0x39, 0x3a, 0x39, 0x37, 0x3a, 0x31, 0x36, 0x3a, 0x38, 0x66, + 0x3a, 0x32, 0x34, 0x3a, 0x63, 0x35, 0x3a, 0x38, 0x66, 0x3a, 0x63, 0x35, + 0x3a, 0x30, 0x32, 0x3a, 0x33, 0x62, 0x3a, 0x66, 0x35, 0x3a, 0x64, 0x61, + 0x3a, 0x35, 0x62, 0x3a, 0x65, 0x32, 0x3a, 0x65, 0x62, 0x3a, 0x36, 0x65, + 0x3a, 0x31, 0x64, 0x3a, 0x64, 0x38, 0x3a, 0x39, 0x30, 0x3a, 0x32, 0x65, + 0x3a, 0x64, 0x35, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, + 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, + 0x77, 0x7a, 0x43, 0x43, 0x41, 0x36, 0x75, 0x67, 0x41, 0x77, 0x49, 0x42, + 0x41, 0x67, 0x49, 0x55, 0x43, 0x6e, 0x36, 0x6d, 0x33, 0x30, 0x74, 0x45, + 0x6e, 0x74, 0x70, 0x71, 0x4a, 0x49, 0x57, 0x65, 0x35, 0x72, 0x67, 0x56, + 0x30, 0x78, 0x5a, 0x2f, 0x75, 0x37, 0x45, 0x77, 0x44, 0x51, 0x59, 0x4a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, + 0x0a, 0x42, 0x51, 0x41, 0x77, 0x52, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x54, 0x46, 0x55, + 0x78, 0x46, 0x6a, 0x41, 0x55, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, + 0x4d, 0x44, 0x55, 0x78, 0x31, 0x65, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, + 0x30, 0x49, 0x46, 0x4d, 0x75, 0x51, 0x53, 0x34, 0x78, 0x48, 0x7a, 0x41, + 0x64, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x4d, 0x4d, 0x46, 0x6b, + 0x78, 0x31, 0x65, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x45, + 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62, 0x43, 0x42, 0x53, 0x62, 0x32, + 0x39, 0x30, 0x49, 0x44, 0x49, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, + 0x55, 0x77, 0x4d, 0x7a, 0x41, 0x31, 0x4d, 0x54, 0x4d, 0x79, 0x4d, 0x54, + 0x55, 0x33, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x55, 0x77, 0x0a, 0x4d, + 0x7a, 0x41, 0x31, 0x4d, 0x54, 0x4d, 0x79, 0x4d, 0x54, 0x55, 0x33, 0x57, + 0x6a, 0x42, 0x47, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x4d, 0x56, 0x54, 0x45, 0x57, 0x4d, + 0x42, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x4e, 0x54, + 0x48, 0x56, 0x34, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x55, + 0x79, 0x35, 0x42, 0x0a, 0x4c, 0x6a, 0x45, 0x66, 0x4d, 0x42, 0x30, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x57, 0x54, 0x48, 0x56, 0x34, + 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x67, 0x52, 0x32, 0x78, 0x76, + 0x59, 0x6d, 0x46, 0x73, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, + 0x4d, 0x6a, 0x43, 0x43, 0x41, 0x69, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x0a, 0x41, 0x51, 0x45, + 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x50, 0x41, 0x44, 0x43, + 0x43, 0x41, 0x67, 0x6f, 0x43, 0x67, 0x67, 0x49, 0x42, 0x41, 0x4e, 0x65, + 0x46, 0x6c, 0x37, 0x38, 0x52, 0x6d, 0x4f, 0x6e, 0x77, 0x59, 0x6f, 0x4e, + 0x4d, 0x50, 0x49, 0x66, 0x35, 0x55, 0x32, 0x6f, 0x33, 0x43, 0x2f, 0x49, + 0x50, 0x50, 0x49, 0x66, 0x4f, 0x62, 0x39, 0x77, 0x6d, 0x4b, 0x62, 0x33, + 0x46, 0x0a, 0x69, 0x62, 0x72, 0x4a, 0x67, 0x7a, 0x33, 0x33, 0x37, 0x73, + 0x70, 0x62, 0x78, 0x6d, 0x31, 0x4a, 0x63, 0x37, 0x54, 0x4a, 0x52, 0x71, + 0x4d, 0x62, 0x4e, 0x42, 0x4d, 0x2f, 0x77, 0x59, 0x6c, 0x46, 0x56, 0x2f, + 0x54, 0x5a, 0x73, 0x66, 0x73, 0x32, 0x5a, 0x55, 0x76, 0x37, 0x43, 0x4f, + 0x4a, 0x49, 0x63, 0x52, 0x48, 0x49, 0x62, 0x6a, 0x75, 0x65, 0x6e, 0x64, + 0x2b, 0x4a, 0x5a, 0x54, 0x65, 0x6d, 0x0a, 0x68, 0x66, 0x59, 0x37, 0x52, + 0x42, 0x69, 0x32, 0x78, 0x6a, 0x63, 0x77, 0x59, 0x6b, 0x53, 0x53, 0x6c, + 0x32, 0x6c, 0x39, 0x51, 0x6a, 0x41, 0x6b, 0x35, 0x41, 0x30, 0x4d, 0x69, + 0x57, 0x74, 0x6a, 0x33, 0x73, 0x58, 0x68, 0x33, 0x30, 0x36, 0x70, 0x46, + 0x47, 0x78, 0x54, 0x34, 0x47, 0x48, 0x4f, 0x39, 0x68, 0x63, 0x76, 0x48, + 0x54, 0x79, 0x39, 0x35, 0x69, 0x4a, 0x4d, 0x48, 0x5a, 0x50, 0x31, 0x0a, + 0x45, 0x4d, 0x53, 0x68, 0x64, 0x75, 0x78, 0x71, 0x33, 0x73, 0x56, 0x73, + 0x33, 0x35, 0x61, 0x30, 0x56, 0x6b, 0x42, 0x43, 0x77, 0x47, 0x4b, 0x53, + 0x4d, 0x4b, 0x45, 0x74, 0x46, 0x5a, 0x53, 0x67, 0x30, 0x69, 0x41, 0x47, + 0x43, 0x57, 0x35, 0x71, 0x62, 0x65, 0x58, 0x72, 0x74, 0x37, 0x37, 0x55, + 0x38, 0x50, 0x45, 0x56, 0x66, 0x49, 0x76, 0x6d, 0x54, 0x72, 0x6f, 0x54, + 0x7a, 0x45, 0x73, 0x6e, 0x0a, 0x58, 0x70, 0x6b, 0x38, 0x46, 0x31, 0x32, + 0x50, 0x67, 0x58, 0x38, 0x7a, 0x50, 0x55, 0x2f, 0x54, 0x50, 0x78, 0x76, + 0x73, 0x58, 0x44, 0x2f, 0x77, 0x50, 0x45, 0x78, 0x31, 0x62, 0x76, 0x4b, + 0x6d, 0x31, 0x5a, 0x33, 0x61, 0x4c, 0x51, 0x64, 0x6a, 0x41, 0x73, 0x5a, + 0x79, 0x36, 0x5a, 0x53, 0x38, 0x54, 0x45, 0x6d, 0x56, 0x54, 0x34, 0x68, + 0x53, 0x79, 0x4e, 0x76, 0x6f, 0x61, 0x59, 0x4c, 0x34, 0x0a, 0x7a, 0x44, + 0x52, 0x62, 0x49, 0x76, 0x43, 0x47, 0x70, 0x34, 0x6d, 0x39, 0x53, 0x41, + 0x70, 0x74, 0x5a, 0x6f, 0x46, 0x74, 0x79, 0x4d, 0x68, 0x6b, 0x2b, 0x77, + 0x48, 0x68, 0x39, 0x4f, 0x48, 0x65, 0x32, 0x5a, 0x37, 0x64, 0x32, 0x31, + 0x76, 0x55, 0x4b, 0x70, 0x6b, 0x6d, 0x46, 0x52, 0x73, 0x65, 0x54, 0x4a, + 0x49, 0x70, 0x67, 0x70, 0x37, 0x56, 0x6b, 0x6f, 0x47, 0x53, 0x51, 0x58, + 0x41, 0x5a, 0x0a, 0x39, 0x36, 0x54, 0x6c, 0x6b, 0x30, 0x75, 0x38, 0x64, + 0x32, 0x63, 0x78, 0x33, 0x52, 0x7a, 0x39, 0x4d, 0x58, 0x41, 0x4e, 0x46, + 0x35, 0x6b, 0x4d, 0x2b, 0x51, 0x77, 0x35, 0x47, 0x53, 0x6f, 0x58, 0x74, + 0x54, 0x42, 0x78, 0x56, 0x64, 0x55, 0x50, 0x72, 0x6c, 0x6a, 0x68, 0x50, + 0x53, 0x38, 0x30, 0x6d, 0x38, 0x2b, 0x66, 0x39, 0x6e, 0x69, 0x46, 0x77, + 0x70, 0x4e, 0x36, 0x63, 0x6a, 0x35, 0x6d, 0x0a, 0x6a, 0x35, 0x77, 0x57, + 0x45, 0x57, 0x43, 0x50, 0x6e, 0x6f, 0x6c, 0x76, 0x5a, 0x37, 0x37, 0x67, + 0x52, 0x31, 0x6f, 0x37, 0x44, 0x4a, 0x70, 0x6e, 0x69, 0x38, 0x39, 0x47, + 0x78, 0x71, 0x34, 0x34, 0x6f, 0x2f, 0x4b, 0x6e, 0x76, 0x4f, 0x62, 0x57, + 0x68, 0x57, 0x73, 0x7a, 0x4a, 0x48, 0x41, 0x69, 0x53, 0x38, 0x73, 0x49, + 0x6d, 0x37, 0x76, 0x49, 0x2b, 0x41, 0x49, 0x70, 0x48, 0x62, 0x34, 0x67, + 0x0a, 0x44, 0x45, 0x61, 0x2f, 0x61, 0x34, 0x65, 0x62, 0x73, 0x79, 0x70, + 0x6d, 0x51, 0x6a, 0x56, 0x47, 0x62, 0x4b, 0x71, 0x36, 0x72, 0x66, 0x6d, + 0x59, 0x65, 0x2b, 0x6c, 0x51, 0x56, 0x52, 0x51, 0x78, 0x76, 0x37, 0x48, + 0x61, 0x4c, 0x65, 0x32, 0x41, 0x72, 0x57, 0x67, 0x6b, 0x2b, 0x32, 0x6d, + 0x72, 0x32, 0x48, 0x45, 0x54, 0x4d, 0x4f, 0x5a, 0x6e, 0x73, 0x34, 0x64, + 0x41, 0x2f, 0x59, 0x6c, 0x2b, 0x0a, 0x38, 0x6b, 0x50, 0x52, 0x45, 0x64, + 0x38, 0x76, 0x5a, 0x53, 0x39, 0x6b, 0x7a, 0x6c, 0x38, 0x55, 0x75, 0x62, + 0x47, 0x2f, 0x4d, 0x62, 0x32, 0x48, 0x65, 0x46, 0x70, 0x5a, 0x5a, 0x59, + 0x69, 0x71, 0x2f, 0x46, 0x6b, 0x79, 0x53, 0x49, 0x62, 0x57, 0x54, 0x4c, + 0x6b, 0x70, 0x53, 0x35, 0x58, 0x54, 0x64, 0x76, 0x4e, 0x33, 0x4a, 0x57, + 0x31, 0x43, 0x48, 0x44, 0x69, 0x44, 0x54, 0x66, 0x32, 0x6a, 0x0a, 0x58, + 0x35, 0x74, 0x2f, 0x4c, 0x61, 0x78, 0x35, 0x47, 0x77, 0x35, 0x43, 0x4d, + 0x5a, 0x64, 0x6a, 0x70, 0x50, 0x75, 0x4b, 0x61, 0x64, 0x55, 0x69, 0x44, + 0x54, 0x53, 0x51, 0x4d, 0x43, 0x36, 0x6f, 0x74, 0x4f, 0x42, 0x74, 0x74, + 0x70, 0x53, 0x73, 0x76, 0x49, 0x74, 0x4f, 0x31, 0x33, 0x44, 0x38, 0x78, + 0x54, 0x69, 0x4f, 0x5a, 0x43, 0x58, 0x68, 0x54, 0x54, 0x6d, 0x51, 0x7a, + 0x73, 0x6d, 0x48, 0x0a, 0x68, 0x46, 0x68, 0x78, 0x41, 0x67, 0x4d, 0x42, + 0x41, 0x41, 0x47, 0x6a, 0x67, 0x61, 0x67, 0x77, 0x67, 0x61, 0x55, 0x77, + 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, + 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x42, 0x43, + 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x41, 0x45, 0x4f, 0x7a, 0x41, 0x35, + 0x4d, 0x44, 0x63, 0x47, 0x42, 0x79, 0x75, 0x42, 0x0a, 0x4b, 0x77, 0x45, + 0x42, 0x41, 0x51, 0x6f, 0x77, 0x4c, 0x44, 0x41, 0x71, 0x42, 0x67, 0x67, + 0x72, 0x42, 0x67, 0x45, 0x46, 0x42, 0x51, 0x63, 0x43, 0x41, 0x52, 0x59, + 0x65, 0x61, 0x48, 0x52, 0x30, 0x63, 0x48, 0x4d, 0x36, 0x4c, 0x79, 0x39, + 0x79, 0x5a, 0x58, 0x42, 0x76, 0x63, 0x32, 0x6c, 0x30, 0x62, 0x33, 0x4a, + 0x35, 0x4c, 0x6d, 0x78, 0x31, 0x65, 0x48, 0x52, 0x79, 0x64, 0x58, 0x4e, + 0x30, 0x0a, 0x4c, 0x6d, 0x78, 0x31, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, + 0x49, 0x42, 0x42, 0x6a, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, + 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x54, 0x2f, 0x47, 0x43, + 0x68, 0x32, 0x2b, 0x55, 0x67, 0x46, 0x4c, 0x4b, 0x47, 0x75, 0x38, 0x53, + 0x73, 0x62, 0x4b, 0x37, 0x4a, 0x54, 0x0a, 0x2b, 0x45, 0x74, 0x38, 0x73, + 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, + 0x67, 0x51, 0x55, 0x2f, 0x78, 0x67, 0x6f, 0x64, 0x76, 0x6c, 0x49, 0x42, + 0x53, 0x79, 0x68, 0x72, 0x76, 0x45, 0x72, 0x47, 0x79, 0x75, 0x79, 0x55, + 0x2f, 0x68, 0x4c, 0x66, 0x4c, 0x4d, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x0a, + 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x42, 0x41, 0x47, 0x6f, 0x5a, + 0x46, 0x4f, 0x31, 0x75, 0x65, 0x63, 0x45, 0x73, 0x68, 0x39, 0x51, 0x4e, + 0x63, 0x48, 0x37, 0x58, 0x39, 0x6e, 0x6a, 0x4a, 0x43, 0x77, 0x52, 0x4f, + 0x78, 0x4c, 0x48, 0x4f, 0x6b, 0x33, 0x44, 0x2b, 0x73, 0x46, 0x54, 0x41, + 0x4d, 0x73, 0x32, 0x5a, 0x4d, 0x47, 0x51, 0x58, 0x76, 0x77, 0x2f, 0x6c, + 0x34, 0x6a, 0x50, 0x39, 0x0a, 0x42, 0x7a, 0x5a, 0x41, 0x63, 0x67, 0x34, + 0x61, 0x74, 0x6d, 0x70, 0x5a, 0x31, 0x67, 0x44, 0x6c, 0x61, 0x43, 0x44, + 0x64, 0x4c, 0x6e, 0x49, 0x4e, 0x48, 0x32, 0x70, 0x6b, 0x4d, 0x53, 0x43, + 0x45, 0x66, 0x55, 0x6d, 0x6d, 0x57, 0x6a, 0x66, 0x72, 0x52, 0x63, 0x6d, + 0x46, 0x39, 0x64, 0x54, 0x48, 0x46, 0x35, 0x6b, 0x48, 0x35, 0x70, 0x74, + 0x56, 0x35, 0x41, 0x7a, 0x6f, 0x71, 0x62, 0x54, 0x4f, 0x0a, 0x6a, 0x46, + 0x75, 0x31, 0x45, 0x56, 0x7a, 0x50, 0x69, 0x67, 0x34, 0x4e, 0x31, 0x71, + 0x78, 0x33, 0x67, 0x66, 0x34, 0x79, 0x6e, 0x43, 0x53, 0x65, 0x63, 0x73, + 0x35, 0x55, 0x38, 0x39, 0x42, 0x76, 0x6f, 0x6c, 0x62, 0x57, 0x37, 0x4d, + 0x4d, 0x33, 0x4c, 0x47, 0x56, 0x59, 0x76, 0x6c, 0x63, 0x41, 0x47, 0x76, + 0x49, 0x31, 0x2b, 0x75, 0x74, 0x37, 0x4d, 0x56, 0x33, 0x43, 0x77, 0x52, + 0x49, 0x39, 0x0a, 0x6c, 0x6f, 0x47, 0x49, 0x6c, 0x6f, 0x6e, 0x42, 0x57, + 0x56, 0x78, 0x36, 0x35, 0x6e, 0x39, 0x77, 0x4e, 0x4f, 0x65, 0x44, 0x34, + 0x72, 0x48, 0x68, 0x34, 0x62, 0x68, 0x59, 0x37, 0x39, 0x53, 0x56, 0x35, + 0x47, 0x43, 0x63, 0x38, 0x4a, 0x61, 0x58, 0x63, 0x6f, 0x7a, 0x72, 0x68, + 0x41, 0x49, 0x75, 0x5a, 0x59, 0x2b, 0x6b, 0x74, 0x39, 0x4a, 0x2f, 0x5a, + 0x39, 0x33, 0x49, 0x30, 0x35, 0x35, 0x63, 0x0a, 0x71, 0x71, 0x6d, 0x6b, + 0x6f, 0x43, 0x55, 0x55, 0x42, 0x70, 0x76, 0x73, 0x54, 0x33, 0x34, 0x74, + 0x43, 0x33, 0x38, 0x64, 0x64, 0x66, 0x45, 0x7a, 0x32, 0x4f, 0x33, 0x4f, + 0x75, 0x48, 0x56, 0x74, 0x50, 0x6c, 0x75, 0x35, 0x6d, 0x42, 0x30, 0x78, + 0x44, 0x56, 0x62, 0x59, 0x51, 0x77, 0x38, 0x77, 0x6b, 0x62, 0x49, 0x45, + 0x61, 0x39, 0x31, 0x57, 0x76, 0x70, 0x57, 0x41, 0x56, 0x57, 0x65, 0x2b, + 0x0a, 0x32, 0x4d, 0x32, 0x44, 0x32, 0x52, 0x6a, 0x75, 0x4c, 0x67, 0x2b, + 0x47, 0x4c, 0x5a, 0x4b, 0x65, 0x63, 0x42, 0x50, 0x73, 0x33, 0x6c, 0x48, + 0x4a, 0x51, 0x33, 0x67, 0x43, 0x70, 0x55, 0x33, 0x49, 0x2b, 0x56, 0x2f, + 0x45, 0x6b, 0x56, 0x68, 0x47, 0x46, 0x6e, 0x64, 0x61, 0x64, 0x4b, 0x70, + 0x41, 0x76, 0x41, 0x65, 0x66, 0x4d, 0x4c, 0x6d, 0x78, 0x39, 0x78, 0x49, + 0x58, 0x33, 0x65, 0x50, 0x2f, 0x0a, 0x4a, 0x45, 0x41, 0x64, 0x65, 0x6d, + 0x72, 0x52, 0x54, 0x78, 0x67, 0x4b, 0x71, 0x70, 0x41, 0x64, 0x36, 0x30, + 0x41, 0x65, 0x33, 0x36, 0x45, 0x65, 0x52, 0x4a, 0x49, 0x51, 0x6d, 0x76, + 0x4b, 0x4e, 0x34, 0x64, 0x46, 0x4c, 0x52, 0x70, 0x37, 0x6f, 0x52, 0x55, + 0x4b, 0x58, 0x36, 0x6b, 0x57, 0x5a, 0x38, 0x2b, 0x78, 0x6d, 0x31, 0x51, + 0x4c, 0x36, 0x38, 0x71, 0x5a, 0x4b, 0x4a, 0x4b, 0x72, 0x65, 0x0a, 0x7a, + 0x72, 0x6e, 0x4b, 0x2b, 0x54, 0x2b, 0x54, 0x62, 0x2f, 0x6d, 0x6a, 0x75, + 0x75, 0x71, 0x6c, 0x50, 0x70, 0x6d, 0x74, 0x2f, 0x66, 0x39, 0x37, 0x6d, + 0x66, 0x56, 0x6c, 0x37, 0x76, 0x42, 0x5a, 0x4b, 0x47, 0x66, 0x58, 0x6b, + 0x4a, 0x57, 0x6b, 0x45, 0x34, 0x53, 0x70, 0x68, 0x4d, 0x48, 0x6f, 0x7a, + 0x73, 0x35, 0x31, 0x6b, 0x32, 0x4d, 0x61, 0x76, 0x44, 0x7a, 0x71, 0x31, + 0x57, 0x51, 0x66, 0x0a, 0x4c, 0x53, 0x6f, 0x53, 0x4f, 0x63, 0x62, 0x44, + 0x57, 0x6a, 0x4c, 0x74, 0x52, 0x35, 0x45, 0x57, 0x44, 0x72, 0x77, 0x34, + 0x77, 0x56, 0x44, 0x65, 0x6a, 0x38, 0x6f, 0x71, 0x6b, 0x44, 0x51, 0x63, + 0x37, 0x6b, 0x47, 0x55, 0x6e, 0x46, 0x34, 0x5a, 0x4c, 0x76, 0x68, 0x46, + 0x53, 0x5a, 0x6c, 0x30, 0x6b, 0x62, 0x41, 0x45, 0x62, 0x2b, 0x4d, 0x45, + 0x57, 0x72, 0x47, 0x72, 0x4b, 0x71, 0x76, 0x2b, 0x0a, 0x78, 0x39, 0x43, + 0x57, 0x74, 0x74, 0x72, 0x68, 0x53, 0x6d, 0x51, 0x47, 0x62, 0x6d, 0x42, + 0x4e, 0x76, 0x55, 0x4a, 0x4f, 0x2f, 0x33, 0x6a, 0x61, 0x4a, 0x4d, 0x6f, + 0x62, 0x74, 0x4e, 0x65, 0x57, 0x4f, 0x57, 0x79, 0x75, 0x38, 0x51, 0x36, + 0x71, 0x70, 0x33, 0x31, 0x49, 0x69, 0x79, 0x42, 0x4d, 0x7a, 0x32, 0x54, + 0x57, 0x75, 0x4a, 0x64, 0x47, 0x73, 0x45, 0x37, 0x52, 0x4b, 0x6c, 0x59, + 0x36, 0x0a, 0x6f, 0x4a, 0x4f, 0x39, 0x72, 0x34, 0x41, 0x6b, 0x34, 0x41, + 0x70, 0x2b, 0x35, 0x38, 0x72, 0x56, 0x79, 0x75, 0x69, 0x46, 0x56, 0x64, + 0x77, 0x32, 0x4b, 0x75, 0x47, 0x55, 0x61, 0x4a, 0x50, 0x48, 0x5a, 0x6e, + 0x4a, 0x45, 0x44, 0x34, 0x41, 0x68, 0x4d, 0x6d, 0x77, 0x6c, 0x78, 0x79, + 0x4f, 0x41, 0x67, 0x77, 0x72, 0x72, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, + 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x54, + 0x55, 0x42, 0x49, 0x54, 0x41, 0x4b, 0x20, 0x4b, 0x61, 0x6d, 0x75, 0x20, + 0x53, 0x4d, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x4b, 0x6f, 0x6b, 0x20, 0x53, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x6b, 0x61, 0x73, 0x69, 0x20, 0x2d, + 0x20, 0x53, 0x75, 0x72, 0x75, 0x6d, 0x20, 0x31, 0x20, 0x4f, 0x3d, 0x54, + 0x75, 0x72, 0x6b, 0x69, 0x79, 0x65, 0x20, 0x42, 0x69, 0x6c, 0x69, 0x6d, + 0x73, 0x65, 0x6c, 0x20, 0x76, 0x65, 0x20, 0x54, 0x65, 0x6b, 0x6e, 0x6f, + 0x6c, 0x6f, 0x6a, 0x69, 0x6b, 0x20, 0x41, 0x72, 0x61, 0x73, 0x74, 0x69, + 0x72, 0x6d, 0x61, 0x20, 0x4b, 0x75, 0x72, 0x75, 0x6d, 0x75, 0x20, 0x2d, + 0x20, 0x54, 0x55, 0x42, 0x49, 0x54, 0x41, 0x4b, 0x20, 0x4f, 0x55, 0x3d, + 0x4b, 0x61, 0x6d, 0x75, 0x20, 0x53, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x6b, 0x61, 0x73, 0x79, 0x6f, 0x6e, 0x20, 0x4d, 0x65, 0x72, 0x6b, 0x65, + 0x7a, 0x69, 0x20, 0x2d, 0x20, 0x4b, 0x61, 0x6d, 0x75, 0x20, 0x53, 0x4d, + 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x54, 0x55, 0x42, 0x49, 0x54, 0x41, 0x4b, 0x20, 0x4b, + 0x61, 0x6d, 0x75, 0x20, 0x53, 0x4d, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x4b, + 0x6f, 0x6b, 0x20, 0x53, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x6b, 0x61, + 0x73, 0x69, 0x20, 0x2d, 0x20, 0x53, 0x75, 0x72, 0x75, 0x6d, 0x20, 0x31, + 0x20, 0x4f, 0x3d, 0x54, 0x75, 0x72, 0x6b, 0x69, 0x79, 0x65, 0x20, 0x42, + 0x69, 0x6c, 0x69, 0x6d, 0x73, 0x65, 0x6c, 0x20, 0x76, 0x65, 0x20, 0x54, + 0x65, 0x6b, 0x6e, 0x6f, 0x6c, 0x6f, 0x6a, 0x69, 0x6b, 0x20, 0x41, 0x72, + 0x61, 0x73, 0x74, 0x69, 0x72, 0x6d, 0x61, 0x20, 0x4b, 0x75, 0x72, 0x75, + 0x6d, 0x75, 0x20, 0x2d, 0x20, 0x54, 0x55, 0x42, 0x49, 0x54, 0x41, 0x4b, + 0x20, 0x4f, 0x55, 0x3d, 0x4b, 0x61, 0x6d, 0x75, 0x20, 0x53, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x6b, 0x61, 0x73, 0x79, 0x6f, 0x6e, 0x20, 0x4d, + 0x65, 0x72, 0x6b, 0x65, 0x7a, 0x69, 0x20, 0x2d, 0x20, 0x4b, 0x61, 0x6d, + 0x75, 0x20, 0x53, 0x4d, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x54, 0x55, 0x42, 0x49, 0x54, 0x41, 0x4b, 0x20, 0x4b, + 0x61, 0x6d, 0x75, 0x20, 0x53, 0x4d, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x4b, + 0x6f, 0x6b, 0x20, 0x53, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x6b, 0x61, + 0x73, 0x69, 0x20, 0x2d, 0x20, 0x53, 0x75, 0x72, 0x75, 0x6d, 0x20, 0x31, + 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, + 0x31, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x63, 0x3a, + 0x30, 0x30, 0x3a, 0x38, 0x31, 0x3a, 0x64, 0x63, 0x3a, 0x36, 0x39, 0x3a, + 0x32, 0x66, 0x3a, 0x33, 0x65, 0x3a, 0x32, 0x66, 0x3a, 0x62, 0x30, 0x3a, + 0x33, 0x62, 0x3a, 0x66, 0x36, 0x3a, 0x33, 0x64, 0x3a, 0x35, 0x61, 0x3a, + 0x39, 0x31, 0x3a, 0x38, 0x65, 0x3a, 0x34, 0x39, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x31, 0x3a, 0x34, 0x33, 0x3a, 0x36, + 0x34, 0x3a, 0x39, 0x62, 0x3a, 0x65, 0x63, 0x3a, 0x63, 0x65, 0x3a, 0x32, + 0x37, 0x3a, 0x65, 0x63, 0x3a, 0x65, 0x64, 0x3a, 0x33, 0x61, 0x3a, 0x33, + 0x66, 0x3a, 0x30, 0x62, 0x3a, 0x38, 0x66, 0x3a, 0x30, 0x64, 0x3a, 0x65, + 0x34, 0x3a, 0x65, 0x38, 0x3a, 0x39, 0x31, 0x3a, 0x64, 0x64, 0x3a, 0x65, + 0x65, 0x3a, 0x63, 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, + 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x34, 0x36, 0x3a, 0x65, 0x64, 0x3a, 0x63, 0x33, 0x3a, + 0x36, 0x38, 0x3a, 0x39, 0x30, 0x3a, 0x34, 0x36, 0x3a, 0x64, 0x35, 0x3a, + 0x33, 0x61, 0x3a, 0x34, 0x35, 0x3a, 0x33, 0x66, 0x3a, 0x62, 0x33, 0x3a, + 0x31, 0x30, 0x3a, 0x34, 0x61, 0x3a, 0x62, 0x38, 0x3a, 0x30, 0x64, 0x3a, + 0x63, 0x61, 0x3a, 0x65, 0x63, 0x3a, 0x36, 0x35, 0x3a, 0x38, 0x62, 0x3a, + 0x32, 0x36, 0x3a, 0x36, 0x30, 0x3a, 0x65, 0x61, 0x3a, 0x31, 0x36, 0x3a, + 0x32, 0x39, 0x3a, 0x64, 0x64, 0x3a, 0x37, 0x65, 0x3a, 0x38, 0x36, 0x3a, + 0x37, 0x39, 0x3a, 0x39, 0x30, 0x3a, 0x36, 0x34, 0x3a, 0x38, 0x37, 0x3a, + 0x31, 0x36, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, + 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x59, + 0x7a, 0x43, 0x43, 0x41, 0x30, 0x75, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, + 0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, + 0x44, 0x43, 0x42, 0x30, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x46, 0x49, 0x78, 0x0a, + 0x47, 0x44, 0x41, 0x57, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x54, + 0x44, 0x30, 0x64, 0x6c, 0x59, 0x6e, 0x70, 0x6c, 0x49, 0x43, 0x30, 0x67, + 0x53, 0x32, 0x39, 0x6a, 0x59, 0x57, 0x56, 0x73, 0x61, 0x54, 0x46, 0x43, + 0x4d, 0x45, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x35, + 0x56, 0x48, 0x56, 0x79, 0x61, 0x32, 0x6c, 0x35, 0x5a, 0x53, 0x42, 0x43, + 0x61, 0x57, 0x78, 0x70, 0x0a, 0x62, 0x58, 0x4e, 0x6c, 0x62, 0x43, 0x42, + 0x32, 0x5a, 0x53, 0x42, 0x55, 0x5a, 0x57, 0x74, 0x75, 0x62, 0x32, 0x78, + 0x76, 0x61, 0x6d, 0x6c, 0x72, 0x49, 0x45, 0x46, 0x79, 0x59, 0x58, 0x4e, + 0x30, 0x61, 0x58, 0x4a, 0x74, 0x59, 0x53, 0x42, 0x4c, 0x64, 0x58, 0x4a, + 0x31, 0x62, 0x58, 0x55, 0x67, 0x4c, 0x53, 0x42, 0x55, 0x56, 0x55, 0x4a, + 0x4a, 0x56, 0x45, 0x46, 0x4c, 0x4d, 0x53, 0x30, 0x77, 0x0a, 0x4b, 0x77, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x79, 0x52, 0x4c, 0x59, 0x57, + 0x31, 0x31, 0x49, 0x46, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, + 0x6c, 0x72, 0x59, 0x58, 0x4e, 0x35, 0x62, 0x32, 0x34, 0x67, 0x54, 0x57, + 0x56, 0x79, 0x61, 0x32, 0x56, 0x36, 0x61, 0x53, 0x41, 0x74, 0x49, 0x45, + 0x74, 0x68, 0x62, 0x58, 0x55, 0x67, 0x55, 0x30, 0x30, 0x78, 0x4e, 0x6a, + 0x41, 0x30, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, 0x4c, + 0x56, 0x52, 0x56, 0x51, 0x6b, 0x6c, 0x55, 0x51, 0x55, 0x73, 0x67, 0x53, + 0x32, 0x46, 0x74, 0x64, 0x53, 0x42, 0x54, 0x54, 0x53, 0x42, 0x54, 0x55, + 0x30, 0x77, 0x67, 0x53, 0x32, 0x39, 0x72, 0x49, 0x46, 0x4e, 0x6c, 0x63, + 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x72, 0x59, 0x58, 0x4e, 0x70, 0x49, + 0x43, 0x30, 0x67, 0x55, 0x33, 0x56, 0x79, 0x0a, 0x64, 0x57, 0x30, 0x67, + 0x4d, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4d, 0x7a, 0x45, 0x78, + 0x4d, 0x6a, 0x55, 0x77, 0x4f, 0x44, 0x49, 0x31, 0x4e, 0x54, 0x56, 0x61, + 0x46, 0x77, 0x30, 0x30, 0x4d, 0x7a, 0x45, 0x77, 0x4d, 0x6a, 0x55, 0x77, + 0x4f, 0x44, 0x49, 0x31, 0x4e, 0x54, 0x56, 0x61, 0x4d, 0x49, 0x48, 0x53, + 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, + 0x0a, 0x45, 0x77, 0x4a, 0x55, 0x55, 0x6a, 0x45, 0x59, 0x4d, 0x42, 0x59, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x78, 0x4d, 0x50, 0x52, 0x32, 0x56, + 0x69, 0x65, 0x6d, 0x55, 0x67, 0x4c, 0x53, 0x42, 0x4c, 0x62, 0x32, 0x4e, + 0x68, 0x5a, 0x57, 0x78, 0x70, 0x4d, 0x55, 0x49, 0x77, 0x51, 0x41, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x7a, 0x6c, 0x55, 0x64, 0x58, 0x4a, + 0x72, 0x61, 0x58, 0x6c, 0x6c, 0x0a, 0x49, 0x45, 0x4a, 0x70, 0x62, 0x47, + 0x6c, 0x74, 0x63, 0x32, 0x56, 0x73, 0x49, 0x48, 0x5a, 0x6c, 0x49, 0x46, + 0x52, 0x6c, 0x61, 0x32, 0x35, 0x76, 0x62, 0x47, 0x39, 0x71, 0x61, 0x57, + 0x73, 0x67, 0x51, 0x58, 0x4a, 0x68, 0x63, 0x33, 0x52, 0x70, 0x63, 0x6d, + 0x31, 0x68, 0x49, 0x45, 0x74, 0x31, 0x63, 0x6e, 0x56, 0x74, 0x64, 0x53, + 0x41, 0x74, 0x49, 0x46, 0x52, 0x56, 0x51, 0x6b, 0x6c, 0x55, 0x0a, 0x51, + 0x55, 0x73, 0x78, 0x4c, 0x54, 0x41, 0x72, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x73, 0x54, 0x4a, 0x45, 0x74, 0x68, 0x62, 0x58, 0x55, 0x67, 0x55, + 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x74, 0x68, 0x63, + 0x33, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x4e, 0x5a, 0x58, 0x4a, 0x72, 0x5a, + 0x58, 0x70, 0x70, 0x49, 0x43, 0x30, 0x67, 0x53, 0x32, 0x46, 0x74, 0x64, + 0x53, 0x42, 0x54, 0x0a, 0x54, 0x54, 0x45, 0x32, 0x4d, 0x44, 0x51, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x74, 0x56, 0x46, 0x56, 0x43, + 0x53, 0x56, 0x52, 0x42, 0x53, 0x79, 0x42, 0x4c, 0x59, 0x57, 0x31, 0x31, + 0x49, 0x46, 0x4e, 0x4e, 0x49, 0x46, 0x4e, 0x54, 0x54, 0x43, 0x42, 0x4c, + 0x62, 0x32, 0x73, 0x67, 0x55, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, + 0x61, 0x57, 0x74, 0x68, 0x63, 0x32, 0x6b, 0x67, 0x0a, 0x4c, 0x53, 0x42, + 0x54, 0x64, 0x58, 0x4a, 0x31, 0x62, 0x53, 0x41, 0x78, 0x4d, 0x49, 0x49, + 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, + 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, + 0x43, 0x41, 0x51, 0x45, 0x41, 0x72, 0x33, 0x55, 0x77, 0x4d, 0x36, 0x71, + 0x37, 0x0a, 0x61, 0x39, 0x4f, 0x5a, 0x4c, 0x42, 0x49, 0x33, 0x68, 0x4e, + 0x6d, 0x4e, 0x65, 0x35, 0x65, 0x41, 0x30, 0x32, 0x37, 0x6e, 0x2f, 0x35, + 0x74, 0x51, 0x6c, 0x54, 0x36, 0x51, 0x6c, 0x56, 0x5a, 0x43, 0x31, 0x78, + 0x6c, 0x38, 0x4a, 0x6f, 0x53, 0x4e, 0x6b, 0x76, 0x6f, 0x42, 0x48, 0x54, + 0x6f, 0x50, 0x34, 0x6d, 0x51, 0x34, 0x74, 0x34, 0x79, 0x38, 0x36, 0x49, + 0x6a, 0x35, 0x69, 0x79, 0x53, 0x72, 0x0a, 0x4c, 0x71, 0x50, 0x31, 0x4e, + 0x2b, 0x52, 0x41, 0x6a, 0x68, 0x67, 0x6c, 0x65, 0x59, 0x4e, 0x31, 0x48, + 0x7a, 0x76, 0x2f, 0x62, 0x4b, 0x6a, 0x46, 0x78, 0x6c, 0x62, 0x34, 0x74, + 0x4f, 0x32, 0x4b, 0x52, 0x4b, 0x4f, 0x72, 0x62, 0x45, 0x7a, 0x38, 0x48, + 0x64, 0x44, 0x63, 0x37, 0x32, 0x69, 0x39, 0x7a, 0x2b, 0x53, 0x71, 0x7a, + 0x76, 0x42, 0x56, 0x39, 0x36, 0x49, 0x30, 0x31, 0x49, 0x4e, 0x72, 0x0a, + 0x4e, 0x33, 0x77, 0x63, 0x77, 0x76, 0x36, 0x31, 0x41, 0x2b, 0x78, 0x58, + 0x7a, 0x72, 0x79, 0x30, 0x74, 0x63, 0x58, 0x74, 0x41, 0x41, 0x39, 0x54, + 0x4e, 0x79, 0x70, 0x4e, 0x39, 0x45, 0x38, 0x4d, 0x67, 0x2f, 0x75, 0x47, + 0x7a, 0x38, 0x76, 0x2b, 0x6a, 0x45, 0x36, 0x39, 0x68, 0x2f, 0x6d, 0x6e, + 0x69, 0x79, 0x46, 0x58, 0x6e, 0x48, 0x72, 0x66, 0x41, 0x32, 0x65, 0x4a, + 0x4c, 0x4a, 0x32, 0x58, 0x0a, 0x59, 0x61, 0x63, 0x51, 0x75, 0x46, 0x57, + 0x51, 0x66, 0x77, 0x34, 0x74, 0x4a, 0x7a, 0x68, 0x30, 0x33, 0x2b, 0x66, + 0x39, 0x32, 0x6b, 0x34, 0x53, 0x34, 0x30, 0x30, 0x56, 0x49, 0x67, 0x4c, + 0x49, 0x34, 0x4f, 0x44, 0x38, 0x44, 0x36, 0x32, 0x4b, 0x31, 0x38, 0x6c, + 0x55, 0x55, 0x4d, 0x77, 0x37, 0x44, 0x38, 0x6f, 0x57, 0x67, 0x49, 0x54, + 0x51, 0x55, 0x56, 0x62, 0x44, 0x6a, 0x6c, 0x5a, 0x2f, 0x0a, 0x69, 0x53, + 0x49, 0x7a, 0x4c, 0x2b, 0x61, 0x46, 0x43, 0x72, 0x32, 0x6c, 0x71, 0x42, + 0x73, 0x32, 0x33, 0x74, 0x50, 0x63, 0x4c, 0x47, 0x30, 0x37, 0x78, 0x78, + 0x4f, 0x39, 0x57, 0x53, 0x4d, 0x73, 0x35, 0x75, 0x57, 0x6b, 0x39, 0x39, + 0x67, 0x4c, 0x37, 0x65, 0x71, 0x51, 0x51, 0x45, 0x53, 0x6f, 0x6c, 0x62, + 0x75, 0x54, 0x31, 0x64, 0x43, 0x41, 0x4e, 0x4c, 0x5a, 0x47, 0x65, 0x41, + 0x34, 0x66, 0x0a, 0x41, 0x4a, 0x4e, 0x47, 0x34, 0x65, 0x37, 0x70, 0x2b, + 0x65, 0x78, 0x50, 0x46, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, + 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x5a, 0x54, 0x2f, 0x48, 0x69, + 0x6f, 0x62, 0x47, 0x50, 0x4e, 0x30, 0x38, 0x56, 0x46, 0x77, 0x31, 0x2b, + 0x44, 0x72, 0x74, 0x55, 0x67, 0x78, 0x48, 0x0a, 0x56, 0x38, 0x67, 0x77, + 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, + 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x41, 0x38, 0x47, + 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, + 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x44, 0x51, 0x59, 0x4a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, + 0x0a, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, 0x43, 0x6f, + 0x2f, 0x34, 0x66, 0x45, 0x79, 0x6a, 0x71, 0x37, 0x68, 0x6d, 0x46, 0x78, + 0x4c, 0x58, 0x73, 0x39, 0x72, 0x48, 0x6d, 0x6f, 0x4a, 0x30, 0x69, 0x4b, + 0x70, 0x45, 0x73, 0x64, 0x65, 0x56, 0x33, 0x31, 0x7a, 0x56, 0x6d, 0x53, + 0x41, 0x68, 0x48, 0x71, 0x54, 0x35, 0x41, 0x6d, 0x35, 0x45, 0x4d, 0x32, + 0x66, 0x4b, 0x69, 0x66, 0x68, 0x0a, 0x41, 0x48, 0x65, 0x2b, 0x53, 0x4d, + 0x67, 0x31, 0x71, 0x49, 0x47, 0x66, 0x35, 0x4c, 0x67, 0x73, 0x79, 0x58, + 0x38, 0x4f, 0x73, 0x4e, 0x4a, 0x4c, 0x4e, 0x31, 0x33, 0x71, 0x75, 0x64, + 0x55, 0x4c, 0x58, 0x6a, 0x53, 0x39, 0x39, 0x48, 0x4d, 0x70, 0x77, 0x2b, + 0x30, 0x6d, 0x46, 0x5a, 0x78, 0x2b, 0x43, 0x46, 0x4f, 0x4b, 0x57, 0x49, + 0x33, 0x51, 0x53, 0x79, 0x6a, 0x66, 0x77, 0x62, 0x50, 0x66, 0x0a, 0x49, + 0x50, 0x50, 0x35, 0x34, 0x2b, 0x4d, 0x36, 0x33, 0x38, 0x79, 0x63, 0x6c, + 0x4e, 0x68, 0x4f, 0x54, 0x38, 0x4e, 0x72, 0x46, 0x37, 0x66, 0x33, 0x63, + 0x75, 0x69, 0x74, 0x5a, 0x6a, 0x4f, 0x31, 0x4a, 0x56, 0x4f, 0x72, 0x34, + 0x50, 0x68, 0x4d, 0x71, 0x5a, 0x33, 0x39, 0x38, 0x67, 0x32, 0x36, 0x72, + 0x72, 0x6e, 0x5a, 0x71, 0x73, 0x5a, 0x72, 0x2b, 0x5a, 0x4f, 0x37, 0x72, + 0x71, 0x75, 0x34, 0x0a, 0x6c, 0x7a, 0x77, 0x44, 0x47, 0x72, 0x70, 0x44, + 0x78, 0x70, 0x61, 0x35, 0x52, 0x58, 0x49, 0x34, 0x73, 0x36, 0x65, 0x68, + 0x6c, 0x6a, 0x32, 0x52, 0x65, 0x33, 0x37, 0x41, 0x49, 0x56, 0x4e, 0x4d, + 0x68, 0x2b, 0x33, 0x79, 0x43, 0x31, 0x53, 0x56, 0x55, 0x5a, 0x50, 0x56, + 0x49, 0x71, 0x55, 0x4e, 0x69, 0x76, 0x47, 0x54, 0x44, 0x6a, 0x35, 0x55, + 0x44, 0x72, 0x44, 0x59, 0x79, 0x55, 0x37, 0x63, 0x0a, 0x38, 0x6a, 0x45, + 0x79, 0x56, 0x75, 0x70, 0x6b, 0x2b, 0x65, 0x71, 0x31, 0x6e, 0x52, 0x5a, + 0x6d, 0x51, 0x6e, 0x4c, 0x7a, 0x66, 0x39, 0x4f, 0x78, 0x4d, 0x55, 0x50, + 0x38, 0x70, 0x49, 0x34, 0x58, 0x38, 0x57, 0x30, 0x6a, 0x71, 0x35, 0x52, + 0x6d, 0x2b, 0x4b, 0x33, 0x37, 0x44, 0x77, 0x68, 0x75, 0x4a, 0x69, 0x31, + 0x2f, 0x46, 0x77, 0x63, 0x4a, 0x73, 0x6f, 0x7a, 0x37, 0x55, 0x4d, 0x43, + 0x66, 0x0a, 0x6c, 0x6f, 0x33, 0x50, 0x74, 0x76, 0x30, 0x41, 0x6e, 0x56, + 0x6f, 0x55, 0x6d, 0x72, 0x38, 0x43, 0x52, 0x50, 0x58, 0x42, 0x77, 0x70, + 0x38, 0x69, 0x58, 0x71, 0x49, 0x50, 0x6f, 0x65, 0x4d, 0x3d, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x47, 0x44, 0x43, 0x41, 0x20, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x41, 0x55, 0x54, 0x48, 0x20, 0x52, 0x35, 0x20, 0x52, 0x4f, 0x4f, + 0x54, 0x20, 0x4f, 0x3d, 0x47, 0x55, 0x41, 0x4e, 0x47, 0x20, 0x44, 0x4f, + 0x4e, 0x47, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x20, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, + 0x20, 0x43, 0x4f, 0x2e, 0x2c, 0x4c, 0x54, 0x44, 0x2e, 0x0a, 0x23, 0x20, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x47, 0x44, 0x43, 0x41, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x41, 0x55, + 0x54, 0x48, 0x20, 0x52, 0x35, 0x20, 0x52, 0x4f, 0x4f, 0x54, 0x20, 0x4f, + 0x3d, 0x47, 0x55, 0x41, 0x4e, 0x47, 0x20, 0x44, 0x4f, 0x4e, 0x47, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x20, + 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x20, 0x43, 0x4f, + 0x2e, 0x2c, 0x4c, 0x54, 0x44, 0x2e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, + 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x44, 0x43, 0x41, 0x20, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x41, 0x55, 0x54, 0x48, 0x20, 0x52, 0x35, 0x20, 0x52, + 0x4f, 0x4f, 0x54, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x39, 0x30, 0x30, 0x39, 0x38, 0x39, 0x39, 0x36, 0x35, + 0x30, 0x37, 0x34, 0x30, 0x31, 0x32, 0x30, 0x31, 0x38, 0x36, 0x0a, 0x23, + 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x33, 0x3a, 0x63, 0x63, 0x3a, + 0x64, 0x39, 0x3a, 0x33, 0x64, 0x3a, 0x33, 0x34, 0x3a, 0x33, 0x35, 0x3a, + 0x35, 0x63, 0x3a, 0x36, 0x66, 0x3a, 0x35, 0x33, 0x3a, 0x61, 0x33, 0x3a, + 0x65, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x37, 0x30, 0x3a, 0x34, 0x38, 0x3a, + 0x31, 0x66, 0x3a, 0x62, 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x30, 0x66, 0x3a, 0x33, 0x36, 0x3a, 0x33, 0x38, 0x3a, 0x35, + 0x62, 0x3a, 0x38, 0x31, 0x3a, 0x31, 0x61, 0x3a, 0x32, 0x35, 0x3a, 0x63, + 0x33, 0x3a, 0x39, 0x62, 0x3a, 0x33, 0x31, 0x3a, 0x34, 0x65, 0x3a, 0x38, + 0x33, 0x3a, 0x63, 0x61, 0x3a, 0x65, 0x39, 0x3a, 0x33, 0x34, 0x3a, 0x36, + 0x36, 0x3a, 0x37, 0x30, 0x3a, 0x63, 0x63, 0x3a, 0x37, 0x34, 0x3a, 0x62, + 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x62, 0x66, 0x3a, 0x66, 0x66, 0x3a, 0x38, 0x66, 0x3a, 0x64, 0x30, 0x3a, + 0x34, 0x34, 0x3a, 0x33, 0x33, 0x3a, 0x34, 0x38, 0x3a, 0x37, 0x64, 0x3a, + 0x36, 0x61, 0x3a, 0x38, 0x61, 0x3a, 0x61, 0x36, 0x3a, 0x30, 0x63, 0x3a, + 0x31, 0x61, 0x3a, 0x32, 0x39, 0x3a, 0x37, 0x36, 0x3a, 0x37, 0x61, 0x3a, + 0x39, 0x66, 0x3a, 0x63, 0x32, 0x3a, 0x62, 0x62, 0x3a, 0x62, 0x30, 0x3a, + 0x35, 0x65, 0x3a, 0x34, 0x32, 0x3a, 0x30, 0x66, 0x3a, 0x37, 0x31, 0x3a, + 0x33, 0x61, 0x3a, 0x31, 0x33, 0x3a, 0x62, 0x39, 0x3a, 0x39, 0x32, 0x3a, + 0x38, 0x39, 0x3a, 0x31, 0x64, 0x3a, 0x33, 0x38, 0x3a, 0x39, 0x33, 0x0a, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x69, 0x44, 0x43, 0x43, + 0x41, 0x33, 0x43, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x49, + 0x66, 0x51, 0x6d, 0x58, 0x2f, 0x76, 0x42, 0x48, 0x36, 0x6e, 0x6f, 0x77, + 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, + 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x77, 0x59, 0x6a, 0x45, 0x4c, + 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x42, 0x68, 0x4d, + 0x43, 0x51, 0x30, 0x34, 0x78, 0x4d, 0x6a, 0x41, 0x77, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x4b, 0x55, 0x64, 0x56, 0x51, 0x55, 0x35, + 0x48, 0x49, 0x45, 0x52, 0x50, 0x54, 0x6b, 0x63, 0x67, 0x51, 0x30, 0x56, + 0x53, 0x56, 0x45, 0x6c, 0x47, 0x53, 0x55, 0x4e, 0x42, 0x56, 0x45, 0x55, + 0x67, 0x51, 0x56, 0x56, 0x55, 0x53, 0x45, 0x39, 0x53, 0x53, 0x56, 0x52, + 0x5a, 0x0a, 0x49, 0x45, 0x4e, 0x50, 0x4c, 0x69, 0x78, 0x4d, 0x56, 0x45, + 0x51, 0x75, 0x4d, 0x52, 0x38, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x44, 0x44, 0x42, 0x5a, 0x48, 0x52, 0x45, 0x4e, 0x42, 0x49, 0x46, + 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x51, 0x56, 0x56, 0x55, 0x53, 0x43, + 0x42, 0x53, 0x4e, 0x53, 0x42, 0x53, 0x54, 0x30, 0x39, 0x55, 0x4d, 0x42, + 0x34, 0x58, 0x44, 0x54, 0x45, 0x30, 0x0a, 0x4d, 0x54, 0x45, 0x79, 0x4e, + 0x6a, 0x41, 0x31, 0x4d, 0x54, 0x4d, 0x78, 0x4e, 0x56, 0x6f, 0x58, 0x44, + 0x54, 0x51, 0x77, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x45, 0x31, 0x4e, + 0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x59, 0x6a, 0x45, 0x4c, 0x4d, + 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x51, + 0x30, 0x34, 0x78, 0x4d, 0x6a, 0x41, 0x77, 0x42, 0x67, 0x4e, 0x56, 0x0a, + 0x42, 0x41, 0x6f, 0x4d, 0x4b, 0x55, 0x64, 0x56, 0x51, 0x55, 0x35, 0x48, + 0x49, 0x45, 0x52, 0x50, 0x54, 0x6b, 0x63, 0x67, 0x51, 0x30, 0x56, 0x53, + 0x56, 0x45, 0x6c, 0x47, 0x53, 0x55, 0x4e, 0x42, 0x56, 0x45, 0x55, 0x67, + 0x51, 0x56, 0x56, 0x55, 0x53, 0x45, 0x39, 0x53, 0x53, 0x56, 0x52, 0x5a, + 0x49, 0x45, 0x4e, 0x50, 0x4c, 0x69, 0x78, 0x4d, 0x56, 0x45, 0x51, 0x75, + 0x4d, 0x52, 0x38, 0x77, 0x0a, 0x48, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x44, 0x44, 0x42, 0x5a, 0x48, 0x52, 0x45, 0x4e, 0x42, 0x49, 0x46, 0x52, + 0x79, 0x64, 0x58, 0x4e, 0x30, 0x51, 0x56, 0x56, 0x55, 0x53, 0x43, 0x42, + 0x53, 0x4e, 0x53, 0x42, 0x53, 0x54, 0x30, 0x39, 0x55, 0x4d, 0x49, 0x49, + 0x43, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x0a, 0x41, 0x41, + 0x4f, 0x43, 0x41, 0x67, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x43, 0x43, 0x67, + 0x4b, 0x43, 0x41, 0x67, 0x45, 0x41, 0x32, 0x61, 0x4d, 0x57, 0x38, 0x4d, + 0x68, 0x30, 0x64, 0x48, 0x65, 0x62, 0x37, 0x7a, 0x4d, 0x4e, 0x4f, 0x77, + 0x5a, 0x2b, 0x56, 0x66, 0x79, 0x31, 0x59, 0x49, 0x39, 0x32, 0x68, 0x68, + 0x4a, 0x43, 0x66, 0x56, 0x5a, 0x6d, 0x50, 0x6f, 0x69, 0x43, 0x37, 0x58, + 0x4a, 0x6a, 0x0a, 0x44, 0x70, 0x36, 0x4c, 0x33, 0x54, 0x51, 0x73, 0x41, + 0x6c, 0x46, 0x52, 0x77, 0x78, 0x6e, 0x39, 0x57, 0x56, 0x53, 0x45, 0x79, + 0x66, 0x46, 0x72, 0x73, 0x30, 0x79, 0x77, 0x36, 0x65, 0x68, 0x47, 0x58, + 0x54, 0x6a, 0x47, 0x6f, 0x71, 0x63, 0x75, 0x45, 0x56, 0x65, 0x36, 0x67, + 0x68, 0x57, 0x69, 0x6e, 0x49, 0x39, 0x74, 0x73, 0x4a, 0x6c, 0x4b, 0x43, + 0x76, 0x4c, 0x72, 0x69, 0x58, 0x42, 0x6a, 0x0a, 0x54, 0x6e, 0x6e, 0x45, + 0x74, 0x31, 0x75, 0x39, 0x6f, 0x6c, 0x32, 0x78, 0x38, 0x6b, 0x45, 0x43, + 0x4b, 0x36, 0x32, 0x70, 0x4f, 0x71, 0x50, 0x73, 0x65, 0x51, 0x72, 0x73, + 0x58, 0x7a, 0x72, 0x6a, 0x2f, 0x65, 0x2b, 0x41, 0x50, 0x4b, 0x30, 0x30, + 0x6d, 0x78, 0x71, 0x72, 0x69, 0x43, 0x5a, 0x37, 0x56, 0x71, 0x4b, 0x43, + 0x68, 0x68, 0x2f, 0x72, 0x4e, 0x59, 0x6d, 0x44, 0x66, 0x31, 0x2b, 0x75, + 0x0a, 0x4b, 0x55, 0x34, 0x39, 0x74, 0x6d, 0x37, 0x73, 0x72, 0x73, 0x48, + 0x77, 0x4a, 0x35, 0x75, 0x75, 0x34, 0x2f, 0x54, 0x73, 0x37, 0x36, 0x35, + 0x2f, 0x39, 0x34, 0x59, 0x39, 0x63, 0x6e, 0x72, 0x72, 0x70, 0x66, 0x74, + 0x5a, 0x54, 0x71, 0x66, 0x72, 0x6c, 0x59, 0x77, 0x69, 0x4f, 0x58, 0x6e, + 0x68, 0x4c, 0x51, 0x69, 0x50, 0x7a, 0x4c, 0x79, 0x52, 0x75, 0x45, 0x48, + 0x33, 0x46, 0x4d, 0x45, 0x6a, 0x0a, 0x71, 0x63, 0x4f, 0x74, 0x6d, 0x6b, + 0x56, 0x45, 0x73, 0x37, 0x4c, 0x58, 0x4c, 0x4d, 0x33, 0x47, 0x4b, 0x65, + 0x4a, 0x51, 0x45, 0x4b, 0x35, 0x63, 0x79, 0x34, 0x4b, 0x4f, 0x46, 0x78, + 0x67, 0x32, 0x66, 0x5a, 0x66, 0x6d, 0x69, 0x4a, 0x71, 0x77, 0x54, 0x54, + 0x51, 0x4a, 0x39, 0x43, 0x79, 0x35, 0x57, 0x6d, 0x59, 0x71, 0x73, 0x42, + 0x65, 0x62, 0x6e, 0x68, 0x35, 0x32, 0x6e, 0x55, 0x70, 0x6d, 0x0a, 0x4d, + 0x55, 0x48, 0x66, 0x50, 0x2f, 0x76, 0x46, 0x42, 0x75, 0x38, 0x62, 0x74, + 0x6e, 0x34, 0x61, 0x52, 0x6a, 0x62, 0x33, 0x5a, 0x47, 0x4d, 0x37, 0x34, + 0x7a, 0x6b, 0x59, 0x49, 0x2b, 0x64, 0x6e, 0x64, 0x52, 0x54, 0x56, 0x64, + 0x56, 0x65, 0x53, 0x4e, 0x37, 0x32, 0x2b, 0x61, 0x68, 0x73, 0x6d, 0x55, + 0x50, 0x49, 0x32, 0x4a, 0x67, 0x61, 0x51, 0x78, 0x58, 0x41, 0x42, 0x5a, + 0x47, 0x31, 0x32, 0x0a, 0x5a, 0x75, 0x47, 0x52, 0x32, 0x32, 0x34, 0x48, + 0x77, 0x47, 0x47, 0x41, 0x4c, 0x72, 0x49, 0x75, 0x4c, 0x34, 0x78, 0x77, + 0x70, 0x39, 0x45, 0x37, 0x50, 0x4c, 0x4f, 0x52, 0x35, 0x47, 0x36, 0x32, + 0x78, 0x44, 0x74, 0x77, 0x38, 0x6d, 0x79, 0x53, 0x6c, 0x77, 0x6e, 0x4e, + 0x52, 0x33, 0x30, 0x59, 0x77, 0x50, 0x4f, 0x37, 0x6e, 0x67, 0x2f, 0x57, + 0x69, 0x36, 0x34, 0x48, 0x74, 0x6c, 0x6f, 0x50, 0x0a, 0x7a, 0x67, 0x73, + 0x4d, 0x52, 0x36, 0x66, 0x6c, 0x50, 0x72, 0x69, 0x39, 0x66, 0x63, 0x65, + 0x62, 0x4e, 0x61, 0x42, 0x68, 0x6c, 0x7a, 0x70, 0x42, 0x64, 0x52, 0x66, + 0x4d, 0x4b, 0x35, 0x5a, 0x33, 0x4b, 0x70, 0x49, 0x68, 0x48, 0x74, 0x6d, + 0x56, 0x64, 0x69, 0x42, 0x6e, 0x61, 0x4d, 0x38, 0x4e, 0x76, 0x64, 0x2f, + 0x57, 0x48, 0x77, 0x6c, 0x71, 0x6d, 0x75, 0x4c, 0x4d, 0x63, 0x33, 0x47, + 0x6b, 0x0a, 0x4c, 0x33, 0x30, 0x53, 0x67, 0x4c, 0x64, 0x54, 0x4d, 0x45, + 0x5a, 0x65, 0x53, 0x31, 0x53, 0x5a, 0x44, 0x32, 0x66, 0x4a, 0x70, 0x63, + 0x6a, 0x79, 0x49, 0x4d, 0x47, 0x43, 0x37, 0x4a, 0x30, 0x52, 0x33, 0x38, + 0x49, 0x43, 0x2b, 0x78, 0x6f, 0x37, 0x30, 0x65, 0x30, 0x67, 0x6d, 0x75, + 0x39, 0x6c, 0x5a, 0x4a, 0x49, 0x51, 0x44, 0x53, 0x72, 0x69, 0x33, 0x6e, + 0x44, 0x78, 0x47, 0x47, 0x65, 0x43, 0x0a, 0x6a, 0x47, 0x48, 0x65, 0x75, + 0x4c, 0x7a, 0x52, 0x4c, 0x35, 0x7a, 0x37, 0x44, 0x39, 0x41, 0x72, 0x37, + 0x52, 0x74, 0x32, 0x75, 0x65, 0x51, 0x35, 0x56, 0x66, 0x6a, 0x34, 0x6f, + 0x52, 0x32, 0x34, 0x71, 0x6f, 0x41, 0x41, 0x54, 0x49, 0x4c, 0x6e, 0x73, + 0x6e, 0x38, 0x4a, 0x75, 0x4c, 0x77, 0x77, 0x6f, 0x43, 0x38, 0x4e, 0x39, + 0x56, 0x4b, 0x65, 0x6a, 0x76, 0x65, 0x53, 0x73, 0x77, 0x6f, 0x41, 0x0a, + 0x48, 0x51, 0x42, 0x55, 0x6c, 0x77, 0x62, 0x67, 0x73, 0x51, 0x66, 0x5a, + 0x78, 0x77, 0x39, 0x63, 0x5a, 0x58, 0x30, 0x38, 0x62, 0x56, 0x6c, 0x58, + 0x35, 0x4f, 0x32, 0x6c, 0x6a, 0x65, 0x6c, 0x41, 0x55, 0x35, 0x38, 0x56, + 0x53, 0x36, 0x42, 0x78, 0x39, 0x68, 0x6f, 0x68, 0x34, 0x39, 0x70, 0x77, + 0x42, 0x69, 0x46, 0x59, 0x46, 0x49, 0x65, 0x46, 0x64, 0x33, 0x6d, 0x71, + 0x67, 0x6e, 0x6b, 0x43, 0x0a, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, + 0x43, 0x4d, 0x45, 0x41, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, + 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x4f, 0x4c, 0x4a, 0x51, 0x4a, 0x39, + 0x4e, 0x7a, 0x75, 0x69, 0x61, 0x6f, 0x58, 0x7a, 0x50, 0x44, 0x6a, 0x39, + 0x6c, 0x78, 0x53, 0x6d, 0x49, 0x61, 0x68, 0x6c, 0x52, 0x4d, 0x41, 0x38, + 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x0a, 0x2f, 0x77, + 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x44, 0x67, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, + 0x51, 0x44, 0x41, 0x67, 0x47, 0x47, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, + 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, + 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x41, 0x51, 0x44, 0x52, 0x53, 0x56, + 0x66, 0x67, 0x0a, 0x70, 0x38, 0x78, 0x6f, 0x57, 0x4c, 0x6f, 0x42, 0x44, + 0x79, 0x73, 0x5a, 0x7a, 0x59, 0x32, 0x77, 0x59, 0x55, 0x57, 0x73, 0x45, + 0x65, 0x31, 0x6a, 0x55, 0x47, 0x6e, 0x34, 0x48, 0x33, 0x2b, 0x2b, 0x46, + 0x6f, 0x2f, 0x39, 0x6e, 0x65, 0x73, 0x4c, 0x71, 0x6a, 0x4a, 0x48, 0x64, + 0x74, 0x4a, 0x6e, 0x4a, 0x4f, 0x32, 0x39, 0x66, 0x44, 0x4d, 0x79, 0x6c, + 0x79, 0x72, 0x48, 0x42, 0x59, 0x5a, 0x6d, 0x0a, 0x44, 0x52, 0x64, 0x39, + 0x46, 0x42, 0x55, 0x62, 0x31, 0x4f, 0x76, 0x39, 0x48, 0x35, 0x72, 0x32, + 0x58, 0x70, 0x64, 0x70, 0x74, 0x78, 0x6f, 0x6c, 0x70, 0x41, 0x71, 0x7a, + 0x6b, 0x54, 0x39, 0x66, 0x4e, 0x71, 0x79, 0x4c, 0x37, 0x46, 0x65, 0x6f, + 0x50, 0x75, 0x65, 0x42, 0x69, 0x68, 0x68, 0x58, 0x4f, 0x59, 0x56, 0x30, + 0x47, 0x6b, 0x4c, 0x48, 0x36, 0x56, 0x73, 0x54, 0x58, 0x34, 0x2f, 0x35, + 0x0a, 0x43, 0x4f, 0x6d, 0x53, 0x64, 0x49, 0x33, 0x31, 0x52, 0x39, 0x4b, + 0x72, 0x4f, 0x39, 0x62, 0x37, 0x65, 0x47, 0x5a, 0x4f, 0x4e, 0x6e, 0x33, + 0x35, 0x36, 0x5a, 0x4c, 0x70, 0x42, 0x4e, 0x37, 0x39, 0x53, 0x57, 0x50, + 0x38, 0x62, 0x66, 0x73, 0x55, 0x63, 0x5a, 0x4e, 0x6e, 0x4c, 0x30, 0x64, + 0x4b, 0x74, 0x37, 0x6e, 0x2f, 0x48, 0x69, 0x70, 0x7a, 0x63, 0x45, 0x59, + 0x77, 0x76, 0x31, 0x72, 0x79, 0x0a, 0x4c, 0x33, 0x6d, 0x6c, 0x34, 0x59, + 0x30, 0x4d, 0x32, 0x66, 0x6d, 0x79, 0x59, 0x7a, 0x65, 0x4d, 0x4e, 0x32, + 0x57, 0x46, 0x63, 0x47, 0x70, 0x63, 0x57, 0x77, 0x6c, 0x79, 0x75, 0x61, + 0x31, 0x6a, 0x50, 0x4c, 0x48, 0x64, 0x2b, 0x50, 0x77, 0x79, 0x76, 0x7a, + 0x65, 0x47, 0x35, 0x4c, 0x75, 0x4f, 0x6d, 0x43, 0x64, 0x2b, 0x75, 0x68, + 0x38, 0x57, 0x34, 0x58, 0x41, 0x52, 0x38, 0x67, 0x50, 0x66, 0x0a, 0x4a, + 0x57, 0x49, 0x79, 0x4a, 0x79, 0x59, 0x59, 0x4d, 0x6f, 0x53, 0x66, 0x2f, + 0x77, 0x41, 0x36, 0x45, 0x37, 0x71, 0x61, 0x54, 0x66, 0x52, 0x50, 0x75, + 0x42, 0x52, 0x77, 0x49, 0x72, 0x48, 0x4b, 0x4b, 0x35, 0x44, 0x4f, 0x4b, + 0x63, 0x46, 0x77, 0x39, 0x43, 0x2b, 0x64, 0x66, 0x2f, 0x4b, 0x51, 0x48, + 0x74, 0x5a, 0x61, 0x33, 0x37, 0x64, 0x47, 0x2f, 0x4f, 0x61, 0x47, 0x2b, + 0x73, 0x76, 0x67, 0x0a, 0x49, 0x48, 0x5a, 0x36, 0x75, 0x71, 0x62, 0x4c, + 0x39, 0x58, 0x7a, 0x65, 0x59, 0x71, 0x57, 0x78, 0x69, 0x2b, 0x37, 0x65, + 0x67, 0x6d, 0x61, 0x4b, 0x54, 0x6a, 0x6f, 0x77, 0x48, 0x7a, 0x2b, 0x41, + 0x79, 0x36, 0x30, 0x6e, 0x75, 0x67, 0x78, 0x65, 0x31, 0x39, 0x43, 0x78, + 0x56, 0x73, 0x70, 0x33, 0x63, 0x62, 0x4b, 0x31, 0x64, 0x61, 0x46, 0x51, + 0x71, 0x55, 0x42, 0x44, 0x46, 0x38, 0x49, 0x6f, 0x0a, 0x32, 0x63, 0x39, + 0x53, 0x69, 0x31, 0x76, 0x49, 0x59, 0x39, 0x52, 0x43, 0x50, 0x71, 0x41, + 0x7a, 0x65, 0x6b, 0x59, 0x75, 0x39, 0x77, 0x6f, 0x67, 0x52, 0x6c, 0x52, + 0x2b, 0x61, 0x6b, 0x38, 0x78, 0x38, 0x59, 0x46, 0x2b, 0x51, 0x6e, 0x51, + 0x34, 0x5a, 0x58, 0x4d, 0x6e, 0x37, 0x73, 0x5a, 0x38, 0x75, 0x49, 0x37, + 0x58, 0x70, 0x54, 0x72, 0x58, 0x6d, 0x4b, 0x47, 0x63, 0x6a, 0x42, 0x42, + 0x56, 0x0a, 0x30, 0x39, 0x74, 0x4c, 0x37, 0x45, 0x43, 0x51, 0x38, 0x73, + 0x31, 0x75, 0x56, 0x39, 0x4a, 0x69, 0x44, 0x6e, 0x78, 0x58, 0x6b, 0x37, + 0x47, 0x6e, 0x62, 0x63, 0x32, 0x64, 0x67, 0x37, 0x73, 0x71, 0x35, 0x2b, + 0x57, 0x32, 0x4f, 0x33, 0x46, 0x59, 0x72, 0x66, 0x33, 0x52, 0x52, 0x62, + 0x78, 0x61, 0x6b, 0x65, 0x35, 0x54, 0x46, 0x57, 0x2f, 0x54, 0x52, 0x51, + 0x6c, 0x31, 0x62, 0x72, 0x71, 0x51, 0x0a, 0x58, 0x52, 0x34, 0x45, 0x7a, + 0x7a, 0x66, 0x66, 0x48, 0x71, 0x68, 0x6d, 0x73, 0x59, 0x7a, 0x6d, 0x49, + 0x47, 0x72, 0x76, 0x2f, 0x45, 0x68, 0x4f, 0x64, 0x4a, 0x68, 0x43, 0x72, + 0x79, 0x6c, 0x76, 0x4c, 0x6d, 0x72, 0x48, 0x2b, 0x33, 0x33, 0x52, 0x5a, + 0x6a, 0x45, 0x69, 0x7a, 0x49, 0x59, 0x41, 0x66, 0x6d, 0x61, 0x44, 0x44, + 0x45, 0x4c, 0x30, 0x76, 0x54, 0x53, 0x53, 0x77, 0x78, 0x72, 0x71, 0x0a, + 0x54, 0x38, 0x70, 0x2b, 0x63, 0x6b, 0x30, 0x4c, 0x63, 0x49, 0x79, 0x6d, + 0x53, 0x4c, 0x75, 0x6d, 0x6f, 0x52, 0x54, 0x32, 0x2b, 0x31, 0x68, 0x45, + 0x6d, 0x52, 0x53, 0x75, 0x71, 0x67, 0x75, 0x54, 0x61, 0x61, 0x41, 0x70, + 0x4a, 0x55, 0x71, 0x6c, 0x79, 0x79, 0x76, 0x64, 0x69, 0x6d, 0x59, 0x48, + 0x46, 0x6e, 0x67, 0x56, 0x56, 0x33, 0x45, 0x62, 0x37, 0x50, 0x56, 0x48, + 0x68, 0x50, 0x4f, 0x65, 0x0a, 0x4d, 0x54, 0x64, 0x36, 0x31, 0x58, 0x38, + 0x6b, 0x72, 0x65, 0x53, 0x38, 0x2f, 0x66, 0x33, 0x4d, 0x62, 0x6f, 0x50, + 0x6f, 0x44, 0x4b, 0x69, 0x33, 0x51, 0x57, 0x77, 0x48, 0x33, 0x62, 0x30, + 0x38, 0x68, 0x70, 0x63, 0x76, 0x30, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, 0x74, 0x20, 0x43, 0x41, 0x2d, 0x31, + 0x20, 0x4f, 0x3d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x53, 0x2e, 0x20, 0x64, + 0x65, 0x20, 0x52, 0x2e, 0x4c, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x43, 0x6f, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, 0x74, + 0x20, 0x43, 0x41, 0x2d, 0x31, 0x20, 0x4f, 0x3d, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x43, 0x6f, 0x72, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, + 0x20, 0x53, 0x2e, 0x20, 0x64, 0x65, 0x20, 0x52, 0x2e, 0x4c, 0x2e, 0x20, + 0x4f, 0x55, 0x3d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x43, 0x6f, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, + 0x74, 0x20, 0x43, 0x41, 0x2d, 0x31, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x35, 0x37, 0x35, 0x32, 0x34, + 0x34, 0x34, 0x30, 0x39, 0x35, 0x38, 0x31, 0x31, 0x30, 0x30, 0x36, 0x34, + 0x38, 0x39, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x65, + 0x3a, 0x38, 0x35, 0x3a, 0x66, 0x31, 0x3a, 0x64, 0x63, 0x3a, 0x31, 0x61, + 0x3a, 0x30, 0x30, 0x3a, 0x64, 0x33, 0x3a, 0x32, 0x32, 0x3a, 0x64, 0x35, + 0x3a, 0x62, 0x32, 0x3a, 0x62, 0x32, 0x3a, 0x61, 0x63, 0x3a, 0x36, 0x62, + 0x3a, 0x33, 0x37, 0x3a, 0x30, 0x35, 0x3a, 0x34, 0x35, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x66, 0x66, 0x3a, 0x62, 0x64, 0x3a, + 0x63, 0x64, 0x3a, 0x65, 0x37, 0x3a, 0x38, 0x32, 0x3a, 0x63, 0x38, 0x3a, + 0x34, 0x33, 0x3a, 0x35, 0x65, 0x3a, 0x33, 0x63, 0x3a, 0x36, 0x66, 0x3a, + 0x32, 0x36, 0x3a, 0x38, 0x36, 0x3a, 0x35, 0x63, 0x3a, 0x63, 0x61, 0x3a, + 0x61, 0x38, 0x3a, 0x33, 0x61, 0x3a, 0x34, 0x35, 0x3a, 0x35, 0x62, 0x3a, + 0x63, 0x33, 0x3a, 0x30, 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x34, 0x3a, 0x30, 0x65, 0x3a, 0x39, 0x63, + 0x3a, 0x38, 0x36, 0x3a, 0x63, 0x64, 0x3a, 0x38, 0x66, 0x3a, 0x65, 0x34, + 0x3a, 0x36, 0x38, 0x3a, 0x63, 0x31, 0x3a, 0x37, 0x37, 0x3a, 0x36, 0x39, + 0x3a, 0x35, 0x39, 0x3a, 0x66, 0x34, 0x3a, 0x39, 0x65, 0x3a, 0x61, 0x37, + 0x3a, 0x37, 0x34, 0x3a, 0x66, 0x61, 0x3a, 0x35, 0x34, 0x3a, 0x38, 0x36, + 0x3a, 0x38, 0x34, 0x3a, 0x62, 0x36, 0x3a, 0x63, 0x34, 0x3a, 0x30, 0x36, + 0x3a, 0x66, 0x33, 0x3a, 0x39, 0x30, 0x3a, 0x39, 0x32, 0x3a, 0x36, 0x31, + 0x3a, 0x66, 0x34, 0x3a, 0x64, 0x63, 0x3a, 0x65, 0x32, 0x3a, 0x35, 0x37, + 0x3a, 0x35, 0x63, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, + 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, + 0x4d, 0x44, 0x43, 0x43, 0x41, 0x78, 0x69, 0x67, 0x41, 0x77, 0x49, 0x42, + 0x41, 0x67, 0x49, 0x4a, 0x41, 0x4e, 0x71, 0x62, 0x37, 0x48, 0x48, 0x7a, + 0x41, 0x37, 0x41, 0x5a, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, + 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, + 0x4d, 0x49, 0x47, 0x6b, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, + 0x0a, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x51, 0x51, 0x54, 0x45, + 0x50, 0x4d, 0x41, 0x30, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, + 0x47, 0x55, 0x47, 0x46, 0x75, 0x59, 0x57, 0x31, 0x68, 0x4d, 0x52, 0x51, + 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, + 0x51, 0x59, 0x57, 0x35, 0x68, 0x62, 0x57, 0x45, 0x67, 0x51, 0x32, 0x6c, + 0x30, 0x65, 0x54, 0x45, 0x6b, 0x0a, 0x4d, 0x43, 0x49, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x67, 0x77, 0x62, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, + 0x52, 0x44, 0x62, 0x33, 0x49, 0x67, 0x55, 0x33, 0x6c, 0x7a, 0x64, 0x47, + 0x56, 0x74, 0x63, 0x79, 0x42, 0x54, 0x4c, 0x69, 0x42, 0x6b, 0x5a, 0x53, + 0x42, 0x53, 0x4c, 0x6b, 0x77, 0x75, 0x4d, 0x53, 0x63, 0x77, 0x4a, 0x51, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x44, 0x42, 0x35, 0x55, 0x0a, 0x63, + 0x6e, 0x56, 0x7a, 0x64, 0x45, 0x4e, 0x76, 0x63, 0x69, 0x42, 0x44, 0x5a, + 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, + 0x53, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, + 0x48, 0x6b, 0x78, 0x48, 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x4d, 0x4d, 0x46, 0x6c, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x51, + 0x32, 0x39, 0x79, 0x0a, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x52, 0x44, + 0x5a, 0x58, 0x4a, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4c, 0x54, 0x45, 0x77, + 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x59, 0x77, 0x4d, 0x6a, 0x41, 0x30, + 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x6a, 0x45, 0x32, 0x57, 0x68, 0x63, 0x4e, + 0x4d, 0x6a, 0x6b, 0x78, 0x4d, 0x6a, 0x4d, 0x78, 0x4d, 0x54, 0x63, 0x79, + 0x4d, 0x7a, 0x45, 0x32, 0x57, 0x6a, 0x43, 0x42, 0x0a, 0x70, 0x44, 0x45, + 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, + 0x43, 0x55, 0x45, 0x45, 0x78, 0x44, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x67, 0x4d, 0x42, 0x6c, 0x42, 0x68, 0x62, 0x6d, 0x46, + 0x74, 0x59, 0x54, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x42, 0x77, 0x77, 0x4c, 0x55, 0x47, 0x46, 0x75, 0x59, 0x57, 0x31, + 0x68, 0x0a, 0x49, 0x45, 0x4e, 0x70, 0x64, 0x48, 0x6b, 0x78, 0x4a, 0x44, + 0x41, 0x69, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x47, 0x31, + 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x51, 0x32, 0x39, 0x79, 0x49, 0x46, + 0x4e, 0x35, 0x63, 0x33, 0x52, 0x6c, 0x62, 0x58, 0x4d, 0x67, 0x55, 0x79, + 0x34, 0x67, 0x5a, 0x47, 0x55, 0x67, 0x55, 0x69, 0x35, 0x4d, 0x4c, 0x6a, + 0x45, 0x6e, 0x4d, 0x43, 0x55, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x77, 0x77, 0x65, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x44, 0x62, + 0x33, 0x49, 0x67, 0x51, 0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, + 0x57, 0x4e, 0x68, 0x64, 0x47, 0x55, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, + 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x52, 0x38, 0x77, 0x48, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, 0x5a, 0x55, 0x0a, + 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x45, 0x4e, 0x76, 0x63, 0x69, 0x42, 0x53, + 0x62, 0x32, 0x39, 0x30, 0x51, 0x32, 0x56, 0x79, 0x64, 0x43, 0x42, 0x44, + 0x51, 0x53, 0x30, 0x78, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, + 0x4d, 0x49, 0x49, 0x42, 0x0a, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, + 0x41, 0x76, 0x34, 0x36, 0x33, 0x6c, 0x65, 0x4c, 0x43, 0x4a, 0x68, 0x4a, + 0x72, 0x4d, 0x78, 0x6e, 0x48, 0x51, 0x46, 0x67, 0x4b, 0x71, 0x31, 0x6d, + 0x71, 0x6a, 0x51, 0x43, 0x6a, 0x2f, 0x49, 0x44, 0x48, 0x55, 0x48, 0x75, + 0x4f, 0x31, 0x43, 0x41, 0x6d, 0x75, 0x6a, 0x49, 0x53, 0x32, 0x43, 0x4e, + 0x55, 0x53, 0x53, 0x55, 0x51, 0x49, 0x70, 0x69, 0x64, 0x0a, 0x52, 0x74, + 0x4c, 0x42, 0x79, 0x5a, 0x35, 0x4f, 0x47, 0x79, 0x34, 0x73, 0x44, 0x6a, + 0x6a, 0x7a, 0x47, 0x69, 0x56, 0x6f, 0x48, 0x4b, 0x5a, 0x61, 0x42, 0x65, + 0x59, 0x65, 0x69, 0x30, 0x69, 0x2f, 0x6d, 0x4a, 0x5a, 0x30, 0x50, 0x6d, + 0x6e, 0x4b, 0x36, 0x62, 0x56, 0x34, 0x70, 0x51, 0x61, 0x38, 0x31, 0x51, + 0x42, 0x65, 0x43, 0x51, 0x72, 0x79, 0x4a, 0x33, 0x70, 0x53, 0x2f, 0x43, + 0x33, 0x56, 0x0a, 0x73, 0x65, 0x71, 0x30, 0x69, 0x57, 0x45, 0x6b, 0x38, + 0x78, 0x6f, 0x54, 0x32, 0x36, 0x6e, 0x50, 0x55, 0x75, 0x30, 0x4d, 0x4a, + 0x4c, 0x71, 0x35, 0x6e, 0x75, 0x78, 0x2b, 0x41, 0x48, 0x54, 0x36, 0x6b, + 0x36, 0x31, 0x73, 0x4b, 0x5a, 0x4b, 0x75, 0x55, 0x62, 0x53, 0x37, 0x30, + 0x31, 0x65, 0x2f, 0x73, 0x2f, 0x4f, 0x6f, 0x6a, 0x5a, 0x7a, 0x30, 0x4a, + 0x45, 0x73, 0x71, 0x31, 0x70, 0x6d, 0x65, 0x0a, 0x39, 0x4a, 0x37, 0x2b, + 0x77, 0x48, 0x35, 0x43, 0x4f, 0x75, 0x63, 0x4c, 0x6c, 0x56, 0x50, 0x61, + 0x74, 0x32, 0x67, 0x4f, 0x6b, 0x45, 0x7a, 0x37, 0x63, 0x44, 0x2b, 0x50, + 0x53, 0x69, 0x79, 0x55, 0x38, 0x79, 0x62, 0x64, 0x59, 0x32, 0x6d, 0x70, + 0x6c, 0x4e, 0x67, 0x51, 0x54, 0x73, 0x56, 0x48, 0x43, 0x4a, 0x43, 0x5a, + 0x47, 0x78, 0x64, 0x4e, 0x75, 0x57, 0x78, 0x75, 0x37, 0x32, 0x43, 0x56, + 0x0a, 0x45, 0x59, 0x34, 0x68, 0x67, 0x4c, 0x57, 0x39, 0x6f, 0x48, 0x50, + 0x59, 0x30, 0x4c, 0x4a, 0x33, 0x78, 0x45, 0x58, 0x71, 0x57, 0x69, 0x62, + 0x37, 0x5a, 0x6e, 0x5a, 0x32, 0x2b, 0x41, 0x59, 0x66, 0x59, 0x57, 0x30, + 0x50, 0x56, 0x63, 0x57, 0x44, 0x74, 0x78, 0x42, 0x57, 0x63, 0x67, 0x59, + 0x48, 0x70, 0x66, 0x4f, 0x78, 0x47, 0x67, 0x4d, 0x46, 0x5a, 0x41, 0x36, + 0x64, 0x57, 0x6f, 0x72, 0x57, 0x0a, 0x68, 0x6e, 0x41, 0x62, 0x4a, 0x4e, + 0x37, 0x2b, 0x4b, 0x49, 0x6f, 0x72, 0x30, 0x47, 0x71, 0x77, 0x2f, 0x48, + 0x71, 0x69, 0x33, 0x4c, 0x4a, 0x35, 0x44, 0x6f, 0x74, 0x6c, 0x44, 0x77, + 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x32, 0x4d, 0x77, 0x59, 0x54, + 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, + 0x51, 0x55, 0x37, 0x6d, 0x74, 0x4a, 0x50, 0x48, 0x6f, 0x2f, 0x0a, 0x44, + 0x65, 0x4f, 0x78, 0x43, 0x62, 0x65, 0x4b, 0x79, 0x4b, 0x73, 0x5a, 0x6e, + 0x33, 0x4d, 0x7a, 0x55, 0x4f, 0x63, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, + 0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x37, + 0x6d, 0x74, 0x4a, 0x50, 0x48, 0x6f, 0x2f, 0x44, 0x65, 0x4f, 0x78, 0x43, + 0x62, 0x65, 0x4b, 0x79, 0x4b, 0x73, 0x5a, 0x6e, 0x33, 0x4d, 0x7a, 0x55, + 0x4f, 0x63, 0x77, 0x0a, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, + 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, + 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, + 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x59, 0x59, 0x77, + 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, + 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, 0x0a, 0x67, 0x67, 0x45, + 0x42, 0x41, 0x43, 0x55, 0x59, 0x31, 0x4a, 0x47, 0x50, 0x45, 0x2b, 0x36, + 0x50, 0x48, 0x68, 0x30, 0x52, 0x55, 0x39, 0x6f, 0x74, 0x52, 0x43, 0x6b, + 0x5a, 0x6f, 0x42, 0x35, 0x72, 0x4d, 0x5a, 0x35, 0x4e, 0x44, 0x70, 0x36, + 0x74, 0x50, 0x56, 0x78, 0x42, 0x62, 0x35, 0x55, 0x72, 0x4a, 0x4b, 0x46, + 0x35, 0x6d, 0x44, 0x6f, 0x34, 0x4e, 0x76, 0x75, 0x37, 0x5a, 0x70, 0x35, + 0x49, 0x0a, 0x2f, 0x35, 0x43, 0x51, 0x37, 0x7a, 0x33, 0x55, 0x75, 0x4a, + 0x75, 0x30, 0x68, 0x33, 0x55, 0x2f, 0x49, 0x4a, 0x76, 0x4f, 0x63, 0x73, + 0x2b, 0x68, 0x56, 0x63, 0x46, 0x4e, 0x5a, 0x4b, 0x49, 0x5a, 0x42, 0x71, + 0x45, 0x48, 0x4d, 0x77, 0x77, 0x4c, 0x4b, 0x65, 0x58, 0x78, 0x36, 0x71, + 0x75, 0x6a, 0x37, 0x4c, 0x55, 0x4b, 0x64, 0x4a, 0x44, 0x48, 0x66, 0x58, + 0x4c, 0x79, 0x31, 0x31, 0x79, 0x66, 0x0a, 0x6b, 0x65, 0x2b, 0x52, 0x69, + 0x37, 0x66, 0x63, 0x37, 0x57, 0x61, 0x69, 0x7a, 0x34, 0x35, 0x6d, 0x4f, + 0x37, 0x79, 0x66, 0x4f, 0x67, 0x4c, 0x67, 0x4a, 0x39, 0x30, 0x57, 0x6d, + 0x4d, 0x43, 0x56, 0x31, 0x41, 0x71, 0x6b, 0x35, 0x49, 0x47, 0x61, 0x64, + 0x5a, 0x51, 0x31, 0x6e, 0x4a, 0x42, 0x66, 0x69, 0x44, 0x63, 0x47, 0x72, + 0x56, 0x6d, 0x56, 0x43, 0x72, 0x44, 0x52, 0x5a, 0x39, 0x4d, 0x5a, 0x0a, + 0x79, 0x6f, 0x6e, 0x6e, 0x4d, 0x6c, 0x6f, 0x32, 0x48, 0x44, 0x36, 0x43, + 0x71, 0x46, 0x71, 0x54, 0x76, 0x73, 0x62, 0x51, 0x5a, 0x4a, 0x47, 0x32, + 0x7a, 0x39, 0x6d, 0x32, 0x47, 0x4d, 0x2f, 0x62, 0x66, 0x74, 0x4a, 0x6c, + 0x6f, 0x36, 0x62, 0x45, 0x6a, 0x68, 0x63, 0x78, 0x77, 0x66, 0x74, 0x2b, + 0x64, 0x74, 0x76, 0x54, 0x68, 0x65, 0x4e, 0x59, 0x73, 0x6e, 0x64, 0x36, + 0x64, 0x6a, 0x74, 0x73, 0x0a, 0x4c, 0x31, 0x41, 0x63, 0x35, 0x39, 0x76, + 0x32, 0x5a, 0x33, 0x6b, 0x66, 0x39, 0x59, 0x4b, 0x56, 0x6d, 0x67, 0x65, + 0x6e, 0x46, 0x4b, 0x2b, 0x50, 0x33, 0x43, 0x67, 0x68, 0x5a, 0x77, 0x6e, + 0x53, 0x31, 0x6b, 0x31, 0x61, 0x48, 0x42, 0x6b, 0x63, 0x6a, 0x6e, 0x64, + 0x63, 0x77, 0x35, 0x51, 0x6b, 0x50, 0x54, 0x4a, 0x72, 0x53, 0x33, 0x37, + 0x55, 0x65, 0x4a, 0x53, 0x44, 0x76, 0x6a, 0x64, 0x4e, 0x0a, 0x7a, 0x6c, + 0x2f, 0x48, 0x48, 0x6b, 0x34, 0x38, 0x34, 0x49, 0x6b, 0x7a, 0x6c, 0x51, + 0x73, 0x50, 0x70, 0x54, 0x4c, 0x57, 0x50, 0x46, 0x70, 0x35, 0x4c, 0x42, + 0x6b, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x43, 0x6f, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, 0x74, + 0x20, 0x43, 0x41, 0x2d, 0x32, 0x20, 0x4f, 0x3d, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x43, 0x6f, 0x72, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, + 0x20, 0x53, 0x2e, 0x20, 0x64, 0x65, 0x20, 0x52, 0x2e, 0x4c, 0x2e, 0x20, + 0x4f, 0x55, 0x3d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x43, 0x65, 0x72, 0x74, 0x20, 0x43, 0x41, 0x2d, 0x32, 0x20, 0x4f, + 0x3d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x53, 0x2e, 0x20, 0x64, 0x65, 0x20, + 0x52, 0x2e, 0x4c, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x43, 0x6f, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x43, 0x65, 0x72, 0x74, 0x20, 0x43, 0x41, 0x2d, 0x32, 0x22, + 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x32, + 0x37, 0x31, 0x31, 0x36, 0x39, 0x34, 0x35, 0x31, 0x30, 0x31, 0x39, 0x39, + 0x31, 0x30, 0x31, 0x36, 0x39, 0x38, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x61, 0x32, 0x3a, 0x65, 0x31, 0x3a, 0x66, 0x38, 0x3a, 0x31, + 0x38, 0x3a, 0x30, 0x62, 0x3a, 0x62, 0x61, 0x3a, 0x34, 0x35, 0x3a, 0x64, + 0x35, 0x3a, 0x63, 0x37, 0x3a, 0x34, 0x31, 0x3a, 0x32, 0x61, 0x3a, 0x62, + 0x62, 0x3a, 0x33, 0x37, 0x3a, 0x35, 0x32, 0x3a, 0x34, 0x35, 0x3a, 0x36, + 0x34, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x38, + 0x3a, 0x62, 0x65, 0x3a, 0x36, 0x64, 0x3a, 0x63, 0x62, 0x3a, 0x35, 0x36, + 0x3a, 0x66, 0x31, 0x3a, 0x35, 0x35, 0x3a, 0x62, 0x39, 0x3a, 0x36, 0x33, + 0x3a, 0x64, 0x34, 0x3a, 0x31, 0x32, 0x3a, 0x63, 0x61, 0x3a, 0x34, 0x65, + 0x3a, 0x30, 0x36, 0x3a, 0x33, 0x34, 0x3a, 0x63, 0x37, 0x3a, 0x39, 0x34, + 0x3a, 0x62, 0x32, 0x3a, 0x31, 0x63, 0x3a, 0x63, 0x30, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, 0x37, 0x3a, 0x35, + 0x33, 0x3a, 0x65, 0x39, 0x3a, 0x34, 0x30, 0x3a, 0x33, 0x37, 0x3a, 0x38, + 0x63, 0x3a, 0x31, 0x62, 0x3a, 0x64, 0x35, 0x3a, 0x65, 0x33, 0x3a, 0x38, + 0x33, 0x3a, 0x36, 0x65, 0x3a, 0x33, 0x39, 0x3a, 0x35, 0x64, 0x3a, 0x61, + 0x65, 0x3a, 0x61, 0x35, 0x3a, 0x63, 0x62, 0x3a, 0x38, 0x33, 0x3a, 0x39, + 0x65, 0x3a, 0x35, 0x30, 0x3a, 0x34, 0x36, 0x3a, 0x66, 0x31, 0x3a, 0x62, + 0x64, 0x3a, 0x30, 0x65, 0x3a, 0x61, 0x65, 0x3a, 0x31, 0x39, 0x3a, 0x35, + 0x31, 0x3a, 0x63, 0x66, 0x3a, 0x31, 0x30, 0x3a, 0x66, 0x65, 0x3a, 0x63, + 0x37, 0x3a, 0x63, 0x39, 0x3a, 0x36, 0x35, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x47, 0x4c, 0x7a, 0x43, 0x43, 0x42, 0x42, 0x65, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x49, 0x4a, 0x61, 0x48, 0x66, + 0x79, 0x6a, 0x50, 0x4c, 0x57, 0x51, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, + 0x42, 0x51, 0x41, 0x77, 0x67, 0x61, 0x51, 0x78, 0x43, 0x7a, 0x41, 0x4a, + 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x42, + 0x42, 0x4d, 0x51, 0x38, 0x77, 0x44, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x49, 0x44, 0x41, 0x5a, 0x51, 0x59, 0x57, 0x35, 0x68, 0x62, 0x57, 0x45, + 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, + 0x4d, 0x43, 0x31, 0x42, 0x68, 0x62, 0x6d, 0x46, 0x74, 0x59, 0x53, 0x42, + 0x44, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x53, 0x51, 0x77, 0x0a, 0x49, 0x67, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x74, 0x55, 0x63, 0x6e, + 0x56, 0x7a, 0x64, 0x45, 0x4e, 0x76, 0x63, 0x69, 0x42, 0x54, 0x65, 0x58, + 0x4e, 0x30, 0x5a, 0x57, 0x31, 0x7a, 0x49, 0x46, 0x4d, 0x75, 0x49, 0x47, + 0x52, 0x6c, 0x49, 0x46, 0x49, 0x75, 0x54, 0x43, 0x34, 0x78, 0x4a, 0x7a, + 0x41, 0x6c, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x4d, 0x48, 0x6c, + 0x52, 0x79, 0x0a, 0x64, 0x58, 0x4e, 0x30, 0x51, 0x32, 0x39, 0x79, 0x49, + 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, + 0x58, 0x52, 0x6c, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, + 0x6d, 0x6c, 0x30, 0x65, 0x54, 0x45, 0x66, 0x4d, 0x42, 0x30, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x57, 0x56, 0x48, 0x4a, 0x31, 0x63, + 0x33, 0x52, 0x44, 0x62, 0x33, 0x49, 0x67, 0x0a, 0x55, 0x6d, 0x39, 0x76, + 0x64, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x51, 0x67, 0x51, 0x30, 0x45, 0x74, + 0x4d, 0x6a, 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4e, 0x6a, 0x41, 0x79, + 0x4d, 0x44, 0x51, 0x78, 0x4d, 0x6a, 0x4d, 0x79, 0x4d, 0x6a, 0x4e, 0x61, + 0x46, 0x77, 0x30, 0x7a, 0x4e, 0x44, 0x45, 0x79, 0x4d, 0x7a, 0x45, 0x78, + 0x4e, 0x7a, 0x49, 0x32, 0x4d, 0x7a, 0x6c, 0x61, 0x4d, 0x49, 0x47, 0x6b, + 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x47, 0x45, 0x77, 0x4a, 0x51, 0x51, 0x54, 0x45, 0x50, 0x4d, 0x41, 0x30, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x47, 0x55, 0x47, 0x46, + 0x75, 0x59, 0x57, 0x31, 0x68, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x51, 0x59, 0x57, 0x35, + 0x68, 0x62, 0x57, 0x45, 0x67, 0x0a, 0x51, 0x32, 0x6c, 0x30, 0x65, 0x54, + 0x45, 0x6b, 0x4d, 0x43, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, + 0x77, 0x62, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x44, 0x62, 0x33, + 0x49, 0x67, 0x55, 0x33, 0x6c, 0x7a, 0x64, 0x47, 0x56, 0x74, 0x63, 0x79, + 0x42, 0x54, 0x4c, 0x69, 0x42, 0x6b, 0x5a, 0x53, 0x42, 0x53, 0x4c, 0x6b, + 0x77, 0x75, 0x4d, 0x53, 0x63, 0x77, 0x4a, 0x51, 0x59, 0x44, 0x0a, 0x56, + 0x51, 0x51, 0x4c, 0x44, 0x42, 0x35, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, + 0x45, 0x4e, 0x76, 0x63, 0x69, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, + 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, 0x53, 0x42, 0x42, 0x64, + 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x78, 0x48, + 0x7a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x46, + 0x6c, 0x52, 0x79, 0x0a, 0x64, 0x58, 0x4e, 0x30, 0x51, 0x32, 0x39, 0x79, + 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x52, 0x44, 0x5a, 0x58, 0x4a, 0x30, + 0x49, 0x45, 0x4e, 0x42, 0x4c, 0x54, 0x49, 0x77, 0x67, 0x67, 0x49, 0x69, + 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, + 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, + 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x0a, 0x41, 0x6f, 0x49, + 0x43, 0x41, 0x51, 0x43, 0x6e, 0x49, 0x47, 0x37, 0x43, 0x4b, 0x71, 0x4a, + 0x69, 0x4a, 0x4a, 0x57, 0x51, 0x64, 0x73, 0x67, 0x34, 0x66, 0x6f, 0x44, + 0x53, 0x71, 0x38, 0x47, 0x62, 0x5a, 0x51, 0x57, 0x55, 0x39, 0x4d, 0x45, + 0x4b, 0x45, 0x4e, 0x55, 0x43, 0x72, 0x4f, 0x32, 0x66, 0x6b, 0x38, 0x65, + 0x48, 0x79, 0x4c, 0x41, 0x6e, 0x4b, 0x30, 0x49, 0x4d, 0x50, 0x51, 0x6f, + 0x2b, 0x0a, 0x51, 0x56, 0x71, 0x65, 0x64, 0x64, 0x32, 0x4e, 0x79, 0x75, + 0x43, 0x62, 0x37, 0x47, 0x67, 0x79, 0x70, 0x47, 0x6d, 0x53, 0x61, 0x49, + 0x77, 0x4c, 0x67, 0x51, 0x35, 0x57, 0x6f, 0x44, 0x34, 0x61, 0x33, 0x53, + 0x77, 0x6c, 0x46, 0x49, 0x49, 0x76, 0x6c, 0x39, 0x4e, 0x6b, 0x52, 0x76, + 0x52, 0x55, 0x71, 0x64, 0x77, 0x36, 0x56, 0x43, 0x30, 0x78, 0x4b, 0x35, + 0x6d, 0x43, 0x38, 0x74, 0x6b, 0x71, 0x0a, 0x31, 0x2b, 0x39, 0x78, 0x41, + 0x4c, 0x67, 0x78, 0x70, 0x4c, 0x35, 0x36, 0x4a, 0x41, 0x66, 0x44, 0x51, + 0x69, 0x44, 0x79, 0x69, 0x74, 0x53, 0x53, 0x42, 0x42, 0x74, 0x6c, 0x56, + 0x6b, 0x78, 0x73, 0x31, 0x50, 0x75, 0x32, 0x59, 0x56, 0x70, 0x48, 0x49, + 0x37, 0x54, 0x59, 0x61, 0x62, 0x53, 0x33, 0x4f, 0x74, 0x42, 0x30, 0x50, + 0x41, 0x78, 0x31, 0x6f, 0x59, 0x78, 0x4f, 0x64, 0x71, 0x48, 0x70, 0x0a, + 0x32, 0x79, 0x71, 0x6c, 0x4f, 0x2f, 0x72, 0x4f, 0x73, 0x50, 0x39, 0x2b, + 0x61, 0x69, 0x6a, 0x39, 0x4a, 0x78, 0x7a, 0x49, 0x73, 0x65, 0x6b, 0x70, + 0x38, 0x56, 0x64, 0x75, 0x5a, 0x4c, 0x54, 0x51, 0x77, 0x52, 0x56, 0x74, + 0x44, 0x72, 0x34, 0x75, 0x44, 0x6b, 0x62, 0x49, 0x58, 0x76, 0x52, 0x52, + 0x2f, 0x75, 0x38, 0x4f, 0x59, 0x7a, 0x6f, 0x37, 0x63, 0x62, 0x72, 0x50, + 0x62, 0x31, 0x6e, 0x4b, 0x0a, 0x44, 0x4f, 0x4f, 0x62, 0x58, 0x55, 0x6d, + 0x34, 0x54, 0x4f, 0x4a, 0x58, 0x73, 0x5a, 0x69, 0x4b, 0x51, 0x6c, 0x65, + 0x63, 0x64, 0x75, 0x2f, 0x76, 0x76, 0x64, 0x46, 0x6f, 0x71, 0x4e, 0x4c, + 0x30, 0x43, 0x62, 0x74, 0x33, 0x4e, 0x62, 0x34, 0x6c, 0x67, 0x67, 0x6a, + 0x45, 0x46, 0x69, 0x78, 0x45, 0x49, 0x46, 0x61, 0x70, 0x52, 0x42, 0x46, + 0x33, 0x37, 0x31, 0x32, 0x30, 0x48, 0x61, 0x70, 0x65, 0x0a, 0x61, 0x7a, + 0x36, 0x4c, 0x4d, 0x76, 0x59, 0x48, 0x4c, 0x31, 0x63, 0x45, 0x6b, 0x73, + 0x72, 0x31, 0x2f, 0x70, 0x33, 0x43, 0x36, 0x65, 0x69, 0x7a, 0x6a, 0x6b, + 0x78, 0x4c, 0x41, 0x6a, 0x48, 0x5a, 0x35, 0x44, 0x78, 0x49, 0x67, 0x69, + 0x66, 0x33, 0x47, 0x49, 0x4a, 0x32, 0x53, 0x44, 0x70, 0x78, 0x73, 0x52, + 0x4f, 0x68, 0x4f, 0x64, 0x55, 0x75, 0x78, 0x54, 0x54, 0x43, 0x48, 0x57, + 0x4b, 0x46, 0x0a, 0x33, 0x77, 0x50, 0x2b, 0x54, 0x66, 0x53, 0x76, 0x50, + 0x64, 0x39, 0x63, 0x57, 0x34, 0x33, 0x36, 0x63, 0x4f, 0x47, 0x6c, 0x66, + 0x69, 0x66, 0x48, 0x68, 0x69, 0x35, 0x71, 0x6a, 0x78, 0x4c, 0x47, 0x68, + 0x46, 0x35, 0x44, 0x55, 0x56, 0x43, 0x63, 0x47, 0x5a, 0x74, 0x34, 0x35, + 0x76, 0x7a, 0x32, 0x37, 0x55, 0x64, 0x2b, 0x65, 0x7a, 0x31, 0x6d, 0x37, + 0x78, 0x4d, 0x54, 0x69, 0x46, 0x38, 0x38, 0x0a, 0x6f, 0x57, 0x50, 0x37, + 0x2b, 0x61, 0x79, 0x48, 0x4e, 0x5a, 0x2f, 0x7a, 0x67, 0x70, 0x36, 0x6b, + 0x50, 0x77, 0x71, 0x63, 0x4d, 0x57, 0x6d, 0x4c, 0x6d, 0x61, 0x53, 0x49, + 0x53, 0x6f, 0x35, 0x75, 0x5a, 0x6b, 0x33, 0x76, 0x46, 0x73, 0x51, 0x50, + 0x65, 0x53, 0x67, 0x68, 0x59, 0x41, 0x32, 0x46, 0x46, 0x6e, 0x33, 0x58, + 0x56, 0x44, 0x6a, 0x78, 0x6b, 0x6c, 0x62, 0x39, 0x74, 0x54, 0x4e, 0x4d, + 0x0a, 0x67, 0x39, 0x7a, 0x58, 0x45, 0x4a, 0x39, 0x4c, 0x2f, 0x63, 0x62, + 0x34, 0x51, 0x72, 0x32, 0x36, 0x66, 0x48, 0x4d, 0x43, 0x34, 0x50, 0x39, + 0x39, 0x7a, 0x56, 0x76, 0x68, 0x31, 0x4b, 0x78, 0x68, 0x65, 0x31, 0x66, + 0x56, 0x53, 0x6e, 0x74, 0x62, 0x31, 0x49, 0x56, 0x59, 0x4a, 0x31, 0x32, + 0x2f, 0x2b, 0x43, 0x74, 0x67, 0x72, 0x4b, 0x41, 0x6d, 0x72, 0x68, 0x51, + 0x68, 0x4a, 0x38, 0x5a, 0x33, 0x0a, 0x6d, 0x6a, 0x4f, 0x41, 0x50, 0x46, + 0x35, 0x47, 0x50, 0x2f, 0x66, 0x44, 0x73, 0x61, 0x4f, 0x47, 0x4d, 0x38, + 0x62, 0x6f, 0x58, 0x67, 0x32, 0x35, 0x4e, 0x53, 0x79, 0x71, 0x52, 0x73, + 0x47, 0x46, 0x41, 0x6e, 0x57, 0x41, 0x6f, 0x4f, 0x73, 0x6b, 0x2b, 0x78, + 0x57, 0x71, 0x35, 0x47, 0x64, 0x2f, 0x62, 0x6e, 0x63, 0x2f, 0x39, 0x41, + 0x53, 0x4b, 0x4c, 0x33, 0x78, 0x37, 0x34, 0x78, 0x64, 0x68, 0x0a, 0x38, + 0x4e, 0x30, 0x4a, 0x71, 0x53, 0x44, 0x49, 0x76, 0x67, 0x6d, 0x6b, 0x30, + 0x48, 0x35, 0x45, 0x77, 0x37, 0x49, 0x77, 0x53, 0x6a, 0x69, 0x71, 0x71, + 0x65, 0x77, 0x59, 0x6d, 0x67, 0x65, 0x43, 0x4b, 0x39, 0x75, 0x34, 0x6e, + 0x42, 0x69, 0x74, 0x32, 0x75, 0x42, 0x47, 0x46, 0x36, 0x7a, 0x50, 0x58, + 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x32, 0x4d, 0x77, 0x59, + 0x54, 0x41, 0x64, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, + 0x46, 0x67, 0x51, 0x55, 0x32, 0x66, 0x34, 0x68, 0x51, 0x47, 0x36, 0x55, + 0x6e, 0x72, 0x79, 0x62, 0x50, 0x5a, 0x78, 0x39, 0x6d, 0x43, 0x41, 0x5a, + 0x35, 0x59, 0x77, 0x77, 0x59, 0x72, 0x49, 0x77, 0x48, 0x77, 0x59, 0x44, + 0x56, 0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, + 0x32, 0x66, 0x34, 0x68, 0x51, 0x47, 0x36, 0x55, 0x0a, 0x6e, 0x72, 0x79, + 0x62, 0x50, 0x5a, 0x78, 0x39, 0x6d, 0x43, 0x41, 0x5a, 0x35, 0x59, 0x77, + 0x77, 0x59, 0x72, 0x49, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, + 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, + 0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, + 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x59, 0x59, + 0x77, 0x0a, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, + 0x49, 0x42, 0x41, 0x4a, 0x35, 0x46, 0x6e, 0x67, 0x77, 0x37, 0x74, 0x75, + 0x2f, 0x68, 0x4f, 0x73, 0x68, 0x38, 0x30, 0x51, 0x41, 0x39, 0x7a, 0x2b, + 0x4c, 0x71, 0x42, 0x72, 0x57, 0x79, 0x4f, 0x72, 0x73, 0x47, 0x53, 0x32, + 0x68, 0x36, 0x30, 0x43, 0x4f, 0x58, 0x0a, 0x64, 0x4b, 0x63, 0x73, 0x38, + 0x41, 0x6a, 0x59, 0x65, 0x56, 0x72, 0x58, 0x57, 0x6f, 0x53, 0x4b, 0x32, + 0x42, 0x4b, 0x61, 0x47, 0x39, 0x6c, 0x39, 0x58, 0x45, 0x31, 0x77, 0x78, + 0x61, 0x58, 0x35, 0x71, 0x2b, 0x57, 0x6a, 0x69, 0x59, 0x6e, 0x64, 0x41, + 0x66, 0x72, 0x73, 0x33, 0x66, 0x6e, 0x70, 0x6b, 0x70, 0x66, 0x62, 0x73, + 0x45, 0x5a, 0x43, 0x38, 0x39, 0x4e, 0x69, 0x71, 0x70, 0x58, 0x2b, 0x0a, + 0x4d, 0x57, 0x63, 0x55, 0x61, 0x56, 0x69, 0x51, 0x43, 0x71, 0x6f, 0x4c, + 0x37, 0x6a, 0x63, 0x6a, 0x78, 0x31, 0x42, 0x52, 0x74, 0x50, 0x56, 0x2b, + 0x6e, 0x75, 0x4e, 0x37, 0x39, 0x2b, 0x54, 0x4d, 0x51, 0x6a, 0x49, 0x74, + 0x53, 0x51, 0x7a, 0x4c, 0x2f, 0x30, 0x6b, 0x4d, 0x6d, 0x78, 0x34, 0x30, + 0x2f, 0x57, 0x35, 0x75, 0x6c, 0x6f, 0x70, 0x35, 0x41, 0x37, 0x5a, 0x76, + 0x32, 0x77, 0x6e, 0x4c, 0x0a, 0x2f, 0x56, 0x39, 0x6c, 0x46, 0x44, 0x66, + 0x68, 0x4f, 0x50, 0x58, 0x7a, 0x59, 0x52, 0x5a, 0x59, 0x35, 0x4c, 0x56, + 0x74, 0x44, 0x51, 0x73, 0x45, 0x47, 0x7a, 0x39, 0x51, 0x4c, 0x58, 0x2b, + 0x7a, 0x78, 0x33, 0x6f, 0x61, 0x46, 0x6f, 0x42, 0x67, 0x2b, 0x49, 0x6f, + 0x66, 0x36, 0x52, 0x73, 0x71, 0x78, 0x76, 0x6d, 0x36, 0x41, 0x52, 0x70, + 0x70, 0x76, 0x39, 0x4a, 0x59, 0x78, 0x31, 0x52, 0x58, 0x0a, 0x43, 0x49, + 0x2f, 0x68, 0x4f, 0x57, 0x42, 0x33, 0x53, 0x36, 0x78, 0x5a, 0x68, 0x42, + 0x71, 0x49, 0x38, 0x64, 0x33, 0x4c, 0x54, 0x33, 0x6a, 0x58, 0x35, 0x2b, + 0x45, 0x7a, 0x4c, 0x66, 0x7a, 0x75, 0x51, 0x66, 0x6f, 0x67, 0x73, 0x4c, + 0x37, 0x4c, 0x39, 0x7a, 0x69, 0x55, 0x77, 0x4f, 0x48, 0x51, 0x68, 0x51, + 0x2b, 0x37, 0x37, 0x53, 0x78, 0x7a, 0x71, 0x2b, 0x33, 0x2b, 0x6b, 0x6e, + 0x59, 0x61, 0x0a, 0x5a, 0x48, 0x39, 0x62, 0x44, 0x54, 0x4d, 0x4a, 0x42, + 0x7a, 0x4e, 0x37, 0x42, 0x6a, 0x38, 0x52, 0x70, 0x46, 0x78, 0x77, 0x50, + 0x49, 0x58, 0x41, 0x7a, 0x2b, 0x4f, 0x51, 0x71, 0x49, 0x4e, 0x33, 0x2b, + 0x74, 0x76, 0x6d, 0x78, 0x59, 0x78, 0x6f, 0x5a, 0x78, 0x42, 0x6e, 0x70, + 0x56, 0x49, 0x74, 0x38, 0x4d, 0x53, 0x5a, 0x6a, 0x33, 0x2b, 0x2f, 0x30, + 0x57, 0x76, 0x69, 0x74, 0x55, 0x66, 0x57, 0x0a, 0x32, 0x64, 0x43, 0x46, + 0x6d, 0x55, 0x32, 0x55, 0x6d, 0x77, 0x39, 0x4c, 0x6a, 0x65, 0x34, 0x41, + 0x57, 0x6b, 0x63, 0x64, 0x45, 0x51, 0x4f, 0x73, 0x51, 0x52, 0x69, 0x76, + 0x68, 0x37, 0x64, 0x76, 0x44, 0x44, 0x71, 0x50, 0x79, 0x73, 0x2f, 0x63, + 0x41, 0x38, 0x47, 0x69, 0x43, 0x63, 0x6a, 0x6c, 0x2f, 0x59, 0x42, 0x65, + 0x79, 0x47, 0x42, 0x43, 0x41, 0x52, 0x73, 0x61, 0x55, 0x31, 0x71, 0x37, + 0x0a, 0x4e, 0x36, 0x61, 0x33, 0x76, 0x4c, 0x71, 0x45, 0x36, 0x52, 0x35, + 0x73, 0x47, 0x74, 0x52, 0x6b, 0x32, 0x74, 0x52, 0x44, 0x2f, 0x70, 0x4f, + 0x4c, 0x53, 0x2f, 0x49, 0x73, 0x65, 0x52, 0x59, 0x51, 0x31, 0x4a, 0x4d, + 0x4c, 0x69, 0x49, 0x2b, 0x68, 0x32, 0x49, 0x59, 0x55, 0x52, 0x70, 0x46, + 0x48, 0x6d, 0x79, 0x67, 0x6b, 0x37, 0x31, 0x64, 0x53, 0x54, 0x6c, 0x78, + 0x43, 0x6e, 0x4b, 0x72, 0x33, 0x0a, 0x53, 0x65, 0x77, 0x6e, 0x36, 0x45, + 0x41, 0x65, 0x73, 0x36, 0x61, 0x4a, 0x49, 0x6e, 0x4b, 0x63, 0x39, 0x51, + 0x30, 0x7a, 0x74, 0x46, 0x69, 0x6a, 0x4d, 0x44, 0x76, 0x64, 0x31, 0x47, + 0x70, 0x55, 0x6b, 0x37, 0x34, 0x61, 0x54, 0x66, 0x4f, 0x54, 0x6c, 0x50, + 0x66, 0x38, 0x68, 0x41, 0x73, 0x2f, 0x68, 0x43, 0x42, 0x63, 0x4e, 0x41, + 0x4e, 0x45, 0x78, 0x64, 0x71, 0x74, 0x76, 0x41, 0x72, 0x42, 0x0a, 0x41, + 0x73, 0x38, 0x65, 0x35, 0x5a, 0x54, 0x5a, 0x38, 0x34, 0x35, 0x62, 0x32, + 0x45, 0x7a, 0x77, 0x6e, 0x65, 0x78, 0x68, 0x46, 0x37, 0x73, 0x55, 0x4d, + 0x6c, 0x51, 0x4d, 0x41, 0x69, 0x6d, 0x54, 0x48, 0x70, 0x4b, 0x47, 0x39, + 0x6e, 0x2f, 0x76, 0x35, 0x35, 0x49, 0x46, 0x44, 0x6c, 0x6e, 0x64, 0x6d, + 0x51, 0x67, 0x75, 0x4c, 0x76, 0x71, 0x63, 0x41, 0x46, 0x4c, 0x54, 0x78, + 0x57, 0x59, 0x70, 0x0a, 0x35, 0x4b, 0x65, 0x58, 0x52, 0x4b, 0x51, 0x4f, + 0x4b, 0x49, 0x45, 0x54, 0x4e, 0x63, 0x58, 0x32, 0x62, 0x32, 0x54, 0x6d, + 0x51, 0x63, 0x54, 0x56, 0x4c, 0x38, 0x77, 0x30, 0x52, 0x53, 0x58, 0x50, + 0x51, 0x51, 0x43, 0x57, 0x50, 0x55, 0x6f, 0x75, 0x77, 0x70, 0x61, 0x59, + 0x54, 0x30, 0x35, 0x4b, 0x6e, 0x4a, 0x65, 0x33, 0x32, 0x78, 0x2b, 0x53, + 0x4d, 0x73, 0x6a, 0x2f, 0x44, 0x31, 0x46, 0x75, 0x0a, 0x31, 0x75, 0x77, + 0x4a, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, + 0x6f, 0x72, 0x20, 0x45, 0x43, 0x41, 0x2d, 0x31, 0x20, 0x4f, 0x3d, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x73, 0x20, 0x53, 0x2e, 0x20, 0x64, 0x65, 0x20, 0x52, 0x2e, + 0x4c, 0x2e, 0x20, 0x4f, 0x55, 0x3d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, + 0x6f, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, + 0x45, 0x43, 0x41, 0x2d, 0x31, 0x20, 0x4f, 0x3d, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x43, 0x6f, 0x72, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, + 0x20, 0x53, 0x2e, 0x20, 0x64, 0x65, 0x20, 0x52, 0x2e, 0x4c, 0x2e, 0x20, + 0x4f, 0x55, 0x3d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x43, 0x6f, 0x72, 0x20, 0x45, 0x43, 0x41, 0x2d, 0x31, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x39, 0x35, + 0x34, 0x38, 0x32, 0x34, 0x32, 0x39, 0x34, 0x36, 0x39, 0x38, 0x38, 0x36, + 0x32, 0x35, 0x39, 0x38, 0x34, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x32, 0x37, 0x3a, 0x39, 0x32, 0x3a, 0x32, 0x33, 0x3a, 0x31, 0x64, + 0x3a, 0x30, 0x61, 0x3a, 0x66, 0x35, 0x3a, 0x34, 0x30, 0x3a, 0x37, 0x63, + 0x3a, 0x65, 0x39, 0x3a, 0x65, 0x36, 0x3a, 0x36, 0x62, 0x3a, 0x39, 0x64, + 0x3a, 0x64, 0x38, 0x3a, 0x66, 0x35, 0x3a, 0x65, 0x37, 0x3a, 0x36, 0x63, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x38, 0x3a, + 0x64, 0x31, 0x3a, 0x64, 0x66, 0x3a, 0x39, 0x35, 0x3a, 0x39, 0x35, 0x3a, + 0x36, 0x37, 0x3a, 0x36, 0x62, 0x3a, 0x36, 0x33, 0x3a, 0x63, 0x30, 0x3a, + 0x66, 0x30, 0x3a, 0x35, 0x62, 0x3a, 0x31, 0x63, 0x3a, 0x31, 0x37, 0x3a, + 0x34, 0x64, 0x3a, 0x38, 0x62, 0x3a, 0x38, 0x34, 0x3a, 0x30, 0x62, 0x3a, + 0x63, 0x38, 0x3a, 0x37, 0x38, 0x3a, 0x62, 0x64, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x61, 0x3a, 0x38, 0x38, + 0x3a, 0x35, 0x64, 0x3a, 0x62, 0x31, 0x3a, 0x39, 0x63, 0x3a, 0x30, 0x31, + 0x3a, 0x64, 0x39, 0x3a, 0x31, 0x32, 0x3a, 0x63, 0x35, 0x3a, 0x37, 0x35, + 0x3a, 0x39, 0x33, 0x3a, 0x38, 0x38, 0x3a, 0x39, 0x33, 0x3a, 0x38, 0x63, + 0x3a, 0x61, 0x66, 0x3a, 0x62, 0x62, 0x3a, 0x64, 0x66, 0x3a, 0x30, 0x33, + 0x3a, 0x31, 0x61, 0x3a, 0x62, 0x32, 0x3a, 0x64, 0x34, 0x3a, 0x38, 0x65, + 0x3a, 0x39, 0x31, 0x3a, 0x65, 0x65, 0x3a, 0x31, 0x35, 0x3a, 0x35, 0x38, + 0x3a, 0x39, 0x62, 0x3a, 0x34, 0x32, 0x3a, 0x39, 0x37, 0x3a, 0x31, 0x64, + 0x3a, 0x30, 0x33, 0x3a, 0x39, 0x63, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x45, 0x49, 0x44, 0x43, 0x43, 0x41, 0x77, 0x69, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x4a, 0x41, 0x49, 0x53, 0x43, 0x4c, + 0x46, 0x38, 0x63, 0x59, 0x74, 0x42, 0x41, 0x4d, 0x41, 0x30, 0x47, 0x43, + 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, + 0x77, 0x55, 0x41, 0x4d, 0x49, 0x47, 0x63, 0x4d, 0x51, 0x73, 0x77, 0x43, + 0x51, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x51, + 0x51, 0x54, 0x45, 0x50, 0x4d, 0x41, 0x30, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x41, 0x77, 0x47, 0x55, 0x47, 0x46, 0x75, 0x59, 0x57, 0x31, 0x68, + 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, + 0x44, 0x41, 0x74, 0x51, 0x59, 0x57, 0x35, 0x68, 0x62, 0x57, 0x45, 0x67, + 0x51, 0x32, 0x6c, 0x30, 0x65, 0x54, 0x45, 0x6b, 0x0a, 0x4d, 0x43, 0x49, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x62, 0x56, 0x48, 0x4a, + 0x31, 0x63, 0x33, 0x52, 0x44, 0x62, 0x33, 0x49, 0x67, 0x55, 0x33, 0x6c, + 0x7a, 0x64, 0x47, 0x56, 0x74, 0x63, 0x79, 0x42, 0x54, 0x4c, 0x69, 0x42, + 0x6b, 0x5a, 0x53, 0x42, 0x53, 0x4c, 0x6b, 0x77, 0x75, 0x4d, 0x53, 0x63, + 0x77, 0x4a, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x44, 0x42, 0x35, + 0x55, 0x0a, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x45, 0x4e, 0x76, 0x63, 0x69, + 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, + 0x46, 0x30, 0x5a, 0x53, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, + 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x78, 0x46, 0x7a, 0x41, 0x56, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x44, 0x6c, 0x52, 0x79, 0x64, 0x58, + 0x4e, 0x30, 0x51, 0x32, 0x39, 0x79, 0x0a, 0x49, 0x45, 0x56, 0x44, 0x51, + 0x53, 0x30, 0x78, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x32, 0x4d, + 0x44, 0x49, 0x77, 0x4e, 0x44, 0x45, 0x79, 0x4d, 0x7a, 0x49, 0x7a, 0x4d, + 0x31, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x35, 0x4d, 0x54, 0x49, 0x7a, 0x4d, + 0x54, 0x45, 0x33, 0x4d, 0x6a, 0x67, 0x77, 0x4e, 0x31, 0x6f, 0x77, 0x67, + 0x5a, 0x77, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x0a, + 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x42, 0x42, 0x4d, 0x51, 0x38, 0x77, + 0x44, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, 0x44, 0x41, 0x5a, 0x51, + 0x59, 0x57, 0x35, 0x68, 0x62, 0x57, 0x45, 0x78, 0x46, 0x44, 0x41, 0x53, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x4d, 0x43, 0x31, 0x42, 0x68, + 0x62, 0x6d, 0x46, 0x74, 0x59, 0x53, 0x42, 0x44, 0x61, 0x58, 0x52, 0x35, + 0x4d, 0x53, 0x51, 0x77, 0x0a, 0x49, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x4b, 0x44, 0x42, 0x74, 0x55, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x45, 0x4e, + 0x76, 0x63, 0x69, 0x42, 0x54, 0x65, 0x58, 0x4e, 0x30, 0x5a, 0x57, 0x31, + 0x7a, 0x49, 0x46, 0x4d, 0x75, 0x49, 0x47, 0x52, 0x6c, 0x49, 0x46, 0x49, + 0x75, 0x54, 0x43, 0x34, 0x78, 0x4a, 0x7a, 0x41, 0x6c, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x73, 0x4d, 0x48, 0x6c, 0x52, 0x79, 0x0a, 0x64, 0x58, + 0x4e, 0x30, 0x51, 0x32, 0x39, 0x79, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, + 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x49, 0x45, + 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x54, + 0x45, 0x58, 0x4d, 0x42, 0x55, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, + 0x77, 0x4f, 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x52, 0x44, 0x62, 0x33, + 0x49, 0x67, 0x0a, 0x52, 0x55, 0x4e, 0x42, 0x4c, 0x54, 0x45, 0x77, 0x67, + 0x67, 0x45, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, + 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, + 0x34, 0x49, 0x42, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x45, 0x4b, 0x41, + 0x6f, 0x49, 0x42, 0x41, 0x51, 0x44, 0x50, 0x6a, 0x2b, 0x41, 0x52, 0x74, + 0x5a, 0x2b, 0x6f, 0x64, 0x6e, 0x62, 0x62, 0x0a, 0x33, 0x77, 0x39, 0x55, + 0x37, 0x33, 0x4e, 0x6a, 0x4b, 0x59, 0x4b, 0x74, 0x52, 0x38, 0x61, 0x6a, + 0x61, 0x2b, 0x33, 0x2b, 0x58, 0x7a, 0x50, 0x34, 0x51, 0x31, 0x48, 0x70, + 0x47, 0x6a, 0x4f, 0x52, 0x4d, 0x52, 0x65, 0x67, 0x64, 0x4d, 0x54, 0x55, + 0x70, 0x77, 0x48, 0x6d, 0x73, 0x70, 0x49, 0x2b, 0x61, 0x70, 0x33, 0x74, + 0x44, 0x76, 0x6c, 0x30, 0x6d, 0x45, 0x44, 0x54, 0x50, 0x77, 0x4f, 0x41, + 0x0a, 0x42, 0x6f, 0x4a, 0x41, 0x36, 0x4c, 0x48, 0x69, 0x70, 0x31, 0x47, + 0x6e, 0x48, 0x59, 0x4d, 0x6d, 0x61, 0x36, 0x76, 0x65, 0x2b, 0x68, 0x65, + 0x52, 0x4b, 0x39, 0x6a, 0x47, 0x72, 0x42, 0x36, 0x78, 0x6e, 0x68, 0x6b, + 0x42, 0x31, 0x5a, 0x65, 0x6d, 0x36, 0x67, 0x32, 0x33, 0x78, 0x46, 0x55, + 0x66, 0x4a, 0x33, 0x7a, 0x53, 0x43, 0x4e, 0x56, 0x32, 0x48, 0x79, 0x6b, + 0x56, 0x68, 0x30, 0x41, 0x35, 0x0a, 0x33, 0x54, 0x68, 0x46, 0x45, 0x58, + 0x58, 0x51, 0x6d, 0x71, 0x63, 0x30, 0x34, 0x4c, 0x2f, 0x4e, 0x79, 0x46, + 0x49, 0x64, 0x75, 0x55, 0x64, 0x2b, 0x44, 0x62, 0x69, 0x37, 0x78, 0x67, + 0x7a, 0x32, 0x63, 0x31, 0x63, 0x57, 0x57, 0x6e, 0x35, 0x44, 0x6b, 0x52, + 0x39, 0x56, 0x4f, 0x73, 0x5a, 0x74, 0x52, 0x41, 0x53, 0x71, 0x6e, 0x4b, + 0x6d, 0x63, 0x70, 0x30, 0x79, 0x4a, 0x46, 0x34, 0x4f, 0x75, 0x0a, 0x6f, + 0x77, 0x52, 0x65, 0x55, 0x6f, 0x43, 0x4c, 0x48, 0x68, 0x49, 0x6c, 0x45, + 0x52, 0x6e, 0x58, 0x44, 0x48, 0x31, 0x39, 0x4d, 0x55, 0x52, 0x42, 0x36, + 0x74, 0x75, 0x76, 0x73, 0x42, 0x7a, 0x76, 0x67, 0x64, 0x41, 0x73, 0x78, + 0x5a, 0x6f, 0x68, 0x6d, 0x7a, 0x33, 0x74, 0x51, 0x6a, 0x74, 0x51, 0x4a, + 0x76, 0x4c, 0x73, 0x7a, 0x6e, 0x46, 0x68, 0x42, 0x6d, 0x49, 0x68, 0x56, + 0x45, 0x35, 0x2f, 0x0a, 0x77, 0x5a, 0x30, 0x2b, 0x66, 0x79, 0x43, 0x4d, + 0x67, 0x4d, 0x73, 0x71, 0x32, 0x4a, 0x64, 0x69, 0x79, 0x49, 0x4d, 0x7a, + 0x6b, 0x58, 0x32, 0x77, 0x6f, 0x6c, 0x6f, 0x50, 0x56, 0x2b, 0x67, 0x37, + 0x7a, 0x50, 0x49, 0x6c, 0x73, 0x74, 0x52, 0x38, 0x4c, 0x2b, 0x78, 0x4e, + 0x78, 0x71, 0x45, 0x36, 0x46, 0x58, 0x72, 0x6e, 0x74, 0x6c, 0x30, 0x31, + 0x39, 0x66, 0x5a, 0x49, 0x53, 0x6a, 0x5a, 0x46, 0x0a, 0x5a, 0x74, 0x53, + 0x36, 0x6d, 0x46, 0x6a, 0x42, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, + 0x6a, 0x59, 0x7a, 0x42, 0x68, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x52, 0x45, 0x6e, 0x6b, 0x6a, + 0x31, 0x7a, 0x47, 0x31, 0x49, 0x31, 0x4b, 0x42, 0x4c, 0x66, 0x2f, 0x35, + 0x5a, 0x4a, 0x43, 0x2b, 0x44, 0x6c, 0x35, 0x6d, 0x61, 0x68, 0x6a, 0x41, + 0x66, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, + 0x41, 0x57, 0x67, 0x42, 0x52, 0x45, 0x6e, 0x6b, 0x6a, 0x31, 0x7a, 0x47, + 0x31, 0x49, 0x31, 0x4b, 0x42, 0x4c, 0x66, 0x2f, 0x35, 0x5a, 0x4a, 0x43, + 0x2b, 0x44, 0x6c, 0x35, 0x6d, 0x61, 0x68, 0x6a, 0x41, 0x50, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, + 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x0a, 0x4d, 0x41, 0x34, 0x47, 0x41, + 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, + 0x77, 0x49, 0x42, 0x68, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, + 0x41, 0x4f, 0x43, 0x41, 0x51, 0x45, 0x41, 0x42, 0x54, 0x34, 0x31, 0x58, + 0x42, 0x56, 0x77, 0x6d, 0x38, 0x6e, 0x48, 0x63, 0x32, 0x46, 0x76, 0x0a, + 0x63, 0x69, 0x76, 0x55, 0x77, 0x6f, 0x2f, 0x79, 0x51, 0x31, 0x30, 0x43, + 0x7a, 0x73, 0x53, 0x55, 0x75, 0x5a, 0x51, 0x52, 0x67, 0x32, 0x64, 0x64, + 0x34, 0x6d, 0x64, 0x73, 0x64, 0x58, 0x61, 0x2f, 0x75, 0x77, 0x79, 0x71, + 0x4e, 0x73, 0x61, 0x74, 0x52, 0x35, 0x4e, 0x6a, 0x33, 0x42, 0x35, 0x2b, + 0x31, 0x74, 0x34, 0x75, 0x2f, 0x75, 0x6b, 0x5a, 0x4d, 0x6a, 0x67, 0x44, + 0x66, 0x78, 0x54, 0x32, 0x0a, 0x41, 0x48, 0x4d, 0x73, 0x57, 0x62, 0x45, + 0x68, 0x42, 0x75, 0x48, 0x37, 0x72, 0x42, 0x69, 0x56, 0x44, 0x4b, 0x50, + 0x2f, 0x6d, 0x5a, 0x62, 0x33, 0x4b, 0x79, 0x65, 0x62, 0x31, 0x53, 0x54, + 0x4d, 0x48, 0x64, 0x33, 0x42, 0x4f, 0x75, 0x43, 0x59, 0x52, 0x4c, 0x44, + 0x45, 0x35, 0x44, 0x35, 0x33, 0x73, 0x58, 0x4f, 0x70, 0x5a, 0x43, 0x7a, + 0x32, 0x48, 0x41, 0x46, 0x38, 0x50, 0x31, 0x31, 0x46, 0x0a, 0x68, 0x63, + 0x43, 0x46, 0x35, 0x79, 0x57, 0x50, 0x6c, 0x64, 0x77, 0x58, 0x38, 0x7a, + 0x79, 0x66, 0x47, 0x6d, 0x36, 0x77, 0x79, 0x75, 0x4d, 0x64, 0x4b, 0x75, + 0x6c, 0x4d, 0x59, 0x2f, 0x6f, 0x6b, 0x59, 0x57, 0x4c, 0x57, 0x32, 0x6e, + 0x36, 0x32, 0x48, 0x47, 0x7a, 0x31, 0x41, 0x68, 0x33, 0x55, 0x4b, 0x74, + 0x31, 0x56, 0x6b, 0x4f, 0x73, 0x71, 0x45, 0x55, 0x63, 0x38, 0x4c, 0x6c, + 0x35, 0x30, 0x0a, 0x73, 0x6f, 0x49, 0x69, 0x70, 0x58, 0x31, 0x54, 0x48, + 0x30, 0x58, 0x73, 0x4a, 0x35, 0x46, 0x39, 0x35, 0x79, 0x49, 0x57, 0x36, + 0x4d, 0x42, 0x6f, 0x4e, 0x74, 0x6a, 0x47, 0x38, 0x55, 0x2b, 0x41, 0x52, + 0x44, 0x4c, 0x35, 0x34, 0x64, 0x48, 0x52, 0x48, 0x61, 0x72, 0x65, 0x71, + 0x4b, 0x75, 0x63, 0x42, 0x4b, 0x2b, 0x74, 0x49, 0x41, 0x35, 0x6b, 0x6d, + 0x45, 0x32, 0x6c, 0x61, 0x38, 0x42, 0x49, 0x0a, 0x57, 0x4a, 0x5a, 0x70, + 0x54, 0x64, 0x77, 0x48, 0x6a, 0x46, 0x47, 0x54, 0x6f, 0x74, 0x2b, 0x66, + 0x44, 0x7a, 0x32, 0x4c, 0x59, 0x4c, 0x53, 0x43, 0x6a, 0x61, 0x6f, 0x49, + 0x54, 0x6d, 0x4a, 0x46, 0x34, 0x50, 0x6b, 0x4c, 0x30, 0x75, 0x44, 0x67, + 0x50, 0x46, 0x76, 0x65, 0x58, 0x48, 0x45, 0x6e, 0x4a, 0x63, 0x4c, 0x6d, + 0x41, 0x34, 0x47, 0x4c, 0x45, 0x46, 0x50, 0x6a, 0x78, 0x31, 0x57, 0x69, + 0x0a, 0x74, 0x4a, 0x2f, 0x58, 0x35, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x53, 0x53, 0x4c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x20, 0x52, 0x53, 0x41, 0x20, 0x4f, 0x3d, 0x53, 0x53, 0x4c, + 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x53, 0x53, 0x4c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x52, 0x53, 0x41, 0x20, 0x4f, 0x3d, 0x53, 0x53, + 0x4c, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x53, 0x53, 0x4c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x20, 0x52, 0x53, 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x3a, 0x20, 0x38, 0x38, 0x37, 0x35, 0x36, 0x34, 0x30, 0x32, + 0x39, 0x36, 0x35, 0x35, 0x38, 0x33, 0x31, 0x30, 0x30, 0x34, 0x31, 0x0a, + 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x36, 0x3a, 0x36, 0x39, + 0x3a, 0x31, 0x32, 0x3a, 0x63, 0x30, 0x3a, 0x37, 0x30, 0x3a, 0x66, 0x31, + 0x3a, 0x65, 0x63, 0x3a, 0x61, 0x63, 0x3a, 0x61, 0x63, 0x3a, 0x63, 0x32, + 0x3a, 0x64, 0x35, 0x3a, 0x62, 0x63, 0x3a, 0x61, 0x35, 0x3a, 0x35, 0x62, + 0x3a, 0x61, 0x31, 0x3a, 0x32, 0x39, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x62, 0x37, 0x3a, 0x61, 0x62, 0x3a, 0x33, 0x33, 0x3a, + 0x30, 0x38, 0x3a, 0x64, 0x31, 0x3a, 0x65, 0x61, 0x3a, 0x34, 0x34, 0x3a, + 0x37, 0x37, 0x3a, 0x62, 0x61, 0x3a, 0x31, 0x34, 0x3a, 0x38, 0x30, 0x3a, + 0x31, 0x32, 0x3a, 0x35, 0x61, 0x3a, 0x36, 0x66, 0x3a, 0x62, 0x64, 0x3a, + 0x61, 0x39, 0x3a, 0x33, 0x36, 0x3a, 0x34, 0x39, 0x3a, 0x30, 0x63, 0x3a, + 0x62, 0x62, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x38, 0x35, 0x3a, 0x36, 0x36, 0x3a, 0x36, 0x61, 0x3a, 0x35, 0x36, + 0x3a, 0x32, 0x65, 0x3a, 0x65, 0x30, 0x3a, 0x62, 0x65, 0x3a, 0x35, 0x63, + 0x3a, 0x65, 0x39, 0x3a, 0x32, 0x35, 0x3a, 0x63, 0x31, 0x3a, 0x64, 0x38, + 0x3a, 0x38, 0x39, 0x3a, 0x30, 0x61, 0x3a, 0x36, 0x66, 0x3a, 0x37, 0x36, + 0x3a, 0x61, 0x38, 0x3a, 0x37, 0x65, 0x3a, 0x63, 0x31, 0x3a, 0x36, 0x64, + 0x3a, 0x34, 0x64, 0x3a, 0x37, 0x64, 0x3a, 0x35, 0x66, 0x3a, 0x32, 0x39, + 0x3a, 0x65, 0x61, 0x3a, 0x37, 0x34, 0x3a, 0x31, 0x39, 0x3a, 0x63, 0x66, + 0x3a, 0x32, 0x30, 0x3a, 0x31, 0x32, 0x3a, 0x33, 0x62, 0x3a, 0x36, 0x39, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x33, 0x54, 0x43, + 0x43, 0x41, 0x38, 0x57, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x49, 0x65, 0x79, 0x79, 0x62, 0x30, 0x78, 0x61, 0x41, 0x4d, 0x70, 0x6b, + 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, + 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x77, 0x66, 0x44, 0x45, + 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x0a, 0x42, 0x68, + 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x44, 0x6a, 0x41, 0x4d, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x67, 0x4d, 0x42, 0x56, 0x52, 0x6c, 0x65, 0x47, + 0x46, 0x7a, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x48, 0x44, 0x41, 0x64, 0x49, 0x62, 0x33, 0x56, 0x7a, 0x64, 0x47, + 0x39, 0x75, 0x4d, 0x52, 0x67, 0x77, 0x46, 0x67, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4b, 0x0a, 0x44, 0x41, 0x39, 0x54, 0x55, 0x30, 0x77, 0x67, 0x51, + 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, 0x58, 0x52, 0x70, 0x62, + 0x32, 0x34, 0x78, 0x4d, 0x54, 0x41, 0x76, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x4d, 0x4d, 0x4b, 0x46, 0x4e, 0x54, 0x54, 0x43, 0x35, 0x6a, 0x62, + 0x32, 0x30, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x5a, + 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x0a, 0x59, 0x32, 0x46, 0x30, + 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, + 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x53, 0x42, 0x53, 0x55, 0x30, 0x45, 0x77, + 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x59, 0x77, 0x4d, 0x6a, 0x45, 0x79, + 0x4d, 0x54, 0x63, 0x7a, 0x4f, 0x54, 0x4d, 0x35, 0x57, 0x68, 0x63, 0x4e, + 0x4e, 0x44, 0x45, 0x77, 0x4d, 0x6a, 0x45, 0x79, 0x4d, 0x54, 0x63, 0x7a, + 0x0a, 0x4f, 0x54, 0x4d, 0x35, 0x57, 0x6a, 0x42, 0x38, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, + 0x56, 0x55, 0x7a, 0x45, 0x4f, 0x4d, 0x41, 0x77, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x41, 0x77, 0x46, 0x56, 0x47, 0x56, 0x34, 0x59, 0x58, 0x4d, + 0x78, 0x45, 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, + 0x4d, 0x42, 0x30, 0x68, 0x76, 0x0a, 0x64, 0x58, 0x4e, 0x30, 0x62, 0x32, + 0x34, 0x78, 0x47, 0x44, 0x41, 0x57, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x6f, 0x4d, 0x44, 0x31, 0x4e, 0x54, 0x54, 0x43, 0x42, 0x44, 0x62, 0x33, + 0x4a, 0x77, 0x62, 0x33, 0x4a, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6a, + 0x45, 0x78, 0x4d, 0x43, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, + 0x77, 0x6f, 0x55, 0x31, 0x4e, 0x4d, 0x4c, 0x6d, 0x4e, 0x76, 0x0a, 0x62, + 0x53, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x6c, 0x63, + 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x70, 0x62, + 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, + 0x58, 0x52, 0x35, 0x49, 0x46, 0x4a, 0x54, 0x51, 0x54, 0x43, 0x43, 0x41, + 0x69, 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x63, 0x4e, 0x0a, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, + 0x67, 0x67, 0x49, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x67, 0x6f, 0x43, + 0x67, 0x67, 0x49, 0x42, 0x41, 0x50, 0x6b, 0x50, 0x33, 0x61, 0x4d, 0x72, + 0x66, 0x63, 0x76, 0x51, 0x4b, 0x76, 0x37, 0x73, 0x5a, 0x34, 0x57, 0x6d, + 0x35, 0x79, 0x34, 0x62, 0x75, 0x6e, 0x66, 0x68, 0x34, 0x2f, 0x57, 0x76, + 0x70, 0x4f, 0x7a, 0x36, 0x53, 0x6c, 0x32, 0x52, 0x0a, 0x78, 0x46, 0x64, + 0x48, 0x61, 0x78, 0x68, 0x33, 0x61, 0x33, 0x62, 0x79, 0x2f, 0x5a, 0x50, + 0x6b, 0x50, 0x51, 0x2f, 0x43, 0x46, 0x70, 0x34, 0x4c, 0x5a, 0x73, 0x4e, + 0x57, 0x6c, 0x4a, 0x34, 0x58, 0x67, 0x34, 0x58, 0x4f, 0x56, 0x75, 0x2f, + 0x79, 0x46, 0x76, 0x30, 0x41, 0x59, 0x76, 0x55, 0x69, 0x43, 0x56, 0x54, + 0x6f, 0x5a, 0x52, 0x64, 0x4f, 0x51, 0x62, 0x6e, 0x67, 0x54, 0x30, 0x61, + 0x58, 0x0a, 0x71, 0x68, 0x76, 0x49, 0x75, 0x47, 0x35, 0x69, 0x58, 0x6d, + 0x6d, 0x78, 0x58, 0x39, 0x73, 0x71, 0x41, 0x6e, 0x37, 0x38, 0x62, 0x4d, + 0x72, 0x7a, 0x51, 0x64, 0x6a, 0x74, 0x30, 0x4f, 0x6a, 0x38, 0x50, 0x32, + 0x46, 0x49, 0x37, 0x62, 0x41, 0x44, 0x46, 0x42, 0x30, 0x51, 0x44, 0x6b, + 0x73, 0x5a, 0x34, 0x4c, 0x74, 0x4f, 0x37, 0x49, 0x5a, 0x6c, 0x2f, 0x7a, + 0x62, 0x7a, 0x58, 0x6d, 0x63, 0x43, 0x0a, 0x43, 0x35, 0x32, 0x47, 0x56, + 0x57, 0x48, 0x39, 0x65, 0x6a, 0x6a, 0x74, 0x2f, 0x75, 0x49, 0x5a, 0x41, + 0x4c, 0x64, 0x76, 0x6f, 0x56, 0x42, 0x69, 0x64, 0x58, 0x51, 0x38, 0x6f, + 0x50, 0x72, 0x49, 0x4a, 0x5a, 0x4b, 0x30, 0x62, 0x6e, 0x6f, 0x69, 0x78, + 0x2f, 0x67, 0x65, 0x6f, 0x65, 0x4f, 0x79, 0x33, 0x5a, 0x45, 0x78, 0x71, + 0x79, 0x73, 0x64, 0x42, 0x50, 0x2b, 0x6c, 0x53, 0x67, 0x51, 0x33, 0x0a, + 0x36, 0x59, 0x57, 0x6b, 0x4d, 0x79, 0x76, 0x39, 0x34, 0x74, 0x5a, 0x56, + 0x4e, 0x48, 0x77, 0x5a, 0x70, 0x45, 0x70, 0x6f, 0x78, 0x37, 0x4b, 0x6f, + 0x30, 0x37, 0x66, 0x4b, 0x6f, 0x5a, 0x4f, 0x49, 0x36, 0x38, 0x47, 0x58, + 0x76, 0x49, 0x7a, 0x35, 0x48, 0x64, 0x6b, 0x69, 0x68, 0x43, 0x52, 0x30, + 0x78, 0x77, 0x51, 0x39, 0x61, 0x71, 0x6b, 0x70, 0x6b, 0x38, 0x7a, 0x72, + 0x75, 0x46, 0x76, 0x68, 0x0a, 0x2f, 0x6c, 0x38, 0x6c, 0x71, 0x6a, 0x52, + 0x59, 0x79, 0x4d, 0x45, 0x6a, 0x56, 0x4a, 0x30, 0x62, 0x6d, 0x42, 0x48, + 0x44, 0x4f, 0x4a, 0x78, 0x2b, 0x50, 0x59, 0x5a, 0x73, 0x70, 0x51, 0x39, + 0x41, 0x68, 0x6e, 0x77, 0x43, 0x39, 0x46, 0x77, 0x43, 0x54, 0x79, 0x6a, + 0x4c, 0x72, 0x6e, 0x47, 0x66, 0x44, 0x7a, 0x72, 0x49, 0x4d, 0x2f, 0x34, + 0x52, 0x4a, 0x54, 0x58, 0x71, 0x2f, 0x4c, 0x72, 0x46, 0x0a, 0x59, 0x44, + 0x33, 0x5a, 0x66, 0x42, 0x6a, 0x56, 0x73, 0x71, 0x6e, 0x54, 0x64, 0x58, + 0x67, 0x44, 0x63, 0x69, 0x4c, 0x4b, 0x4f, 0x73, 0x4d, 0x66, 0x37, 0x79, + 0x7a, 0x6c, 0x4c, 0x71, 0x6e, 0x36, 0x6e, 0x69, 0x79, 0x32, 0x55, 0x55, + 0x62, 0x39, 0x72, 0x77, 0x50, 0x57, 0x36, 0x6d, 0x42, 0x6f, 0x36, 0x6f, + 0x55, 0x57, 0x4e, 0x6d, 0x75, 0x46, 0x36, 0x52, 0x37, 0x41, 0x73, 0x39, + 0x33, 0x45, 0x0a, 0x4a, 0x4e, 0x79, 0x41, 0x4b, 0x6f, 0x46, 0x42, 0x62, + 0x5a, 0x51, 0x2b, 0x79, 0x4f, 0x44, 0x4a, 0x67, 0x55, 0x45, 0x41, 0x6e, + 0x6c, 0x36, 0x2f, 0x66, 0x38, 0x55, 0x49, 0x6d, 0x4b, 0x49, 0x59, 0x4c, + 0x45, 0x4a, 0x41, 0x73, 0x2f, 0x6c, 0x76, 0x4f, 0x43, 0x64, 0x4c, 0x54, + 0x6f, 0x44, 0x30, 0x50, 0x59, 0x46, 0x48, 0x34, 0x49, 0x68, 0x38, 0x36, + 0x68, 0x7a, 0x4f, 0x74, 0x58, 0x56, 0x63, 0x0a, 0x55, 0x53, 0x34, 0x63, + 0x4b, 0x33, 0x38, 0x61, 0x63, 0x69, 0x6a, 0x6e, 0x41, 0x4c, 0x58, 0x52, + 0x64, 0x4d, 0x62, 0x58, 0x35, 0x4a, 0x2b, 0x74, 0x42, 0x35, 0x4f, 0x32, + 0x55, 0x7a, 0x55, 0x31, 0x2f, 0x44, 0x66, 0x6b, 0x77, 0x2f, 0x5a, 0x64, + 0x46, 0x72, 0x34, 0x68, 0x63, 0x39, 0x36, 0x53, 0x43, 0x76, 0x69, 0x67, + 0x59, 0x32, 0x71, 0x38, 0x6c, 0x70, 0x4a, 0x71, 0x50, 0x76, 0x69, 0x38, + 0x0a, 0x5a, 0x56, 0x57, 0x62, 0x33, 0x76, 0x55, 0x4e, 0x69, 0x53, 0x59, + 0x45, 0x2f, 0x43, 0x55, 0x61, 0x70, 0x69, 0x56, 0x70, 0x79, 0x38, 0x4a, + 0x74, 0x79, 0x6e, 0x7a, 0x69, 0x57, 0x56, 0x2b, 0x58, 0x72, 0x4f, 0x76, + 0x76, 0x4c, 0x73, 0x69, 0x38, 0x31, 0x78, 0x74, 0x5a, 0x50, 0x43, 0x76, + 0x4d, 0x38, 0x68, 0x6e, 0x49, 0x6b, 0x32, 0x73, 0x6e, 0x59, 0x78, 0x6e, + 0x50, 0x2f, 0x4f, 0x6b, 0x6d, 0x0a, 0x2b, 0x4d, 0x70, 0x78, 0x6d, 0x33, + 0x2b, 0x54, 0x2f, 0x6a, 0x52, 0x6e, 0x68, 0x45, 0x36, 0x5a, 0x36, 0x2f, + 0x79, 0x7a, 0x65, 0x41, 0x6b, 0x7a, 0x63, 0x4c, 0x70, 0x6d, 0x70, 0x6e, + 0x62, 0x74, 0x47, 0x33, 0x50, 0x72, 0x47, 0x71, 0x55, 0x4e, 0x78, 0x43, + 0x49, 0x54, 0x49, 0x4a, 0x52, 0x57, 0x43, 0x6b, 0x34, 0x73, 0x62, 0x45, + 0x36, 0x78, 0x2f, 0x63, 0x2b, 0x63, 0x43, 0x62, 0x71, 0x69, 0x0a, 0x4d, + 0x2b, 0x32, 0x48, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x59, + 0x7a, 0x42, 0x68, 0x4d, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, + 0x67, 0x51, 0x57, 0x42, 0x42, 0x54, 0x64, 0x42, 0x41, 0x6b, 0x48, 0x6f, + 0x76, 0x56, 0x36, 0x66, 0x56, 0x4a, 0x54, 0x45, 0x70, 0x4b, 0x56, 0x37, + 0x6a, 0x69, 0x41, 0x4a, 0x51, 0x32, 0x6d, 0x57, 0x54, 0x41, 0x50, 0x42, + 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, + 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x42, 0x38, 0x47, + 0x41, 0x31, 0x55, 0x64, 0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, 0x61, 0x41, + 0x46, 0x4e, 0x30, 0x45, 0x43, 0x51, 0x65, 0x69, 0x39, 0x58, 0x70, 0x39, + 0x55, 0x6c, 0x4d, 0x53, 0x6b, 0x70, 0x58, 0x75, 0x4f, 0x49, 0x41, 0x6c, + 0x44, 0x61, 0x5a, 0x5a, 0x4d, 0x41, 0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, + 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, + 0x42, 0x68, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, + 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x41, 0x4f, + 0x43, 0x41, 0x67, 0x45, 0x41, 0x49, 0x42, 0x67, 0x52, 0x6c, 0x43, 0x6e, + 0x37, 0x4a, 0x70, 0x30, 0x63, 0x48, 0x68, 0x35, 0x77, 0x59, 0x66, 0x47, + 0x56, 0x0a, 0x63, 0x70, 0x4e, 0x78, 0x4a, 0x4b, 0x31, 0x6f, 0x6b, 0x31, + 0x69, 0x4f, 0x4d, 0x71, 0x38, 0x62, 0x73, 0x33, 0x41, 0x44, 0x2f, 0x43, + 0x55, 0x72, 0x64, 0x49, 0x57, 0x51, 0x50, 0x58, 0x68, 0x71, 0x39, 0x4c, + 0x6d, 0x4c, 0x70, 0x5a, 0x63, 0x37, 0x74, 0x52, 0x69, 0x52, 0x75, 0x78, + 0x36, 0x6e, 0x2b, 0x55, 0x42, 0x62, 0x6b, 0x66, 0x6c, 0x56, 0x6d, 0x61, + 0x38, 0x65, 0x45, 0x64, 0x42, 0x63, 0x0a, 0x48, 0x61, 0x64, 0x6d, 0x34, + 0x37, 0x47, 0x55, 0x42, 0x77, 0x77, 0x79, 0x4f, 0x61, 0x62, 0x71, 0x47, + 0x37, 0x42, 0x35, 0x32, 0x42, 0x32, 0x63, 0x63, 0x45, 0x54, 0x6a, 0x69, + 0x74, 0x33, 0x45, 0x2b, 0x5a, 0x55, 0x66, 0x69, 0x6a, 0x68, 0x44, 0x50, + 0x77, 0x47, 0x46, 0x70, 0x55, 0x65, 0x6e, 0x50, 0x55, 0x61, 0x79, 0x76, + 0x4f, 0x55, 0x69, 0x61, 0x50, 0x64, 0x37, 0x6e, 0x4e, 0x67, 0x73, 0x0a, + 0x50, 0x67, 0x6f, 0x68, 0x79, 0x43, 0x30, 0x7a, 0x72, 0x4c, 0x2f, 0x46, + 0x67, 0x5a, 0x6b, 0x78, 0x64, 0x4d, 0x46, 0x31, 0x63, 0x63, 0x57, 0x2b, + 0x73, 0x66, 0x41, 0x6a, 0x52, 0x66, 0x53, 0x64, 0x61, 0x2f, 0x77, 0x5a, + 0x59, 0x35, 0x32, 0x6a, 0x76, 0x41, 0x54, 0x47, 0x47, 0x41, 0x73, 0x6c, + 0x75, 0x31, 0x4f, 0x4a, 0x44, 0x37, 0x4f, 0x41, 0x55, 0x4e, 0x35, 0x46, + 0x37, 0x6b, 0x52, 0x2f, 0x0a, 0x71, 0x35, 0x52, 0x34, 0x5a, 0x4a, 0x6a, + 0x54, 0x39, 0x69, 0x6a, 0x64, 0x68, 0x39, 0x68, 0x77, 0x5a, 0x58, 0x54, + 0x37, 0x44, 0x72, 0x6b, 0x54, 0x36, 0x36, 0x63, 0x50, 0x59, 0x61, 0x6b, + 0x79, 0x6c, 0x73, 0x7a, 0x65, 0x75, 0x2b, 0x31, 0x6a, 0x54, 0x42, 0x69, + 0x37, 0x71, 0x55, 0x44, 0x33, 0x6f, 0x46, 0x52, 0x75, 0x49, 0x49, 0x68, + 0x78, 0x64, 0x52, 0x6a, 0x71, 0x65, 0x72, 0x51, 0x30, 0x0a, 0x63, 0x75, + 0x41, 0x6a, 0x4a, 0x33, 0x64, 0x63, 0x74, 0x70, 0x44, 0x71, 0x68, 0x69, + 0x56, 0x41, 0x71, 0x2b, 0x38, 0x7a, 0x44, 0x38, 0x75, 0x66, 0x67, 0x72, + 0x36, 0x69, 0x49, 0x50, 0x76, 0x32, 0x74, 0x53, 0x30, 0x61, 0x35, 0x73, + 0x4b, 0x46, 0x73, 0x58, 0x51, 0x50, 0x2b, 0x38, 0x68, 0x6c, 0x41, 0x71, + 0x52, 0x53, 0x41, 0x55, 0x66, 0x64, 0x53, 0x53, 0x4c, 0x42, 0x76, 0x39, + 0x6a, 0x72, 0x0a, 0x61, 0x36, 0x78, 0x2b, 0x33, 0x75, 0x78, 0x6a, 0x4d, + 0x78, 0x57, 0x33, 0x49, 0x77, 0x69, 0x50, 0x78, 0x67, 0x2b, 0x4e, 0x51, + 0x56, 0x72, 0x64, 0x6a, 0x73, 0x57, 0x35, 0x6a, 0x2b, 0x56, 0x46, 0x50, + 0x33, 0x6a, 0x62, 0x75, 0x74, 0x49, 0x62, 0x51, 0x4c, 0x48, 0x2b, 0x63, + 0x55, 0x30, 0x2f, 0x34, 0x49, 0x47, 0x69, 0x75, 0x6c, 0x36, 0x30, 0x37, + 0x42, 0x58, 0x67, 0x6b, 0x39, 0x30, 0x49, 0x0a, 0x48, 0x33, 0x37, 0x68, + 0x56, 0x5a, 0x6b, 0x4c, 0x49, 0x64, 0x36, 0x54, 0x6e, 0x67, 0x72, 0x37, + 0x35, 0x71, 0x4e, 0x4a, 0x76, 0x54, 0x59, 0x77, 0x2f, 0x75, 0x64, 0x33, + 0x73, 0x71, 0x42, 0x31, 0x6c, 0x37, 0x55, 0x74, 0x67, 0x59, 0x67, 0x58, + 0x5a, 0x53, 0x44, 0x33, 0x32, 0x70, 0x41, 0x41, 0x6e, 0x38, 0x6c, 0x53, + 0x7a, 0x44, 0x4c, 0x4b, 0x4e, 0x58, 0x7a, 0x31, 0x50, 0x51, 0x2f, 0x59, + 0x0a, 0x4b, 0x39, 0x66, 0x31, 0x4a, 0x6d, 0x7a, 0x4a, 0x42, 0x6a, 0x53, + 0x57, 0x46, 0x75, 0x70, 0x77, 0x57, 0x52, 0x6f, 0x79, 0x65, 0x58, 0x6b, + 0x4c, 0x74, 0x6f, 0x68, 0x2f, 0x44, 0x31, 0x4a, 0x49, 0x50, 0x62, 0x39, + 0x73, 0x32, 0x4b, 0x4a, 0x45, 0x4c, 0x74, 0x46, 0x4f, 0x74, 0x33, 0x4a, + 0x59, 0x30, 0x34, 0x6b, 0x54, 0x6c, 0x66, 0x35, 0x45, 0x71, 0x2f, 0x6a, + 0x58, 0x69, 0x78, 0x74, 0x75, 0x0a, 0x6e, 0x4c, 0x77, 0x73, 0x6f, 0x46, + 0x76, 0x56, 0x61, 0x67, 0x43, 0x76, 0x58, 0x7a, 0x66, 0x68, 0x31, 0x66, + 0x6f, 0x51, 0x43, 0x35, 0x69, 0x63, 0x68, 0x75, 0x63, 0x6d, 0x6a, 0x38, + 0x37, 0x77, 0x37, 0x47, 0x36, 0x4b, 0x56, 0x77, 0x75, 0x41, 0x34, 0x30, + 0x36, 0x79, 0x77, 0x4b, 0x42, 0x6a, 0x59, 0x5a, 0x43, 0x36, 0x56, 0x57, + 0x67, 0x33, 0x64, 0x47, 0x71, 0x32, 0x6b, 0x74, 0x75, 0x66, 0x0a, 0x6f, + 0x59, 0x59, 0x69, 0x74, 0x6d, 0x55, 0x6e, 0x44, 0x75, 0x79, 0x32, 0x6e, + 0x30, 0x4a, 0x67, 0x35, 0x47, 0x66, 0x43, 0x74, 0x64, 0x70, 0x42, 0x43, + 0x38, 0x54, 0x54, 0x69, 0x32, 0x45, 0x62, 0x76, 0x50, 0x6f, 0x66, 0x6b, + 0x53, 0x76, 0x58, 0x52, 0x41, 0x64, 0x65, 0x75, 0x69, 0x6d, 0x73, 0x32, + 0x63, 0x58, 0x70, 0x37, 0x31, 0x4e, 0x49, 0x57, 0x75, 0x75, 0x41, 0x38, + 0x53, 0x68, 0x59, 0x0a, 0x49, 0x63, 0x32, 0x77, 0x42, 0x6c, 0x58, 0x37, + 0x4a, 0x7a, 0x39, 0x54, 0x6b, 0x48, 0x43, 0x70, 0x42, 0x42, 0x35, 0x58, + 0x4a, 0x37, 0x6b, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x53, 0x4c, + 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x45, 0x43, + 0x43, 0x20, 0x4f, 0x3d, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x6f, 0x72, 0x70, + 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x53, + 0x4c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x45, + 0x43, 0x43, 0x20, 0x4f, 0x3d, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x6f, 0x72, + 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x53, 0x53, 0x4c, 0x2e, 0x63, + 0x6f, 0x6d, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x45, 0x43, 0x43, 0x22, + 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x38, + 0x34, 0x39, 0x35, 0x37, 0x32, 0x33, 0x38, 0x31, 0x33, 0x32, 0x39, 0x37, + 0x32, 0x31, 0x36, 0x34, 0x32, 0x34, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x32, 0x65, 0x3a, 0x64, 0x61, 0x3a, 0x65, 0x34, 0x3a, 0x33, + 0x39, 0x3a, 0x37, 0x66, 0x3a, 0x39, 0x63, 0x3a, 0x38, 0x66, 0x3a, 0x33, + 0x37, 0x3a, 0x64, 0x31, 0x3a, 0x37, 0x30, 0x3a, 0x39, 0x66, 0x3a, 0x32, + 0x36, 0x3a, 0x31, 0x37, 0x3a, 0x35, 0x31, 0x3a, 0x33, 0x61, 0x3a, 0x38, + 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x33, + 0x3a, 0x31, 0x39, 0x3a, 0x37, 0x63, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x34, + 0x3a, 0x65, 0x36, 0x3a, 0x35, 0x34, 0x3a, 0x61, 0x66, 0x3a, 0x31, 0x62, + 0x3a, 0x63, 0x34, 0x3a, 0x61, 0x62, 0x3a, 0x32, 0x30, 0x3a, 0x39, 0x35, + 0x3a, 0x37, 0x61, 0x3a, 0x65, 0x32, 0x3a, 0x63, 0x33, 0x3a, 0x30, 0x65, + 0x3a, 0x31, 0x33, 0x3a, 0x30, 0x32, 0x3a, 0x36, 0x61, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x34, 0x3a, 0x31, + 0x37, 0x3a, 0x62, 0x62, 0x3a, 0x30, 0x36, 0x3a, 0x63, 0x63, 0x3a, 0x36, + 0x30, 0x3a, 0x30, 0x37, 0x3a, 0x64, 0x61, 0x3a, 0x31, 0x62, 0x3a, 0x39, + 0x36, 0x3a, 0x31, 0x63, 0x3a, 0x39, 0x32, 0x3a, 0x30, 0x62, 0x3a, 0x38, + 0x61, 0x3a, 0x62, 0x34, 0x3a, 0x63, 0x65, 0x3a, 0x33, 0x66, 0x3a, 0x61, + 0x64, 0x3a, 0x38, 0x32, 0x3a, 0x30, 0x65, 0x3a, 0x34, 0x61, 0x3a, 0x61, + 0x33, 0x3a, 0x30, 0x62, 0x3a, 0x39, 0x61, 0x3a, 0x63, 0x62, 0x3a, 0x63, + 0x34, 0x3a, 0x61, 0x37, 0x3a, 0x34, 0x65, 0x3a, 0x62, 0x64, 0x3a, 0x63, + 0x65, 0x3a, 0x62, 0x63, 0x3a, 0x36, 0x35, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x43, 0x6a, 0x54, 0x43, 0x43, 0x41, 0x68, 0x53, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x49, 0x64, 0x65, 0x62, 0x66, + 0x79, 0x38, 0x46, 0x6f, 0x57, 0x36, 0x67, 0x77, 0x43, 0x67, 0x59, 0x49, + 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, + 0x66, 0x44, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x42, 0x68, 0x4d, 0x43, 0x0a, 0x56, 0x56, 0x4d, 0x78, 0x44, 0x6a, 0x41, + 0x4d, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x4d, 0x42, 0x56, 0x52, + 0x6c, 0x65, 0x47, 0x46, 0x7a, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x64, 0x49, 0x62, 0x33, 0x56, + 0x7a, 0x64, 0x47, 0x39, 0x75, 0x4d, 0x52, 0x67, 0x77, 0x46, 0x67, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, 0x39, 0x54, 0x0a, 0x55, 0x30, + 0x77, 0x67, 0x51, 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, 0x58, + 0x52, 0x70, 0x62, 0x32, 0x34, 0x78, 0x4d, 0x54, 0x41, 0x76, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x4b, 0x46, 0x4e, 0x54, 0x54, 0x43, + 0x35, 0x6a, 0x62, 0x32, 0x30, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, + 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, + 0x46, 0x30, 0x0a, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, + 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, 0x65, 0x53, 0x42, 0x46, 0x51, + 0x30, 0x4d, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x59, 0x77, 0x4d, + 0x6a, 0x45, 0x79, 0x4d, 0x54, 0x67, 0x78, 0x4e, 0x44, 0x41, 0x7a, 0x57, + 0x68, 0x63, 0x4e, 0x4e, 0x44, 0x45, 0x77, 0x4d, 0x6a, 0x45, 0x79, 0x4d, + 0x54, 0x67, 0x78, 0x4e, 0x44, 0x41, 0x7a, 0x0a, 0x57, 0x6a, 0x42, 0x38, + 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, + 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x4f, 0x4d, 0x41, 0x77, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x46, 0x56, 0x47, 0x56, 0x34, + 0x59, 0x58, 0x4d, 0x78, 0x45, 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x63, 0x4d, 0x42, 0x30, 0x68, 0x76, 0x64, 0x58, 0x4e, 0x30, + 0x0a, 0x62, 0x32, 0x34, 0x78, 0x47, 0x44, 0x41, 0x57, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x44, 0x31, 0x4e, 0x54, 0x54, 0x43, 0x42, + 0x44, 0x62, 0x33, 0x4a, 0x77, 0x62, 0x33, 0x4a, 0x68, 0x64, 0x47, 0x6c, + 0x76, 0x62, 0x6a, 0x45, 0x78, 0x4d, 0x43, 0x38, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x41, 0x77, 0x77, 0x6f, 0x55, 0x31, 0x4e, 0x4d, 0x4c, 0x6d, 0x4e, + 0x76, 0x62, 0x53, 0x42, 0x53, 0x0a, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, + 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, + 0x52, 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, + 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x49, 0x45, 0x56, 0x44, 0x51, 0x7a, + 0x42, 0x32, 0x4d, 0x42, 0x41, 0x47, 0x42, 0x79, 0x71, 0x47, 0x53, 0x4d, + 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x42, 0x53, 0x75, 0x42, 0x0a, 0x42, + 0x41, 0x41, 0x69, 0x41, 0x32, 0x49, 0x41, 0x42, 0x45, 0x56, 0x75, 0x71, + 0x56, 0x44, 0x45, 0x70, 0x69, 0x4d, 0x32, 0x6e, 0x6c, 0x38, 0x6f, 0x6a, + 0x52, 0x66, 0x4c, 0x6c, 0x69, 0x4a, 0x6b, 0x50, 0x39, 0x78, 0x36, 0x6a, + 0x68, 0x33, 0x4d, 0x43, 0x4c, 0x4f, 0x69, 0x63, 0x53, 0x53, 0x36, 0x6a, + 0x6b, 0x6d, 0x35, 0x42, 0x42, 0x74, 0x48, 0x6c, 0x6c, 0x69, 0x72, 0x4c, + 0x5a, 0x58, 0x49, 0x0a, 0x37, 0x5a, 0x34, 0x49, 0x4e, 0x63, 0x67, 0x6e, + 0x36, 0x34, 0x6d, 0x4d, 0x55, 0x31, 0x6a, 0x72, 0x59, 0x6f, 0x72, 0x2b, + 0x38, 0x46, 0x73, 0x50, 0x61, 0x7a, 0x46, 0x53, 0x59, 0x30, 0x45, 0x37, + 0x69, 0x63, 0x33, 0x73, 0x37, 0x4c, 0x61, 0x4e, 0x47, 0x64, 0x4d, 0x30, + 0x42, 0x39, 0x79, 0x37, 0x78, 0x67, 0x5a, 0x2f, 0x77, 0x6b, 0x57, 0x56, + 0x37, 0x4d, 0x74, 0x2f, 0x71, 0x43, 0x50, 0x67, 0x0a, 0x43, 0x65, 0x6d, + 0x42, 0x2b, 0x76, 0x4e, 0x48, 0x30, 0x36, 0x4e, 0x6a, 0x4d, 0x47, 0x45, + 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, + 0x45, 0x46, 0x49, 0x4c, 0x52, 0x68, 0x58, 0x4d, 0x77, 0x35, 0x7a, 0x55, + 0x45, 0x30, 0x34, 0x34, 0x43, 0x6b, 0x76, 0x76, 0x6c, 0x70, 0x4e, 0x48, + 0x45, 0x49, 0x65, 0x6a, 0x4e, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x0a, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, + 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x52, + 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x67, 0x74, + 0x47, 0x46, 0x63, 0x7a, 0x44, 0x6e, 0x4e, 0x51, 0x54, 0x54, 0x6a, 0x67, + 0x4b, 0x53, 0x2b, 0x2b, 0x57, 0x6b, 0x30, 0x63, 0x51, 0x68, 0x36, 0x4d, + 0x30, 0x77, 0x44, 0x67, 0x59, 0x44, 0x0a, 0x56, 0x52, 0x30, 0x50, 0x41, + 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x47, 0x47, 0x4d, + 0x41, 0x6f, 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, + 0x41, 0x4d, 0x43, 0x41, 0x32, 0x63, 0x41, 0x4d, 0x47, 0x51, 0x43, 0x4d, + 0x47, 0x2f, 0x6e, 0x36, 0x31, 0x6b, 0x52, 0x70, 0x47, 0x44, 0x50, 0x59, + 0x62, 0x43, 0x57, 0x65, 0x2b, 0x30, 0x46, 0x2b, 0x53, 0x38, 0x54, 0x0a, + 0x6b, 0x64, 0x7a, 0x74, 0x35, 0x66, 0x78, 0x51, 0x61, 0x78, 0x46, 0x47, + 0x52, 0x72, 0x4d, 0x63, 0x49, 0x51, 0x42, 0x69, 0x75, 0x37, 0x37, 0x44, + 0x35, 0x2b, 0x6a, 0x4e, 0x42, 0x35, 0x6e, 0x35, 0x44, 0x51, 0x74, 0x64, + 0x63, 0x6a, 0x37, 0x45, 0x71, 0x67, 0x49, 0x77, 0x48, 0x37, 0x79, 0x36, + 0x43, 0x2b, 0x49, 0x77, 0x4a, 0x50, 0x74, 0x38, 0x62, 0x59, 0x42, 0x56, + 0x43, 0x70, 0x6b, 0x2b, 0x0a, 0x67, 0x41, 0x30, 0x7a, 0x35, 0x57, 0x61, + 0x6a, 0x73, 0x36, 0x4f, 0x37, 0x70, 0x64, 0x57, 0x4c, 0x6a, 0x77, 0x6b, + 0x73, 0x70, 0x6c, 0x31, 0x2b, 0x34, 0x76, 0x41, 0x48, 0x43, 0x47, 0x68, + 0x74, 0x30, 0x6e, 0x78, 0x70, 0x62, 0x6c, 0x2f, 0x66, 0x35, 0x57, 0x70, + 0x6c, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x53, 0x4c, 0x2e, 0x63, 0x6f, + 0x6d, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x52, 0x53, + 0x41, 0x20, 0x52, 0x32, 0x20, 0x4f, 0x3d, 0x53, 0x53, 0x4c, 0x20, 0x43, + 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x23, + 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, + 0x3d, 0x53, 0x53, 0x4c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x45, 0x56, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x20, 0x52, 0x53, 0x41, 0x20, 0x52, 0x32, 0x20, + 0x4f, 0x3d, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x53, 0x53, 0x4c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, + 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x52, 0x53, 0x41, 0x20, + 0x52, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x3a, 0x20, 0x36, 0x32, 0x34, 0x38, 0x32, 0x32, 0x37, 0x34, 0x39, 0x34, + 0x33, 0x35, 0x32, 0x39, 0x34, 0x33, 0x33, 0x35, 0x30, 0x0a, 0x23, 0x20, + 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x31, 0x3a, 0x31, 0x65, 0x3a, 0x33, + 0x31, 0x3a, 0x35, 0x38, 0x3a, 0x31, 0x61, 0x3a, 0x61, 0x65, 0x3a, 0x35, + 0x34, 0x3a, 0x35, 0x33, 0x3a, 0x30, 0x32, 0x3a, 0x66, 0x36, 0x3a, 0x31, + 0x37, 0x3a, 0x36, 0x61, 0x3a, 0x31, 0x31, 0x3a, 0x37, 0x62, 0x3a, 0x34, + 0x64, 0x3a, 0x39, 0x35, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x37, 0x34, 0x3a, 0x33, 0x61, 0x3a, 0x66, 0x30, 0x3a, 0x35, 0x32, + 0x3a, 0x39, 0x62, 0x3a, 0x64, 0x30, 0x3a, 0x33, 0x32, 0x3a, 0x61, 0x30, + 0x3a, 0x66, 0x34, 0x3a, 0x34, 0x61, 0x3a, 0x38, 0x33, 0x3a, 0x63, 0x64, + 0x3a, 0x64, 0x34, 0x3a, 0x62, 0x61, 0x3a, 0x61, 0x39, 0x3a, 0x37, 0x62, + 0x3a, 0x37, 0x63, 0x3a, 0x32, 0x65, 0x3a, 0x63, 0x34, 0x3a, 0x39, 0x61, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, + 0x65, 0x3a, 0x37, 0x62, 0x3a, 0x66, 0x31, 0x3a, 0x36, 0x63, 0x3a, 0x63, + 0x32, 0x3a, 0x32, 0x34, 0x3a, 0x38, 0x35, 0x3a, 0x61, 0x37, 0x3a, 0x62, + 0x62, 0x3a, 0x65, 0x32, 0x3a, 0x61, 0x61, 0x3a, 0x38, 0x36, 0x3a, 0x39, + 0x36, 0x3a, 0x37, 0x35, 0x3a, 0x30, 0x37, 0x3a, 0x36, 0x31, 0x3a, 0x62, + 0x30, 0x3a, 0x61, 0x65, 0x3a, 0x33, 0x39, 0x3a, 0x62, 0x65, 0x3a, 0x33, + 0x62, 0x3a, 0x32, 0x66, 0x3a, 0x65, 0x39, 0x3a, 0x64, 0x30, 0x3a, 0x63, + 0x63, 0x3a, 0x36, 0x64, 0x3a, 0x34, 0x65, 0x3a, 0x66, 0x37, 0x3a, 0x33, + 0x34, 0x3a, 0x39, 0x31, 0x3a, 0x34, 0x32, 0x3a, 0x35, 0x63, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x36, 0x7a, 0x43, 0x43, 0x41, + 0x39, 0x4f, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x49, 0x56, + 0x72, 0x59, 0x70, 0x7a, 0x54, 0x53, 0x38, 0x65, 0x50, 0x59, 0x77, 0x44, + 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, + 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x77, 0x67, 0x59, 0x49, 0x78, 0x43, + 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x59, 0x54, + 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x51, 0x34, 0x77, 0x44, 0x41, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x49, 0x44, 0x41, 0x56, 0x55, 0x5a, 0x58, 0x68, 0x68, + 0x63, 0x7a, 0x45, 0x51, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x42, 0x77, 0x77, 0x48, 0x53, 0x47, 0x39, 0x31, 0x63, 0x33, 0x52, 0x76, + 0x62, 0x6a, 0x45, 0x59, 0x4d, 0x42, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x0a, 0x43, 0x67, 0x77, 0x50, 0x55, 0x31, 0x4e, 0x4d, 0x49, 0x45, 0x4e, + 0x76, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x61, 0x57, 0x39, + 0x75, 0x4d, 0x54, 0x63, 0x77, 0x4e, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x44, 0x44, 0x43, 0x35, 0x54, 0x55, 0x30, 0x77, 0x75, 0x59, 0x32, 0x39, + 0x74, 0x49, 0x45, 0x56, 0x57, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, + 0x67, 0x51, 0x32, 0x56, 0x79, 0x0a, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, + 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, + 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x48, 0x6b, 0x67, 0x55, 0x6c, + 0x4e, 0x42, 0x49, 0x46, 0x49, 0x79, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, + 0x45, 0x33, 0x4d, 0x44, 0x55, 0x7a, 0x4d, 0x54, 0x45, 0x34, 0x4d, 0x54, + 0x51, 0x7a, 0x4e, 0x31, 0x6f, 0x58, 0x44, 0x54, 0x51, 0x79, 0x0a, 0x4d, + 0x44, 0x55, 0x7a, 0x4d, 0x44, 0x45, 0x34, 0x4d, 0x54, 0x51, 0x7a, 0x4e, + 0x31, 0x6f, 0x77, 0x67, 0x59, 0x49, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, + 0x51, 0x34, 0x77, 0x44, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, 0x44, + 0x41, 0x56, 0x55, 0x5a, 0x58, 0x68, 0x68, 0x63, 0x7a, 0x45, 0x51, 0x4d, + 0x41, 0x34, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, 0x77, 0x77, 0x48, + 0x53, 0x47, 0x39, 0x31, 0x63, 0x33, 0x52, 0x76, 0x62, 0x6a, 0x45, 0x59, + 0x4d, 0x42, 0x59, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x50, + 0x55, 0x31, 0x4e, 0x4d, 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, + 0x63, 0x6d, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x54, 0x63, 0x77, + 0x4e, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x0a, 0x44, 0x43, 0x35, + 0x54, 0x55, 0x30, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x49, 0x45, 0x56, + 0x57, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x32, 0x56, + 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, + 0x76, 0x62, 0x69, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, + 0x70, 0x64, 0x48, 0x6b, 0x67, 0x55, 0x6c, 0x4e, 0x42, 0x49, 0x46, 0x49, + 0x79, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, + 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, + 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x38, 0x41, 0x4d, 0x49, + 0x49, 0x43, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x67, 0x45, 0x41, 0x6a, 0x7a, + 0x5a, 0x6c, 0x51, 0x4f, 0x48, 0x57, 0x54, 0x63, 0x44, 0x58, 0x74, 0x4f, + 0x6c, 0x47, 0x32, 0x6d, 0x76, 0x71, 0x0a, 0x4d, 0x30, 0x66, 0x4e, 0x54, + 0x50, 0x6c, 0x39, 0x66, 0x62, 0x36, 0x39, 0x4c, 0x54, 0x33, 0x77, 0x32, + 0x33, 0x6a, 0x68, 0x68, 0x71, 0x58, 0x5a, 0x75, 0x67, 0x6c, 0x58, 0x61, + 0x4f, 0x31, 0x58, 0x50, 0x71, 0x44, 0x51, 0x43, 0x45, 0x47, 0x44, 0x35, + 0x79, 0x68, 0x42, 0x4a, 0x42, 0x2f, 0x6a, 0x63, 0x68, 0x58, 0x51, 0x41, + 0x52, 0x72, 0x37, 0x58, 0x6e, 0x41, 0x6a, 0x73, 0x73, 0x75, 0x66, 0x0a, + 0x4f, 0x65, 0x50, 0x50, 0x78, 0x55, 0x37, 0x47, 0x6b, 0x6d, 0x30, 0x6d, + 0x78, 0x6e, 0x75, 0x37, 0x73, 0x39, 0x6f, 0x6e, 0x6e, 0x51, 0x71, 0x47, + 0x36, 0x59, 0x45, 0x33, 0x42, 0x66, 0x37, 0x77, 0x63, 0x58, 0x48, 0x73, + 0x77, 0x78, 0x7a, 0x70, 0x59, 0x36, 0x49, 0x58, 0x46, 0x4a, 0x33, 0x76, + 0x47, 0x32, 0x66, 0x54, 0x68, 0x56, 0x55, 0x43, 0x41, 0x74, 0x5a, 0x4a, + 0x79, 0x63, 0x78, 0x61, 0x0a, 0x34, 0x62, 0x48, 0x33, 0x62, 0x7a, 0x4b, + 0x66, 0x79, 0x64, 0x51, 0x37, 0x69, 0x45, 0x47, 0x6f, 0x6e, 0x4c, 0x33, + 0x4c, 0x71, 0x39, 0x74, 0x74, 0x65, 0x77, 0x6b, 0x66, 0x6f, 0x6b, 0x78, + 0x79, 0x6b, 0x4e, 0x6f, 0x72, 0x43, 0x50, 0x7a, 0x50, 0x50, 0x46, 0x54, + 0x4f, 0x5a, 0x77, 0x2b, 0x6f, 0x7a, 0x31, 0x32, 0x57, 0x47, 0x51, 0x76, + 0x45, 0x34, 0x33, 0x4c, 0x72, 0x72, 0x64, 0x46, 0x39, 0x0a, 0x48, 0x53, + 0x66, 0x76, 0x6b, 0x75, 0x73, 0x51, 0x76, 0x31, 0x76, 0x72, 0x4f, 0x36, + 0x2f, 0x50, 0x67, 0x4e, 0x33, 0x42, 0x30, 0x70, 0x59, 0x45, 0x57, 0x33, + 0x70, 0x2b, 0x70, 0x4b, 0x6b, 0x38, 0x4f, 0x48, 0x61, 0x6b, 0x59, 0x6f, + 0x36, 0x67, 0x4f, 0x56, 0x37, 0x71, 0x64, 0x38, 0x39, 0x64, 0x41, 0x46, + 0x6d, 0x50, 0x5a, 0x69, 0x77, 0x2b, 0x42, 0x36, 0x4b, 0x6a, 0x42, 0x53, + 0x59, 0x52, 0x0a, 0x61, 0x5a, 0x66, 0x71, 0x68, 0x62, 0x63, 0x50, 0x6c, + 0x67, 0x74, 0x4c, 0x79, 0x45, 0x44, 0x68, 0x55, 0x4c, 0x6f, 0x75, 0x69, + 0x73, 0x76, 0x33, 0x44, 0x35, 0x6f, 0x69, 0x35, 0x33, 0x2b, 0x61, 0x4e, + 0x78, 0x50, 0x4e, 0x38, 0x6b, 0x30, 0x54, 0x61, 0x79, 0x48, 0x52, 0x77, + 0x4d, 0x77, 0x69, 0x38, 0x71, 0x46, 0x47, 0x39, 0x6b, 0x52, 0x70, 0x6e, + 0x4d, 0x70, 0x68, 0x4e, 0x51, 0x63, 0x41, 0x0a, 0x62, 0x39, 0x5a, 0x68, + 0x43, 0x42, 0x48, 0x71, 0x75, 0x72, 0x6a, 0x32, 0x36, 0x62, 0x4e, 0x67, + 0x35, 0x55, 0x32, 0x35, 0x37, 0x4a, 0x38, 0x55, 0x5a, 0x73, 0x6c, 0x58, + 0x57, 0x4e, 0x76, 0x4e, 0x68, 0x32, 0x6e, 0x34, 0x69, 0x6f, 0x59, 0x53, + 0x41, 0x30, 0x65, 0x2f, 0x5a, 0x68, 0x4e, 0x32, 0x72, 0x48, 0x64, 0x39, + 0x4e, 0x43, 0x53, 0x46, 0x67, 0x38, 0x33, 0x58, 0x71, 0x70, 0x79, 0x51, + 0x0a, 0x47, 0x70, 0x38, 0x68, 0x4c, 0x48, 0x39, 0x34, 0x74, 0x32, 0x53, + 0x34, 0x32, 0x4f, 0x69, 0x6d, 0x39, 0x48, 0x69, 0x7a, 0x56, 0x63, 0x75, + 0x45, 0x30, 0x6a, 0x4c, 0x45, 0x65, 0x4b, 0x36, 0x6a, 0x6a, 0x32, 0x48, + 0x64, 0x7a, 0x67, 0x68, 0x54, 0x72, 0x65, 0x79, 0x49, 0x2f, 0x42, 0x58, + 0x6b, 0x6d, 0x67, 0x33, 0x6d, 0x6e, 0x78, 0x70, 0x33, 0x7a, 0x6b, 0x79, + 0x50, 0x75, 0x42, 0x51, 0x56, 0x0a, 0x50, 0x57, 0x4b, 0x63, 0x68, 0x6a, + 0x67, 0x47, 0x41, 0x47, 0x59, 0x53, 0x35, 0x46, 0x6c, 0x32, 0x57, 0x6c, + 0x50, 0x41, 0x41, 0x70, 0x69, 0x69, 0x45, 0x43, 0x74, 0x6f, 0x52, 0x48, + 0x75, 0x4f, 0x65, 0x63, 0x34, 0x7a, 0x53, 0x6e, 0x61, 0x71, 0x57, 0x34, + 0x45, 0x57, 0x47, 0x37, 0x57, 0x4b, 0x32, 0x4e, 0x41, 0x41, 0x65, 0x31, + 0x35, 0x69, 0x74, 0x41, 0x6e, 0x57, 0x68, 0x6d, 0x4d, 0x4f, 0x0a, 0x70, + 0x67, 0x57, 0x56, 0x53, 0x62, 0x6f, 0x6f, 0x69, 0x34, 0x69, 0x54, 0x73, + 0x6a, 0x51, 0x63, 0x32, 0x4b, 0x52, 0x56, 0x62, 0x72, 0x63, 0x63, 0x30, + 0x4e, 0x36, 0x5a, 0x56, 0x54, 0x73, 0x6a, 0x39, 0x43, 0x4c, 0x67, 0x2b, + 0x53, 0x6c, 0x6d, 0x4a, 0x75, 0x77, 0x67, 0x55, 0x48, 0x66, 0x62, 0x53, + 0x67, 0x75, 0x50, 0x76, 0x75, 0x55, 0x43, 0x59, 0x48, 0x42, 0x42, 0x58, + 0x74, 0x53, 0x75, 0x0a, 0x55, 0x44, 0x6b, 0x69, 0x46, 0x43, 0x62, 0x4c, + 0x73, 0x6a, 0x74, 0x7a, 0x64, 0x46, 0x56, 0x48, 0x42, 0x33, 0x6d, 0x42, + 0x4f, 0x61, 0x67, 0x77, 0x45, 0x30, 0x54, 0x6c, 0x42, 0x49, 0x71, 0x75, + 0x6c, 0x68, 0x4d, 0x6c, 0x51, 0x67, 0x2b, 0x35, 0x55, 0x38, 0x53, 0x62, + 0x2f, 0x4d, 0x33, 0x6b, 0x48, 0x4e, 0x34, 0x38, 0x2b, 0x71, 0x76, 0x57, + 0x42, 0x6b, 0x6f, 0x66, 0x5a, 0x36, 0x61, 0x59, 0x0a, 0x4d, 0x42, 0x7a, + 0x64, 0x4c, 0x4e, 0x76, 0x63, 0x47, 0x4a, 0x56, 0x58, 0x5a, 0x73, 0x62, + 0x2f, 0x58, 0x49, 0x74, 0x57, 0x39, 0x58, 0x63, 0x43, 0x41, 0x77, 0x45, + 0x41, 0x41, 0x61, 0x4e, 0x6a, 0x4d, 0x47, 0x45, 0x77, 0x44, 0x77, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, + 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x66, 0x42, 0x67, 0x4e, + 0x56, 0x0a, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, + 0x54, 0x35, 0x59, 0x4c, 0x76, 0x55, 0x34, 0x39, 0x55, 0x30, 0x39, 0x72, + 0x6a, 0x31, 0x42, 0x6f, 0x41, 0x6c, 0x70, 0x33, 0x50, 0x62, 0x52, 0x6d, + 0x6d, 0x6f, 0x6e, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, + 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x2b, 0x57, 0x43, 0x37, 0x31, 0x4f, + 0x50, 0x56, 0x4e, 0x50, 0x61, 0x34, 0x0a, 0x39, 0x51, 0x61, 0x41, 0x4a, + 0x61, 0x64, 0x7a, 0x32, 0x30, 0x5a, 0x70, 0x71, 0x4a, 0x34, 0x77, 0x44, + 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, + 0x41, 0x51, 0x44, 0x41, 0x67, 0x47, 0x47, 0x4d, 0x41, 0x30, 0x47, 0x43, + 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, + 0x77, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x41, 0x51, 0x42, 0x57, 0x0a, + 0x73, 0x34, 0x37, 0x4c, 0x43, 0x70, 0x31, 0x4a, 0x6a, 0x72, 0x2b, 0x6b, + 0x78, 0x4a, 0x47, 0x37, 0x5a, 0x68, 0x63, 0x46, 0x55, 0x5a, 0x68, 0x31, + 0x2b, 0x2b, 0x56, 0x51, 0x4c, 0x48, 0x71, 0x65, 0x38, 0x52, 0x54, 0x36, + 0x71, 0x39, 0x4f, 0x4b, 0x50, 0x76, 0x2b, 0x52, 0x4b, 0x59, 0x39, 0x6a, + 0x69, 0x39, 0x69, 0x30, 0x71, 0x56, 0x51, 0x42, 0x44, 0x62, 0x36, 0x54, + 0x68, 0x69, 0x2f, 0x35, 0x0a, 0x53, 0x6d, 0x33, 0x48, 0x58, 0x76, 0x56, + 0x58, 0x2b, 0x63, 0x70, 0x56, 0x48, 0x42, 0x4b, 0x2b, 0x52, 0x77, 0x38, + 0x32, 0x78, 0x64, 0x39, 0x71, 0x74, 0x39, 0x74, 0x31, 0x77, 0x6b, 0x63, + 0x6c, 0x66, 0x37, 0x6e, 0x78, 0x59, 0x2f, 0x68, 0x6f, 0x4c, 0x56, 0x55, + 0x45, 0x30, 0x66, 0x4b, 0x4e, 0x73, 0x4b, 0x54, 0x50, 0x76, 0x44, 0x78, + 0x65, 0x48, 0x33, 0x6a, 0x6e, 0x70, 0x61, 0x41, 0x67, 0x0a, 0x63, 0x4c, + 0x41, 0x45, 0x78, 0x62, 0x66, 0x33, 0x63, 0x71, 0x66, 0x65, 0x49, 0x67, + 0x32, 0x39, 0x4d, 0x79, 0x56, 0x47, 0x6a, 0x47, 0x53, 0x53, 0x4a, 0x75, + 0x4d, 0x2b, 0x4c, 0x6d, 0x4f, 0x57, 0x32, 0x70, 0x75, 0x4d, 0x50, 0x66, + 0x67, 0x59, 0x43, 0x64, 0x63, 0x44, 0x7a, 0x48, 0x32, 0x47, 0x67, 0x75, + 0x44, 0x4b, 0x42, 0x41, 0x64, 0x52, 0x55, 0x4e, 0x66, 0x2f, 0x6b, 0x74, + 0x55, 0x4d, 0x0a, 0x37, 0x39, 0x71, 0x47, 0x6e, 0x35, 0x6e, 0x58, 0x36, + 0x37, 0x65, 0x76, 0x61, 0x4f, 0x49, 0x35, 0x4a, 0x70, 0x53, 0x36, 0x61, + 0x4c, 0x65, 0x2f, 0x67, 0x39, 0x50, 0x71, 0x65, 0x6d, 0x63, 0x39, 0x59, + 0x6d, 0x65, 0x75, 0x4a, 0x65, 0x56, 0x79, 0x36, 0x4f, 0x4c, 0x6b, 0x37, + 0x4b, 0x34, 0x53, 0x39, 0x6b, 0x73, 0x72, 0x50, 0x4a, 0x2f, 0x70, 0x73, + 0x45, 0x44, 0x7a, 0x4f, 0x46, 0x53, 0x7a, 0x0a, 0x2f, 0x62, 0x64, 0x6f, + 0x79, 0x4e, 0x72, 0x47, 0x6a, 0x31, 0x45, 0x38, 0x73, 0x76, 0x75, 0x52, + 0x33, 0x42, 0x7a, 0x6e, 0x6d, 0x35, 0x33, 0x68, 0x74, 0x77, 0x31, 0x79, + 0x6a, 0x2b, 0x4b, 0x6b, 0x78, 0x4b, 0x6c, 0x34, 0x2b, 0x65, 0x73, 0x55, + 0x72, 0x4d, 0x5a, 0x44, 0x42, 0x63, 0x4a, 0x6c, 0x4f, 0x53, 0x67, 0x59, + 0x41, 0x73, 0x4f, 0x43, 0x73, 0x70, 0x30, 0x46, 0x76, 0x6d, 0x58, 0x74, + 0x0a, 0x6c, 0x6c, 0x39, 0x6c, 0x64, 0x44, 0x7a, 0x37, 0x43, 0x54, 0x55, + 0x75, 0x65, 0x35, 0x77, 0x54, 0x2f, 0x52, 0x73, 0x50, 0x58, 0x63, 0x64, + 0x74, 0x67, 0x54, 0x70, 0x57, 0x44, 0x38, 0x77, 0x37, 0x34, 0x61, 0x38, + 0x43, 0x4c, 0x79, 0x4b, 0x73, 0x52, 0x73, 0x70, 0x47, 0x50, 0x4b, 0x41, + 0x63, 0x54, 0x4e, 0x5a, 0x45, 0x74, 0x46, 0x34, 0x75, 0x58, 0x42, 0x56, + 0x6d, 0x43, 0x65, 0x45, 0x6d, 0x0a, 0x4b, 0x66, 0x37, 0x47, 0x55, 0x6d, + 0x47, 0x36, 0x73, 0x58, 0x50, 0x2f, 0x77, 0x77, 0x79, 0x63, 0x35, 0x57, + 0x78, 0x71, 0x6c, 0x44, 0x38, 0x55, 0x79, 0x6b, 0x41, 0x57, 0x6c, 0x59, + 0x54, 0x7a, 0x57, 0x61, 0x6d, 0x73, 0x58, 0x30, 0x78, 0x68, 0x6b, 0x32, + 0x33, 0x52, 0x4f, 0x38, 0x79, 0x69, 0x6c, 0x51, 0x77, 0x69, 0x70, 0x6d, + 0x64, 0x6e, 0x52, 0x43, 0x36, 0x35, 0x32, 0x64, 0x4b, 0x4b, 0x0a, 0x51, + 0x62, 0x4e, 0x6d, 0x43, 0x31, 0x72, 0x37, 0x66, 0x53, 0x4f, 0x6c, 0x38, + 0x68, 0x71, 0x77, 0x2f, 0x39, 0x36, 0x62, 0x67, 0x35, 0x51, 0x75, 0x30, + 0x54, 0x2f, 0x66, 0x6b, 0x72, 0x65, 0x52, 0x72, 0x77, 0x55, 0x37, 0x5a, + 0x63, 0x65, 0x67, 0x62, 0x4c, 0x48, 0x4e, 0x59, 0x68, 0x4c, 0x44, 0x6b, + 0x42, 0x76, 0x6a, 0x4a, 0x63, 0x34, 0x30, 0x76, 0x47, 0x39, 0x33, 0x64, + 0x72, 0x45, 0x51, 0x0a, 0x77, 0x2f, 0x63, 0x46, 0x47, 0x73, 0x44, 0x57, + 0x72, 0x33, 0x52, 0x69, 0x53, 0x42, 0x64, 0x33, 0x6b, 0x6d, 0x6d, 0x51, + 0x59, 0x52, 0x7a, 0x65, 0x6c, 0x59, 0x42, 0x30, 0x56, 0x49, 0x38, 0x59, + 0x48, 0x4d, 0x50, 0x7a, 0x41, 0x39, 0x43, 0x2f, 0x70, 0x45, 0x4e, 0x31, + 0x68, 0x6c, 0x4d, 0x59, 0x65, 0x67, 0x6f, 0x75, 0x43, 0x52, 0x77, 0x32, + 0x6e, 0x35, 0x48, 0x39, 0x67, 0x6f, 0x6f, 0x69, 0x0a, 0x53, 0x39, 0x45, + 0x4f, 0x55, 0x43, 0x58, 0x64, 0x79, 0x77, 0x4d, 0x4d, 0x46, 0x38, 0x6d, + 0x44, 0x41, 0x41, 0x68, 0x4f, 0x4e, 0x55, 0x32, 0x4b, 0x69, 0x2b, 0x33, + 0x77, 0x41, 0x70, 0x52, 0x6d, 0x4c, 0x45, 0x52, 0x2f, 0x79, 0x35, 0x55, + 0x6e, 0x6c, 0x68, 0x65, 0x74, 0x43, 0x54, 0x43, 0x73, 0x74, 0x6e, 0x45, + 0x58, 0x62, 0x6f, 0x73, 0x58, 0x39, 0x68, 0x77, 0x4a, 0x31, 0x43, 0x30, + 0x37, 0x0a, 0x6d, 0x4b, 0x56, 0x78, 0x30, 0x31, 0x51, 0x54, 0x32, 0x57, + 0x44, 0x7a, 0x39, 0x55, 0x74, 0x6d, 0x54, 0x2f, 0x72, 0x78, 0x37, 0x69, + 0x41, 0x53, 0x6a, 0x62, 0x53, 0x73, 0x56, 0x37, 0x46, 0x46, 0x59, 0x36, + 0x47, 0x73, 0x64, 0x71, 0x6e, 0x43, 0x2b, 0x77, 0x3d, 0x3d, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x53, 0x53, 0x4c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x45, + 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x45, 0x43, 0x43, 0x20, 0x4f, + 0x3d, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x53, 0x53, 0x4c, 0x2e, 0x63, + 0x6f, 0x6d, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x45, + 0x43, 0x43, 0x20, 0x4f, 0x3d, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x6f, 0x72, + 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x53, 0x53, 0x4c, 0x2e, 0x63, + 0x6f, 0x6d, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x45, + 0x43, 0x43, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x3a, 0x20, 0x33, 0x31, 0x38, 0x32, 0x32, 0x34, 0x36, 0x35, 0x32, 0x36, + 0x37, 0x35, 0x34, 0x35, 0x35, 0x35, 0x32, 0x38, 0x35, 0x0a, 0x23, 0x20, + 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x39, 0x3a, 0x35, 0x33, 0x3a, 0x32, + 0x32, 0x3a, 0x36, 0x35, 0x3a, 0x38, 0x33, 0x3a, 0x34, 0x32, 0x3a, 0x30, + 0x31, 0x3a, 0x35, 0x34, 0x3a, 0x63, 0x30, 0x3a, 0x63, 0x65, 0x3a, 0x34, + 0x32, 0x3a, 0x62, 0x39, 0x3a, 0x35, 0x61, 0x3a, 0x37, 0x63, 0x3a, 0x66, + 0x32, 0x3a, 0x39, 0x30, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x34, 0x63, 0x3a, 0x64, 0x64, 0x3a, 0x35, 0x31, 0x3a, 0x61, 0x33, + 0x3a, 0x64, 0x31, 0x3a, 0x66, 0x35, 0x3a, 0x32, 0x30, 0x3a, 0x33, 0x32, + 0x3a, 0x31, 0x34, 0x3a, 0x62, 0x30, 0x3a, 0x63, 0x36, 0x3a, 0x63, 0x35, + 0x3a, 0x33, 0x32, 0x3a, 0x32, 0x33, 0x3a, 0x30, 0x33, 0x3a, 0x39, 0x31, + 0x3a, 0x63, 0x37, 0x3a, 0x34, 0x36, 0x3a, 0x34, 0x32, 0x3a, 0x36, 0x64, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, + 0x32, 0x3a, 0x61, 0x32, 0x3a, 0x63, 0x31, 0x3a, 0x66, 0x37, 0x3a, 0x62, + 0x64, 0x3a, 0x65, 0x64, 0x3a, 0x37, 0x30, 0x3a, 0x34, 0x63, 0x3a, 0x63, + 0x31, 0x3a, 0x65, 0x37, 0x3a, 0x30, 0x31, 0x3a, 0x62, 0x35, 0x3a, 0x66, + 0x34, 0x3a, 0x30, 0x38, 0x3a, 0x63, 0x33, 0x3a, 0x31, 0x30, 0x3a, 0x38, + 0x38, 0x3a, 0x30, 0x66, 0x3a, 0x65, 0x39, 0x3a, 0x35, 0x36, 0x3a, 0x62, + 0x35, 0x3a, 0x64, 0x65, 0x3a, 0x32, 0x61, 0x3a, 0x34, 0x61, 0x3a, 0x34, + 0x34, 0x3a, 0x66, 0x39, 0x3a, 0x39, 0x63, 0x3a, 0x38, 0x37, 0x3a, 0x33, + 0x61, 0x3a, 0x32, 0x35, 0x3a, 0x61, 0x37, 0x3a, 0x63, 0x38, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6c, 0x44, 0x43, 0x43, 0x41, + 0x68, 0x71, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x49, 0x4c, + 0x43, 0x6d, 0x63, 0x57, 0x78, 0x62, 0x74, 0x42, 0x5a, 0x55, 0x77, 0x43, + 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, + 0x77, 0x49, 0x77, 0x66, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x0a, 0x56, 0x56, 0x4d, 0x78, + 0x44, 0x6a, 0x41, 0x4d, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x4d, + 0x42, 0x56, 0x52, 0x6c, 0x65, 0x47, 0x46, 0x7a, 0x4d, 0x52, 0x41, 0x77, + 0x44, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x64, 0x49, + 0x62, 0x33, 0x56, 0x7a, 0x64, 0x47, 0x39, 0x75, 0x4d, 0x52, 0x67, 0x77, + 0x46, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, 0x39, 0x54, + 0x0a, 0x55, 0x30, 0x77, 0x67, 0x51, 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, + 0x79, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, 0x34, 0x78, 0x4e, 0x44, 0x41, + 0x79, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x4b, 0x31, 0x4e, + 0x54, 0x54, 0x43, 0x35, 0x6a, 0x62, 0x32, 0x30, 0x67, 0x52, 0x56, 0x59, + 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x5a, 0x58, 0x4a, + 0x30, 0x61, 0x57, 0x5a, 0x70, 0x0a, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, + 0x39, 0x75, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, + 0x6c, 0x30, 0x65, 0x53, 0x42, 0x46, 0x51, 0x30, 0x4d, 0x77, 0x48, 0x68, + 0x63, 0x4e, 0x4d, 0x54, 0x59, 0x77, 0x4d, 0x6a, 0x45, 0x79, 0x4d, 0x54, + 0x67, 0x78, 0x4e, 0x54, 0x49, 0x7a, 0x57, 0x68, 0x63, 0x4e, 0x4e, 0x44, + 0x45, 0x77, 0x4d, 0x6a, 0x45, 0x79, 0x4d, 0x54, 0x67, 0x78, 0x0a, 0x4e, + 0x54, 0x49, 0x7a, 0x57, 0x6a, 0x42, 0x2f, 0x4d, 0x51, 0x73, 0x77, 0x43, + 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, + 0x7a, 0x45, 0x4f, 0x4d, 0x41, 0x77, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, + 0x41, 0x77, 0x46, 0x56, 0x47, 0x56, 0x34, 0x59, 0x58, 0x4d, 0x78, 0x45, + 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x4d, 0x42, + 0x30, 0x68, 0x76, 0x0a, 0x64, 0x58, 0x4e, 0x30, 0x62, 0x32, 0x34, 0x78, + 0x47, 0x44, 0x41, 0x57, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, + 0x44, 0x31, 0x4e, 0x54, 0x54, 0x43, 0x42, 0x44, 0x62, 0x33, 0x4a, 0x77, + 0x62, 0x33, 0x4a, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x30, + 0x4d, 0x44, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x72, + 0x55, 0x31, 0x4e, 0x4d, 0x4c, 0x6d, 0x4e, 0x76, 0x0a, 0x62, 0x53, 0x42, + 0x46, 0x56, 0x69, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, + 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, + 0x70, 0x62, 0x32, 0x34, 0x67, 0x51, 0x58, 0x56, 0x30, 0x61, 0x47, 0x39, + 0x79, 0x61, 0x58, 0x52, 0x35, 0x49, 0x45, 0x56, 0x44, 0x51, 0x7a, 0x42, + 0x32, 0x4d, 0x42, 0x41, 0x47, 0x42, 0x79, 0x71, 0x47, 0x53, 0x4d, 0x34, + 0x39, 0x0a, 0x41, 0x67, 0x45, 0x47, 0x42, 0x53, 0x75, 0x42, 0x42, 0x41, + 0x41, 0x69, 0x41, 0x32, 0x49, 0x41, 0x42, 0x4b, 0x6f, 0x53, 0x52, 0x35, + 0x43, 0x59, 0x47, 0x2f, 0x76, 0x76, 0x77, 0x30, 0x41, 0x48, 0x67, 0x79, + 0x42, 0x4f, 0x38, 0x54, 0x43, 0x43, 0x6f, 0x67, 0x62, 0x52, 0x38, 0x70, + 0x4b, 0x47, 0x59, 0x66, 0x4c, 0x32, 0x49, 0x57, 0x6a, 0x4b, 0x41, 0x4d, + 0x54, 0x48, 0x36, 0x6b, 0x4d, 0x41, 0x0a, 0x56, 0x49, 0x62, 0x63, 0x2f, + 0x52, 0x2f, 0x66, 0x41, 0x4c, 0x68, 0x42, 0x59, 0x6c, 0x7a, 0x63, 0x63, + 0x42, 0x59, 0x79, 0x33, 0x68, 0x2b, 0x5a, 0x31, 0x4d, 0x7a, 0x46, 0x42, + 0x38, 0x67, 0x49, 0x48, 0x32, 0x45, 0x57, 0x42, 0x31, 0x45, 0x39, 0x66, + 0x56, 0x77, 0x48, 0x55, 0x2b, 0x4d, 0x31, 0x4f, 0x49, 0x7a, 0x66, 0x7a, + 0x5a, 0x2f, 0x5a, 0x4c, 0x67, 0x31, 0x4b, 0x74, 0x68, 0x6b, 0x75, 0x0a, + 0x57, 0x6e, 0x42, 0x61, 0x42, 0x75, 0x32, 0x2b, 0x38, 0x4b, 0x47, 0x77, + 0x79, 0x74, 0x41, 0x4a, 0x4b, 0x61, 0x4e, 0x6a, 0x4d, 0x47, 0x45, 0x77, + 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, + 0x46, 0x46, 0x76, 0x4b, 0x58, 0x75, 0x58, 0x65, 0x30, 0x6f, 0x47, 0x71, + 0x7a, 0x61, 0x67, 0x74, 0x5a, 0x46, 0x47, 0x32, 0x32, 0x58, 0x4b, 0x62, + 0x6c, 0x2b, 0x5a, 0x50, 0x0a, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, + 0x42, 0x41, 0x66, 0x38, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, + 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x57, 0x38, 0x70, + 0x65, 0x35, 0x64, 0x37, 0x53, 0x67, 0x61, 0x72, 0x4e, 0x71, 0x43, 0x31, + 0x6b, 0x55, 0x62, 0x62, 0x5a, 0x63, 0x70, 0x75, 0x58, 0x0a, 0x35, 0x6b, + 0x38, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x47, 0x47, 0x4d, 0x41, + 0x6f, 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, + 0x4d, 0x43, 0x41, 0x32, 0x67, 0x41, 0x4d, 0x47, 0x55, 0x43, 0x4d, 0x51, + 0x43, 0x4b, 0x35, 0x6b, 0x43, 0x4a, 0x4e, 0x2b, 0x76, 0x70, 0x31, 0x52, + 0x50, 0x5a, 0x0a, 0x79, 0x74, 0x52, 0x72, 0x4a, 0x50, 0x4f, 0x77, 0x50, + 0x59, 0x64, 0x47, 0x57, 0x42, 0x72, 0x73, 0x73, 0x64, 0x39, 0x76, 0x2b, + 0x31, 0x61, 0x36, 0x63, 0x47, 0x76, 0x48, 0x4f, 0x4d, 0x7a, 0x6f, 0x73, + 0x59, 0x78, 0x50, 0x44, 0x2f, 0x66, 0x78, 0x5a, 0x33, 0x59, 0x4f, 0x67, + 0x39, 0x41, 0x65, 0x55, 0x59, 0x38, 0x43, 0x4d, 0x44, 0x33, 0x32, 0x49, + 0x79, 0x67, 0x6d, 0x54, 0x4d, 0x5a, 0x67, 0x0a, 0x68, 0x35, 0x4d, 0x6d, + 0x6d, 0x37, 0x49, 0x31, 0x48, 0x72, 0x72, 0x57, 0x39, 0x7a, 0x7a, 0x52, + 0x48, 0x4d, 0x37, 0x36, 0x4a, 0x54, 0x79, 0x6d, 0x47, 0x6f, 0x45, 0x56, + 0x57, 0x2f, 0x4d, 0x53, 0x44, 0x32, 0x7a, 0x75, 0x5a, 0x59, 0x72, 0x4a, + 0x68, 0x36, 0x6a, 0x35, 0x42, 0x2b, 0x42, 0x69, 0x6d, 0x6f, 0x78, 0x63, + 0x53, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x3d, 0x47, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x4f, 0x55, 0x3d, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x36, 0x0a, + 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x4f, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, + 0x6e, 0x20, 0x4f, 0x55, 0x3d, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, + 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, + 0x2d, 0x20, 0x52, 0x36, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x3a, 0x20, 0x22, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, + 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, + 0x52, 0x36, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x3a, 0x20, 0x31, 0x34, 0x31, 0x37, 0x37, 0x36, 0x36, 0x36, 0x31, 0x37, + 0x39, 0x37, 0x33, 0x34, 0x34, 0x34, 0x39, 0x38, 0x39, 0x32, 0x35, 0x32, + 0x36, 0x37, 0x30, 0x33, 0x30, 0x31, 0x36, 0x31, 0x39, 0x35, 0x33, 0x37, + 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x66, 0x3a, 0x64, + 0x64, 0x3a, 0x30, 0x37, 0x3a, 0x65, 0x34, 0x3a, 0x64, 0x34, 0x3a, 0x32, + 0x32, 0x3a, 0x36, 0x34, 0x3a, 0x33, 0x39, 0x3a, 0x31, 0x65, 0x3a, 0x30, + 0x63, 0x3a, 0x33, 0x37, 0x3a, 0x34, 0x32, 0x3a, 0x65, 0x61, 0x3a, 0x64, + 0x31, 0x3a, 0x63, 0x36, 0x3a, 0x61, 0x65, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x30, 0x3a, 0x39, 0x34, 0x3a, 0x36, 0x34, + 0x3a, 0x30, 0x65, 0x3a, 0x62, 0x35, 0x3a, 0x61, 0x37, 0x3a, 0x61, 0x31, + 0x3a, 0x63, 0x61, 0x3a, 0x31, 0x31, 0x3a, 0x39, 0x63, 0x3a, 0x31, 0x66, + 0x3a, 0x64, 0x64, 0x3a, 0x64, 0x35, 0x3a, 0x39, 0x66, 0x3a, 0x38, 0x31, + 0x3a, 0x30, 0x32, 0x3a, 0x36, 0x33, 0x3a, 0x61, 0x37, 0x3a, 0x66, 0x62, + 0x3a, 0x64, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x32, 0x63, 0x3a, 0x61, 0x62, 0x3a, 0x65, 0x61, 0x3a, 0x66, + 0x65, 0x3a, 0x33, 0x37, 0x3a, 0x64, 0x30, 0x3a, 0x36, 0x63, 0x3a, 0x61, + 0x32, 0x3a, 0x32, 0x61, 0x3a, 0x62, 0x61, 0x3a, 0x37, 0x33, 0x3a, 0x39, + 0x31, 0x3a, 0x63, 0x30, 0x3a, 0x30, 0x33, 0x3a, 0x33, 0x64, 0x3a, 0x32, + 0x35, 0x3a, 0x39, 0x38, 0x3a, 0x32, 0x39, 0x3a, 0x35, 0x32, 0x3a, 0x63, + 0x34, 0x3a, 0x35, 0x33, 0x3a, 0x36, 0x34, 0x3a, 0x37, 0x33, 0x3a, 0x34, + 0x39, 0x3a, 0x37, 0x36, 0x3a, 0x33, 0x61, 0x3a, 0x33, 0x61, 0x3a, 0x62, + 0x35, 0x3a, 0x61, 0x64, 0x3a, 0x36, 0x63, 0x3a, 0x63, 0x66, 0x3a, 0x36, + 0x39, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x67, 0x7a, + 0x43, 0x43, 0x41, 0x32, 0x75, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, + 0x49, 0x4f, 0x52, 0x65, 0x61, 0x37, 0x41, 0x34, 0x4d, 0x7a, 0x77, 0x34, + 0x56, 0x6c, 0x53, 0x4f, 0x62, 0x2f, 0x52, 0x56, 0x45, 0x77, 0x44, 0x51, + 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, + 0x45, 0x4d, 0x42, 0x51, 0x41, 0x77, 0x54, 0x44, 0x45, 0x67, 0x0a, 0x4d, + 0x42, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x58, 0x52, + 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, 0x55, 0x32, 0x6c, 0x6e, 0x62, + 0x69, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x49, + 0x43, 0x30, 0x67, 0x55, 0x6a, 0x59, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x43, 0x6b, 0x64, 0x73, 0x62, + 0x32, 0x4a, 0x68, 0x0a, 0x62, 0x46, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x78, + 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x54, + 0x43, 0x6b, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62, 0x46, 0x4e, 0x70, + 0x5a, 0x32, 0x34, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x51, 0x78, + 0x4d, 0x6a, 0x45, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, + 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x51, 0x78, 0x0a, 0x4d, 0x6a, 0x45, + 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x6a, 0x42, + 0x4d, 0x4d, 0x53, 0x41, 0x77, 0x48, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x4c, 0x45, 0x78, 0x64, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x78, + 0x54, 0x61, 0x57, 0x64, 0x75, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, + 0x67, 0x51, 0x30, 0x45, 0x67, 0x4c, 0x53, 0x42, 0x53, 0x4e, 0x6a, 0x45, + 0x54, 0x0a, 0x4d, 0x42, 0x45, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, + 0x4d, 0x4b, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d, 0x46, 0x73, 0x55, 0x32, + 0x6c, 0x6e, 0x62, 0x6a, 0x45, 0x54, 0x4d, 0x42, 0x45, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x41, 0x78, 0x4d, 0x4b, 0x52, 0x32, 0x78, 0x76, 0x59, 0x6d, + 0x46, 0x73, 0x55, 0x32, 0x6c, 0x6e, 0x62, 0x6a, 0x43, 0x43, 0x41, 0x69, + 0x49, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, + 0x67, 0x49, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x67, 0x6f, 0x43, 0x67, + 0x67, 0x49, 0x42, 0x41, 0x4a, 0x55, 0x48, 0x36, 0x48, 0x50, 0x4b, 0x5a, + 0x76, 0x6e, 0x73, 0x46, 0x4d, 0x70, 0x37, 0x50, 0x50, 0x63, 0x4e, 0x43, + 0x50, 0x47, 0x30, 0x52, 0x51, 0x73, 0x73, 0x67, 0x72, 0x52, 0x49, 0x0a, + 0x78, 0x75, 0x74, 0x62, 0x50, 0x4b, 0x36, 0x44, 0x75, 0x45, 0x47, 0x53, + 0x4d, 0x78, 0x53, 0x6b, 0x62, 0x33, 0x2f, 0x70, 0x4b, 0x73, 0x7a, 0x47, + 0x73, 0x49, 0x68, 0x72, 0x78, 0x62, 0x61, 0x4a, 0x30, 0x63, 0x61, 0x79, + 0x2f, 0x78, 0x54, 0x4f, 0x55, 0x52, 0x51, 0x68, 0x37, 0x45, 0x72, 0x64, + 0x47, 0x31, 0x72, 0x47, 0x31, 0x6f, 0x66, 0x75, 0x54, 0x54, 0x6f, 0x56, + 0x42, 0x75, 0x31, 0x6b, 0x0a, 0x5a, 0x67, 0x75, 0x53, 0x67, 0x4d, 0x70, + 0x45, 0x33, 0x6e, 0x4f, 0x55, 0x54, 0x76, 0x4f, 0x6e, 0x69, 0x58, 0x39, + 0x50, 0x65, 0x47, 0x4d, 0x49, 0x79, 0x42, 0x4a, 0x51, 0x62, 0x55, 0x4a, + 0x6d, 0x4c, 0x30, 0x32, 0x35, 0x65, 0x53, 0x68, 0x4e, 0x55, 0x68, 0x71, + 0x4b, 0x47, 0x6f, 0x43, 0x33, 0x47, 0x59, 0x45, 0x4f, 0x66, 0x73, 0x53, + 0x4b, 0x76, 0x47, 0x52, 0x4d, 0x49, 0x52, 0x78, 0x44, 0x0a, 0x61, 0x4e, + 0x63, 0x39, 0x50, 0x49, 0x72, 0x46, 0x73, 0x6d, 0x62, 0x56, 0x6b, 0x4a, + 0x71, 0x33, 0x4d, 0x51, 0x62, 0x46, 0x76, 0x75, 0x4a, 0x74, 0x4d, 0x67, + 0x61, 0x6d, 0x48, 0x76, 0x6d, 0x35, 0x36, 0x36, 0x71, 0x6a, 0x75, 0x4c, + 0x2b, 0x2b, 0x67, 0x6d, 0x4e, 0x51, 0x30, 0x50, 0x41, 0x59, 0x69, 0x64, + 0x2f, 0x6b, 0x44, 0x33, 0x6e, 0x31, 0x36, 0x71, 0x49, 0x66, 0x4b, 0x74, + 0x4a, 0x77, 0x0a, 0x4c, 0x6e, 0x76, 0x6e, 0x76, 0x4a, 0x4f, 0x37, 0x62, + 0x56, 0x50, 0x69, 0x53, 0x48, 0x79, 0x4d, 0x45, 0x41, 0x63, 0x34, 0x2f, + 0x32, 0x61, 0x79, 0x64, 0x32, 0x46, 0x2b, 0x34, 0x4f, 0x71, 0x4d, 0x50, + 0x4b, 0x71, 0x30, 0x70, 0x50, 0x62, 0x7a, 0x6c, 0x55, 0x6f, 0x53, 0x42, + 0x32, 0x33, 0x39, 0x6a, 0x4c, 0x4b, 0x4a, 0x7a, 0x39, 0x43, 0x67, 0x59, + 0x58, 0x66, 0x49, 0x57, 0x48, 0x53, 0x77, 0x0a, 0x31, 0x43, 0x4d, 0x36, + 0x39, 0x31, 0x30, 0x36, 0x79, 0x71, 0x4c, 0x62, 0x6e, 0x51, 0x6e, 0x65, + 0x58, 0x55, 0x51, 0x74, 0x6b, 0x50, 0x47, 0x42, 0x7a, 0x56, 0x65, 0x53, + 0x2b, 0x6e, 0x36, 0x38, 0x55, 0x41, 0x52, 0x6a, 0x4e, 0x4e, 0x39, 0x72, + 0x6b, 0x78, 0x69, 0x2b, 0x61, 0x7a, 0x61, 0x79, 0x4f, 0x65, 0x53, 0x73, + 0x4a, 0x44, 0x61, 0x33, 0x38, 0x4f, 0x2b, 0x32, 0x48, 0x42, 0x4e, 0x58, + 0x0a, 0x6b, 0x37, 0x62, 0x65, 0x73, 0x76, 0x6a, 0x69, 0x68, 0x62, 0x64, + 0x7a, 0x6f, 0x72, 0x67, 0x31, 0x71, 0x6b, 0x58, 0x79, 0x34, 0x4a, 0x30, + 0x32, 0x6f, 0x57, 0x39, 0x55, 0x69, 0x76, 0x46, 0x79, 0x56, 0x6d, 0x34, + 0x75, 0x69, 0x4d, 0x56, 0x52, 0x51, 0x6b, 0x51, 0x56, 0x6c, 0x4f, 0x36, + 0x6a, 0x78, 0x54, 0x69, 0x57, 0x6d, 0x30, 0x35, 0x4f, 0x57, 0x67, 0x74, + 0x48, 0x38, 0x77, 0x59, 0x32, 0x0a, 0x53, 0x58, 0x63, 0x77, 0x76, 0x48, + 0x45, 0x33, 0x35, 0x61, 0x62, 0x73, 0x49, 0x51, 0x68, 0x31, 0x2f, 0x4f, + 0x5a, 0x68, 0x46, 0x6a, 0x39, 0x33, 0x31, 0x64, 0x6d, 0x52, 0x6c, 0x34, + 0x51, 0x4b, 0x62, 0x4e, 0x51, 0x43, 0x54, 0x58, 0x54, 0x41, 0x46, 0x4f, + 0x33, 0x39, 0x4f, 0x66, 0x75, 0x44, 0x38, 0x6c, 0x34, 0x55, 0x6f, 0x51, + 0x53, 0x77, 0x43, 0x2b, 0x6e, 0x2b, 0x37, 0x6f, 0x2f, 0x68, 0x0a, 0x62, + 0x67, 0x75, 0x79, 0x43, 0x4c, 0x4e, 0x68, 0x5a, 0x67, 0x6c, 0x71, 0x73, + 0x51, 0x59, 0x36, 0x5a, 0x5a, 0x5a, 0x5a, 0x77, 0x50, 0x41, 0x31, 0x2f, + 0x63, 0x6e, 0x61, 0x4b, 0x49, 0x30, 0x61, 0x45, 0x59, 0x64, 0x77, 0x67, + 0x51, 0x71, 0x6f, 0x6d, 0x6e, 0x55, 0x64, 0x6e, 0x6a, 0x71, 0x47, 0x42, + 0x51, 0x43, 0x65, 0x32, 0x34, 0x44, 0x57, 0x4a, 0x66, 0x6e, 0x63, 0x42, + 0x5a, 0x34, 0x6e, 0x0a, 0x57, 0x55, 0x78, 0x32, 0x4f, 0x56, 0x76, 0x71, + 0x2b, 0x61, 0x57, 0x68, 0x32, 0x49, 0x4d, 0x50, 0x30, 0x66, 0x2f, 0x66, + 0x4d, 0x42, 0x48, 0x35, 0x68, 0x63, 0x38, 0x7a, 0x53, 0x50, 0x58, 0x4b, + 0x62, 0x57, 0x51, 0x55, 0x4c, 0x48, 0x70, 0x59, 0x54, 0x39, 0x4e, 0x4c, + 0x43, 0x45, 0x6e, 0x46, 0x6c, 0x57, 0x51, 0x61, 0x59, 0x77, 0x35, 0x35, + 0x50, 0x66, 0x57, 0x7a, 0x6a, 0x4d, 0x70, 0x59, 0x0a, 0x72, 0x5a, 0x78, + 0x43, 0x52, 0x58, 0x6c, 0x75, 0x44, 0x6f, 0x63, 0x5a, 0x58, 0x46, 0x53, + 0x78, 0x5a, 0x62, 0x61, 0x2f, 0x6a, 0x4a, 0x76, 0x63, 0x45, 0x2b, 0x6b, + 0x4e, 0x62, 0x37, 0x67, 0x75, 0x33, 0x47, 0x64, 0x75, 0x79, 0x59, 0x73, + 0x52, 0x74, 0x59, 0x51, 0x55, 0x69, 0x67, 0x41, 0x5a, 0x63, 0x49, 0x4e, + 0x35, 0x6b, 0x5a, 0x65, 0x52, 0x31, 0x42, 0x6f, 0x6e, 0x76, 0x7a, 0x63, + 0x65, 0x0a, 0x4d, 0x67, 0x66, 0x59, 0x46, 0x47, 0x4d, 0x38, 0x4b, 0x45, + 0x79, 0x76, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x59, 0x7a, + 0x42, 0x68, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, + 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, + 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, + 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x0a, 0x41, 0x51, 0x48, 0x2f, 0x4d, + 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, + 0x42, 0x53, 0x75, 0x62, 0x41, 0x57, 0x6a, 0x6b, 0x78, 0x50, 0x69, 0x6f, + 0x75, 0x66, 0x69, 0x31, 0x78, 0x7a, 0x57, 0x78, 0x2f, 0x42, 0x2f, 0x79, + 0x47, 0x64, 0x54, 0x6f, 0x44, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x53, 0x75, 0x0a, + 0x62, 0x41, 0x57, 0x6a, 0x6b, 0x78, 0x50, 0x69, 0x6f, 0x75, 0x66, 0x69, + 0x31, 0x78, 0x7a, 0x57, 0x78, 0x2f, 0x42, 0x2f, 0x79, 0x47, 0x64, 0x54, + 0x6f, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, + 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x77, 0x46, 0x41, 0x41, 0x4f, 0x43, + 0x41, 0x67, 0x45, 0x41, 0x67, 0x79, 0x58, 0x74, 0x36, 0x4e, 0x48, 0x39, + 0x6c, 0x56, 0x4c, 0x4e, 0x0a, 0x6e, 0x73, 0x41, 0x45, 0x6f, 0x4a, 0x46, + 0x70, 0x35, 0x6c, 0x7a, 0x51, 0x68, 0x4e, 0x37, 0x63, 0x72, 0x61, 0x4a, + 0x50, 0x36, 0x45, 0x64, 0x34, 0x31, 0x6d, 0x57, 0x59, 0x71, 0x56, 0x75, + 0x6f, 0x50, 0x49, 0x64, 0x38, 0x41, 0x6f, 0x72, 0x52, 0x62, 0x72, 0x63, + 0x57, 0x63, 0x2b, 0x5a, 0x66, 0x77, 0x46, 0x53, 0x59, 0x31, 0x58, 0x53, + 0x2b, 0x77, 0x63, 0x33, 0x69, 0x45, 0x5a, 0x47, 0x74, 0x0a, 0x49, 0x78, + 0x67, 0x39, 0x33, 0x65, 0x46, 0x79, 0x52, 0x4a, 0x61, 0x30, 0x6c, 0x56, + 0x37, 0x41, 0x65, 0x34, 0x36, 0x5a, 0x65, 0x42, 0x5a, 0x44, 0x45, 0x31, + 0x5a, 0x58, 0x73, 0x36, 0x4b, 0x7a, 0x4f, 0x37, 0x56, 0x33, 0x33, 0x45, + 0x42, 0x79, 0x72, 0x4b, 0x50, 0x72, 0x6d, 0x7a, 0x55, 0x2b, 0x73, 0x51, + 0x67, 0x68, 0x6f, 0x65, 0x66, 0x45, 0x51, 0x7a, 0x64, 0x35, 0x4d, 0x72, + 0x36, 0x31, 0x0a, 0x35, 0x35, 0x77, 0x73, 0x54, 0x4c, 0x78, 0x44, 0x4b, + 0x5a, 0x6d, 0x4f, 0x4d, 0x4e, 0x4f, 0x73, 0x49, 0x65, 0x44, 0x6a, 0x48, + 0x66, 0x72, 0x59, 0x42, 0x7a, 0x4e, 0x32, 0x56, 0x41, 0x41, 0x69, 0x4b, + 0x72, 0x6c, 0x4e, 0x49, 0x43, 0x35, 0x77, 0x61, 0x4e, 0x72, 0x6c, 0x55, + 0x2f, 0x79, 0x44, 0x58, 0x4e, 0x4f, 0x64, 0x38, 0x76, 0x39, 0x45, 0x44, + 0x45, 0x52, 0x6d, 0x38, 0x74, 0x4c, 0x6a, 0x0a, 0x76, 0x55, 0x59, 0x41, + 0x47, 0x6d, 0x30, 0x43, 0x75, 0x69, 0x56, 0x64, 0x6a, 0x61, 0x45, 0x78, + 0x55, 0x64, 0x31, 0x55, 0x52, 0x68, 0x78, 0x4e, 0x32, 0x35, 0x6d, 0x57, + 0x37, 0x78, 0x6f, 0x63, 0x42, 0x46, 0x79, 0x6d, 0x46, 0x65, 0x39, 0x34, + 0x34, 0x48, 0x6e, 0x2b, 0x58, 0x64, 0x73, 0x2b, 0x71, 0x6b, 0x78, 0x56, + 0x2f, 0x5a, 0x6f, 0x56, 0x71, 0x57, 0x2f, 0x68, 0x70, 0x76, 0x76, 0x66, + 0x0a, 0x63, 0x44, 0x44, 0x70, 0x77, 0x2b, 0x35, 0x43, 0x52, 0x75, 0x33, + 0x43, 0x6b, 0x77, 0x57, 0x4a, 0x2b, 0x6e, 0x31, 0x6a, 0x65, 0x7a, 0x2f, + 0x51, 0x63, 0x59, 0x46, 0x38, 0x41, 0x4f, 0x69, 0x59, 0x72, 0x67, 0x35, + 0x34, 0x4e, 0x4d, 0x4d, 0x6c, 0x2b, 0x36, 0x38, 0x4b, 0x6e, 0x79, 0x42, + 0x72, 0x33, 0x54, 0x73, 0x54, 0x6a, 0x78, 0x4b, 0x4d, 0x34, 0x6b, 0x45, + 0x61, 0x53, 0x48, 0x70, 0x7a, 0x0a, 0x6f, 0x48, 0x64, 0x70, 0x78, 0x37, + 0x5a, 0x63, 0x66, 0x34, 0x4c, 0x49, 0x48, 0x76, 0x35, 0x59, 0x47, 0x79, + 0x67, 0x72, 0x71, 0x47, 0x79, 0x74, 0x58, 0x6d, 0x33, 0x41, 0x42, 0x64, + 0x4a, 0x37, 0x74, 0x2b, 0x75, 0x41, 0x2f, 0x69, 0x55, 0x33, 0x2f, 0x67, + 0x4b, 0x62, 0x61, 0x4b, 0x78, 0x43, 0x58, 0x63, 0x50, 0x75, 0x39, 0x63, + 0x7a, 0x63, 0x38, 0x46, 0x42, 0x31, 0x30, 0x6a, 0x5a, 0x70, 0x0a, 0x6e, + 0x4f, 0x5a, 0x37, 0x42, 0x4e, 0x39, 0x75, 0x42, 0x6d, 0x6d, 0x32, 0x33, + 0x67, 0x6f, 0x4a, 0x53, 0x46, 0x6d, 0x48, 0x36, 0x33, 0x73, 0x55, 0x59, + 0x48, 0x70, 0x6b, 0x71, 0x6d, 0x6c, 0x44, 0x37, 0x35, 0x48, 0x48, 0x54, + 0x4f, 0x77, 0x59, 0x33, 0x57, 0x7a, 0x76, 0x55, 0x79, 0x32, 0x4d, 0x6d, + 0x65, 0x46, 0x65, 0x38, 0x6e, 0x49, 0x2b, 0x7a, 0x31, 0x54, 0x49, 0x76, + 0x57, 0x66, 0x73, 0x0a, 0x70, 0x41, 0x39, 0x4d, 0x52, 0x66, 0x2f, 0x54, + 0x75, 0x54, 0x41, 0x6a, 0x42, 0x30, 0x79, 0x50, 0x45, 0x4c, 0x2b, 0x47, + 0x6c, 0x74, 0x6d, 0x5a, 0x57, 0x72, 0x53, 0x5a, 0x56, 0x78, 0x79, 0x6b, + 0x7a, 0x4c, 0x73, 0x56, 0x69, 0x56, 0x4f, 0x36, 0x4c, 0x41, 0x55, 0x50, + 0x35, 0x4d, 0x53, 0x65, 0x47, 0x62, 0x45, 0x59, 0x4e, 0x4e, 0x56, 0x4d, + 0x6e, 0x62, 0x72, 0x74, 0x39, 0x78, 0x2b, 0x76, 0x0a, 0x4a, 0x4a, 0x55, + 0x45, 0x65, 0x4b, 0x67, 0x44, 0x75, 0x2b, 0x36, 0x42, 0x35, 0x64, 0x70, + 0x66, 0x66, 0x49, 0x74, 0x4b, 0x6f, 0x5a, 0x42, 0x30, 0x4a, 0x61, 0x65, + 0x7a, 0x50, 0x6b, 0x76, 0x49, 0x4c, 0x46, 0x61, 0x39, 0x78, 0x38, 0x6a, + 0x76, 0x4f, 0x4f, 0x4a, 0x63, 0x6b, 0x76, 0x42, 0x35, 0x39, 0x35, 0x79, + 0x45, 0x75, 0x6e, 0x51, 0x74, 0x59, 0x51, 0x45, 0x67, 0x66, 0x6e, 0x37, + 0x52, 0x0a, 0x38, 0x6b, 0x38, 0x48, 0x57, 0x56, 0x2b, 0x4c, 0x4c, 0x55, + 0x4e, 0x53, 0x36, 0x30, 0x59, 0x4d, 0x6c, 0x4f, 0x48, 0x31, 0x5a, 0x6b, + 0x64, 0x35, 0x64, 0x39, 0x56, 0x55, 0x57, 0x78, 0x2b, 0x74, 0x4a, 0x44, + 0x66, 0x4c, 0x52, 0x56, 0x70, 0x4f, 0x6f, 0x45, 0x52, 0x49, 0x79, 0x4e, + 0x69, 0x77, 0x6d, 0x63, 0x55, 0x56, 0x68, 0x41, 0x6e, 0x32, 0x31, 0x6b, + 0x6c, 0x4a, 0x77, 0x47, 0x57, 0x34, 0x0a, 0x35, 0x68, 0x70, 0x78, 0x62, + 0x71, 0x43, 0x6f, 0x38, 0x59, 0x4c, 0x6f, 0x52, 0x54, 0x35, 0x73, 0x31, + 0x67, 0x4c, 0x58, 0x43, 0x6d, 0x65, 0x44, 0x42, 0x56, 0x72, 0x4a, 0x70, + 0x42, 0x41, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x4f, 0x49, 0x53, 0x54, + 0x45, 0x20, 0x57, 0x49, 0x53, 0x65, 0x4b, 0x65, 0x79, 0x20, 0x47, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x43, + 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x57, 0x49, 0x53, 0x65, 0x4b, 0x65, + 0x79, 0x20, 0x4f, 0x55, 0x3d, 0x4f, 0x49, 0x53, 0x54, 0x45, 0x20, 0x46, + 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x45, 0x6e, + 0x64, 0x6f, 0x72, 0x73, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x4f, 0x49, 0x53, + 0x54, 0x45, 0x20, 0x57, 0x49, 0x53, 0x65, 0x4b, 0x65, 0x79, 0x20, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, + 0x43, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x57, 0x49, 0x53, 0x65, 0x4b, + 0x65, 0x79, 0x20, 0x4f, 0x55, 0x3d, 0x4f, 0x49, 0x53, 0x54, 0x45, 0x20, + 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x45, + 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x4f, 0x49, 0x53, 0x54, 0x45, 0x20, + 0x57, 0x49, 0x53, 0x65, 0x4b, 0x65, 0x79, 0x20, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x43, 0x20, 0x43, + 0x41, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x34, 0x34, 0x30, 0x38, 0x34, 0x33, 0x34, 0x35, 0x36, 0x32, 0x31, + 0x30, 0x33, 0x38, 0x35, 0x34, 0x38, 0x31, 0x34, 0x36, 0x30, 0x36, 0x34, + 0x38, 0x30, 0x34, 0x35, 0x36, 0x35, 0x34, 0x33, 0x36, 0x31, 0x35, 0x32, + 0x35, 0x35, 0x34, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, + 0x39, 0x3a, 0x64, 0x36, 0x3a, 0x62, 0x39, 0x3a, 0x32, 0x64, 0x3a, 0x32, + 0x66, 0x3a, 0x39, 0x33, 0x3a, 0x36, 0x34, 0x3a, 0x66, 0x38, 0x3a, 0x61, + 0x35, 0x3a, 0x36, 0x39, 0x3a, 0x63, 0x61, 0x3a, 0x39, 0x31, 0x3a, 0x65, + 0x39, 0x3a, 0x36, 0x38, 0x3a, 0x30, 0x37, 0x3a, 0x32, 0x33, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x30, 0x3a, 0x31, 0x31, + 0x3a, 0x38, 0x34, 0x3a, 0x35, 0x65, 0x3a, 0x33, 0x34, 0x3a, 0x64, 0x65, + 0x3a, 0x62, 0x65, 0x3a, 0x38, 0x38, 0x3a, 0x38, 0x31, 0x3a, 0x62, 0x39, + 0x3a, 0x39, 0x63, 0x3a, 0x66, 0x36, 0x3a, 0x31, 0x36, 0x3a, 0x32, 0x36, + 0x3a, 0x64, 0x31, 0x3a, 0x39, 0x36, 0x3a, 0x31, 0x66, 0x3a, 0x63, 0x33, + 0x3a, 0x62, 0x39, 0x3a, 0x33, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x35, 0x3a, 0x36, 0x30, 0x3a, 0x66, + 0x39, 0x3a, 0x31, 0x63, 0x3a, 0x33, 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x64, + 0x61, 0x3a, 0x62, 0x61, 0x3a, 0x39, 0x35, 0x3a, 0x37, 0x30, 0x3a, 0x62, + 0x35, 0x3a, 0x66, 0x65, 0x3a, 0x61, 0x30, 0x3a, 0x64, 0x62, 0x3a, 0x65, + 0x33, 0x3a, 0x36, 0x66, 0x3a, 0x66, 0x31, 0x3a, 0x31, 0x61, 0x3a, 0x38, + 0x33, 0x3a, 0x32, 0x33, 0x3a, 0x62, 0x65, 0x3a, 0x39, 0x34, 0x3a, 0x38, + 0x36, 0x3a, 0x38, 0x35, 0x3a, 0x34, 0x66, 0x3a, 0x62, 0x33, 0x3a, 0x66, + 0x33, 0x3a, 0x34, 0x61, 0x3a, 0x35, 0x35, 0x3a, 0x37, 0x31, 0x3a, 0x31, + 0x39, 0x3a, 0x38, 0x64, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x43, 0x61, 0x54, 0x43, 0x43, 0x41, 0x65, 0x2b, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x51, 0x49, 0x53, 0x70, 0x57, 0x44, 0x4b, 0x37, + 0x61, 0x44, 0x4b, 0x74, 0x41, 0x52, 0x62, 0x38, 0x72, 0x6f, 0x69, 0x30, + 0x36, 0x36, 0x6a, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, + 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x7a, 0x42, 0x74, 0x4d, 0x51, 0x73, + 0x77, 0x0a, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, + 0x4a, 0x44, 0x53, 0x44, 0x45, 0x51, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x68, 0x4d, 0x48, 0x56, 0x30, 0x6c, 0x54, 0x5a, 0x55, + 0x74, 0x6c, 0x65, 0x54, 0x45, 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x78, 0x4d, 0x5a, 0x54, 0x30, 0x6c, 0x54, 0x56, 0x45, + 0x55, 0x67, 0x52, 0x6d, 0x39, 0x31, 0x0a, 0x62, 0x6d, 0x52, 0x68, 0x64, + 0x47, 0x6c, 0x76, 0x62, 0x69, 0x42, 0x46, 0x62, 0x6d, 0x52, 0x76, 0x63, + 0x6e, 0x4e, 0x6c, 0x5a, 0x44, 0x45, 0x6f, 0x4d, 0x43, 0x59, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x66, 0x54, 0x30, 0x6c, 0x54, 0x56, + 0x45, 0x55, 0x67, 0x56, 0x30, 0x6c, 0x54, 0x5a, 0x55, 0x74, 0x6c, 0x65, + 0x53, 0x42, 0x48, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x77, 0x67, 0x0a, + 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x48, 0x51, 0x79, 0x42, 0x44, + 0x51, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4e, 0x7a, 0x41, 0x31, + 0x4d, 0x44, 0x6b, 0x77, 0x4f, 0x54, 0x51, 0x34, 0x4d, 0x7a, 0x52, 0x61, + 0x46, 0x77, 0x30, 0x30, 0x4d, 0x6a, 0x41, 0x31, 0x4d, 0x44, 0x6b, 0x77, + 0x4f, 0x54, 0x55, 0x34, 0x4d, 0x7a, 0x4e, 0x61, 0x4d, 0x47, 0x30, 0x78, + 0x43, 0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, + 0x54, 0x41, 0x6b, 0x4e, 0x49, 0x4d, 0x52, 0x41, 0x77, 0x44, 0x67, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x4b, 0x45, 0x77, 0x64, 0x58, 0x53, 0x56, 0x4e, + 0x6c, 0x53, 0x32, 0x56, 0x35, 0x4d, 0x53, 0x49, 0x77, 0x49, 0x41, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x78, 0x6c, 0x50, 0x53, 0x56, 0x4e, + 0x55, 0x52, 0x53, 0x42, 0x47, 0x62, 0x33, 0x56, 0x75, 0x0a, 0x5a, 0x47, + 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x45, 0x56, 0x75, 0x5a, 0x47, + 0x39, 0x79, 0x63, 0x32, 0x56, 0x6b, 0x4d, 0x53, 0x67, 0x77, 0x4a, 0x67, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x39, 0x50, 0x53, 0x56, + 0x4e, 0x55, 0x52, 0x53, 0x42, 0x58, 0x53, 0x56, 0x4e, 0x6c, 0x53, 0x32, + 0x56, 0x35, 0x49, 0x45, 0x64, 0x73, 0x62, 0x32, 0x4a, 0x68, 0x62, 0x43, + 0x42, 0x53, 0x0a, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x64, 0x44, 0x49, + 0x45, 0x4e, 0x42, 0x4d, 0x48, 0x59, 0x77, 0x45, 0x41, 0x59, 0x48, 0x4b, + 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x43, 0x41, 0x51, 0x59, 0x46, 0x4b, + 0x34, 0x45, 0x45, 0x41, 0x43, 0x49, 0x44, 0x59, 0x67, 0x41, 0x45, 0x54, + 0x4f, 0x6c, 0x51, 0x77, 0x4d, 0x59, 0x50, 0x63, 0x68, 0x69, 0x38, 0x32, + 0x50, 0x47, 0x36, 0x73, 0x34, 0x6e, 0x69, 0x0a, 0x65, 0x55, 0x71, 0x6a, + 0x46, 0x71, 0x64, 0x72, 0x56, 0x43, 0x54, 0x62, 0x55, 0x66, 0x2f, 0x71, + 0x39, 0x41, 0x6b, 0x6b, 0x77, 0x77, 0x73, 0x69, 0x6e, 0x38, 0x74, 0x71, + 0x4a, 0x34, 0x4b, 0x42, 0x44, 0x64, 0x4c, 0x41, 0x72, 0x7a, 0x48, 0x6b, + 0x64, 0x49, 0x4a, 0x75, 0x79, 0x69, 0x58, 0x5a, 0x6a, 0x48, 0x57, 0x64, + 0x38, 0x64, 0x76, 0x51, 0x6d, 0x71, 0x4a, 0x4c, 0x49, 0x58, 0x34, 0x57, + 0x0a, 0x70, 0x32, 0x4f, 0x51, 0x30, 0x6a, 0x6e, 0x55, 0x73, 0x59, 0x64, + 0x34, 0x58, 0x78, 0x69, 0x57, 0x44, 0x31, 0x41, 0x62, 0x4e, 0x54, 0x63, + 0x50, 0x61, 0x73, 0x62, 0x63, 0x32, 0x52, 0x4e, 0x4e, 0x70, 0x49, 0x36, + 0x51, 0x4e, 0x2b, 0x61, 0x39, 0x57, 0x7a, 0x47, 0x52, 0x6f, 0x31, 0x51, + 0x77, 0x55, 0x6a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, + 0x42, 0x41, 0x66, 0x38, 0x45, 0x0a, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, + 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, + 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, + 0x51, 0x55, 0x53, 0x49, 0x63, 0x55, 0x72, 0x4f, 0x50, 0x44, 0x6e, 0x70, + 0x42, 0x67, 0x4f, 0x74, 0x66, 0x4b, 0x69, 0x65, 0x37, 0x54, 0x0a, 0x72, + 0x59, 0x79, 0x30, 0x55, 0x47, 0x59, 0x77, 0x45, 0x41, 0x59, 0x4a, 0x4b, + 0x77, 0x59, 0x42, 0x42, 0x41, 0x47, 0x43, 0x4e, 0x78, 0x55, 0x42, 0x42, + 0x41, 0x4d, 0x43, 0x41, 0x51, 0x41, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, + 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x4d, 0x44, 0x61, + 0x41, 0x41, 0x77, 0x5a, 0x51, 0x49, 0x77, 0x4a, 0x73, 0x64, 0x70, 0x57, + 0x39, 0x7a, 0x56, 0x0a, 0x35, 0x37, 0x4c, 0x6e, 0x79, 0x41, 0x79, 0x4d, + 0x6a, 0x4d, 0x50, 0x64, 0x65, 0x59, 0x77, 0x62, 0x59, 0x39, 0x58, 0x4a, + 0x55, 0x70, 0x52, 0x4f, 0x54, 0x59, 0x4a, 0x4b, 0x63, 0x78, 0x36, 0x79, + 0x67, 0x49, 0x53, 0x70, 0x4a, 0x63, 0x42, 0x4d, 0x57, 0x6d, 0x31, 0x4a, + 0x4b, 0x57, 0x42, 0x34, 0x45, 0x2b, 0x4a, 0x2b, 0x53, 0x4f, 0x74, 0x6b, + 0x41, 0x6a, 0x45, 0x41, 0x32, 0x7a, 0x51, 0x67, 0x0a, 0x4d, 0x67, 0x6a, + 0x2f, 0x6d, 0x6b, 0x6b, 0x43, 0x74, 0x6f, 0x6a, 0x65, 0x46, 0x4b, 0x39, + 0x64, 0x62, 0x4a, 0x6c, 0x78, 0x6a, 0x52, 0x6f, 0x2f, 0x69, 0x39, 0x66, + 0x67, 0x6f, 0x6a, 0x61, 0x47, 0x48, 0x41, 0x65, 0x43, 0x4f, 0x6e, 0x5a, + 0x54, 0x2f, 0x63, 0x4b, 0x69, 0x37, 0x65, 0x39, 0x37, 0x73, 0x49, 0x42, + 0x50, 0x57, 0x41, 0x39, 0x4c, 0x55, 0x7a, 0x6d, 0x39, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x47, 0x54, 0x53, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, + 0x31, 0x20, 0x4f, 0x3d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x20, 0x4c, 0x4c, 0x43, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x54, 0x53, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x31, 0x20, 0x4f, 0x3d, 0x47, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x4c, 0x4c, 0x43, 0x0a, + 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x54, + 0x53, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x31, 0x22, 0x0a, 0x23, + 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x34, 0x36, + 0x35, 0x38, 0x37, 0x31, 0x37, 0x35, 0x39, 0x37, 0x31, 0x37, 0x36, 0x35, + 0x30, 0x31, 0x37, 0x36, 0x31, 0x38, 0x34, 0x33, 0x39, 0x37, 0x35, 0x37, + 0x38, 0x31, 0x30, 0x32, 0x36, 0x35, 0x35, 0x35, 0x32, 0x30, 0x39, 0x37, + 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x32, 0x3a, 0x31, + 0x61, 0x3a, 0x65, 0x66, 0x3a, 0x64, 0x34, 0x3a, 0x64, 0x32, 0x3a, 0x34, + 0x61, 0x3a, 0x66, 0x32, 0x3a, 0x39, 0x66, 0x3a, 0x65, 0x32, 0x3a, 0x33, + 0x64, 0x3a, 0x39, 0x37, 0x3a, 0x30, 0x36, 0x3a, 0x31, 0x34, 0x3a, 0x37, + 0x30, 0x3a, 0x37, 0x32, 0x3a, 0x38, 0x35, 0x0a, 0x23, 0x20, 0x53, 0x48, + 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x31, 0x3a, 0x63, 0x39, 0x3a, 0x35, 0x30, + 0x3a, 0x65, 0x36, 0x3a, 0x65, 0x66, 0x3a, 0x32, 0x32, 0x3a, 0x66, 0x38, + 0x3a, 0x34, 0x63, 0x3a, 0x35, 0x36, 0x3a, 0x34, 0x35, 0x3a, 0x37, 0x32, + 0x3a, 0x38, 0x62, 0x3a, 0x39, 0x32, 0x3a, 0x32, 0x30, 0x3a, 0x36, 0x30, + 0x3a, 0x64, 0x37, 0x3a, 0x64, 0x35, 0x3a, 0x61, 0x37, 0x3a, 0x61, 0x33, + 0x3a, 0x65, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x32, 0x61, 0x3a, 0x35, 0x37, 0x3a, 0x35, 0x34, 0x3a, 0x37, + 0x31, 0x3a, 0x65, 0x33, 0x3a, 0x31, 0x33, 0x3a, 0x34, 0x30, 0x3a, 0x62, + 0x63, 0x3a, 0x32, 0x31, 0x3a, 0x35, 0x38, 0x3a, 0x31, 0x63, 0x3a, 0x62, + 0x64, 0x3a, 0x32, 0x63, 0x3a, 0x66, 0x31, 0x3a, 0x33, 0x65, 0x3a, 0x31, + 0x35, 0x3a, 0x38, 0x34, 0x3a, 0x36, 0x33, 0x3a, 0x32, 0x30, 0x3a, 0x33, + 0x65, 0x3a, 0x63, 0x65, 0x3a, 0x39, 0x34, 0x3a, 0x62, 0x63, 0x3a, 0x66, + 0x39, 0x3a, 0x64, 0x33, 0x3a, 0x63, 0x63, 0x3a, 0x31, 0x39, 0x3a, 0x36, + 0x62, 0x3a, 0x66, 0x30, 0x3a, 0x39, 0x61, 0x3a, 0x35, 0x34, 0x3a, 0x37, + 0x32, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x57, 0x6a, + 0x43, 0x43, 0x41, 0x30, 0x4b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, + 0x49, 0x51, 0x62, 0x6b, 0x65, 0x70, 0x78, 0x55, 0x74, 0x48, 0x44, 0x41, + 0x33, 0x73, 0x4d, 0x39, 0x43, 0x4a, 0x75, 0x52, 0x7a, 0x30, 0x34, 0x54, + 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, + 0x30, 0x42, 0x41, 0x51, 0x77, 0x46, 0x41, 0x44, 0x42, 0x48, 0x0a, 0x4d, + 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, + 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x5a, 0x52, 0x32, 0x39, 0x76, 0x5a, + 0x32, 0x78, 0x6c, 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, + 0x46, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, 0x7a, 0x49, + 0x45, 0x78, 0x4d, 0x0a, 0x51, 0x7a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x4c, 0x52, 0x31, 0x52, 0x54, + 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x55, 0x6a, 0x45, 0x77, + 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x59, 0x77, 0x4e, 0x6a, 0x49, 0x79, + 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, + 0x4d, 0x7a, 0x59, 0x77, 0x4e, 0x6a, 0x49, 0x79, 0x0a, 0x4d, 0x44, 0x41, + 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x6a, 0x42, 0x48, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, + 0x56, 0x55, 0x7a, 0x45, 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x68, 0x4d, 0x5a, 0x52, 0x32, 0x39, 0x76, 0x5a, 0x32, 0x78, + 0x6c, 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x46, 0x4e, + 0x6c, 0x0a, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, 0x7a, 0x49, 0x45, + 0x78, 0x4d, 0x51, 0x7a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x41, 0x78, 0x4d, 0x4c, 0x52, 0x31, 0x52, 0x54, 0x49, 0x46, + 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x55, 0x6a, 0x45, 0x77, 0x67, 0x67, + 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, + 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x0a, 0x41, 0x51, 0x55, 0x41, 0x41, + 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, + 0x6f, 0x49, 0x43, 0x41, 0x51, 0x43, 0x32, 0x45, 0x51, 0x4b, 0x4c, 0x48, + 0x75, 0x4f, 0x68, 0x64, 0x35, 0x73, 0x37, 0x33, 0x4c, 0x2b, 0x55, 0x50, + 0x72, 0x65, 0x56, 0x70, 0x30, 0x41, 0x38, 0x6f, 0x66, 0x32, 0x43, 0x2b, + 0x58, 0x30, 0x79, 0x42, 0x6f, 0x4a, 0x78, 0x39, 0x76, 0x61, 0x4d, 0x0a, + 0x66, 0x2f, 0x76, 0x6f, 0x32, 0x37, 0x78, 0x71, 0x4c, 0x70, 0x65, 0x58, + 0x6f, 0x34, 0x78, 0x4c, 0x2b, 0x53, 0x76, 0x32, 0x73, 0x66, 0x6e, 0x4f, + 0x68, 0x42, 0x32, 0x78, 0x2b, 0x63, 0x57, 0x58, 0x33, 0x75, 0x2b, 0x35, + 0x38, 0x71, 0x50, 0x70, 0x76, 0x42, 0x4b, 0x4a, 0x58, 0x71, 0x65, 0x71, + 0x55, 0x71, 0x76, 0x34, 0x49, 0x79, 0x66, 0x4c, 0x70, 0x4c, 0x47, 0x63, + 0x59, 0x39, 0x76, 0x58, 0x0a, 0x6d, 0x58, 0x37, 0x77, 0x43, 0x6c, 0x37, + 0x72, 0x61, 0x4b, 0x62, 0x30, 0x78, 0x6c, 0x70, 0x48, 0x44, 0x55, 0x30, + 0x51, 0x4d, 0x2b, 0x4e, 0x4f, 0x73, 0x52, 0x4f, 0x6a, 0x79, 0x42, 0x68, + 0x73, 0x53, 0x2b, 0x7a, 0x38, 0x43, 0x5a, 0x44, 0x66, 0x6e, 0x57, 0x51, + 0x70, 0x4a, 0x53, 0x4d, 0x48, 0x6f, 0x62, 0x54, 0x53, 0x50, 0x53, 0x35, + 0x67, 0x34, 0x4d, 0x2f, 0x53, 0x43, 0x59, 0x65, 0x37, 0x0a, 0x7a, 0x55, + 0x6a, 0x77, 0x54, 0x63, 0x4c, 0x43, 0x65, 0x6f, 0x69, 0x4b, 0x75, 0x37, + 0x72, 0x50, 0x57, 0x52, 0x6e, 0x57, 0x72, 0x34, 0x2b, 0x77, 0x42, 0x37, + 0x43, 0x65, 0x4d, 0x66, 0x47, 0x43, 0x77, 0x63, 0x44, 0x66, 0x4c, 0x71, + 0x5a, 0x74, 0x62, 0x42, 0x6b, 0x4f, 0x74, 0x64, 0x68, 0x2b, 0x4a, 0x68, + 0x70, 0x46, 0x41, 0x7a, 0x32, 0x77, 0x65, 0x61, 0x53, 0x55, 0x4b, 0x4b, + 0x30, 0x50, 0x0a, 0x66, 0x79, 0x62, 0x6c, 0x71, 0x41, 0x6a, 0x2b, 0x6c, + 0x75, 0x67, 0x38, 0x61, 0x4a, 0x52, 0x54, 0x37, 0x6f, 0x4d, 0x36, 0x69, + 0x43, 0x73, 0x56, 0x6c, 0x67, 0x6d, 0x79, 0x34, 0x48, 0x71, 0x4d, 0x4c, + 0x6e, 0x58, 0x57, 0x6e, 0x4f, 0x75, 0x6e, 0x56, 0x6d, 0x53, 0x50, 0x6c, + 0x6b, 0x39, 0x6f, 0x72, 0x6a, 0x32, 0x58, 0x77, 0x6f, 0x53, 0x50, 0x77, + 0x4c, 0x78, 0x41, 0x77, 0x41, 0x74, 0x63, 0x0a, 0x76, 0x66, 0x61, 0x48, + 0x73, 0x7a, 0x56, 0x73, 0x72, 0x42, 0x68, 0x51, 0x66, 0x34, 0x54, 0x67, + 0x54, 0x4d, 0x32, 0x53, 0x30, 0x79, 0x44, 0x70, 0x4d, 0x37, 0x78, 0x53, + 0x6d, 0x61, 0x38, 0x79, 0x74, 0x53, 0x6d, 0x7a, 0x4a, 0x53, 0x71, 0x30, + 0x53, 0x50, 0x6c, 0x79, 0x34, 0x63, 0x70, 0x6b, 0x39, 0x2b, 0x61, 0x43, + 0x45, 0x49, 0x33, 0x6f, 0x6e, 0x63, 0x4b, 0x4b, 0x69, 0x50, 0x6f, 0x34, + 0x0a, 0x5a, 0x6f, 0x72, 0x38, 0x59, 0x2f, 0x6b, 0x42, 0x2b, 0x58, 0x6a, + 0x39, 0x65, 0x31, 0x78, 0x33, 0x2b, 0x6e, 0x61, 0x48, 0x2b, 0x75, 0x7a, + 0x66, 0x73, 0x51, 0x35, 0x35, 0x6c, 0x56, 0x65, 0x30, 0x76, 0x53, 0x62, + 0x76, 0x31, 0x67, 0x48, 0x52, 0x36, 0x78, 0x59, 0x4b, 0x75, 0x34, 0x34, + 0x4c, 0x74, 0x63, 0x58, 0x46, 0x69, 0x6c, 0x57, 0x72, 0x30, 0x36, 0x7a, + 0x71, 0x6b, 0x55, 0x73, 0x70, 0x0a, 0x7a, 0x42, 0x6d, 0x6b, 0x4d, 0x69, + 0x56, 0x4f, 0x4b, 0x76, 0x46, 0x6c, 0x52, 0x4e, 0x41, 0x43, 0x7a, 0x71, + 0x72, 0x4f, 0x53, 0x62, 0x54, 0x71, 0x6e, 0x33, 0x79, 0x44, 0x73, 0x45, + 0x42, 0x37, 0x35, 0x30, 0x4f, 0x72, 0x70, 0x32, 0x79, 0x6a, 0x6a, 0x33, + 0x32, 0x4a, 0x67, 0x66, 0x70, 0x4d, 0x70, 0x66, 0x2f, 0x56, 0x6a, 0x73, + 0x50, 0x4f, 0x53, 0x2b, 0x43, 0x31, 0x32, 0x4c, 0x4f, 0x4f, 0x0a, 0x52, + 0x63, 0x39, 0x32, 0x77, 0x4f, 0x31, 0x41, 0x4b, 0x2f, 0x31, 0x54, 0x44, + 0x37, 0x43, 0x6e, 0x31, 0x54, 0x73, 0x4e, 0x73, 0x59, 0x71, 0x69, 0x41, + 0x39, 0x34, 0x78, 0x72, 0x63, 0x78, 0x33, 0x36, 0x6d, 0x39, 0x37, 0x50, + 0x74, 0x62, 0x66, 0x6b, 0x53, 0x49, 0x53, 0x35, 0x72, 0x37, 0x36, 0x32, + 0x44, 0x4c, 0x38, 0x45, 0x47, 0x4d, 0x55, 0x55, 0x58, 0x4c, 0x65, 0x58, + 0x64, 0x59, 0x57, 0x0a, 0x6b, 0x37, 0x30, 0x70, 0x61, 0x44, 0x50, 0x76, + 0x4f, 0x6d, 0x62, 0x73, 0x42, 0x34, 0x6f, 0x6d, 0x33, 0x78, 0x50, 0x58, + 0x56, 0x32, 0x56, 0x34, 0x4a, 0x39, 0x35, 0x65, 0x53, 0x52, 0x51, 0x41, + 0x6f, 0x67, 0x42, 0x2f, 0x6d, 0x71, 0x67, 0x68, 0x74, 0x71, 0x6d, 0x78, + 0x6c, 0x62, 0x43, 0x6c, 0x75, 0x51, 0x30, 0x57, 0x45, 0x64, 0x72, 0x48, + 0x62, 0x45, 0x67, 0x38, 0x51, 0x4f, 0x42, 0x2b, 0x0a, 0x44, 0x56, 0x72, + 0x4e, 0x56, 0x6a, 0x7a, 0x52, 0x6c, 0x77, 0x57, 0x35, 0x79, 0x30, 0x76, + 0x74, 0x4f, 0x55, 0x75, 0x63, 0x78, 0x44, 0x2f, 0x53, 0x56, 0x52, 0x4e, + 0x75, 0x4a, 0x4c, 0x44, 0x57, 0x63, 0x66, 0x72, 0x30, 0x77, 0x62, 0x72, + 0x4d, 0x37, 0x52, 0x76, 0x31, 0x2f, 0x6f, 0x46, 0x42, 0x32, 0x41, 0x43, + 0x59, 0x50, 0x54, 0x72, 0x49, 0x72, 0x6e, 0x71, 0x59, 0x4e, 0x78, 0x67, + 0x46, 0x0a, 0x6c, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x30, + 0x49, 0x77, 0x51, 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, + 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, + 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, + 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x51, 0x34, 0x45, 0x46, + 0x67, 0x51, 0x55, 0x35, 0x4b, 0x38, 0x72, 0x4a, 0x6e, 0x45, 0x61, 0x4b, + 0x30, 0x67, 0x6e, 0x68, 0x53, 0x39, 0x53, 0x5a, 0x69, 0x7a, 0x76, 0x38, + 0x49, 0x6b, 0x54, 0x63, 0x54, 0x34, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4d, 0x42, + 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x42, 0x41, 0x44, 0x69, 0x57, 0x0a, + 0x43, 0x75, 0x34, 0x39, 0x74, 0x4a, 0x59, 0x65, 0x58, 0x2b, 0x2b, 0x64, + 0x6e, 0x41, 0x73, 0x7a, 0x6e, 0x79, 0x76, 0x67, 0x79, 0x76, 0x33, 0x53, + 0x6a, 0x67, 0x6f, 0x66, 0x51, 0x58, 0x53, 0x6c, 0x66, 0x4b, 0x71, 0x45, + 0x31, 0x4f, 0x58, 0x79, 0x48, 0x75, 0x59, 0x33, 0x55, 0x6a, 0x4b, 0x63, + 0x43, 0x39, 0x46, 0x68, 0x48, 0x62, 0x38, 0x6f, 0x77, 0x62, 0x5a, 0x45, + 0x4b, 0x54, 0x56, 0x31, 0x0a, 0x64, 0x35, 0x69, 0x79, 0x66, 0x4e, 0x6d, + 0x39, 0x64, 0x4b, 0x79, 0x4b, 0x61, 0x4f, 0x4f, 0x70, 0x4d, 0x51, 0x6b, + 0x70, 0x41, 0x57, 0x42, 0x7a, 0x34, 0x30, 0x64, 0x38, 0x55, 0x36, 0x69, + 0x51, 0x53, 0x69, 0x66, 0x76, 0x53, 0x39, 0x65, 0x66, 0x6b, 0x2b, 0x65, + 0x43, 0x4e, 0x73, 0x36, 0x61, 0x61, 0x41, 0x79, 0x43, 0x35, 0x38, 0x2f, + 0x55, 0x45, 0x42, 0x5a, 0x76, 0x58, 0x77, 0x36, 0x5a, 0x0a, 0x58, 0x50, + 0x59, 0x66, 0x63, 0x58, 0x33, 0x76, 0x37, 0x33, 0x73, 0x76, 0x66, 0x75, + 0x6f, 0x32, 0x31, 0x70, 0x64, 0x77, 0x43, 0x78, 0x58, 0x75, 0x31, 0x31, + 0x78, 0x57, 0x61, 0x6a, 0x4f, 0x6c, 0x34, 0x30, 0x6b, 0x34, 0x44, 0x4c, + 0x68, 0x39, 0x2b, 0x34, 0x32, 0x46, 0x70, 0x4c, 0x46, 0x5a, 0x58, 0x76, + 0x52, 0x71, 0x34, 0x64, 0x32, 0x68, 0x39, 0x6d, 0x52, 0x45, 0x72, 0x75, + 0x5a, 0x52, 0x0a, 0x67, 0x79, 0x46, 0x6d, 0x78, 0x68, 0x45, 0x2b, 0x38, + 0x38, 0x35, 0x48, 0x37, 0x70, 0x77, 0x6f, 0x48, 0x79, 0x58, 0x61, 0x2f, + 0x36, 0x78, 0x6d, 0x6c, 0x64, 0x30, 0x31, 0x44, 0x31, 0x7a, 0x76, 0x49, + 0x43, 0x78, 0x69, 0x2f, 0x5a, 0x47, 0x36, 0x71, 0x63, 0x7a, 0x38, 0x57, + 0x70, 0x79, 0x54, 0x67, 0x59, 0x4d, 0x70, 0x6c, 0x30, 0x70, 0x38, 0x57, + 0x6e, 0x4b, 0x30, 0x4f, 0x64, 0x43, 0x33, 0x0a, 0x64, 0x38, 0x74, 0x35, + 0x2f, 0x57, 0x6b, 0x36, 0x6b, 0x6a, 0x66, 0x74, 0x62, 0x6a, 0x68, 0x6c, + 0x52, 0x6e, 0x37, 0x70, 0x59, 0x4c, 0x31, 0x35, 0x69, 0x4a, 0x64, 0x66, + 0x4f, 0x42, 0x4c, 0x30, 0x37, 0x71, 0x39, 0x62, 0x67, 0x73, 0x69, 0x47, + 0x31, 0x65, 0x47, 0x5a, 0x62, 0x59, 0x77, 0x45, 0x38, 0x6e, 0x61, 0x36, + 0x53, 0x66, 0x5a, 0x75, 0x36, 0x57, 0x30, 0x65, 0x58, 0x36, 0x44, 0x76, + 0x0a, 0x4a, 0x34, 0x4a, 0x32, 0x51, 0x50, 0x69, 0x6d, 0x30, 0x31, 0x68, + 0x63, 0x44, 0x79, 0x78, 0x43, 0x32, 0x6b, 0x4c, 0x47, 0x65, 0x34, 0x67, + 0x30, 0x78, 0x38, 0x48, 0x59, 0x52, 0x5a, 0x76, 0x42, 0x50, 0x73, 0x56, + 0x68, 0x48, 0x64, 0x6c, 0x6a, 0x55, 0x45, 0x6e, 0x32, 0x4e, 0x49, 0x56, + 0x71, 0x34, 0x42, 0x6a, 0x46, 0x62, 0x6b, 0x65, 0x72, 0x51, 0x55, 0x49, + 0x70, 0x6d, 0x2f, 0x5a, 0x67, 0x0a, 0x44, 0x64, 0x49, 0x78, 0x30, 0x32, + 0x4f, 0x59, 0x49, 0x35, 0x4e, 0x61, 0x41, 0x49, 0x46, 0x49, 0x74, 0x4f, + 0x2f, 0x4e, 0x69, 0x73, 0x33, 0x4a, 0x7a, 0x35, 0x6e, 0x75, 0x32, 0x5a, + 0x36, 0x71, 0x4e, 0x75, 0x46, 0x6f, 0x53, 0x33, 0x46, 0x4a, 0x46, 0x44, + 0x59, 0x6f, 0x4f, 0x6a, 0x30, 0x64, 0x7a, 0x70, 0x71, 0x50, 0x4a, 0x65, + 0x61, 0x41, 0x63, 0x57, 0x45, 0x72, 0x74, 0x58, 0x76, 0x4d, 0x0a, 0x2b, + 0x53, 0x55, 0x57, 0x67, 0x65, 0x45, 0x78, 0x58, 0x36, 0x47, 0x6a, 0x66, + 0x68, 0x61, 0x6b, 0x6e, 0x42, 0x5a, 0x71, 0x6c, 0x78, 0x69, 0x39, 0x64, + 0x6e, 0x4b, 0x6c, 0x43, 0x35, 0x34, 0x64, 0x4e, 0x75, 0x59, 0x76, 0x6f, + 0x53, 0x2b, 0x2b, 0x63, 0x4a, 0x45, 0x50, 0x71, 0x4f, 0x62, 0x61, 0x2b, + 0x4d, 0x53, 0x53, 0x51, 0x47, 0x77, 0x6c, 0x66, 0x6e, 0x75, 0x7a, 0x43, + 0x64, 0x79, 0x79, 0x0a, 0x46, 0x36, 0x32, 0x41, 0x52, 0x50, 0x42, 0x6f, + 0x70, 0x59, 0x2b, 0x55, 0x64, 0x66, 0x39, 0x30, 0x57, 0x75, 0x69, 0x6f, + 0x41, 0x6e, 0x77, 0x4d, 0x43, 0x65, 0x4b, 0x70, 0x53, 0x77, 0x75, 0x67, + 0x68, 0x51, 0x74, 0x69, 0x75, 0x65, 0x2b, 0x68, 0x4d, 0x5a, 0x4c, 0x37, + 0x37, 0x2f, 0x5a, 0x52, 0x42, 0x49, 0x6c, 0x73, 0x36, 0x4b, 0x6c, 0x30, + 0x6f, 0x62, 0x73, 0x58, 0x73, 0x37, 0x58, 0x39, 0x0a, 0x53, 0x51, 0x39, + 0x38, 0x50, 0x4f, 0x79, 0x44, 0x47, 0x43, 0x42, 0x44, 0x54, 0x74, 0x57, + 0x54, 0x75, 0x72, 0x51, 0x30, 0x73, 0x52, 0x38, 0x57, 0x4e, 0x68, 0x38, + 0x4d, 0x35, 0x6d, 0x51, 0x35, 0x46, 0x6b, 0x7a, 0x63, 0x34, 0x50, 0x34, + 0x64, 0x79, 0x4b, 0x6c, 0x69, 0x50, 0x55, 0x44, 0x71, 0x79, 0x73, 0x55, + 0x30, 0x41, 0x72, 0x53, 0x75, 0x69, 0x59, 0x67, 0x7a, 0x4e, 0x64, 0x77, + 0x73, 0x0a, 0x45, 0x33, 0x50, 0x59, 0x4a, 0x2f, 0x48, 0x51, 0x63, 0x75, + 0x35, 0x31, 0x4f, 0x79, 0x4c, 0x65, 0x6d, 0x47, 0x68, 0x6d, 0x57, 0x2f, + 0x48, 0x47, 0x59, 0x30, 0x64, 0x56, 0x48, 0x4c, 0x71, 0x6c, 0x43, 0x46, + 0x46, 0x31, 0x70, 0x6b, 0x67, 0x6c, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, + 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, + 0x54, 0x53, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x32, 0x20, 0x4f, + 0x3d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x4c, + 0x4c, 0x43, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x54, 0x53, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x52, 0x32, 0x20, 0x4f, 0x3d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x20, 0x4c, 0x4c, 0x43, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x54, 0x53, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x32, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x34, 0x36, 0x35, 0x38, 0x37, + 0x31, 0x37, 0x36, 0x30, 0x35, 0x35, 0x37, 0x36, 0x37, 0x30, 0x35, 0x33, + 0x38, 0x31, 0x34, 0x34, 0x37, 0x39, 0x33, 0x38, 0x36, 0x39, 0x35, 0x33, + 0x31, 0x31, 0x32, 0x35, 0x34, 0x37, 0x39, 0x35, 0x31, 0x0a, 0x23, 0x20, + 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x34, 0x3a, 0x65, 0x64, 0x3a, 0x39, + 0x61, 0x3a, 0x30, 0x65, 0x3a, 0x61, 0x34, 0x3a, 0x30, 0x39, 0x3a, 0x33, + 0x62, 0x3a, 0x30, 0x30, 0x3a, 0x66, 0x32, 0x3a, 0x61, 0x65, 0x3a, 0x34, + 0x63, 0x3a, 0x61, 0x33, 0x3a, 0x63, 0x36, 0x3a, 0x36, 0x31, 0x3a, 0x62, + 0x30, 0x3a, 0x38, 0x62, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x64, 0x32, 0x3a, 0x37, 0x33, 0x3a, 0x39, 0x36, 0x3a, 0x32, 0x61, + 0x3a, 0x32, 0x61, 0x3a, 0x35, 0x65, 0x3a, 0x33, 0x39, 0x3a, 0x39, 0x66, + 0x3a, 0x37, 0x33, 0x3a, 0x33, 0x66, 0x3a, 0x65, 0x31, 0x3a, 0x63, 0x37, + 0x3a, 0x31, 0x65, 0x3a, 0x36, 0x34, 0x3a, 0x33, 0x66, 0x3a, 0x30, 0x33, + 0x3a, 0x33, 0x38, 0x3a, 0x33, 0x34, 0x3a, 0x66, 0x63, 0x3a, 0x34, 0x64, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, + 0x34, 0x3a, 0x35, 0x64, 0x3a, 0x37, 0x62, 0x3a, 0x62, 0x30, 0x3a, 0x38, + 0x65, 0x3a, 0x36, 0x64, 0x3a, 0x36, 0x37, 0x3a, 0x65, 0x36, 0x3a, 0x32, + 0x65, 0x3a, 0x34, 0x32, 0x3a, 0x33, 0x35, 0x3a, 0x31, 0x31, 0x3a, 0x30, + 0x62, 0x3a, 0x35, 0x36, 0x3a, 0x34, 0x65, 0x3a, 0x35, 0x66, 0x3a, 0x37, + 0x38, 0x3a, 0x66, 0x64, 0x3a, 0x39, 0x32, 0x3a, 0x65, 0x66, 0x3a, 0x30, + 0x35, 0x3a, 0x38, 0x63, 0x3a, 0x38, 0x34, 0x3a, 0x30, 0x61, 0x3a, 0x65, + 0x61, 0x3a, 0x34, 0x65, 0x3a, 0x36, 0x34, 0x3a, 0x35, 0x35, 0x3a, 0x64, + 0x37, 0x3a, 0x35, 0x38, 0x3a, 0x35, 0x63, 0x3a, 0x36, 0x30, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x57, 0x6a, 0x43, 0x43, 0x41, + 0x30, 0x4b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x62, + 0x6b, 0x65, 0x70, 0x78, 0x6c, 0x71, 0x7a, 0x35, 0x79, 0x44, 0x46, 0x4d, + 0x4a, 0x6f, 0x2f, 0x61, 0x46, 0x4c, 0x79, 0x62, 0x7a, 0x41, 0x4e, 0x42, + 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, + 0x51, 0x77, 0x46, 0x41, 0x44, 0x42, 0x48, 0x0a, 0x4d, 0x51, 0x73, 0x77, + 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, + 0x55, 0x7a, 0x45, 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x43, 0x68, 0x4d, 0x5a, 0x52, 0x32, 0x39, 0x76, 0x5a, 0x32, 0x78, 0x6c, + 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x46, 0x4e, 0x6c, + 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, 0x7a, 0x49, 0x45, 0x78, 0x4d, + 0x0a, 0x51, 0x7a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x41, 0x78, 0x4d, 0x4c, 0x52, 0x31, 0x52, 0x54, 0x49, 0x46, 0x4a, + 0x76, 0x62, 0x33, 0x51, 0x67, 0x55, 0x6a, 0x49, 0x77, 0x48, 0x68, 0x63, + 0x4e, 0x4d, 0x54, 0x59, 0x77, 0x4e, 0x6a, 0x49, 0x79, 0x4d, 0x44, 0x41, + 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x59, + 0x77, 0x4e, 0x6a, 0x49, 0x79, 0x0a, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, + 0x41, 0x77, 0x57, 0x6a, 0x42, 0x48, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, + 0x45, 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, + 0x4d, 0x5a, 0x52, 0x32, 0x39, 0x76, 0x5a, 0x32, 0x78, 0x6c, 0x49, 0x46, + 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, 0x46, 0x4e, 0x6c, 0x0a, 0x63, + 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, 0x7a, 0x49, 0x45, 0x78, 0x4d, 0x51, + 0x7a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, + 0x78, 0x4d, 0x4c, 0x52, 0x31, 0x52, 0x54, 0x49, 0x46, 0x4a, 0x76, 0x62, + 0x33, 0x51, 0x67, 0x55, 0x6a, 0x49, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, + 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, + 0x51, 0x45, 0x42, 0x0a, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, + 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, + 0x41, 0x51, 0x44, 0x4f, 0x33, 0x76, 0x32, 0x6d, 0x2b, 0x2b, 0x7a, 0x73, + 0x46, 0x44, 0x51, 0x38, 0x42, 0x77, 0x5a, 0x61, 0x62, 0x46, 0x6e, 0x33, + 0x47, 0x54, 0x58, 0x64, 0x39, 0x38, 0x47, 0x64, 0x56, 0x61, 0x72, 0x54, + 0x7a, 0x54, 0x75, 0x6b, 0x6b, 0x33, 0x4c, 0x76, 0x0a, 0x43, 0x76, 0x70, + 0x74, 0x6e, 0x66, 0x62, 0x77, 0x68, 0x59, 0x42, 0x62, 0x6f, 0x55, 0x68, + 0x53, 0x6e, 0x7a, 0x6e, 0x46, 0x74, 0x2b, 0x34, 0x6f, 0x72, 0x4f, 0x2f, + 0x4c, 0x64, 0x6d, 0x67, 0x55, 0x75, 0x64, 0x2b, 0x74, 0x41, 0x57, 0x79, + 0x5a, 0x48, 0x38, 0x51, 0x69, 0x48, 0x5a, 0x2f, 0x2b, 0x63, 0x6e, 0x66, + 0x67, 0x4c, 0x46, 0x75, 0x76, 0x35, 0x41, 0x53, 0x2f, 0x54, 0x33, 0x4b, + 0x67, 0x0a, 0x47, 0x6a, 0x53, 0x59, 0x36, 0x44, 0x6c, 0x6f, 0x37, 0x4a, + 0x55, 0x6c, 0x65, 0x33, 0x61, 0x68, 0x35, 0x6d, 0x6d, 0x35, 0x68, 0x52, + 0x6d, 0x39, 0x69, 0x59, 0x7a, 0x2b, 0x72, 0x65, 0x30, 0x32, 0x36, 0x6e, + 0x4f, 0x38, 0x2f, 0x34, 0x50, 0x69, 0x79, 0x33, 0x33, 0x42, 0x30, 0x73, + 0x35, 0x4b, 0x73, 0x34, 0x30, 0x46, 0x6e, 0x6f, 0x74, 0x4a, 0x6b, 0x39, + 0x2f, 0x42, 0x57, 0x39, 0x42, 0x75, 0x0a, 0x58, 0x76, 0x41, 0x75, 0x4d, + 0x43, 0x36, 0x43, 0x2f, 0x50, 0x71, 0x38, 0x74, 0x42, 0x63, 0x4b, 0x53, + 0x4f, 0x57, 0x49, 0x6d, 0x38, 0x57, 0x62, 0x61, 0x39, 0x36, 0x77, 0x79, + 0x72, 0x51, 0x44, 0x38, 0x4e, 0x72, 0x30, 0x6b, 0x4c, 0x68, 0x6c, 0x5a, + 0x50, 0x64, 0x63, 0x54, 0x4b, 0x33, 0x6f, 0x66, 0x6d, 0x5a, 0x65, 0x6d, + 0x64, 0x65, 0x34, 0x77, 0x6a, 0x37, 0x49, 0x30, 0x42, 0x4f, 0x64, 0x0a, + 0x72, 0x65, 0x37, 0x6b, 0x52, 0x58, 0x75, 0x4a, 0x56, 0x66, 0x65, 0x4b, + 0x48, 0x32, 0x4a, 0x53, 0x68, 0x42, 0x4b, 0x7a, 0x77, 0x6b, 0x43, 0x58, + 0x34, 0x34, 0x6f, 0x66, 0x52, 0x35, 0x47, 0x6d, 0x64, 0x46, 0x72, 0x53, + 0x2b, 0x4c, 0x46, 0x6a, 0x4b, 0x42, 0x43, 0x34, 0x73, 0x77, 0x6d, 0x34, + 0x56, 0x6e, 0x64, 0x41, 0x6f, 0x69, 0x61, 0x59, 0x65, 0x63, 0x62, 0x2b, + 0x33, 0x79, 0x58, 0x75, 0x0a, 0x50, 0x75, 0x57, 0x67, 0x66, 0x39, 0x52, + 0x68, 0x44, 0x31, 0x46, 0x4c, 0x50, 0x44, 0x2b, 0x4d, 0x32, 0x75, 0x46, + 0x77, 0x64, 0x4e, 0x6a, 0x43, 0x61, 0x4b, 0x48, 0x35, 0x77, 0x51, 0x7a, + 0x70, 0x6f, 0x65, 0x4a, 0x2f, 0x75, 0x31, 0x55, 0x38, 0x64, 0x67, 0x62, + 0x75, 0x61, 0x6b, 0x37, 0x4d, 0x6b, 0x6f, 0x67, 0x77, 0x54, 0x5a, 0x71, + 0x39, 0x54, 0x77, 0x74, 0x49, 0x6d, 0x6f, 0x53, 0x31, 0x0a, 0x6d, 0x4b, + 0x50, 0x56, 0x2b, 0x33, 0x50, 0x42, 0x56, 0x32, 0x48, 0x64, 0x4b, 0x46, + 0x5a, 0x31, 0x45, 0x36, 0x36, 0x48, 0x6a, 0x75, 0x63, 0x4d, 0x55, 0x51, + 0x6b, 0x51, 0x64, 0x59, 0x68, 0x4d, 0x76, 0x49, 0x33, 0x35, 0x65, 0x7a, + 0x7a, 0x55, 0x49, 0x6b, 0x67, 0x66, 0x4b, 0x74, 0x7a, 0x72, 0x61, 0x37, + 0x74, 0x45, 0x73, 0x63, 0x73, 0x7a, 0x63, 0x54, 0x4a, 0x47, 0x72, 0x36, + 0x31, 0x4b, 0x0a, 0x38, 0x59, 0x7a, 0x6f, 0x64, 0x44, 0x71, 0x73, 0x35, + 0x78, 0x6f, 0x69, 0x63, 0x34, 0x44, 0x53, 0x4d, 0x50, 0x63, 0x6c, 0x51, + 0x73, 0x63, 0x69, 0x4f, 0x7a, 0x73, 0x53, 0x72, 0x5a, 0x59, 0x75, 0x78, + 0x73, 0x4e, 0x32, 0x42, 0x36, 0x6f, 0x67, 0x74, 0x7a, 0x56, 0x4a, 0x56, + 0x2b, 0x6d, 0x53, 0x53, 0x65, 0x68, 0x32, 0x46, 0x6e, 0x49, 0x78, 0x5a, + 0x79, 0x75, 0x57, 0x66, 0x6f, 0x71, 0x6a, 0x0a, 0x78, 0x35, 0x52, 0x57, + 0x49, 0x72, 0x39, 0x71, 0x53, 0x33, 0x34, 0x42, 0x49, 0x62, 0x49, 0x6a, + 0x4d, 0x74, 0x2f, 0x6b, 0x6d, 0x6b, 0x52, 0x74, 0x57, 0x56, 0x74, 0x64, + 0x39, 0x51, 0x43, 0x67, 0x48, 0x4a, 0x76, 0x47, 0x65, 0x4a, 0x65, 0x4e, + 0x6b, 0x50, 0x2b, 0x62, 0x79, 0x4b, 0x71, 0x30, 0x72, 0x78, 0x46, 0x52, + 0x4f, 0x56, 0x37, 0x5a, 0x2b, 0x32, 0x65, 0x74, 0x31, 0x56, 0x73, 0x52, + 0x0a, 0x6e, 0x54, 0x4b, 0x61, 0x47, 0x37, 0x33, 0x56, 0x75, 0x6c, 0x75, + 0x6c, 0x79, 0x63, 0x73, 0x6c, 0x61, 0x56, 0x4e, 0x56, 0x4a, 0x31, 0x7a, + 0x67, 0x79, 0x6a, 0x62, 0x4c, 0x69, 0x47, 0x48, 0x37, 0x48, 0x72, 0x66, + 0x51, 0x79, 0x2b, 0x34, 0x57, 0x2b, 0x39, 0x4f, 0x6d, 0x54, 0x4e, 0x36, + 0x53, 0x70, 0x64, 0x54, 0x69, 0x33, 0x2f, 0x55, 0x47, 0x56, 0x4e, 0x34, + 0x75, 0x6e, 0x55, 0x75, 0x30, 0x0a, 0x6b, 0x7a, 0x43, 0x71, 0x67, 0x63, + 0x37, 0x64, 0x47, 0x74, 0x78, 0x52, 0x63, 0x77, 0x31, 0x50, 0x63, 0x4f, + 0x6e, 0x6c, 0x74, 0x68, 0x59, 0x68, 0x47, 0x58, 0x6d, 0x79, 0x35, 0x6f, + 0x6b, 0x4c, 0x64, 0x57, 0x54, 0x4b, 0x31, 0x61, 0x75, 0x38, 0x43, 0x63, + 0x45, 0x59, 0x6f, 0x66, 0x2f, 0x55, 0x56, 0x4b, 0x47, 0x46, 0x50, 0x50, + 0x30, 0x55, 0x4a, 0x41, 0x4f, 0x79, 0x68, 0x39, 0x4f, 0x6b, 0x0a, 0x74, + 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, + 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, + 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, 0x59, 0x77, 0x44, + 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, + 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x64, 0x42, + 0x67, 0x4e, 0x56, 0x0a, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, + 0x75, 0x2f, 0x2f, 0x4b, 0x6a, 0x69, 0x4f, 0x66, 0x54, 0x35, 0x6e, 0x4b, + 0x32, 0x2b, 0x4a, 0x6f, 0x70, 0x71, 0x55, 0x56, 0x4a, 0x78, 0x63, 0x65, + 0x32, 0x51, 0x34, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4d, 0x42, 0x51, 0x41, 0x44, + 0x67, 0x67, 0x49, 0x42, 0x41, 0x4c, 0x5a, 0x70, 0x0a, 0x38, 0x4b, 0x5a, + 0x33, 0x2f, 0x70, 0x37, 0x75, 0x43, 0x34, 0x47, 0x74, 0x34, 0x63, 0x43, + 0x70, 0x78, 0x2f, 0x6b, 0x31, 0x48, 0x55, 0x43, 0x43, 0x71, 0x2b, 0x59, + 0x45, 0x74, 0x4e, 0x2f, 0x4c, 0x39, 0x78, 0x30, 0x50, 0x67, 0x2f, 0x42, + 0x2b, 0x45, 0x30, 0x32, 0x4e, 0x6a, 0x4f, 0x37, 0x6a, 0x4d, 0x79, 0x4c, + 0x44, 0x4f, 0x66, 0x78, 0x41, 0x33, 0x32, 0x35, 0x42, 0x53, 0x30, 0x4a, + 0x54, 0x0a, 0x76, 0x68, 0x61, 0x49, 0x38, 0x64, 0x49, 0x34, 0x58, 0x73, + 0x52, 0x6f, 0x6d, 0x52, 0x79, 0x59, 0x55, 0x70, 0x4f, 0x4d, 0x35, 0x32, + 0x6a, 0x74, 0x47, 0x32, 0x70, 0x7a, 0x65, 0x67, 0x56, 0x41, 0x54, 0x58, + 0x39, 0x6c, 0x4f, 0x39, 0x5a, 0x59, 0x38, 0x63, 0x36, 0x44, 0x52, 0x32, + 0x44, 0x6a, 0x2f, 0x35, 0x65, 0x70, 0x6e, 0x47, 0x42, 0x33, 0x47, 0x46, + 0x57, 0x31, 0x66, 0x67, 0x69, 0x54, 0x0a, 0x7a, 0x39, 0x44, 0x32, 0x50, + 0x47, 0x63, 0x44, 0x46, 0x57, 0x45, 0x4a, 0x2b, 0x59, 0x46, 0x35, 0x39, + 0x65, 0x78, 0x54, 0x70, 0x4a, 0x2f, 0x4a, 0x6a, 0x77, 0x47, 0x4c, 0x63, + 0x38, 0x52, 0x33, 0x64, 0x74, 0x79, 0x44, 0x6f, 0x76, 0x55, 0x4d, 0x53, + 0x52, 0x71, 0x6f, 0x64, 0x74, 0x36, 0x53, 0x6d, 0x32, 0x54, 0x34, 0x73, + 0x79, 0x7a, 0x46, 0x4a, 0x39, 0x4d, 0x48, 0x77, 0x41, 0x69, 0x41, 0x0a, + 0x70, 0x4a, 0x69, 0x53, 0x34, 0x77, 0x47, 0x57, 0x41, 0x71, 0x6f, 0x43, + 0x37, 0x6f, 0x38, 0x37, 0x78, 0x64, 0x46, 0x74, 0x43, 0x6a, 0x4d, 0x77, + 0x63, 0x33, 0x69, 0x35, 0x54, 0x31, 0x51, 0x57, 0x76, 0x77, 0x73, 0x48, + 0x6f, 0x61, 0x52, 0x63, 0x35, 0x73, 0x76, 0x4a, 0x58, 0x49, 0x53, 0x50, + 0x44, 0x2b, 0x41, 0x56, 0x64, 0x79, 0x78, 0x2b, 0x4a, 0x6e, 0x37, 0x61, + 0x78, 0x45, 0x76, 0x62, 0x0a, 0x70, 0x78, 0x5a, 0x33, 0x42, 0x37, 0x44, + 0x4e, 0x64, 0x65, 0x68, 0x79, 0x51, 0x74, 0x61, 0x56, 0x68, 0x4a, 0x32, + 0x47, 0x67, 0x2f, 0x4c, 0x6b, 0x6b, 0x4d, 0x30, 0x4a, 0x52, 0x39, 0x53, + 0x4c, 0x41, 0x33, 0x44, 0x61, 0x57, 0x73, 0x59, 0x44, 0x51, 0x76, 0x54, + 0x74, 0x4e, 0x36, 0x4c, 0x77, 0x47, 0x31, 0x42, 0x55, 0x53, 0x77, 0x37, + 0x59, 0x68, 0x4e, 0x34, 0x5a, 0x4b, 0x4a, 0x6d, 0x42, 0x0a, 0x52, 0x36, + 0x34, 0x4a, 0x47, 0x7a, 0x39, 0x49, 0x30, 0x63, 0x4e, 0x76, 0x34, 0x72, + 0x42, 0x67, 0x46, 0x2f, 0x58, 0x75, 0x49, 0x77, 0x4b, 0x6c, 0x32, 0x67, + 0x42, 0x62, 0x62, 0x5a, 0x43, 0x72, 0x37, 0x71, 0x4c, 0x70, 0x47, 0x7a, + 0x76, 0x70, 0x78, 0x30, 0x51, 0x6e, 0x52, 0x59, 0x35, 0x72, 0x6e, 0x2f, + 0x57, 0x6b, 0x68, 0x4c, 0x78, 0x33, 0x2b, 0x57, 0x75, 0x58, 0x72, 0x44, + 0x35, 0x52, 0x0a, 0x52, 0x61, 0x49, 0x52, 0x70, 0x73, 0x79, 0x46, 0x37, + 0x67, 0x70, 0x6f, 0x38, 0x6a, 0x35, 0x51, 0x4f, 0x48, 0x6f, 0x6b, 0x59, + 0x68, 0x34, 0x58, 0x49, 0x44, 0x64, 0x74, 0x61, 0x6b, 0x32, 0x33, 0x43, + 0x5a, 0x76, 0x4a, 0x2f, 0x4b, 0x52, 0x59, 0x39, 0x62, 0x62, 0x37, 0x6e, + 0x45, 0x34, 0x59, 0x75, 0x35, 0x55, 0x43, 0x35, 0x36, 0x47, 0x74, 0x6d, + 0x77, 0x66, 0x75, 0x4e, 0x6d, 0x73, 0x6b, 0x0a, 0x30, 0x6a, 0x6d, 0x47, + 0x77, 0x5a, 0x4f, 0x44, 0x55, 0x4e, 0x4b, 0x42, 0x52, 0x71, 0x68, 0x66, + 0x59, 0x6c, 0x63, 0x73, 0x75, 0x32, 0x78, 0x6b, 0x69, 0x41, 0x68, 0x75, + 0x37, 0x78, 0x4e, 0x55, 0x58, 0x39, 0x30, 0x74, 0x78, 0x47, 0x64, 0x6a, + 0x30, 0x38, 0x2b, 0x4a, 0x4e, 0x37, 0x2b, 0x64, 0x49, 0x50, 0x54, 0x37, + 0x65, 0x6f, 0x4f, 0x62, 0x6f, 0x42, 0x36, 0x42, 0x41, 0x46, 0x44, 0x43, + 0x0a, 0x35, 0x41, 0x77, 0x69, 0x57, 0x56, 0x49, 0x51, 0x37, 0x55, 0x4e, + 0x57, 0x68, 0x77, 0x44, 0x34, 0x46, 0x46, 0x4b, 0x6e, 0x48, 0x59, 0x75, + 0x54, 0x6a, 0x4b, 0x4a, 0x4e, 0x52, 0x6e, 0x38, 0x6e, 0x78, 0x6e, 0x47, + 0x62, 0x4a, 0x4e, 0x37, 0x6b, 0x32, 0x6f, 0x61, 0x4c, 0x44, 0x58, 0x35, + 0x72, 0x49, 0x4d, 0x48, 0x41, 0x6e, 0x75, 0x46, 0x6c, 0x32, 0x47, 0x71, + 0x6a, 0x70, 0x75, 0x69, 0x46, 0x0a, 0x69, 0x7a, 0x6f, 0x48, 0x43, 0x42, + 0x79, 0x36, 0x39, 0x59, 0x39, 0x56, 0x6d, 0x68, 0x68, 0x31, 0x66, 0x75, + 0x58, 0x73, 0x67, 0x57, 0x62, 0x52, 0x49, 0x58, 0x4f, 0x68, 0x4e, 0x55, + 0x51, 0x4c, 0x67, 0x44, 0x31, 0x62, 0x6e, 0x46, 0x35, 0x76, 0x4b, 0x68, + 0x65, 0x57, 0x30, 0x59, 0x4d, 0x6a, 0x69, 0x47, 0x5a, 0x74, 0x35, 0x6f, + 0x62, 0x69, 0x63, 0x44, 0x49, 0x76, 0x55, 0x69, 0x4c, 0x6e, 0x0a, 0x79, + 0x4f, 0x64, 0x2f, 0x78, 0x43, 0x78, 0x67, 0x58, 0x53, 0x2f, 0x44, 0x72, + 0x35, 0x35, 0x46, 0x42, 0x63, 0x4f, 0x45, 0x41, 0x72, 0x66, 0x39, 0x4c, + 0x41, 0x68, 0x53, 0x54, 0x34, 0x4c, 0x64, 0x6f, 0x2f, 0x44, 0x55, 0x68, + 0x67, 0x6b, 0x43, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x54, 0x53, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x33, 0x20, 0x4f, 0x3d, 0x47, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x4c, 0x4c, 0x43, 0x0a, + 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x47, 0x54, 0x53, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, + 0x33, 0x20, 0x4f, 0x3d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x54, + 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x20, 0x4c, 0x4c, 0x43, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x54, 0x53, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x52, 0x33, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x3a, 0x20, 0x31, 0x34, 0x36, 0x35, 0x38, 0x37, 0x31, 0x37, 0x36, + 0x31, 0x34, 0x30, 0x35, 0x35, 0x33, 0x33, 0x30, 0x39, 0x35, 0x31, 0x37, + 0x30, 0x34, 0x37, 0x39, 0x39, 0x31, 0x30, 0x38, 0x33, 0x37, 0x30, 0x37, + 0x37, 0x36, 0x33, 0x39, 0x39, 0x37, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, + 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x3a, 0x20, 0x31, 0x61, 0x3a, 0x37, 0x39, 0x3a, 0x35, 0x62, 0x3a, 0x36, + 0x62, 0x3a, 0x30, 0x34, 0x3a, 0x35, 0x32, 0x3a, 0x39, 0x63, 0x3a, 0x35, + 0x64, 0x3a, 0x63, 0x37, 0x3a, 0x37, 0x34, 0x3a, 0x33, 0x33, 0x3a, 0x31, + 0x62, 0x3a, 0x32, 0x35, 0x3a, 0x39, 0x61, 0x3a, 0x66, 0x39, 0x3a, 0x32, + 0x35, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x30, + 0x3a, 0x64, 0x34, 0x3a, 0x32, 0x34, 0x3a, 0x36, 0x66, 0x3a, 0x30, 0x37, + 0x3a, 0x66, 0x66, 0x3a, 0x64, 0x62, 0x3a, 0x39, 0x31, 0x3a, 0x38, 0x39, + 0x3a, 0x38, 0x61, 0x3a, 0x30, 0x62, 0x3a, 0x65, 0x39, 0x3a, 0x34, 0x39, + 0x3a, 0x36, 0x36, 0x3a, 0x31, 0x31, 0x3a, 0x65, 0x62, 0x3a, 0x38, 0x63, + 0x3a, 0x35, 0x65, 0x3a, 0x34, 0x36, 0x3a, 0x65, 0x35, 0x0a, 0x23, 0x20, + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x35, 0x3a, 0x64, + 0x35, 0x3a, 0x62, 0x38, 0x3a, 0x37, 0x37, 0x3a, 0x34, 0x36, 0x3a, 0x31, + 0x39, 0x3a, 0x65, 0x61, 0x3a, 0x37, 0x64, 0x3a, 0x35, 0x34, 0x3a, 0x63, + 0x65, 0x3a, 0x31, 0x63, 0x3a, 0x61, 0x36, 0x3a, 0x64, 0x30, 0x3a, 0x62, + 0x30, 0x3a, 0x63, 0x34, 0x3a, 0x30, 0x33, 0x3a, 0x65, 0x30, 0x3a, 0x33, + 0x37, 0x3a, 0x61, 0x39, 0x3a, 0x31, 0x37, 0x3a, 0x66, 0x31, 0x3a, 0x33, + 0x31, 0x3a, 0x65, 0x38, 0x3a, 0x61, 0x30, 0x3a, 0x34, 0x65, 0x3a, 0x31, + 0x65, 0x3a, 0x36, 0x62, 0x3a, 0x37, 0x61, 0x3a, 0x37, 0x31, 0x3a, 0x62, + 0x61, 0x3a, 0x62, 0x63, 0x3a, 0x65, 0x35, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x4d, 0x49, 0x49, 0x43, 0x44, 0x44, 0x43, 0x43, 0x41, 0x5a, 0x47, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x62, 0x6b, 0x65, 0x70, + 0x78, 0x32, 0x79, 0x70, 0x63, 0x79, 0x52, 0x41, 0x69, 0x51, 0x38, 0x44, + 0x56, 0x64, 0x32, 0x4e, 0x48, 0x54, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, + 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x7a, 0x42, 0x48, + 0x4d, 0x51, 0x73, 0x77, 0x0a, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x69, 0x4d, 0x43, 0x41, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x5a, 0x52, 0x32, 0x39, + 0x76, 0x5a, 0x32, 0x78, 0x6c, 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, + 0x30, 0x49, 0x46, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, 0x56, + 0x7a, 0x49, 0x45, 0x78, 0x4d, 0x51, 0x7a, 0x45, 0x55, 0x0a, 0x4d, 0x42, + 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x4c, 0x52, 0x31, + 0x52, 0x54, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x55, 0x6a, + 0x4d, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x59, 0x77, 0x4e, 0x6a, + 0x49, 0x79, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, + 0x63, 0x4e, 0x4d, 0x7a, 0x59, 0x77, 0x4e, 0x6a, 0x49, 0x79, 0x4d, 0x44, + 0x41, 0x77, 0x0a, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x6a, 0x42, 0x48, 0x4d, + 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, + 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x5a, 0x52, 0x32, 0x39, 0x76, 0x5a, + 0x32, 0x78, 0x6c, 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, 0x4e, 0x30, 0x49, + 0x46, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70, 0x0a, 0x59, 0x32, 0x56, 0x7a, + 0x49, 0x45, 0x78, 0x4d, 0x51, 0x7a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x4c, 0x52, 0x31, 0x52, 0x54, + 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x55, 0x6a, 0x4d, 0x77, + 0x64, 0x6a, 0x41, 0x51, 0x42, 0x67, 0x63, 0x71, 0x68, 0x6b, 0x6a, 0x4f, + 0x50, 0x51, 0x49, 0x42, 0x42, 0x67, 0x55, 0x72, 0x67, 0x51, 0x51, 0x41, + 0x0a, 0x49, 0x67, 0x4e, 0x69, 0x41, 0x41, 0x51, 0x66, 0x54, 0x7a, 0x4f, + 0x48, 0x4d, 0x79, 0x6d, 0x4b, 0x6f, 0x59, 0x54, 0x65, 0x79, 0x38, 0x63, + 0x68, 0x57, 0x45, 0x47, 0x4a, 0x36, 0x6c, 0x61, 0x64, 0x4b, 0x30, 0x75, + 0x46, 0x78, 0x68, 0x31, 0x4d, 0x4a, 0x37, 0x78, 0x2f, 0x4a, 0x6c, 0x46, + 0x79, 0x62, 0x2b, 0x4b, 0x66, 0x31, 0x71, 0x50, 0x4b, 0x7a, 0x45, 0x55, + 0x55, 0x52, 0x6f, 0x75, 0x74, 0x0a, 0x37, 0x33, 0x36, 0x47, 0x6a, 0x4f, + 0x79, 0x78, 0x66, 0x69, 0x2f, 0x2f, 0x71, 0x58, 0x47, 0x64, 0x47, 0x49, + 0x52, 0x46, 0x42, 0x45, 0x46, 0x56, 0x62, 0x69, 0x76, 0x71, 0x4a, 0x6e, + 0x2b, 0x37, 0x6b, 0x41, 0x48, 0x6a, 0x53, 0x78, 0x6d, 0x36, 0x35, 0x46, + 0x53, 0x57, 0x52, 0x51, 0x6d, 0x78, 0x31, 0x57, 0x79, 0x52, 0x52, 0x4b, + 0x32, 0x45, 0x45, 0x34, 0x36, 0x61, 0x6a, 0x41, 0x32, 0x41, 0x0a, 0x44, + 0x44, 0x4c, 0x32, 0x34, 0x43, 0x65, 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x4d, + 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, + 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x50, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, + 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x42, 0x30, 0x47, 0x41, + 0x31, 0x55, 0x64, 0x0a, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x54, 0x42, + 0x38, 0x53, 0x61, 0x36, 0x6f, 0x43, 0x32, 0x75, 0x68, 0x59, 0x48, 0x50, + 0x30, 0x2f, 0x45, 0x71, 0x45, 0x72, 0x32, 0x34, 0x43, 0x6d, 0x66, 0x39, + 0x76, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, 0x4f, + 0x50, 0x51, 0x51, 0x44, 0x41, 0x77, 0x4e, 0x70, 0x41, 0x44, 0x42, 0x6d, + 0x41, 0x6a, 0x45, 0x41, 0x67, 0x46, 0x75, 0x6b, 0x0a, 0x66, 0x43, 0x50, + 0x41, 0x6c, 0x61, 0x55, 0x73, 0x33, 0x4c, 0x36, 0x4a, 0x62, 0x79, 0x4f, + 0x35, 0x6f, 0x39, 0x31, 0x6c, 0x41, 0x46, 0x4a, 0x65, 0x6b, 0x61, 0x7a, + 0x49, 0x6e, 0x58, 0x4a, 0x30, 0x67, 0x6c, 0x4d, 0x4c, 0x66, 0x61, 0x6c, + 0x41, 0x76, 0x57, 0x68, 0x67, 0x78, 0x65, 0x47, 0x34, 0x56, 0x44, 0x76, + 0x42, 0x4e, 0x68, 0x63, 0x6c, 0x32, 0x4d, 0x47, 0x39, 0x41, 0x6a, 0x45, + 0x41, 0x0a, 0x6e, 0x6a, 0x57, 0x53, 0x64, 0x49, 0x55, 0x6c, 0x55, 0x66, + 0x55, 0x6b, 0x37, 0x47, 0x52, 0x53, 0x4a, 0x46, 0x43, 0x6c, 0x48, 0x39, + 0x76, 0x6f, 0x79, 0x38, 0x6c, 0x32, 0x37, 0x4f, 0x79, 0x43, 0x62, 0x76, + 0x57, 0x46, 0x47, 0x46, 0x50, 0x6f, 0x75, 0x4f, 0x4f, 0x61, 0x4b, 0x61, + 0x71, 0x57, 0x30, 0x34, 0x4d, 0x6a, 0x79, 0x61, 0x52, 0x37, 0x59, 0x62, + 0x50, 0x4d, 0x41, 0x75, 0x68, 0x64, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, + 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, + 0x54, 0x53, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x34, 0x20, 0x4f, + 0x3d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x4c, + 0x4c, 0x43, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x47, 0x54, 0x53, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x52, 0x34, 0x20, 0x4f, 0x3d, 0x47, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x20, 0x4c, 0x4c, 0x43, 0x0a, 0x23, 0x20, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x47, 0x54, 0x53, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x34, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x34, 0x36, 0x35, 0x38, 0x37, + 0x31, 0x37, 0x36, 0x32, 0x32, 0x39, 0x33, 0x35, 0x30, 0x34, 0x33, 0x39, + 0x39, 0x31, 0x36, 0x35, 0x31, 0x39, 0x34, 0x36, 0x38, 0x39, 0x32, 0x39, + 0x37, 0x36, 0x35, 0x32, 0x36, 0x31, 0x37, 0x32, 0x31, 0x0a, 0x23, 0x20, + 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, 0x64, 0x3a, 0x62, 0x36, 0x3a, 0x36, + 0x61, 0x3a, 0x63, 0x34, 0x3a, 0x36, 0x30, 0x3a, 0x31, 0x37, 0x3a, 0x32, + 0x34, 0x3a, 0x36, 0x61, 0x3a, 0x31, 0x61, 0x3a, 0x39, 0x39, 0x3a, 0x61, + 0x38, 0x3a, 0x34, 0x62, 0x3a, 0x65, 0x65, 0x3a, 0x35, 0x65, 0x3a, 0x62, + 0x34, 0x3a, 0x32, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x32, 0x61, 0x3a, 0x31, 0x64, 0x3a, 0x36, 0x30, 0x3a, 0x32, 0x37, + 0x3a, 0x64, 0x39, 0x3a, 0x34, 0x61, 0x3a, 0x62, 0x31, 0x3a, 0x30, 0x61, + 0x3a, 0x31, 0x63, 0x3a, 0x34, 0x64, 0x3a, 0x39, 0x31, 0x3a, 0x35, 0x63, + 0x3a, 0x63, 0x64, 0x3a, 0x33, 0x33, 0x3a, 0x61, 0x30, 0x3a, 0x63, 0x62, + 0x3a, 0x33, 0x65, 0x3a, 0x32, 0x64, 0x3a, 0x35, 0x34, 0x3a, 0x63, 0x62, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x37, + 0x31, 0x3a, 0x63, 0x63, 0x3a, 0x61, 0x35, 0x3a, 0x33, 0x39, 0x3a, 0x31, + 0x66, 0x3a, 0x39, 0x65, 0x3a, 0x37, 0x39, 0x3a, 0x34, 0x62, 0x3a, 0x30, + 0x34, 0x3a, 0x38, 0x30, 0x3a, 0x32, 0x35, 0x3a, 0x33, 0x30, 0x3a, 0x62, + 0x33, 0x3a, 0x36, 0x33, 0x3a, 0x65, 0x31, 0x3a, 0x32, 0x31, 0x3a, 0x64, + 0x61, 0x3a, 0x38, 0x61, 0x3a, 0x33, 0x30, 0x3a, 0x34, 0x33, 0x3a, 0x62, + 0x62, 0x3a, 0x32, 0x36, 0x3a, 0x36, 0x36, 0x3a, 0x32, 0x66, 0x3a, 0x65, + 0x61, 0x3a, 0x34, 0x64, 0x3a, 0x63, 0x61, 0x3a, 0x37, 0x66, 0x3a, 0x63, + 0x39, 0x3a, 0x35, 0x31, 0x3a, 0x61, 0x34, 0x3a, 0x62, 0x64, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x43, 0x6a, 0x43, 0x43, 0x41, + 0x5a, 0x47, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x51, 0x62, + 0x6b, 0x65, 0x70, 0x79, 0x49, 0x75, 0x55, 0x74, 0x75, 0x69, 0x37, 0x4f, + 0x79, 0x72, 0x59, 0x6f, 0x72, 0x4c, 0x42, 0x6d, 0x54, 0x41, 0x4b, 0x42, + 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, + 0x7a, 0x42, 0x48, 0x4d, 0x51, 0x73, 0x77, 0x0a, 0x43, 0x51, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x69, + 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x5a, + 0x52, 0x32, 0x39, 0x76, 0x5a, 0x32, 0x78, 0x6c, 0x49, 0x46, 0x52, 0x79, + 0x64, 0x58, 0x4e, 0x30, 0x49, 0x46, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70, + 0x59, 0x32, 0x56, 0x7a, 0x49, 0x45, 0x78, 0x4d, 0x51, 0x7a, 0x45, 0x55, + 0x0a, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, + 0x4c, 0x52, 0x31, 0x52, 0x54, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, + 0x67, 0x55, 0x6a, 0x51, 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x59, + 0x77, 0x4e, 0x6a, 0x49, 0x79, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, + 0x77, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x59, 0x77, 0x4e, 0x6a, 0x49, + 0x79, 0x4d, 0x44, 0x41, 0x77, 0x0a, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x6a, + 0x42, 0x48, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x69, 0x4d, 0x43, + 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x5a, 0x52, 0x32, + 0x39, 0x76, 0x5a, 0x32, 0x78, 0x6c, 0x49, 0x46, 0x52, 0x79, 0x64, 0x58, + 0x4e, 0x30, 0x49, 0x46, 0x4e, 0x6c, 0x63, 0x6e, 0x5a, 0x70, 0x0a, 0x59, + 0x32, 0x56, 0x7a, 0x49, 0x45, 0x78, 0x4d, 0x51, 0x7a, 0x45, 0x55, 0x4d, + 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4d, 0x4c, 0x52, + 0x31, 0x52, 0x54, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x55, + 0x6a, 0x51, 0x77, 0x64, 0x6a, 0x41, 0x51, 0x42, 0x67, 0x63, 0x71, 0x68, + 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x49, 0x42, 0x42, 0x67, 0x55, 0x72, 0x67, + 0x51, 0x51, 0x41, 0x0a, 0x49, 0x67, 0x4e, 0x69, 0x41, 0x41, 0x54, 0x7a, + 0x64, 0x48, 0x4f, 0x6e, 0x61, 0x49, 0x74, 0x67, 0x72, 0x6b, 0x4f, 0x34, + 0x4e, 0x63, 0x57, 0x42, 0x4d, 0x48, 0x74, 0x4c, 0x53, 0x5a, 0x33, 0x37, + 0x77, 0x57, 0x48, 0x4f, 0x35, 0x74, 0x35, 0x47, 0x76, 0x57, 0x76, 0x56, + 0x59, 0x52, 0x67, 0x31, 0x72, 0x6b, 0x44, 0x64, 0x63, 0x2f, 0x65, 0x4a, + 0x6b, 0x54, 0x42, 0x61, 0x36, 0x7a, 0x7a, 0x75, 0x0a, 0x68, 0x58, 0x79, + 0x69, 0x51, 0x48, 0x59, 0x37, 0x71, 0x63, 0x61, 0x34, 0x52, 0x39, 0x67, + 0x71, 0x35, 0x35, 0x4b, 0x52, 0x61, 0x6e, 0x50, 0x70, 0x73, 0x58, 0x49, + 0x35, 0x6e, 0x79, 0x6d, 0x66, 0x6f, 0x70, 0x6a, 0x54, 0x58, 0x31, 0x35, + 0x59, 0x68, 0x6d, 0x55, 0x50, 0x6f, 0x59, 0x52, 0x6c, 0x42, 0x74, 0x48, + 0x63, 0x69, 0x38, 0x6e, 0x48, 0x63, 0x38, 0x69, 0x4d, 0x61, 0x69, 0x2f, + 0x6c, 0x0a, 0x78, 0x4b, 0x76, 0x52, 0x48, 0x59, 0x71, 0x6a, 0x51, 0x6a, + 0x42, 0x41, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, + 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, + 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, + 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x42, + 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x0a, 0x44, 0x67, 0x51, 0x57, 0x42, + 0x42, 0x53, 0x41, 0x54, 0x4e, 0x62, 0x72, 0x64, 0x50, 0x39, 0x4a, 0x4e, + 0x71, 0x50, 0x56, 0x32, 0x50, 0x79, 0x31, 0x50, 0x73, 0x56, 0x71, 0x38, + 0x4a, 0x51, 0x64, 0x6a, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, + 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x77, 0x4e, 0x6e, 0x41, + 0x44, 0x42, 0x6b, 0x41, 0x6a, 0x42, 0x71, 0x55, 0x46, 0x4a, 0x30, 0x0a, + 0x43, 0x4d, 0x52, 0x77, 0x33, 0x4a, 0x35, 0x51, 0x64, 0x43, 0x48, 0x6f, + 0x6a, 0x58, 0x6f, 0x68, 0x77, 0x30, 0x2b, 0x57, 0x62, 0x68, 0x58, 0x52, + 0x49, 0x6a, 0x56, 0x68, 0x4c, 0x66, 0x6f, 0x49, 0x4e, 0x2b, 0x34, 0x5a, + 0x62, 0x61, 0x33, 0x62, 0x73, 0x73, 0x78, 0x39, 0x42, 0x7a, 0x54, 0x31, + 0x59, 0x42, 0x6b, 0x73, 0x74, 0x54, 0x54, 0x5a, 0x62, 0x79, 0x41, 0x43, + 0x4d, 0x41, 0x4e, 0x78, 0x0a, 0x73, 0x62, 0x71, 0x6a, 0x59, 0x41, 0x75, + 0x47, 0x37, 0x5a, 0x6f, 0x49, 0x61, 0x70, 0x56, 0x6f, 0x6e, 0x2b, 0x4b, + 0x7a, 0x34, 0x5a, 0x4e, 0x6b, 0x66, 0x46, 0x36, 0x54, 0x70, 0x74, 0x39, + 0x35, 0x4c, 0x59, 0x32, 0x46, 0x34, 0x35, 0x54, 0x50, 0x49, 0x31, 0x31, + 0x78, 0x7a, 0x50, 0x4b, 0x77, 0x54, 0x64, 0x62, 0x2b, 0x6d, 0x63, 0x69, + 0x55, 0x71, 0x58, 0x57, 0x69, 0x34, 0x77, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, + 0x4e, 0x3d, 0x55, 0x43, 0x41, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x20, 0x47, 0x32, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x55, + 0x6e, 0x69, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x55, 0x43, + 0x41, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x47, 0x32, 0x20, + 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x55, 0x6e, 0x69, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x55, 0x43, 0x41, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x20, 0x47, 0x32, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x0a, 0x23, 0x20, + 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x32, 0x34, 0x37, + 0x37, 0x39, 0x36, 0x39, 0x33, 0x30, 0x39, 0x33, 0x37, 0x34, 0x31, 0x35, + 0x34, 0x33, 0x39, 0x31, 0x39, 0x31, 0x34, 0x35, 0x32, 0x35, 0x37, 0x38, + 0x35, 0x30, 0x30, 0x37, 0x36, 0x36, 0x33, 0x31, 0x32, 0x37, 0x39, 0x0a, + 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x38, 0x30, 0x3a, 0x66, 0x65, + 0x3a, 0x66, 0x30, 0x3a, 0x63, 0x34, 0x3a, 0x34, 0x61, 0x3a, 0x66, 0x30, + 0x3a, 0x35, 0x63, 0x3a, 0x36, 0x32, 0x3a, 0x33, 0x32, 0x3a, 0x39, 0x66, + 0x3a, 0x31, 0x63, 0x3a, 0x62, 0x61, 0x3a, 0x37, 0x38, 0x3a, 0x61, 0x39, + 0x3a, 0x35, 0x30, 0x3a, 0x66, 0x38, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x32, 0x38, 0x3a, 0x66, 0x39, 0x3a, 0x37, 0x38, 0x3a, + 0x31, 0x36, 0x3a, 0x31, 0x39, 0x3a, 0x37, 0x61, 0x3a, 0x66, 0x66, 0x3a, + 0x31, 0x38, 0x3a, 0x32, 0x35, 0x3a, 0x31, 0x38, 0x3a, 0x61, 0x61, 0x3a, + 0x34, 0x34, 0x3a, 0x66, 0x65, 0x3a, 0x63, 0x31, 0x3a, 0x61, 0x30, 0x3a, + 0x63, 0x65, 0x3a, 0x35, 0x63, 0x3a, 0x62, 0x36, 0x3a, 0x34, 0x63, 0x3a, + 0x38, 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x39, 0x62, 0x3a, 0x65, 0x61, 0x3a, 0x31, 0x31, 0x3a, 0x63, 0x39, + 0x3a, 0x37, 0x36, 0x3a, 0x66, 0x65, 0x3a, 0x30, 0x31, 0x3a, 0x34, 0x37, + 0x3a, 0x36, 0x34, 0x3a, 0x63, 0x31, 0x3a, 0x62, 0x65, 0x3a, 0x35, 0x36, + 0x3a, 0x61, 0x36, 0x3a, 0x66, 0x39, 0x3a, 0x31, 0x34, 0x3a, 0x62, 0x35, + 0x3a, 0x61, 0x35, 0x3a, 0x36, 0x30, 0x3a, 0x33, 0x31, 0x3a, 0x37, 0x61, + 0x3a, 0x62, 0x64, 0x3a, 0x39, 0x39, 0x3a, 0x38, 0x38, 0x3a, 0x33, 0x39, + 0x3a, 0x33, 0x33, 0x3a, 0x38, 0x32, 0x3a, 0x65, 0x35, 0x3a, 0x31, 0x36, + 0x3a, 0x31, 0x61, 0x3a, 0x61, 0x30, 0x3a, 0x34, 0x39, 0x3a, 0x33, 0x63, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x52, 0x6a, 0x43, + 0x43, 0x41, 0x79, 0x36, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x51, 0x58, 0x64, 0x2b, 0x78, 0x32, 0x6c, 0x71, 0x6a, 0x37, 0x56, 0x32, + 0x2b, 0x57, 0x6d, 0x55, 0x67, 0x5a, 0x51, 0x4f, 0x51, 0x37, 0x7a, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, + 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x41, 0x39, 0x0a, 0x4d, 0x51, + 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, + 0x4a, 0x44, 0x54, 0x6a, 0x45, 0x52, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x67, 0x77, 0x49, 0x56, 0x57, 0x35, 0x70, 0x56, 0x48, + 0x4a, 0x31, 0x63, 0x33, 0x51, 0x78, 0x47, 0x7a, 0x41, 0x5a, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x45, 0x6c, 0x56, 0x44, 0x51, 0x53, + 0x42, 0x48, 0x0a, 0x62, 0x47, 0x39, 0x69, 0x59, 0x57, 0x77, 0x67, 0x52, + 0x7a, 0x49, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x44, 0x41, 0x65, 0x46, + 0x77, 0x30, 0x78, 0x4e, 0x6a, 0x41, 0x7a, 0x4d, 0x54, 0x45, 0x77, 0x4d, + 0x44, 0x41, 0x77, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, 0x30, 0x4d, + 0x44, 0x45, 0x79, 0x4d, 0x7a, 0x45, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x4d, + 0x44, 0x42, 0x61, 0x4d, 0x44, 0x30, 0x78, 0x0a, 0x43, 0x7a, 0x41, 0x4a, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x4e, 0x4f, + 0x4d, 0x52, 0x45, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, + 0x44, 0x41, 0x68, 0x56, 0x62, 0x6d, 0x6c, 0x55, 0x63, 0x6e, 0x56, 0x7a, + 0x64, 0x44, 0x45, 0x62, 0x4d, 0x42, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x41, 0x77, 0x77, 0x53, 0x56, 0x55, 0x4e, 0x42, 0x49, 0x45, 0x64, 0x73, + 0x0a, 0x62, 0x32, 0x4a, 0x68, 0x62, 0x43, 0x42, 0x48, 0x4d, 0x69, 0x42, + 0x53, 0x62, 0x32, 0x39, 0x30, 0x4d, 0x49, 0x49, 0x43, 0x49, 0x6a, 0x41, + 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, + 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x38, + 0x41, 0x4d, 0x49, 0x49, 0x43, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x67, 0x45, + 0x41, 0x78, 0x65, 0x59, 0x72, 0x0a, 0x62, 0x33, 0x7a, 0x76, 0x4a, 0x67, + 0x55, 0x6e, 0x6f, 0x34, 0x45, 0x6b, 0x32, 0x6d, 0x2f, 0x4c, 0x41, 0x66, + 0x6d, 0x5a, 0x6d, 0x71, 0x6b, 0x79, 0x77, 0x69, 0x4b, 0x48, 0x59, 0x55, + 0x47, 0x52, 0x4f, 0x38, 0x76, 0x44, 0x61, 0x42, 0x73, 0x47, 0x78, 0x55, + 0x79, 0x70, 0x4b, 0x38, 0x46, 0x6e, 0x46, 0x79, 0x49, 0x64, 0x4b, 0x2b, + 0x33, 0x35, 0x4b, 0x59, 0x6d, 0x54, 0x6f, 0x6e, 0x69, 0x39, 0x0a, 0x6b, + 0x6d, 0x75, 0x67, 0x6f, 0x77, 0x32, 0x69, 0x66, 0x73, 0x71, 0x54, 0x73, + 0x36, 0x62, 0x52, 0x6a, 0x44, 0x58, 0x56, 0x64, 0x66, 0x6b, 0x58, 0x39, + 0x73, 0x39, 0x46, 0x78, 0x65, 0x56, 0x36, 0x37, 0x48, 0x65, 0x54, 0x6f, + 0x49, 0x38, 0x6a, 0x72, 0x67, 0x34, 0x61, 0x41, 0x33, 0x2b, 0x2b, 0x31, + 0x4e, 0x44, 0x74, 0x4c, 0x6e, 0x75, 0x72, 0x52, 0x69, 0x4e, 0x62, 0x2f, + 0x79, 0x7a, 0x6d, 0x0a, 0x56, 0x48, 0x71, 0x55, 0x77, 0x43, 0x6f, 0x56, + 0x38, 0x4d, 0x6d, 0x4e, 0x73, 0x48, 0x6f, 0x37, 0x4a, 0x4f, 0x48, 0x58, + 0x61, 0x4f, 0x49, 0x78, 0x50, 0x41, 0x59, 0x7a, 0x52, 0x72, 0x5a, 0x55, + 0x45, 0x61, 0x61, 0x6c, 0x4c, 0x79, 0x4a, 0x55, 0x4b, 0x6c, 0x67, 0x4e, + 0x41, 0x51, 0x4c, 0x78, 0x2b, 0x68, 0x56, 0x52, 0x5a, 0x32, 0x7a, 0x41, + 0x2b, 0x74, 0x65, 0x32, 0x47, 0x33, 0x2f, 0x52, 0x0a, 0x56, 0x6f, 0x67, + 0x76, 0x47, 0x6a, 0x71, 0x4e, 0x4f, 0x37, 0x75, 0x43, 0x45, 0x65, 0x42, + 0x48, 0x41, 0x4e, 0x42, 0x53, 0x68, 0x36, 0x76, 0x37, 0x68, 0x6e, 0x34, + 0x50, 0x4a, 0x47, 0x74, 0x41, 0x6e, 0x54, 0x52, 0x6e, 0x76, 0x49, 0x33, + 0x48, 0x4c, 0x59, 0x5a, 0x76, 0x65, 0x54, 0x36, 0x4f, 0x71, 0x54, 0x77, + 0x58, 0x53, 0x33, 0x2b, 0x77, 0x6d, 0x65, 0x4f, 0x77, 0x63, 0x57, 0x44, + 0x63, 0x0a, 0x43, 0x2f, 0x56, 0x6b, 0x77, 0x38, 0x35, 0x44, 0x76, 0x47, + 0x31, 0x78, 0x75, 0x64, 0x4c, 0x65, 0x4a, 0x31, 0x75, 0x4b, 0x36, 0x4e, + 0x6a, 0x47, 0x72, 0x75, 0x46, 0x5a, 0x66, 0x63, 0x38, 0x6f, 0x4c, 0x54, + 0x57, 0x34, 0x6c, 0x56, 0x59, 0x61, 0x38, 0x62, 0x4a, 0x59, 0x53, 0x37, + 0x63, 0x53, 0x4e, 0x38, 0x68, 0x38, 0x73, 0x2b, 0x31, 0x4c, 0x67, 0x4f, + 0x47, 0x4e, 0x2b, 0x6a, 0x49, 0x6a, 0x0a, 0x74, 0x6d, 0x2b, 0x33, 0x53, + 0x4a, 0x55, 0x49, 0x73, 0x55, 0x52, 0x4f, 0x68, 0x59, 0x77, 0x36, 0x41, + 0x6c, 0x51, 0x67, 0x4c, 0x39, 0x2b, 0x2f, 0x56, 0x30, 0x38, 0x37, 0x4f, + 0x70, 0x41, 0x68, 0x31, 0x38, 0x45, 0x6d, 0x4e, 0x56, 0x51, 0x67, 0x37, + 0x4d, 0x63, 0x2f, 0x52, 0x2b, 0x7a, 0x76, 0x57, 0x72, 0x39, 0x4c, 0x65, + 0x73, 0x47, 0x74, 0x4f, 0x78, 0x64, 0x51, 0x58, 0x47, 0x4c, 0x59, 0x0a, + 0x44, 0x30, 0x74, 0x4b, 0x33, 0x43, 0x76, 0x36, 0x62, 0x72, 0x78, 0x7a, + 0x6b, 0x73, 0x33, 0x73, 0x78, 0x31, 0x44, 0x6f, 0x51, 0x5a, 0x62, 0x58, + 0x71, 0x58, 0x35, 0x74, 0x32, 0x4f, 0x6b, 0x64, 0x6a, 0x34, 0x71, 0x31, + 0x75, 0x56, 0x69, 0x53, 0x75, 0x6b, 0x71, 0x53, 0x4b, 0x77, 0x78, 0x57, + 0x2f, 0x59, 0x44, 0x72, 0x43, 0x50, 0x42, 0x65, 0x4b, 0x57, 0x34, 0x62, + 0x48, 0x41, 0x79, 0x76, 0x0a, 0x6a, 0x35, 0x4f, 0x4a, 0x72, 0x64, 0x75, + 0x39, 0x6f, 0x35, 0x34, 0x68, 0x79, 0x6f, 0x6b, 0x5a, 0x37, 0x4e, 0x2b, + 0x31, 0x77, 0x78, 0x72, 0x72, 0x46, 0x76, 0x35, 0x34, 0x4e, 0x6b, 0x7a, + 0x57, 0x62, 0x74, 0x41, 0x2b, 0x46, 0x78, 0x79, 0x51, 0x46, 0x32, 0x73, + 0x6d, 0x75, 0x76, 0x74, 0x36, 0x4c, 0x37, 0x38, 0x52, 0x48, 0x42, 0x67, + 0x4f, 0x4c, 0x58, 0x4d, 0x44, 0x6a, 0x36, 0x44, 0x6c, 0x0a, 0x4e, 0x61, + 0x42, 0x61, 0x34, 0x6b, 0x78, 0x31, 0x48, 0x58, 0x48, 0x68, 0x4f, 0x54, + 0x68, 0x54, 0x65, 0x45, 0x44, 0x4d, 0x67, 0x35, 0x50, 0x58, 0x43, 0x70, + 0x36, 0x64, 0x57, 0x34, 0x2b, 0x4b, 0x35, 0x4f, 0x58, 0x67, 0x53, 0x4f, + 0x52, 0x49, 0x73, 0x6b, 0x66, 0x4e, 0x54, 0x69, 0x70, 0x31, 0x4b, 0x6e, + 0x76, 0x79, 0x49, 0x76, 0x62, 0x4a, 0x76, 0x67, 0x6d, 0x52, 0x6c, 0x6c, + 0x64, 0x36, 0x0a, 0x69, 0x49, 0x69, 0x73, 0x37, 0x6e, 0x43, 0x73, 0x2b, + 0x64, 0x77, 0x70, 0x34, 0x77, 0x77, 0x63, 0x4f, 0x78, 0x4a, 0x4f, 0x52, + 0x4e, 0x61, 0x6e, 0x54, 0x72, 0x41, 0x6d, 0x79, 0x50, 0x50, 0x5a, 0x47, + 0x70, 0x65, 0x52, 0x61, 0x4f, 0x72, 0x76, 0x6a, 0x55, 0x59, 0x47, 0x30, + 0x6c, 0x5a, 0x46, 0x57, 0x4a, 0x6f, 0x38, 0x44, 0x41, 0x2b, 0x44, 0x75, + 0x41, 0x55, 0x6c, 0x77, 0x7a, 0x6e, 0x50, 0x0a, 0x4f, 0x36, 0x51, 0x30, + 0x69, 0x62, 0x64, 0x35, 0x45, 0x69, 0x39, 0x48, 0x78, 0x65, 0x65, 0x70, + 0x6c, 0x32, 0x6e, 0x38, 0x70, 0x6e, 0x64, 0x6e, 0x74, 0x64, 0x39, 0x37, + 0x38, 0x58, 0x70, 0x6c, 0x46, 0x65, 0x52, 0x68, 0x56, 0x6d, 0x55, 0x43, + 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, 0x43, 0x4d, 0x45, 0x41, 0x77, + 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, + 0x0a, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x41, 0x38, + 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, + 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x48, 0x51, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x49, 0x48, + 0x45, 0x6a, 0x4d, 0x7a, 0x31, 0x35, 0x44, 0x44, 0x2f, 0x70, 0x51, 0x77, + 0x49, 0x58, 0x34, 0x77, 0x56, 0x0a, 0x5a, 0x79, 0x46, 0x30, 0x41, 0x64, + 0x2f, 0x66, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, + 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, 0x41, 0x34, + 0x49, 0x43, 0x41, 0x51, 0x41, 0x54, 0x5a, 0x53, 0x4c, 0x31, 0x6a, 0x69, + 0x75, 0x74, 0x52, 0x4f, 0x54, 0x4c, 0x2f, 0x37, 0x6c, 0x6f, 0x35, 0x73, + 0x4f, 0x41, 0x53, 0x44, 0x30, 0x45, 0x65, 0x2f, 0x6f, 0x6a, 0x0a, 0x4c, + 0x33, 0x72, 0x74, 0x4e, 0x74, 0x71, 0x79, 0x7a, 0x6d, 0x33, 0x32, 0x35, + 0x70, 0x37, 0x6c, 0x58, 0x31, 0x69, 0x50, 0x79, 0x7a, 0x63, 0x79, 0x6f, + 0x63, 0x68, 0x6c, 0x74, 0x71, 0x34, 0x34, 0x50, 0x54, 0x55, 0x62, 0x50, + 0x72, 0x77, 0x37, 0x74, 0x67, 0x54, 0x51, 0x76, 0x50, 0x6c, 0x4a, 0x39, + 0x5a, 0x76, 0x33, 0x68, 0x63, 0x55, 0x32, 0x74, 0x73, 0x75, 0x38, 0x2b, + 0x4d, 0x67, 0x35, 0x0a, 0x31, 0x65, 0x52, 0x66, 0x42, 0x37, 0x30, 0x56, + 0x56, 0x4a, 0x64, 0x30, 0x79, 0x73, 0x72, 0x74, 0x54, 0x37, 0x71, 0x36, + 0x5a, 0x48, 0x61, 0x66, 0x67, 0x62, 0x69, 0x45, 0x52, 0x55, 0x6c, 0x4d, + 0x6a, 0x57, 0x2b, 0x69, 0x36, 0x37, 0x48, 0x4d, 0x30, 0x63, 0x4f, 0x55, + 0x32, 0x6b, 0x54, 0x43, 0x35, 0x75, 0x4c, 0x71, 0x47, 0x4f, 0x69, 0x69, + 0x48, 0x79, 0x63, 0x46, 0x75, 0x74, 0x66, 0x6c, 0x0a, 0x31, 0x71, 0x6e, + 0x4e, 0x33, 0x65, 0x39, 0x32, 0x6d, 0x49, 0x30, 0x41, 0x44, 0x73, 0x30, + 0x62, 0x2b, 0x67, 0x4f, 0x33, 0x6a, 0x6f, 0x42, 0x59, 0x44, 0x69, 0x63, + 0x2f, 0x55, 0x76, 0x75, 0x55, 0x6f, 0x73, 0x70, 0x65, 0x5a, 0x63, 0x6e, + 0x57, 0x68, 0x4e, 0x71, 0x35, 0x4e, 0x58, 0x48, 0x7a, 0x4a, 0x73, 0x42, + 0x50, 0x64, 0x2b, 0x61, 0x42, 0x4a, 0x39, 0x4a, 0x33, 0x4f, 0x35, 0x6f, + 0x55, 0x0a, 0x62, 0x33, 0x6e, 0x30, 0x39, 0x74, 0x44, 0x68, 0x30, 0x35, + 0x53, 0x36, 0x30, 0x46, 0x64, 0x52, 0x76, 0x53, 0x63, 0x46, 0x44, 0x63, + 0x48, 0x39, 0x79, 0x42, 0x49, 0x77, 0x37, 0x6d, 0x2b, 0x4e, 0x45, 0x53, + 0x73, 0x49, 0x6e, 0x64, 0x54, 0x55, 0x76, 0x34, 0x42, 0x46, 0x46, 0x4a, + 0x71, 0x49, 0x52, 0x4e, 0x6f, 0x77, 0x36, 0x72, 0x53, 0x6e, 0x34, 0x2b, + 0x37, 0x76, 0x57, 0x34, 0x4c, 0x56, 0x0a, 0x50, 0x74, 0x61, 0x74, 0x65, + 0x4a, 0x4c, 0x62, 0x58, 0x44, 0x7a, 0x7a, 0x32, 0x4b, 0x33, 0x36, 0x75, + 0x47, 0x74, 0x2f, 0x78, 0x44, 0x59, 0x6f, 0x74, 0x67, 0x49, 0x56, 0x69, + 0x6c, 0x51, 0x73, 0x6e, 0x4c, 0x41, 0x58, 0x63, 0x34, 0x37, 0x51, 0x4e, + 0x36, 0x4d, 0x55, 0x50, 0x4a, 0x69, 0x56, 0x41, 0x41, 0x77, 0x70, 0x42, + 0x56, 0x75, 0x65, 0x53, 0x55, 0x6d, 0x78, 0x58, 0x38, 0x66, 0x6a, 0x0a, + 0x79, 0x38, 0x38, 0x6e, 0x5a, 0x59, 0x34, 0x31, 0x46, 0x37, 0x64, 0x58, + 0x79, 0x44, 0x44, 0x5a, 0x51, 0x56, 0x75, 0x35, 0x46, 0x4c, 0x62, 0x6f, + 0x77, 0x67, 0x2b, 0x55, 0x4d, 0x61, 0x65, 0x55, 0x6d, 0x4d, 0x78, 0x71, + 0x36, 0x37, 0x58, 0x68, 0x4a, 0x2f, 0x55, 0x51, 0x71, 0x41, 0x48, 0x6f, + 0x6a, 0x68, 0x4a, 0x69, 0x36, 0x49, 0x6a, 0x4d, 0x74, 0x58, 0x39, 0x47, + 0x6c, 0x38, 0x43, 0x62, 0x0a, 0x45, 0x47, 0x59, 0x34, 0x47, 0x6a, 0x5a, + 0x47, 0x58, 0x79, 0x4a, 0x6f, 0x50, 0x64, 0x2f, 0x4a, 0x78, 0x68, 0x4d, + 0x6e, 0x71, 0x31, 0x4d, 0x47, 0x72, 0x4b, 0x49, 0x38, 0x68, 0x67, 0x5a, + 0x6c, 0x62, 0x37, 0x46, 0x2b, 0x73, 0x53, 0x6c, 0x45, 0x6d, 0x71, 0x4f, + 0x36, 0x53, 0x57, 0x6b, 0x6f, 0x61, 0x59, 0x2f, 0x58, 0x35, 0x56, 0x2b, + 0x74, 0x42, 0x49, 0x5a, 0x6b, 0x62, 0x78, 0x71, 0x67, 0x0a, 0x44, 0x4d, + 0x55, 0x49, 0x59, 0x73, 0x36, 0x41, 0x6f, 0x39, 0x44, 0x7a, 0x37, 0x47, + 0x6a, 0x65, 0x76, 0x6a, 0x50, 0x48, 0x46, 0x31, 0x74, 0x2f, 0x67, 0x4d, + 0x52, 0x4d, 0x54, 0x4c, 0x47, 0x6d, 0x68, 0x49, 0x72, 0x44, 0x4f, 0x37, + 0x67, 0x4a, 0x7a, 0x52, 0x53, 0x42, 0x75, 0x68, 0x6a, 0x6a, 0x56, 0x46, + 0x63, 0x32, 0x2f, 0x74, 0x73, 0x76, 0x66, 0x45, 0x65, 0x68, 0x4f, 0x6a, + 0x50, 0x49, 0x0a, 0x2b, 0x56, 0x67, 0x37, 0x52, 0x45, 0x2b, 0x78, 0x79, + 0x67, 0x4b, 0x4a, 0x42, 0x4a, 0x59, 0x6f, 0x61, 0x4d, 0x56, 0x4c, 0x75, + 0x43, 0x61, 0x4a, 0x75, 0x39, 0x59, 0x7a, 0x4c, 0x31, 0x44, 0x56, 0x2f, + 0x70, 0x71, 0x4a, 0x75, 0x68, 0x67, 0x79, 0x6b, 0x6c, 0x54, 0x47, 0x57, + 0x2b, 0x43, 0x64, 0x2b, 0x56, 0x37, 0x6c, 0x44, 0x53, 0x4b, 0x62, 0x39, + 0x74, 0x72, 0x69, 0x79, 0x43, 0x47, 0x79, 0x0a, 0x59, 0x69, 0x47, 0x71, + 0x68, 0x6b, 0x43, 0x79, 0x4c, 0x6d, 0x54, 0x54, 0x58, 0x38, 0x6a, 0x6a, + 0x66, 0x68, 0x46, 0x6e, 0x52, 0x52, 0x38, 0x46, 0x2f, 0x75, 0x4f, 0x69, + 0x37, 0x37, 0x4f, 0x6f, 0x73, 0x2f, 0x4e, 0x39, 0x6a, 0x2f, 0x67, 0x4d, + 0x48, 0x79, 0x49, 0x66, 0x4c, 0x58, 0x43, 0x30, 0x75, 0x41, 0x45, 0x30, + 0x64, 0x6a, 0x41, 0x41, 0x35, 0x53, 0x4e, 0x34, 0x70, 0x31, 0x62, 0x58, + 0x0a, 0x55, 0x42, 0x2b, 0x4b, 0x2b, 0x77, 0x62, 0x31, 0x77, 0x68, 0x6e, + 0x77, 0x30, 0x41, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x55, 0x43, + 0x41, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x55, 0x6e, 0x69, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, + 0x20, 0x43, 0x4e, 0x3d, 0x55, 0x43, 0x41, 0x20, 0x45, 0x78, 0x74, 0x65, + 0x6e, 0x64, 0x65, 0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x4f, 0x3d, 0x55, + 0x6e, 0x69, 0x54, 0x72, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x55, 0x43, 0x41, 0x20, 0x45, 0x78, + 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x31, 0x30, + 0x36, 0x31, 0x30, 0x30, 0x32, 0x37, 0x37, 0x35, 0x35, 0x36, 0x34, 0x38, + 0x36, 0x35, 0x32, 0x39, 0x37, 0x33, 0x36, 0x36, 0x39, 0x39, 0x35, 0x38, + 0x37, 0x39, 0x37, 0x38, 0x35, 0x37, 0x33, 0x36, 0x30, 0x37, 0x30, 0x30, + 0x38, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x31, 0x3a, + 0x66, 0x33, 0x3a, 0x35, 0x66, 0x3a, 0x34, 0x33, 0x3a, 0x63, 0x36, 0x3a, + 0x33, 0x34, 0x3a, 0x39, 0x62, 0x3a, 0x64, 0x61, 0x3a, 0x62, 0x66, 0x3a, + 0x38, 0x63, 0x3a, 0x37, 0x65, 0x3a, 0x30, 0x35, 0x3a, 0x35, 0x33, 0x3a, + 0x61, 0x64, 0x3a, 0x39, 0x36, 0x3a, 0x65, 0x32, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x61, 0x33, 0x3a, 0x61, 0x31, 0x3a, 0x62, + 0x30, 0x3a, 0x36, 0x66, 0x3a, 0x32, 0x34, 0x3a, 0x36, 0x31, 0x3a, 0x32, + 0x33, 0x3a, 0x34, 0x61, 0x3a, 0x65, 0x33, 0x3a, 0x33, 0x36, 0x3a, 0x61, + 0x35, 0x3a, 0x63, 0x32, 0x3a, 0x33, 0x37, 0x3a, 0x66, 0x63, 0x3a, 0x61, + 0x36, 0x3a, 0x66, 0x66, 0x3a, 0x64, 0x64, 0x3a, 0x66, 0x30, 0x3a, 0x64, + 0x37, 0x3a, 0x33, 0x61, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, + 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x64, 0x34, 0x3a, 0x33, 0x61, 0x3a, 0x66, 0x39, 0x3a, + 0x62, 0x33, 0x3a, 0x35, 0x34, 0x3a, 0x37, 0x33, 0x3a, 0x37, 0x35, 0x3a, + 0x35, 0x63, 0x3a, 0x39, 0x36, 0x3a, 0x38, 0x34, 0x3a, 0x66, 0x63, 0x3a, + 0x30, 0x36, 0x3a, 0x64, 0x37, 0x3a, 0x64, 0x38, 0x3a, 0x63, 0x62, 0x3a, + 0x37, 0x30, 0x3a, 0x65, 0x65, 0x3a, 0x35, 0x63, 0x3a, 0x32, 0x38, 0x3a, + 0x65, 0x37, 0x3a, 0x37, 0x33, 0x3a, 0x66, 0x62, 0x3a, 0x32, 0x39, 0x3a, + 0x34, 0x65, 0x3a, 0x62, 0x34, 0x3a, 0x31, 0x65, 0x3a, 0x65, 0x37, 0x3a, + 0x31, 0x37, 0x3a, 0x32, 0x32, 0x3a, 0x39, 0x32, 0x3a, 0x34, 0x64, 0x3a, + 0x32, 0x34, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, + 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x57, + 0x6a, 0x43, 0x43, 0x41, 0x30, 0x4b, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, + 0x67, 0x49, 0x51, 0x54, 0x39, 0x49, 0x72, 0x6a, 0x2f, 0x56, 0x6b, 0x79, + 0x44, 0x4f, 0x65, 0x54, 0x7a, 0x52, 0x59, 0x5a, 0x69, 0x4e, 0x77, 0x59, + 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, + 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x48, 0x0a, + 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, + 0x45, 0x77, 0x4a, 0x44, 0x54, 0x6a, 0x45, 0x52, 0x4d, 0x41, 0x38, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x49, 0x56, 0x57, 0x35, 0x70, + 0x56, 0x48, 0x4a, 0x31, 0x63, 0x33, 0x51, 0x78, 0x4a, 0x54, 0x41, 0x6a, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x48, 0x46, 0x56, 0x44, + 0x51, 0x53, 0x42, 0x46, 0x0a, 0x65, 0x48, 0x52, 0x6c, 0x62, 0x6d, 0x52, + 0x6c, 0x5a, 0x43, 0x42, 0x57, 0x59, 0x57, 0x78, 0x70, 0x5a, 0x47, 0x46, + 0x30, 0x61, 0x57, 0x39, 0x75, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, + 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x55, 0x77, 0x4d, 0x7a, 0x45, + 0x7a, 0x4d, 0x44, 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, + 0x4e, 0x4d, 0x7a, 0x67, 0x78, 0x4d, 0x6a, 0x4d, 0x78, 0x0a, 0x4d, 0x44, + 0x41, 0x77, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x6a, 0x42, 0x48, 0x4d, 0x51, + 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, + 0x4a, 0x44, 0x54, 0x6a, 0x45, 0x52, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x67, 0x77, 0x49, 0x56, 0x57, 0x35, 0x70, 0x56, 0x48, + 0x4a, 0x31, 0x63, 0x33, 0x51, 0x78, 0x4a, 0x54, 0x41, 0x6a, 0x42, 0x67, + 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x4d, 0x4d, 0x48, 0x46, 0x56, 0x44, 0x51, + 0x53, 0x42, 0x46, 0x65, 0x48, 0x52, 0x6c, 0x62, 0x6d, 0x52, 0x6c, 0x5a, + 0x43, 0x42, 0x57, 0x59, 0x57, 0x78, 0x70, 0x5a, 0x47, 0x46, 0x30, 0x61, + 0x57, 0x39, 0x75, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x77, 0x67, + 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, + 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x0a, 0x41, 0x51, 0x55, 0x41, + 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, 0x4b, + 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51, 0x43, 0x70, 0x43, 0x51, 0x63, 0x6f, + 0x45, 0x77, 0x4b, 0x77, 0x6d, 0x65, 0x42, 0x6b, 0x71, 0x68, 0x35, 0x44, + 0x46, 0x6e, 0x70, 0x7a, 0x73, 0x5a, 0x47, 0x67, 0x64, 0x54, 0x36, 0x6f, + 0x2b, 0x75, 0x4d, 0x34, 0x41, 0x48, 0x72, 0x73, 0x69, 0x57, 0x6f, 0x67, + 0x0a, 0x44, 0x34, 0x76, 0x46, 0x73, 0x4a, 0x73, 0x7a, 0x41, 0x31, 0x71, + 0x47, 0x78, 0x6c, 0x69, 0x47, 0x31, 0x63, 0x47, 0x46, 0x75, 0x30, 0x2f, + 0x47, 0x6e, 0x45, 0x42, 0x4e, 0x79, 0x72, 0x37, 0x75, 0x61, 0x5a, 0x61, + 0x34, 0x72, 0x59, 0x45, 0x77, 0x6d, 0x6e, 0x79, 0x53, 0x42, 0x65, 0x73, + 0x46, 0x4b, 0x35, 0x70, 0x49, 0x30, 0x4c, 0x68, 0x32, 0x50, 0x70, 0x62, + 0x49, 0x49, 0x4c, 0x76, 0x53, 0x0a, 0x73, 0x50, 0x47, 0x50, 0x32, 0x4b, + 0x78, 0x46, 0x52, 0x76, 0x2b, 0x71, 0x5a, 0x32, 0x43, 0x30, 0x64, 0x33, + 0x35, 0x71, 0x48, 0x7a, 0x77, 0x61, 0x55, 0x6e, 0x6f, 0x45, 0x50, 0x51, + 0x63, 0x38, 0x68, 0x51, 0x32, 0x45, 0x30, 0x42, 0x39, 0x32, 0x43, 0x76, + 0x64, 0x71, 0x46, 0x4e, 0x39, 0x79, 0x34, 0x7a, 0x52, 0x38, 0x56, 0x30, + 0x35, 0x57, 0x41, 0x54, 0x35, 0x35, 0x38, 0x61, 0x6f, 0x70, 0x0a, 0x4f, + 0x32, 0x7a, 0x36, 0x2b, 0x49, 0x39, 0x74, 0x54, 0x63, 0x67, 0x31, 0x33, + 0x36, 0x37, 0x72, 0x33, 0x43, 0x54, 0x75, 0x65, 0x55, 0x57, 0x6e, 0x68, + 0x62, 0x59, 0x46, 0x69, 0x4e, 0x36, 0x49, 0x58, 0x53, 0x56, 0x38, 0x6c, + 0x32, 0x52, 0x6e, 0x43, 0x64, 0x6d, 0x2f, 0x57, 0x68, 0x55, 0x46, 0x68, + 0x76, 0x4d, 0x4a, 0x48, 0x75, 0x78, 0x59, 0x4d, 0x6a, 0x4d, 0x52, 0x38, + 0x33, 0x64, 0x6b, 0x0a, 0x73, 0x48, 0x59, 0x66, 0x35, 0x42, 0x41, 0x31, + 0x46, 0x78, 0x76, 0x79, 0x44, 0x72, 0x46, 0x73, 0x70, 0x43, 0x71, 0x6a, + 0x63, 0x2f, 0x77, 0x4a, 0x48, 0x78, 0x34, 0x79, 0x47, 0x56, 0x4d, 0x52, + 0x35, 0x39, 0x6d, 0x7a, 0x4c, 0x43, 0x35, 0x32, 0x4c, 0x71, 0x47, 0x6a, + 0x33, 0x6e, 0x35, 0x71, 0x69, 0x41, 0x6e, 0x6f, 0x38, 0x67, 0x65, 0x4b, + 0x2b, 0x4c, 0x4c, 0x4e, 0x45, 0x4f, 0x66, 0x69, 0x0a, 0x63, 0x30, 0x43, + 0x54, 0x75, 0x77, 0x6a, 0x52, 0x50, 0x2b, 0x48, 0x38, 0x43, 0x35, 0x53, + 0x7a, 0x4a, 0x65, 0x39, 0x38, 0x70, 0x74, 0x66, 0x52, 0x72, 0x35, 0x2f, + 0x2f, 0x6c, 0x70, 0x72, 0x31, 0x6b, 0x58, 0x75, 0x59, 0x43, 0x33, 0x66, + 0x55, 0x66, 0x75, 0x67, 0x48, 0x30, 0x6d, 0x4b, 0x31, 0x6c, 0x54, 0x6e, + 0x6a, 0x38, 0x2f, 0x46, 0x74, 0x44, 0x77, 0x35, 0x6c, 0x68, 0x49, 0x70, + 0x6a, 0x0a, 0x56, 0x4d, 0x57, 0x41, 0x74, 0x75, 0x43, 0x65, 0x53, 0x33, + 0x31, 0x48, 0x4a, 0x71, 0x63, 0x42, 0x43, 0x46, 0x33, 0x52, 0x69, 0x4a, + 0x37, 0x58, 0x77, 0x7a, 0x4a, 0x45, 0x2b, 0x6f, 0x4a, 0x4b, 0x43, 0x6d, + 0x68, 0x55, 0x66, 0x7a, 0x68, 0x54, 0x41, 0x38, 0x79, 0x6b, 0x41, 0x44, + 0x4e, 0x6b, 0x55, 0x56, 0x6b, 0x4c, 0x6f, 0x34, 0x4b, 0x52, 0x65, 0x6c, + 0x37, 0x73, 0x46, 0x73, 0x4c, 0x7a, 0x0a, 0x4b, 0x75, 0x5a, 0x69, 0x32, + 0x69, 0x72, 0x62, 0x57, 0x57, 0x49, 0x51, 0x4a, 0x55, 0x6f, 0x71, 0x67, + 0x51, 0x74, 0x48, 0x42, 0x30, 0x4d, 0x47, 0x63, 0x49, 0x66, 0x53, 0x2b, + 0x70, 0x4d, 0x52, 0x4b, 0x58, 0x70, 0x49, 0x54, 0x65, 0x75, 0x55, 0x78, + 0x33, 0x42, 0x4e, 0x72, 0x32, 0x66, 0x56, 0x55, 0x62, 0x47, 0x41, 0x49, + 0x41, 0x45, 0x42, 0x74, 0x48, 0x6f, 0x49, 0x70, 0x70, 0x42, 0x2f, 0x0a, + 0x54, 0x75, 0x44, 0x76, 0x42, 0x30, 0x47, 0x48, 0x72, 0x32, 0x71, 0x6c, + 0x58, 0x6f, 0x76, 0x37, 0x7a, 0x31, 0x43, 0x79, 0x6d, 0x6c, 0x53, 0x76, + 0x77, 0x34, 0x6d, 0x36, 0x57, 0x43, 0x33, 0x31, 0x4d, 0x4a, 0x69, 0x78, + 0x4e, 0x6e, 0x49, 0x35, 0x66, 0x6b, 0x6b, 0x45, 0x2f, 0x53, 0x6d, 0x6e, + 0x54, 0x48, 0x6e, 0x6b, 0x42, 0x56, 0x66, 0x62, 0x6c, 0x4c, 0x6b, 0x57, + 0x55, 0x34, 0x31, 0x47, 0x0a, 0x73, 0x78, 0x32, 0x56, 0x59, 0x56, 0x64, + 0x57, 0x66, 0x36, 0x2f, 0x77, 0x46, 0x6c, 0x74, 0x68, 0x57, 0x47, 0x38, + 0x32, 0x55, 0x42, 0x45, 0x4c, 0x32, 0x4b, 0x77, 0x72, 0x6c, 0x52, 0x59, + 0x61, 0x44, 0x68, 0x38, 0x49, 0x7a, 0x54, 0x59, 0x30, 0x5a, 0x52, 0x42, + 0x69, 0x5a, 0x74, 0x57, 0x41, 0x58, 0x78, 0x51, 0x67, 0x58, 0x79, 0x30, + 0x4d, 0x6f, 0x48, 0x67, 0x4b, 0x61, 0x4e, 0x59, 0x73, 0x0a, 0x31, 0x2b, + 0x6c, 0x76, 0x4b, 0x39, 0x4a, 0x4b, 0x42, 0x5a, 0x50, 0x38, 0x6e, 0x6d, + 0x39, 0x72, 0x5a, 0x2f, 0x2b, 0x49, 0x38, 0x55, 0x36, 0x6c, 0x61, 0x55, + 0x70, 0x53, 0x4e, 0x77, 0x58, 0x71, 0x78, 0x68, 0x61, 0x4e, 0x30, 0x73, + 0x53, 0x5a, 0x30, 0x59, 0x49, 0x72, 0x4f, 0x37, 0x6f, 0x31, 0x64, 0x66, + 0x64, 0x52, 0x55, 0x56, 0x6a, 0x7a, 0x79, 0x41, 0x66, 0x64, 0x35, 0x4c, + 0x51, 0x44, 0x0a, 0x66, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, + 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x32, 0x58, 0x51, 0x36, 0x35, + 0x44, 0x41, 0x39, 0x44, 0x66, 0x63, 0x53, 0x33, 0x48, 0x35, 0x61, 0x42, + 0x5a, 0x38, 0x65, 0x4e, 0x4a, 0x72, 0x33, 0x34, 0x52, 0x51, 0x77, 0x44, + 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x0a, 0x41, 0x51, 0x48, 0x2f, + 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f, + 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, + 0x42, 0x41, 0x4d, 0x43, 0x41, 0x59, 0x59, 0x77, 0x44, 0x51, 0x59, 0x4a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, + 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x42, 0x41, 0x44, 0x61, 0x4e, + 0x0a, 0x6c, 0x38, 0x78, 0x43, 0x46, 0x57, 0x51, 0x70, 0x4e, 0x35, 0x73, + 0x6d, 0x4c, 0x4e, 0x62, 0x37, 0x72, 0x68, 0x56, 0x70, 0x4c, 0x47, 0x73, + 0x61, 0x47, 0x76, 0x64, 0x66, 0x74, 0x76, 0x6b, 0x48, 0x54, 0x46, 0x6e, + 0x71, 0x38, 0x38, 0x6e, 0x49, 0x75, 0x61, 0x37, 0x4d, 0x75, 0x69, 0x35, + 0x36, 0x33, 0x4d, 0x44, 0x31, 0x73, 0x43, 0x33, 0x41, 0x4f, 0x36, 0x2b, + 0x66, 0x63, 0x41, 0x55, 0x52, 0x0a, 0x61, 0x70, 0x38, 0x6c, 0x54, 0x77, + 0x45, 0x70, 0x63, 0x4f, 0x50, 0x6c, 0x44, 0x4f, 0x48, 0x71, 0x57, 0x6e, + 0x7a, 0x63, 0x53, 0x62, 0x76, 0x42, 0x48, 0x69, 0x71, 0x42, 0x39, 0x52, + 0x5a, 0x4c, 0x63, 0x70, 0x48, 0x49, 0x6f, 0x6a, 0x47, 0x35, 0x71, 0x74, + 0x72, 0x38, 0x6e, 0x52, 0x2f, 0x7a, 0x58, 0x55, 0x41, 0x43, 0x45, 0x2f, + 0x78, 0x4f, 0x48, 0x41, 0x62, 0x4b, 0x73, 0x78, 0x53, 0x51, 0x0a, 0x56, + 0x42, 0x63, 0x5a, 0x45, 0x68, 0x72, 0x78, 0x48, 0x39, 0x63, 0x4d, 0x61, + 0x56, 0x72, 0x32, 0x63, 0x58, 0x6a, 0x30, 0x6c, 0x48, 0x32, 0x52, 0x43, + 0x34, 0x37, 0x73, 0x6b, 0x46, 0x53, 0x4f, 0x76, 0x47, 0x2b, 0x68, 0x54, + 0x4b, 0x76, 0x38, 0x64, 0x47, 0x54, 0x39, 0x63, 0x5a, 0x72, 0x34, 0x51, + 0x51, 0x65, 0x68, 0x7a, 0x5a, 0x48, 0x6b, 0x50, 0x4a, 0x72, 0x67, 0x6d, + 0x7a, 0x49, 0x35, 0x0a, 0x63, 0x36, 0x73, 0x71, 0x31, 0x57, 0x6e, 0x49, + 0x65, 0x4a, 0x45, 0x6d, 0x4d, 0x58, 0x33, 0x69, 0x78, 0x7a, 0x44, 0x78, + 0x2f, 0x42, 0x52, 0x34, 0x64, 0x78, 0x49, 0x4f, 0x45, 0x2f, 0x54, 0x64, + 0x46, 0x70, 0x53, 0x2f, 0x53, 0x32, 0x64, 0x37, 0x63, 0x46, 0x4f, 0x46, + 0x79, 0x72, 0x43, 0x37, 0x38, 0x7a, 0x68, 0x4e, 0x4c, 0x4a, 0x41, 0x35, + 0x77, 0x41, 0x33, 0x43, 0x58, 0x57, 0x76, 0x70, 0x0a, 0x34, 0x75, 0x58, + 0x56, 0x69, 0x49, 0x33, 0x57, 0x4c, 0x4c, 0x2b, 0x72, 0x47, 0x37, 0x36, + 0x31, 0x4b, 0x49, 0x63, 0x53, 0x46, 0x33, 0x52, 0x75, 0x2f, 0x48, 0x33, + 0x38, 0x6a, 0x39, 0x43, 0x48, 0x4a, 0x72, 0x41, 0x62, 0x2b, 0x37, 0x6c, + 0x73, 0x71, 0x2b, 0x4b, 0x65, 0x50, 0x52, 0x58, 0x42, 0x4f, 0x79, 0x35, + 0x6e, 0x41, 0x6c, 0x69, 0x52, 0x6e, 0x2b, 0x2f, 0x34, 0x51, 0x68, 0x38, + 0x73, 0x0a, 0x74, 0x32, 0x6a, 0x31, 0x64, 0x61, 0x33, 0x50, 0x74, 0x66, + 0x62, 0x2f, 0x45, 0x58, 0x33, 0x43, 0x38, 0x43, 0x53, 0x6c, 0x72, 0x64, + 0x50, 0x36, 0x6f, 0x44, 0x79, 0x70, 0x2b, 0x6c, 0x33, 0x63, 0x70, 0x61, + 0x44, 0x76, 0x52, 0x4b, 0x53, 0x2b, 0x31, 0x75, 0x6a, 0x6c, 0x35, 0x42, + 0x4f, 0x57, 0x46, 0x33, 0x73, 0x47, 0x50, 0x6a, 0x4c, 0x74, 0x78, 0x37, + 0x64, 0x43, 0x76, 0x48, 0x61, 0x6a, 0x0a, 0x32, 0x47, 0x55, 0x34, 0x4b, + 0x7a, 0x67, 0x31, 0x55, 0x53, 0x45, 0x4f, 0x44, 0x6d, 0x38, 0x75, 0x4e, + 0x42, 0x4e, 0x41, 0x34, 0x53, 0x74, 0x6e, 0x44, 0x47, 0x31, 0x4b, 0x51, + 0x54, 0x41, 0x59, 0x49, 0x31, 0x6f, 0x79, 0x56, 0x5a, 0x6e, 0x4a, 0x46, + 0x2b, 0x41, 0x38, 0x33, 0x76, 0x62, 0x73, 0x65, 0x61, 0x30, 0x72, 0x57, + 0x42, 0x6d, 0x69, 0x72, 0x53, 0x77, 0x69, 0x47, 0x70, 0x57, 0x4f, 0x0a, + 0x76, 0x70, 0x61, 0x51, 0x58, 0x55, 0x4a, 0x58, 0x78, 0x50, 0x6b, 0x55, + 0x41, 0x7a, 0x55, 0x72, 0x48, 0x43, 0x31, 0x52, 0x56, 0x77, 0x69, 0x6e, + 0x4f, 0x74, 0x34, 0x2f, 0x35, 0x4d, 0x69, 0x30, 0x41, 0x33, 0x50, 0x43, + 0x77, 0x53, 0x61, 0x41, 0x75, 0x77, 0x74, 0x43, 0x48, 0x36, 0x30, 0x4e, + 0x72, 0x79, 0x5a, 0x79, 0x32, 0x73, 0x79, 0x2b, 0x73, 0x36, 0x4f, 0x44, + 0x57, 0x41, 0x32, 0x43, 0x0a, 0x78, 0x52, 0x39, 0x47, 0x55, 0x65, 0x4f, + 0x63, 0x47, 0x4d, 0x79, 0x4e, 0x6d, 0x34, 0x33, 0x73, 0x53, 0x65, 0x74, + 0x31, 0x55, 0x4e, 0x57, 0x4d, 0x4b, 0x46, 0x6e, 0x4b, 0x64, 0x44, 0x54, + 0x61, 0x6a, 0x41, 0x73, 0x68, 0x71, 0x78, 0x37, 0x71, 0x47, 0x2b, 0x58, + 0x48, 0x2f, 0x52, 0x55, 0x2b, 0x77, 0x42, 0x65, 0x71, 0x2b, 0x79, 0x4e, + 0x75, 0x4a, 0x6b, 0x62, 0x4c, 0x2b, 0x76, 0x6d, 0x78, 0x0a, 0x63, 0x6d, + 0x74, 0x70, 0x7a, 0x79, 0x4b, 0x45, 0x43, 0x32, 0x49, 0x50, 0x72, 0x4e, + 0x6b, 0x5a, 0x41, 0x4a, 0x53, 0x69, 0x64, 0x6a, 0x7a, 0x55, 0x4c, 0x5a, + 0x72, 0x74, 0x42, 0x4a, 0x34, 0x74, 0x42, 0x6d, 0x49, 0x51, 0x4e, 0x31, + 0x49, 0x63, 0x68, 0x58, 0x49, 0x62, 0x4a, 0x2b, 0x58, 0x4d, 0x78, 0x6a, + 0x48, 0x73, 0x4e, 0x2b, 0x78, 0x6a, 0x57, 0x5a, 0x73, 0x4c, 0x48, 0x58, + 0x62, 0x4d, 0x0a, 0x66, 0x6a, 0x4b, 0x61, 0x69, 0x4a, 0x55, 0x49, 0x4e, + 0x6c, 0x4b, 0x37, 0x33, 0x6e, 0x5a, 0x66, 0x64, 0x6b, 0x6c, 0x4a, 0x72, + 0x58, 0x2b, 0x39, 0x5a, 0x53, 0x43, 0x79, 0x79, 0x63, 0x45, 0x72, 0x64, + 0x68, 0x68, 0x32, 0x6e, 0x31, 0x61, 0x78, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, + 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x67, 0x6e, 0x61, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, 0x3d, 0x44, 0x68, 0x69, 0x6d, 0x79, + 0x6f, 0x74, 0x69, 0x73, 0x20, 0x4f, 0x55, 0x3d, 0x30, 0x30, 0x30, 0x32, + 0x20, 0x34, 0x38, 0x31, 0x34, 0x36, 0x33, 0x30, 0x38, 0x31, 0x30, 0x30, + 0x30, 0x33, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x67, + 0x6e, 0x61, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x4f, + 0x3d, 0x44, 0x68, 0x69, 0x6d, 0x79, 0x6f, 0x74, 0x69, 0x73, 0x20, 0x4f, + 0x55, 0x3d, 0x30, 0x30, 0x30, 0x32, 0x20, 0x34, 0x38, 0x31, 0x34, 0x36, + 0x33, 0x30, 0x38, 0x31, 0x30, 0x30, 0x30, 0x33, 0x36, 0x0a, 0x23, 0x20, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x67, 0x6e, 0x61, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, + 0x32, 0x36, 0x39, 0x37, 0x31, 0x34, 0x34, 0x31, 0x38, 0x38, 0x37, 0x30, + 0x35, 0x39, 0x37, 0x38, 0x34, 0x34, 0x36, 0x39, 0x33, 0x36, 0x36, 0x31, + 0x30, 0x35, 0x34, 0x33, 0x33, 0x34, 0x38, 0x36, 0x32, 0x30, 0x37, 0x35, + 0x36, 0x31, 0x37, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x30, + 0x65, 0x3a, 0x35, 0x63, 0x3a, 0x33, 0x30, 0x3a, 0x36, 0x32, 0x3a, 0x32, + 0x37, 0x3a, 0x65, 0x62, 0x3a, 0x35, 0x62, 0x3a, 0x62, 0x63, 0x3a, 0x64, + 0x37, 0x3a, 0x61, 0x65, 0x3a, 0x36, 0x32, 0x3a, 0x62, 0x61, 0x3a, 0x65, + 0x39, 0x3a, 0x64, 0x35, 0x3a, 0x64, 0x66, 0x3a, 0x37, 0x37, 0x0a, 0x23, + 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x32, 0x64, 0x3a, 0x30, 0x64, + 0x3a, 0x35, 0x32, 0x3a, 0x31, 0x34, 0x3a, 0x66, 0x66, 0x3a, 0x39, 0x65, + 0x3a, 0x61, 0x64, 0x3a, 0x39, 0x39, 0x3a, 0x32, 0x34, 0x3a, 0x30, 0x31, + 0x3a, 0x37, 0x34, 0x3a, 0x32, 0x30, 0x3a, 0x34, 0x37, 0x3a, 0x36, 0x65, + 0x3a, 0x36, 0x63, 0x3a, 0x38, 0x35, 0x3a, 0x32, 0x37, 0x3a, 0x32, 0x37, + 0x3a, 0x66, 0x35, 0x3a, 0x34, 0x33, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x64, 0x34, 0x3a, 0x38, 0x64, 0x3a, 0x33, + 0x64, 0x3a, 0x32, 0x33, 0x3a, 0x65, 0x65, 0x3a, 0x64, 0x62, 0x3a, 0x35, + 0x30, 0x3a, 0x61, 0x34, 0x3a, 0x35, 0x39, 0x3a, 0x65, 0x35, 0x3a, 0x35, + 0x31, 0x3a, 0x39, 0x37, 0x3a, 0x36, 0x30, 0x3a, 0x31, 0x63, 0x3a, 0x32, + 0x37, 0x3a, 0x37, 0x37, 0x3a, 0x34, 0x62, 0x3a, 0x39, 0x64, 0x3a, 0x37, + 0x62, 0x3a, 0x31, 0x38, 0x3a, 0x63, 0x39, 0x3a, 0x34, 0x64, 0x3a, 0x35, + 0x61, 0x3a, 0x30, 0x35, 0x3a, 0x39, 0x35, 0x3a, 0x31, 0x31, 0x3a, 0x61, + 0x31, 0x3a, 0x30, 0x32, 0x3a, 0x35, 0x30, 0x3a, 0x62, 0x39, 0x3a, 0x33, + 0x31, 0x3a, 0x36, 0x38, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, + 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x47, 0x57, 0x7a, 0x43, 0x43, 0x42, 0x45, 0x4f, 0x67, 0x41, 0x77, 0x49, + 0x42, 0x41, 0x67, 0x49, 0x52, 0x41, 0x4d, 0x72, 0x70, 0x47, 0x34, 0x6e, + 0x78, 0x56, 0x51, 0x4d, 0x4e, 0x6f, 0x2b, 0x5a, 0x42, 0x62, 0x63, 0x54, + 0x6a, 0x70, 0x75, 0x45, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, + 0x77, 0x0a, 0x57, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x6c, 0x49, 0x78, 0x45, 0x6a, + 0x41, 0x51, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x43, 0x55, + 0x52, 0x6f, 0x61, 0x57, 0x31, 0x35, 0x62, 0x33, 0x52, 0x70, 0x63, 0x7a, + 0x45, 0x63, 0x4d, 0x42, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x77, + 0x77, 0x54, 0x4d, 0x44, 0x41, 0x77, 0x0a, 0x4d, 0x69, 0x41, 0x30, 0x4f, + 0x44, 0x45, 0x30, 0x4e, 0x6a, 0x4d, 0x77, 0x4f, 0x44, 0x45, 0x77, 0x4d, + 0x44, 0x41, 0x7a, 0x4e, 0x6a, 0x45, 0x5a, 0x4d, 0x42, 0x63, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x51, 0x51, 0x32, 0x56, 0x79, 0x64, + 0x47, 0x6c, 0x6e, 0x62, 0x6d, 0x45, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, + 0x43, 0x42, 0x44, 0x51, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x0a, + 0x4d, 0x7a, 0x45, 0x77, 0x4d, 0x44, 0x45, 0x77, 0x4f, 0x44, 0x4d, 0x79, + 0x4d, 0x6a, 0x64, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4d, 0x7a, 0x45, 0x77, + 0x4d, 0x44, 0x45, 0x77, 0x4f, 0x44, 0x4d, 0x79, 0x4d, 0x6a, 0x64, 0x61, + 0x4d, 0x46, 0x6f, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x5a, 0x53, 0x4d, 0x52, 0x49, 0x77, + 0x45, 0x41, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, 0x6c, + 0x45, 0x61, 0x47, 0x6c, 0x74, 0x65, 0x57, 0x39, 0x30, 0x61, 0x58, 0x4d, + 0x78, 0x48, 0x44, 0x41, 0x61, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, + 0x4d, 0x45, 0x7a, 0x41, 0x77, 0x4d, 0x44, 0x49, 0x67, 0x4e, 0x44, 0x67, + 0x78, 0x4e, 0x44, 0x59, 0x7a, 0x4d, 0x44, 0x67, 0x78, 0x4d, 0x44, 0x41, + 0x77, 0x4d, 0x7a, 0x59, 0x78, 0x47, 0x54, 0x41, 0x58, 0x0a, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x45, 0x45, 0x4e, 0x6c, 0x63, 0x6e, + 0x52, 0x70, 0x5a, 0x32, 0x35, 0x68, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, + 0x51, 0x67, 0x51, 0x30, 0x45, 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, + 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, + 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, + 0x41, 0x77, 0x0a, 0x67, 0x67, 0x49, 0x4b, 0x41, 0x6f, 0x49, 0x43, 0x41, + 0x51, 0x44, 0x4e, 0x47, 0x44, 0x6c, 0x6c, 0x47, 0x6c, 0x6d, 0x78, 0x36, + 0x6d, 0x51, 0x57, 0x44, 0x6f, 0x79, 0x55, 0x4a, 0x4a, 0x56, 0x38, 0x67, + 0x39, 0x50, 0x46, 0x4f, 0x53, 0x62, 0x63, 0x44, 0x4f, 0x38, 0x57, 0x56, + 0x34, 0x33, 0x58, 0x32, 0x4b, 0x79, 0x6a, 0x51, 0x6e, 0x2b, 0x43, 0x79, + 0x75, 0x33, 0x4e, 0x57, 0x39, 0x73, 0x4f, 0x0a, 0x74, 0x79, 0x33, 0x74, + 0x52, 0x51, 0x67, 0x58, 0x73, 0x74, 0x6d, 0x7a, 0x79, 0x39, 0x59, 0x58, + 0x55, 0x6e, 0x49, 0x6f, 0x32, 0x34, 0x35, 0x4f, 0x6e, 0x6f, 0x71, 0x32, + 0x43, 0x2f, 0x6d, 0x65, 0x68, 0x4a, 0x70, 0x4e, 0x64, 0x74, 0x34, 0x69, + 0x4b, 0x56, 0x7a, 0x53, 0x73, 0x39, 0x49, 0x47, 0x50, 0x6a, 0x41, 0x35, + 0x71, 0x58, 0x53, 0x6a, 0x6b, 0x6c, 0x59, 0x63, 0x6f, 0x57, 0x39, 0x4d, + 0x0a, 0x43, 0x69, 0x42, 0x74, 0x6e, 0x79, 0x4e, 0x36, 0x74, 0x4d, 0x62, + 0x61, 0x4c, 0x4f, 0x51, 0x64, 0x4c, 0x4e, 0x79, 0x7a, 0x4b, 0x4e, 0x41, + 0x54, 0x38, 0x6b, 0x78, 0x4f, 0x41, 0x6b, 0x6d, 0x68, 0x56, 0x45, 0x43, + 0x65, 0x35, 0x75, 0x55, 0x46, 0x6f, 0x43, 0x32, 0x45, 0x79, 0x50, 0x2b, + 0x59, 0x62, 0x4e, 0x44, 0x72, 0x69, 0x68, 0x71, 0x45, 0x43, 0x42, 0x36, + 0x33, 0x61, 0x43, 0x50, 0x75, 0x0a, 0x49, 0x39, 0x56, 0x77, 0x7a, 0x6d, + 0x31, 0x52, 0x61, 0x52, 0x44, 0x75, 0x6f, 0x58, 0x72, 0x43, 0x30, 0x53, + 0x49, 0x78, 0x77, 0x6f, 0x4b, 0x46, 0x30, 0x76, 0x4a, 0x56, 0x64, 0x6c, + 0x42, 0x38, 0x4a, 0x58, 0x72, 0x4a, 0x68, 0x46, 0x77, 0x4c, 0x72, 0x4e, + 0x31, 0x43, 0x54, 0x69, 0x76, 0x6e, 0x67, 0x71, 0x49, 0x6b, 0x69, 0x63, + 0x75, 0x51, 0x73, 0x74, 0x44, 0x75, 0x49, 0x37, 0x70, 0x6d, 0x0a, 0x54, + 0x4c, 0x74, 0x69, 0x70, 0x50, 0x6c, 0x54, 0x57, 0x6d, 0x52, 0x37, 0x66, + 0x4a, 0x6a, 0x36, 0x6f, 0x30, 0x69, 0x65, 0x44, 0x35, 0x57, 0x75, 0x70, + 0x78, 0x6a, 0x30, 0x61, 0x75, 0x77, 0x75, 0x41, 0x30, 0x57, 0x76, 0x38, + 0x48, 0x54, 0x34, 0x4b, 0x73, 0x31, 0x36, 0x58, 0x64, 0x47, 0x2b, 0x52, + 0x43, 0x59, 0x79, 0x4b, 0x66, 0x48, 0x78, 0x39, 0x57, 0x7a, 0x4d, 0x66, + 0x67, 0x49, 0x68, 0x0a, 0x43, 0x35, 0x39, 0x76, 0x70, 0x44, 0x2b, 0x2b, + 0x6e, 0x56, 0x50, 0x69, 0x7a, 0x33, 0x32, 0x70, 0x4c, 0x48, 0x78, 0x59, + 0x47, 0x70, 0x66, 0x68, 0x50, 0x54, 0x63, 0x33, 0x47, 0x47, 0x59, 0x6f, + 0x30, 0x6b, 0x44, 0x46, 0x55, 0x59, 0x71, 0x4d, 0x77, 0x79, 0x33, 0x4f, + 0x55, 0x34, 0x67, 0x6b, 0x57, 0x47, 0x51, 0x77, 0x46, 0x73, 0x57, 0x71, + 0x34, 0x4e, 0x59, 0x4b, 0x70, 0x6b, 0x44, 0x66, 0x0a, 0x65, 0x50, 0x62, + 0x31, 0x42, 0x48, 0x78, 0x70, 0x45, 0x34, 0x53, 0x38, 0x30, 0x64, 0x47, + 0x6e, 0x42, 0x73, 0x38, 0x42, 0x39, 0x32, 0x6a, 0x41, 0x71, 0x46, 0x65, + 0x37, 0x4f, 0x6d, 0x47, 0x74, 0x42, 0x49, 0x79, 0x54, 0x34, 0x36, 0x33, + 0x38, 0x38, 0x4e, 0x74, 0x45, 0x62, 0x56, 0x6e, 0x63, 0x53, 0x56, 0x6d, + 0x75, 0x72, 0x4a, 0x71, 0x5a, 0x4e, 0x6a, 0x42, 0x42, 0x65, 0x33, 0x59, + 0x7a, 0x0a, 0x49, 0x6f, 0x65, 0x6a, 0x77, 0x70, 0x4b, 0x47, 0x62, 0x76, + 0x6c, 0x77, 0x37, 0x71, 0x36, 0x48, 0x68, 0x35, 0x55, 0x62, 0x78, 0x48, + 0x71, 0x39, 0x4d, 0x66, 0x50, 0x55, 0x30, 0x75, 0x57, 0x5a, 0x2f, 0x37, + 0x35, 0x49, 0x37, 0x48, 0x58, 0x31, 0x65, 0x42, 0x59, 0x64, 0x70, 0x6e, + 0x44, 0x42, 0x66, 0x7a, 0x77, 0x62, 0x6f, 0x5a, 0x4c, 0x37, 0x7a, 0x38, + 0x67, 0x38, 0x31, 0x73, 0x57, 0x54, 0x0a, 0x43, 0x6f, 0x2f, 0x31, 0x56, + 0x54, 0x70, 0x32, 0x6c, 0x63, 0x35, 0x5a, 0x6d, 0x49, 0x6f, 0x4a, 0x6c, + 0x58, 0x63, 0x79, 0x6d, 0x6f, 0x4f, 0x36, 0x4c, 0x41, 0x51, 0x36, 0x6c, + 0x37, 0x33, 0x55, 0x4c, 0x37, 0x37, 0x58, 0x62, 0x4a, 0x75, 0x69, 0x79, + 0x6e, 0x31, 0x74, 0x4a, 0x73, 0x6c, 0x56, 0x31, 0x63, 0x2f, 0x44, 0x65, + 0x56, 0x49, 0x49, 0x43, 0x5a, 0x6b, 0x48, 0x4a, 0x43, 0x31, 0x6b, 0x0a, + 0x4a, 0x57, 0x75, 0x6d, 0x49, 0x57, 0x6d, 0x62, 0x61, 0x74, 0x31, 0x30, + 0x54, 0x57, 0x75, 0x58, 0x65, 0x6b, 0x47, 0x39, 0x71, 0x78, 0x66, 0x35, + 0x6b, 0x42, 0x64, 0x49, 0x6a, 0x7a, 0x62, 0x35, 0x4c, 0x64, 0x58, 0x46, + 0x32, 0x2b, 0x36, 0x71, 0x68, 0x55, 0x56, 0x42, 0x2b, 0x73, 0x30, 0x36, + 0x52, 0x62, 0x46, 0x6f, 0x35, 0x6a, 0x5a, 0x4d, 0x6d, 0x35, 0x42, 0x58, + 0x37, 0x43, 0x4f, 0x35, 0x0a, 0x68, 0x77, 0x6a, 0x43, 0x78, 0x41, 0x6e, + 0x78, 0x6c, 0x34, 0x59, 0x71, 0x4b, 0x45, 0x33, 0x69, 0x64, 0x4d, 0x44, + 0x61, 0x78, 0x49, 0x7a, 0x62, 0x33, 0x2b, 0x4b, 0x68, 0x46, 0x31, 0x6e, + 0x4f, 0x4a, 0x46, 0x6c, 0x30, 0x4d, 0x64, 0x70, 0x2f, 0x2f, 0x54, 0x42, + 0x74, 0x32, 0x64, 0x7a, 0x68, 0x61, 0x75, 0x48, 0x38, 0x58, 0x77, 0x49, + 0x44, 0x41, 0x51, 0x41, 0x42, 0x6f, 0x34, 0x49, 0x42, 0x0a, 0x47, 0x6a, + 0x43, 0x43, 0x41, 0x52, 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, + 0x30, 0x54, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, + 0x45, 0x42, 0x2f, 0x7a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, + 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, + 0x59, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, + 0x59, 0x45, 0x0a, 0x46, 0x42, 0x69, 0x48, 0x56, 0x75, 0x42, 0x75, 0x64, + 0x2b, 0x34, 0x6b, 0x4e, 0x54, 0x78, 0x4f, 0x63, 0x35, 0x6f, 0x66, 0x31, + 0x75, 0x48, 0x69, 0x65, 0x58, 0x34, 0x72, 0x4d, 0x42, 0x38, 0x47, 0x41, + 0x31, 0x55, 0x64, 0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, 0x61, 0x41, 0x46, + 0x42, 0x69, 0x48, 0x56, 0x75, 0x42, 0x75, 0x64, 0x2b, 0x34, 0x6b, 0x4e, + 0x54, 0x78, 0x4f, 0x63, 0x35, 0x6f, 0x66, 0x0a, 0x31, 0x75, 0x48, 0x69, + 0x65, 0x58, 0x34, 0x72, 0x4d, 0x45, 0x51, 0x47, 0x41, 0x31, 0x55, 0x64, + 0x49, 0x41, 0x51, 0x39, 0x4d, 0x44, 0x73, 0x77, 0x4f, 0x51, 0x59, 0x45, + 0x56, 0x52, 0x30, 0x67, 0x41, 0x44, 0x41, 0x78, 0x4d, 0x43, 0x38, 0x47, + 0x43, 0x43, 0x73, 0x47, 0x41, 0x51, 0x55, 0x46, 0x42, 0x77, 0x49, 0x42, + 0x46, 0x69, 0x4e, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, 0x76, + 0x0a, 0x4c, 0x33, 0x64, 0x33, 0x64, 0x33, 0x63, 0x75, 0x59, 0x32, 0x56, + 0x79, 0x64, 0x47, 0x6c, 0x6e, 0x62, 0x6d, 0x45, 0x75, 0x5a, 0x6e, 0x49, + 0x76, 0x59, 0x58, 0x56, 0x30, 0x62, 0x33, 0x4a, 0x70, 0x64, 0x47, 0x56, + 0x7a, 0x4c, 0x7a, 0x42, 0x74, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x38, + 0x45, 0x5a, 0x6a, 0x42, 0x6b, 0x4d, 0x43, 0x2b, 0x67, 0x4c, 0x61, 0x41, + 0x72, 0x68, 0x69, 0x6c, 0x6f, 0x0a, 0x64, 0x48, 0x52, 0x77, 0x4f, 0x69, + 0x38, 0x76, 0x59, 0x33, 0x4a, 0x73, 0x4c, 0x6d, 0x4e, 0x6c, 0x63, 0x6e, + 0x52, 0x70, 0x5a, 0x32, 0x35, 0x68, 0x4c, 0x6d, 0x5a, 0x79, 0x4c, 0x32, + 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x32, 0x35, 0x68, 0x63, 0x6d, + 0x39, 0x76, 0x64, 0x47, 0x4e, 0x68, 0x4c, 0x6d, 0x4e, 0x79, 0x62, 0x44, + 0x41, 0x78, 0x6f, 0x43, 0x2b, 0x67, 0x4c, 0x59, 0x59, 0x72, 0x0a, 0x61, + 0x48, 0x52, 0x30, 0x63, 0x44, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x79, 0x62, + 0x43, 0x35, 0x6b, 0x61, 0x47, 0x6c, 0x74, 0x65, 0x57, 0x39, 0x30, 0x61, + 0x58, 0x4d, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x32, 0x4e, 0x6c, 0x63, + 0x6e, 0x52, 0x70, 0x5a, 0x32, 0x35, 0x68, 0x63, 0x6d, 0x39, 0x76, 0x64, + 0x47, 0x4e, 0x68, 0x4c, 0x6d, 0x4e, 0x79, 0x62, 0x44, 0x41, 0x4e, 0x42, + 0x67, 0x6b, 0x71, 0x0a, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, + 0x41, 0x51, 0x73, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x45, 0x41, + 0x6c, 0x4c, 0x69, 0x65, 0x54, 0x2f, 0x44, 0x6a, 0x6c, 0x51, 0x67, 0x69, + 0x35, 0x38, 0x31, 0x6f, 0x51, 0x66, 0x63, 0x63, 0x56, 0x64, 0x56, 0x38, + 0x41, 0x4f, 0x49, 0x74, 0x4f, 0x6f, 0x6c, 0x64, 0x61, 0x44, 0x67, 0x76, + 0x55, 0x53, 0x49, 0x4c, 0x53, 0x6f, 0x33, 0x4c, 0x0a, 0x36, 0x62, 0x74, + 0x64, 0x50, 0x72, 0x74, 0x63, 0x50, 0x62, 0x45, 0x6f, 0x2f, 0x75, 0x52, + 0x54, 0x56, 0x52, 0x50, 0x50, 0x6f, 0x5a, 0x41, 0x62, 0x41, 0x68, 0x31, + 0x66, 0x5a, 0x6b, 0x59, 0x4a, 0x4d, 0x79, 0x6a, 0x68, 0x44, 0x53, 0x53, + 0x58, 0x63, 0x4e, 0x4d, 0x51, 0x48, 0x2b, 0x70, 0x6b, 0x56, 0x35, 0x61, + 0x37, 0x58, 0x64, 0x72, 0x6e, 0x78, 0x49, 0x78, 0x50, 0x54, 0x47, 0x52, + 0x47, 0x0a, 0x48, 0x56, 0x79, 0x48, 0x34, 0x31, 0x6e, 0x65, 0x51, 0x74, + 0x47, 0x62, 0x71, 0x48, 0x36, 0x6d, 0x69, 0x64, 0x32, 0x50, 0x48, 0x4d, + 0x6b, 0x77, 0x67, 0x75, 0x30, 0x37, 0x6e, 0x4d, 0x33, 0x41, 0x36, 0x52, + 0x6e, 0x67, 0x61, 0x74, 0x67, 0x43, 0x64, 0x54, 0x65, 0x72, 0x39, 0x7a, + 0x51, 0x6f, 0x4b, 0x4a, 0x48, 0x79, 0x42, 0x41, 0x70, 0x50, 0x4e, 0x65, + 0x4e, 0x67, 0x4a, 0x67, 0x48, 0x36, 0x0a, 0x30, 0x42, 0x47, 0x4d, 0x2b, + 0x52, 0x46, 0x71, 0x37, 0x71, 0x38, 0x39, 0x77, 0x31, 0x44, 0x54, 0x6a, + 0x31, 0x38, 0x7a, 0x65, 0x54, 0x79, 0x47, 0x71, 0x48, 0x4e, 0x46, 0x6b, + 0x49, 0x77, 0x67, 0x74, 0x6e, 0x4a, 0x7a, 0x46, 0x79, 0x4f, 0x2b, 0x42, + 0x32, 0x58, 0x6c, 0x65, 0x4a, 0x49, 0x4e, 0x75, 0x67, 0x48, 0x41, 0x36, + 0x34, 0x77, 0x63, 0x5a, 0x72, 0x2b, 0x73, 0x68, 0x6e, 0x63, 0x42, 0x0a, + 0x6c, 0x41, 0x32, 0x63, 0x35, 0x75, 0x6b, 0x35, 0x6a, 0x52, 0x2b, 0x6d, + 0x55, 0x59, 0x79, 0x5a, 0x44, 0x44, 0x6c, 0x33, 0x34, 0x62, 0x53, 0x62, + 0x2b, 0x68, 0x78, 0x6e, 0x56, 0x32, 0x39, 0x71, 0x61, 0x6f, 0x36, 0x70, + 0x4b, 0x30, 0x78, 0x58, 0x65, 0x58, 0x70, 0x58, 0x49, 0x73, 0x2f, 0x4e, + 0x58, 0x32, 0x4e, 0x47, 0x6a, 0x56, 0x78, 0x5a, 0x4f, 0x6f, 0x62, 0x34, + 0x4d, 0x6b, 0x64, 0x69, 0x0a, 0x6f, 0x32, 0x63, 0x4e, 0x47, 0x4a, 0x48, + 0x63, 0x2b, 0x36, 0x5a, 0x72, 0x39, 0x55, 0x68, 0x68, 0x63, 0x79, 0x4e, + 0x5a, 0x6a, 0x67, 0x4b, 0x6e, 0x76, 0x45, 0x54, 0x71, 0x39, 0x45, 0x6d, + 0x64, 0x38, 0x56, 0x52, 0x59, 0x2b, 0x57, 0x43, 0x76, 0x32, 0x68, 0x69, + 0x6b, 0x4c, 0x79, 0x68, 0x46, 0x33, 0x48, 0x71, 0x67, 0x69, 0x49, 0x5a, + 0x64, 0x38, 0x7a, 0x76, 0x6e, 0x2f, 0x79, 0x6b, 0x31, 0x0a, 0x67, 0x50, + 0x78, 0x6b, 0x51, 0x35, 0x54, 0x6d, 0x34, 0x78, 0x78, 0x76, 0x76, 0x71, + 0x30, 0x4f, 0x4b, 0x6d, 0x4f, 0x5a, 0x4b, 0x38, 0x6c, 0x2b, 0x68, 0x66, + 0x5a, 0x78, 0x36, 0x41, 0x59, 0x44, 0x6c, 0x66, 0x37, 0x65, 0x6a, 0x30, + 0x67, 0x63, 0x57, 0x74, 0x53, 0x53, 0x36, 0x43, 0x76, 0x75, 0x35, 0x7a, + 0x48, 0x62, 0x75, 0x67, 0x52, 0x71, 0x68, 0x35, 0x6a, 0x6e, 0x78, 0x56, + 0x2f, 0x76, 0x0a, 0x66, 0x61, 0x63, 0x69, 0x39, 0x77, 0x48, 0x59, 0x54, + 0x66, 0x6d, 0x4a, 0x30, 0x41, 0x36, 0x61, 0x42, 0x56, 0x6d, 0x6b, 0x6e, + 0x70, 0x6a, 0x5a, 0x62, 0x79, 0x76, 0x4b, 0x63, 0x4c, 0x35, 0x6b, 0x77, + 0x6c, 0x57, 0x6a, 0x39, 0x4f, 0x6d, 0x76, 0x77, 0x35, 0x49, 0x70, 0x33, + 0x49, 0x67, 0x57, 0x4a, 0x4a, 0x6b, 0x38, 0x6a, 0x53, 0x61, 0x59, 0x74, + 0x6c, 0x75, 0x33, 0x7a, 0x4d, 0x36, 0x33, 0x0a, 0x4e, 0x77, 0x66, 0x39, + 0x4a, 0x74, 0x6d, 0x59, 0x68, 0x53, 0x54, 0x2f, 0x57, 0x53, 0x4d, 0x44, + 0x6d, 0x75, 0x32, 0x64, 0x6e, 0x61, 0x6a, 0x6b, 0x58, 0x6a, 0x6a, 0x4f, + 0x31, 0x31, 0x49, 0x4e, 0x62, 0x39, 0x49, 0x2f, 0x62, 0x62, 0x45, 0x46, + 0x61, 0x30, 0x6e, 0x4f, 0x69, 0x70, 0x46, 0x47, 0x63, 0x2f, 0x54, 0x32, + 0x4c, 0x2f, 0x43, 0x6f, 0x63, 0x33, 0x63, 0x4f, 0x5a, 0x61, 0x79, 0x68, + 0x0a, 0x6a, 0x57, 0x5a, 0x53, 0x61, 0x58, 0x35, 0x4c, 0x61, 0x41, 0x7a, + 0x48, 0x48, 0x6a, 0x63, 0x6e, 0x67, 0x36, 0x57, 0x4d, 0x78, 0x77, 0x4c, + 0x6b, 0x46, 0x4d, 0x31, 0x4a, 0x41, 0x62, 0x42, 0x7a, 0x73, 0x2f, 0x33, + 0x47, 0x6b, 0x44, 0x70, 0x76, 0x30, 0x6d, 0x7a, 0x74, 0x4f, 0x2b, 0x37, + 0x73, 0x6b, 0x62, 0x36, 0x69, 0x51, 0x31, 0x32, 0x4c, 0x41, 0x45, 0x70, + 0x6d, 0x4a, 0x55, 0x52, 0x77, 0x0a, 0x33, 0x6b, 0x41, 0x50, 0x2b, 0x48, + 0x77, 0x56, 0x39, 0x36, 0x4c, 0x4f, 0x50, 0x4e, 0x64, 0x65, 0x45, 0x34, + 0x79, 0x42, 0x46, 0x78, 0x67, 0x58, 0x30, 0x62, 0x33, 0x78, 0x64, 0x78, + 0x41, 0x36, 0x31, 0x47, 0x55, 0x35, 0x77, 0x53, 0x65, 0x73, 0x56, 0x79, + 0x77, 0x6c, 0x56, 0x50, 0x2b, 0x69, 0x32, 0x6b, 0x2b, 0x4b, 0x59, 0x54, + 0x6c, 0x65, 0x72, 0x6a, 0x31, 0x4b, 0x6a, 0x4c, 0x30, 0x3d, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x31, 0x20, 0x4f, + 0x3d, 0x65, 0x4d, 0x75, 0x64, 0x68, 0x72, 0x61, 0x20, 0x54, 0x65, 0x63, + 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x20, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x65, 0x64, 0x20, 0x4f, 0x55, 0x3d, 0x65, 0x6d, 0x53, + 0x69, 0x67, 0x6e, 0x20, 0x50, 0x4b, 0x49, 0x0a, 0x23, 0x20, 0x53, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x65, 0x6d, + 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x20, 0x2d, 0x20, 0x47, 0x31, 0x20, 0x4f, 0x3d, 0x65, 0x4d, 0x75, 0x64, + 0x68, 0x72, 0x61, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, + 0x67, 0x69, 0x65, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, + 0x20, 0x4f, 0x55, 0x3d, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x50, + 0x4b, 0x49, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, + 0x22, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, + 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x31, 0x22, 0x0a, 0x23, 0x20, + 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x32, 0x33, 0x35, 0x39, + 0x33, 0x31, 0x38, 0x36, 0x36, 0x36, 0x38, 0x38, 0x33, 0x31, 0x39, 0x33, + 0x30, 0x38, 0x38, 0x31, 0x34, 0x30, 0x34, 0x30, 0x0a, 0x23, 0x20, 0x4d, + 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x3a, 0x20, 0x39, 0x63, 0x3a, 0x34, 0x32, 0x3a, 0x38, 0x34, + 0x3a, 0x35, 0x37, 0x3a, 0x64, 0x64, 0x3a, 0x63, 0x62, 0x3a, 0x30, 0x62, + 0x3a, 0x61, 0x37, 0x3a, 0x32, 0x65, 0x3a, 0x39, 0x35, 0x3a, 0x61, 0x64, + 0x3a, 0x62, 0x36, 0x3a, 0x66, 0x33, 0x3a, 0x64, 0x61, 0x3a, 0x62, 0x63, + 0x3a, 0x61, 0x63, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, + 0x38, 0x61, 0x3a, 0x63, 0x37, 0x3a, 0x61, 0x64, 0x3a, 0x38, 0x66, 0x3a, + 0x37, 0x33, 0x3a, 0x61, 0x63, 0x3a, 0x34, 0x65, 0x3a, 0x63, 0x31, 0x3a, + 0x62, 0x35, 0x3a, 0x37, 0x35, 0x3a, 0x34, 0x64, 0x3a, 0x61, 0x35, 0x3a, + 0x34, 0x30, 0x3a, 0x66, 0x34, 0x3a, 0x66, 0x63, 0x3a, 0x63, 0x66, 0x3a, + 0x37, 0x63, 0x3a, 0x62, 0x35, 0x3a, 0x38, 0x65, 0x3a, 0x38, 0x63, 0x0a, + 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, + 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x34, 0x30, + 0x3a, 0x66, 0x36, 0x3a, 0x61, 0x66, 0x3a, 0x30, 0x33, 0x3a, 0x34, 0x36, + 0x3a, 0x61, 0x39, 0x3a, 0x39, 0x61, 0x3a, 0x61, 0x31, 0x3a, 0x63, 0x64, + 0x3a, 0x31, 0x64, 0x3a, 0x35, 0x35, 0x3a, 0x35, 0x61, 0x3a, 0x34, 0x65, + 0x3a, 0x39, 0x63, 0x3a, 0x63, 0x65, 0x3a, 0x36, 0x32, 0x3a, 0x63, 0x37, + 0x3a, 0x66, 0x39, 0x3a, 0x36, 0x33, 0x3a, 0x34, 0x36, 0x3a, 0x30, 0x33, + 0x3a, 0x65, 0x65, 0x3a, 0x34, 0x30, 0x3a, 0x36, 0x36, 0x3a, 0x31, 0x35, + 0x3a, 0x38, 0x33, 0x3a, 0x33, 0x64, 0x3a, 0x63, 0x38, 0x3a, 0x63, 0x38, + 0x3a, 0x64, 0x30, 0x3a, 0x30, 0x33, 0x3a, 0x36, 0x37, 0x0a, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, 0x6c, 0x44, 0x43, 0x43, 0x41, 0x6e, + 0x79, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x4b, 0x4d, 0x66, + 0x58, 0x6b, 0x59, 0x67, 0x78, 0x73, 0x57, 0x4f, 0x33, 0x57, 0x32, 0x44, + 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, + 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x6e, 0x4d, 0x51, + 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, 0x47, 0x45, + 0x77, 0x4a, 0x4a, 0x54, 0x6a, 0x45, 0x54, 0x4d, 0x42, 0x45, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x4b, 0x5a, 0x57, 0x31, 0x54, 0x61, + 0x57, 0x64, 0x75, 0x49, 0x46, 0x42, 0x4c, 0x53, 0x54, 0x45, 0x6c, 0x4d, + 0x43, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x63, 0x5a, + 0x55, 0x31, 0x31, 0x5a, 0x47, 0x68, 0x79, 0x59, 0x53, 0x42, 0x55, 0x0a, + 0x5a, 0x57, 0x4e, 0x6f, 0x62, 0x6d, 0x39, 0x73, 0x62, 0x32, 0x64, 0x70, + 0x5a, 0x58, 0x4d, 0x67, 0x54, 0x47, 0x6c, 0x74, 0x61, 0x58, 0x52, 0x6c, + 0x5a, 0x44, 0x45, 0x63, 0x4d, 0x42, 0x6f, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x41, 0x78, 0x4d, 0x54, 0x5a, 0x57, 0x31, 0x54, 0x61, 0x57, 0x64, 0x75, + 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, + 0x4c, 0x53, 0x42, 0x48, 0x0a, 0x4d, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, + 0x78, 0x4f, 0x44, 0x41, 0x79, 0x4d, 0x54, 0x67, 0x78, 0x4f, 0x44, 0x4d, + 0x77, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, 0x30, 0x4d, 0x7a, 0x41, + 0x79, 0x4d, 0x54, 0x67, 0x78, 0x4f, 0x44, 0x4d, 0x77, 0x4d, 0x44, 0x42, + 0x61, 0x4d, 0x47, 0x63, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x6c, 0x4f, 0x0a, 0x4d, 0x52, + 0x4d, 0x77, 0x45, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4c, 0x45, 0x77, + 0x70, 0x6c, 0x62, 0x56, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x67, 0x55, 0x45, + 0x74, 0x4a, 0x4d, 0x53, 0x55, 0x77, 0x49, 0x77, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x4b, 0x45, 0x78, 0x78, 0x6c, 0x54, 0x58, 0x56, 0x6b, 0x61, 0x48, + 0x4a, 0x68, 0x49, 0x46, 0x52, 0x6c, 0x59, 0x32, 0x68, 0x75, 0x62, 0x32, + 0x78, 0x76, 0x0a, 0x5a, 0x32, 0x6c, 0x6c, 0x63, 0x79, 0x42, 0x4d, 0x61, + 0x57, 0x31, 0x70, 0x64, 0x47, 0x56, 0x6b, 0x4d, 0x52, 0x77, 0x77, 0x47, + 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x4e, 0x6c, 0x62, + 0x56, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, + 0x43, 0x42, 0x44, 0x51, 0x53, 0x41, 0x74, 0x49, 0x45, 0x63, 0x78, 0x4d, + 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x0a, 0x42, 0x67, 0x6b, 0x71, + 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, + 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, + 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x6b, 0x30, 0x75, 0x37, + 0x36, 0x57, 0x61, 0x4b, 0x37, 0x70, 0x31, 0x62, 0x31, 0x54, 0x53, 0x54, + 0x30, 0x42, 0x73, 0x65, 0x77, 0x2b, 0x65, 0x65, 0x75, 0x47, 0x51, 0x7a, + 0x0a, 0x66, 0x32, 0x4e, 0x34, 0x61, 0x4c, 0x54, 0x4e, 0x4c, 0x6e, 0x46, + 0x31, 0x31, 0x35, 0x73, 0x67, 0x78, 0x6b, 0x30, 0x70, 0x76, 0x4c, 0x5a, + 0x6f, 0x59, 0x49, 0x72, 0x33, 0x49, 0x5a, 0x70, 0x57, 0x4e, 0x56, 0x72, + 0x7a, 0x64, 0x72, 0x33, 0x59, 0x7a, 0x5a, 0x72, 0x2f, 0x6b, 0x31, 0x5a, + 0x4c, 0x70, 0x56, 0x6b, 0x47, 0x6f, 0x5a, 0x4d, 0x30, 0x4b, 0x64, 0x30, + 0x57, 0x4e, 0x48, 0x56, 0x4f, 0x0a, 0x38, 0x6f, 0x47, 0x30, 0x78, 0x35, + 0x5a, 0x4f, 0x72, 0x52, 0x6b, 0x56, 0x55, 0x6b, 0x72, 0x2b, 0x50, 0x48, + 0x42, 0x31, 0x63, 0x4d, 0x32, 0x76, 0x4b, 0x36, 0x73, 0x56, 0x6d, 0x6a, + 0x4d, 0x38, 0x71, 0x72, 0x4f, 0x4c, 0x71, 0x73, 0x31, 0x44, 0x2f, 0x66, + 0x58, 0x71, 0x63, 0x50, 0x2f, 0x74, 0x7a, 0x78, 0x45, 0x37, 0x6c, 0x4d, + 0x35, 0x4f, 0x4d, 0x68, 0x62, 0x54, 0x49, 0x30, 0x41, 0x71, 0x0a, 0x64, + 0x37, 0x4f, 0x76, 0x50, 0x41, 0x45, 0x73, 0x62, 0x4f, 0x32, 0x5a, 0x4c, + 0x49, 0x76, 0x5a, 0x54, 0x6d, 0x6d, 0x59, 0x73, 0x76, 0x65, 0x50, 0x51, + 0x62, 0x41, 0x79, 0x65, 0x47, 0x48, 0x57, 0x44, 0x56, 0x2f, 0x44, 0x2b, + 0x71, 0x4a, 0x41, 0x6b, 0x68, 0x31, 0x63, 0x46, 0x2b, 0x5a, 0x77, 0x50, + 0x6a, 0x58, 0x6e, 0x6f, 0x72, 0x66, 0x43, 0x59, 0x75, 0x4b, 0x72, 0x70, + 0x44, 0x68, 0x4d, 0x0a, 0x74, 0x54, 0x6b, 0x31, 0x62, 0x2b, 0x6f, 0x44, + 0x61, 0x66, 0x6f, 0x36, 0x56, 0x47, 0x69, 0x46, 0x62, 0x64, 0x62, 0x79, + 0x4c, 0x30, 0x4e, 0x56, 0x48, 0x70, 0x45, 0x4e, 0x44, 0x74, 0x6a, 0x56, + 0x61, 0x71, 0x53, 0x57, 0x30, 0x52, 0x4d, 0x38, 0x4c, 0x48, 0x68, 0x51, + 0x36, 0x44, 0x71, 0x53, 0x30, 0x68, 0x64, 0x57, 0x35, 0x54, 0x55, 0x61, + 0x51, 0x42, 0x77, 0x2b, 0x6a, 0x53, 0x7a, 0x74, 0x0a, 0x4f, 0x64, 0x39, + 0x43, 0x34, 0x49, 0x4e, 0x42, 0x64, 0x4e, 0x2b, 0x6a, 0x7a, 0x63, 0x4b, + 0x47, 0x59, 0x45, 0x68, 0x6f, 0x34, 0x32, 0x6b, 0x4c, 0x56, 0x41, 0x43, + 0x4c, 0x35, 0x48, 0x5a, 0x70, 0x49, 0x51, 0x31, 0x35, 0x54, 0x6a, 0x51, + 0x49, 0x58, 0x68, 0x54, 0x43, 0x7a, 0x4c, 0x47, 0x33, 0x72, 0x64, 0x64, + 0x38, 0x63, 0x49, 0x72, 0x48, 0x68, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, + 0x42, 0x0a, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x64, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x2b, 0x2b, + 0x38, 0x4e, 0x68, 0x70, 0x36, 0x77, 0x34, 0x39, 0x32, 0x70, 0x75, 0x66, + 0x45, 0x68, 0x46, 0x33, 0x38, 0x2b, 0x2f, 0x50, 0x42, 0x33, 0x4b, 0x78, + 0x6f, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x0a, 0x41, 0x67, 0x45, 0x47, 0x4d, + 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, + 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x44, + 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, + 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, 0x41, + 0x46, 0x6e, 0x2f, 0x38, 0x6f, 0x7a, 0x31, 0x68, 0x33, 0x31, 0x78, 0x0a, + 0x50, 0x61, 0x4f, 0x66, 0x47, 0x31, 0x76, 0x52, 0x32, 0x76, 0x6a, 0x54, + 0x6e, 0x47, 0x73, 0x32, 0x76, 0x5a, 0x75, 0x70, 0x59, 0x65, 0x76, 0x65, + 0x46, 0x69, 0x78, 0x30, 0x50, 0x5a, 0x37, 0x6d, 0x64, 0x64, 0x72, 0x58, + 0x75, 0x71, 0x65, 0x38, 0x51, 0x68, 0x66, 0x6e, 0x50, 0x5a, 0x48, 0x72, + 0x35, 0x58, 0x33, 0x64, 0x50, 0x70, 0x7a, 0x78, 0x7a, 0x35, 0x4b, 0x73, + 0x62, 0x45, 0x6a, 0x4d, 0x0a, 0x77, 0x69, 0x49, 0x2f, 0x61, 0x54, 0x76, + 0x46, 0x74, 0x68, 0x55, 0x76, 0x6f, 0x7a, 0x58, 0x47, 0x61, 0x43, 0x6f, + 0x63, 0x56, 0x36, 0x38, 0x35, 0x37, 0x34, 0x33, 0x51, 0x4e, 0x63, 0x4d, + 0x59, 0x44, 0x48, 0x73, 0x41, 0x56, 0x68, 0x7a, 0x4e, 0x69, 0x78, 0x6c, + 0x30, 0x33, 0x72, 0x34, 0x50, 0x45, 0x75, 0x44, 0x51, 0x71, 0x71, 0x45, + 0x2f, 0x41, 0x6a, 0x53, 0x78, 0x63, 0x4d, 0x36, 0x64, 0x0a, 0x47, 0x4e, + 0x59, 0x49, 0x41, 0x77, 0x6c, 0x47, 0x37, 0x6d, 0x44, 0x67, 0x66, 0x72, + 0x62, 0x45, 0x53, 0x51, 0x52, 0x52, 0x66, 0x58, 0x42, 0x67, 0x76, 0x4b, + 0x71, 0x79, 0x2f, 0x33, 0x6c, 0x79, 0x65, 0x71, 0x59, 0x64, 0x50, 0x56, + 0x38, 0x71, 0x2b, 0x4d, 0x72, 0x69, 0x2f, 0x54, 0x6d, 0x33, 0x52, 0x37, + 0x6e, 0x72, 0x66, 0x74, 0x38, 0x45, 0x49, 0x36, 0x2f, 0x36, 0x6e, 0x41, + 0x59, 0x48, 0x0a, 0x36, 0x66, 0x74, 0x6a, 0x6b, 0x34, 0x42, 0x41, 0x74, + 0x63, 0x5a, 0x73, 0x43, 0x6a, 0x45, 0x6f, 0x7a, 0x67, 0x79, 0x66, 0x7a, + 0x37, 0x4d, 0x6a, 0x4e, 0x59, 0x42, 0x42, 0x6a, 0x57, 0x7a, 0x45, 0x4e, + 0x33, 0x75, 0x42, 0x4c, 0x34, 0x43, 0x68, 0x51, 0x45, 0x4b, 0x46, 0x36, + 0x64, 0x6b, 0x34, 0x6a, 0x65, 0x69, 0x68, 0x55, 0x38, 0x30, 0x42, 0x76, + 0x32, 0x6e, 0x6f, 0x57, 0x67, 0x62, 0x79, 0x0a, 0x52, 0x51, 0x75, 0x51, + 0x2b, 0x71, 0x37, 0x68, 0x76, 0x35, 0x33, 0x79, 0x72, 0x6c, 0x63, 0x38, + 0x70, 0x61, 0x36, 0x79, 0x56, 0x76, 0x53, 0x4c, 0x5a, 0x55, 0x44, 0x70, + 0x2f, 0x54, 0x47, 0x42, 0x4c, 0x50, 0x51, 0x35, 0x43, 0x64, 0x6a, 0x75, + 0x61, 0x36, 0x65, 0x30, 0x70, 0x68, 0x30, 0x56, 0x70, 0x5a, 0x6a, 0x33, + 0x41, 0x59, 0x48, 0x59, 0x68, 0x58, 0x33, 0x7a, 0x55, 0x56, 0x78, 0x78, + 0x0a, 0x69, 0x4e, 0x36, 0x36, 0x7a, 0x42, 0x2b, 0x41, 0x66, 0x6b, 0x6f, + 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x20, 0x2d, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x65, 0x4d, 0x75, 0x64, + 0x68, 0x72, 0x61, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, + 0x67, 0x69, 0x65, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, + 0x20, 0x4f, 0x55, 0x3d, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x50, + 0x4b, 0x49, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, + 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, + 0x2d, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x3d, 0x65, 0x4d, 0x75, 0x64, 0x68, + 0x72, 0x61, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, + 0x69, 0x65, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x20, + 0x4f, 0x55, 0x3d, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x50, 0x4b, + 0x49, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, + 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x22, + 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x32, + 0x38, 0x37, 0x38, 0x38, 0x30, 0x34, 0x34, 0x30, 0x31, 0x30, 0x31, 0x35, + 0x37, 0x31, 0x30, 0x38, 0x36, 0x39, 0x34, 0x35, 0x31, 0x35, 0x36, 0x0a, + 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x65, 0x3a, 0x30, 0x62, + 0x3a, 0x37, 0x32, 0x3a, 0x64, 0x31, 0x3a, 0x39, 0x66, 0x3a, 0x38, 0x38, + 0x3a, 0x38, 0x65, 0x3a, 0x64, 0x30, 0x3a, 0x35, 0x30, 0x3a, 0x30, 0x33, + 0x3a, 0x65, 0x38, 0x3a, 0x65, 0x33, 0x3a, 0x62, 0x38, 0x3a, 0x38, 0x62, + 0x3a, 0x36, 0x37, 0x3a, 0x34, 0x30, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, + 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x33, 0x30, 0x3a, 0x34, 0x33, 0x3a, 0x66, 0x61, 0x3a, + 0x34, 0x66, 0x3a, 0x66, 0x32, 0x3a, 0x35, 0x37, 0x3a, 0x64, 0x63, 0x3a, + 0x61, 0x30, 0x3a, 0x63, 0x33, 0x3a, 0x38, 0x30, 0x3a, 0x65, 0x65, 0x3a, + 0x32, 0x65, 0x3a, 0x35, 0x38, 0x3a, 0x65, 0x61, 0x3a, 0x37, 0x38, 0x3a, + 0x62, 0x32, 0x3a, 0x33, 0x66, 0x3a, 0x65, 0x36, 0x3a, 0x62, 0x62, 0x3a, + 0x63, 0x31, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x38, 0x36, 0x3a, 0x61, 0x31, 0x3a, 0x65, 0x63, 0x3a, 0x62, 0x61, + 0x3a, 0x30, 0x38, 0x3a, 0x39, 0x63, 0x3a, 0x34, 0x61, 0x3a, 0x38, 0x64, + 0x3a, 0x33, 0x62, 0x3a, 0x62, 0x65, 0x3a, 0x32, 0x37, 0x3a, 0x33, 0x34, + 0x3a, 0x63, 0x36, 0x3a, 0x31, 0x32, 0x3a, 0x62, 0x61, 0x3a, 0x33, 0x34, + 0x3a, 0x31, 0x64, 0x3a, 0x38, 0x31, 0x3a, 0x33, 0x65, 0x3a, 0x30, 0x34, + 0x3a, 0x33, 0x63, 0x3a, 0x66, 0x39, 0x3a, 0x65, 0x38, 0x3a, 0x61, 0x38, + 0x3a, 0x36, 0x32, 0x3a, 0x63, 0x64, 0x3a, 0x35, 0x63, 0x3a, 0x35, 0x37, + 0x3a, 0x61, 0x33, 0x3a, 0x36, 0x62, 0x3a, 0x62, 0x65, 0x3a, 0x36, 0x62, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x54, 0x6a, 0x43, + 0x43, 0x41, 0x64, 0x4f, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, + 0x4b, 0x50, 0x50, 0x59, 0x48, 0x71, 0x57, 0x68, 0x77, 0x44, 0x74, 0x71, + 0x4c, 0x68, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, + 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x7a, 0x42, 0x72, 0x4d, 0x51, 0x73, + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x0a, 0x45, 0x77, + 0x4a, 0x4a, 0x54, 0x6a, 0x45, 0x54, 0x4d, 0x42, 0x45, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x78, 0x4d, 0x4b, 0x5a, 0x57, 0x31, 0x54, 0x61, 0x57, + 0x64, 0x75, 0x49, 0x46, 0x42, 0x4c, 0x53, 0x54, 0x45, 0x6c, 0x4d, 0x43, + 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x63, 0x5a, 0x55, + 0x31, 0x31, 0x5a, 0x47, 0x68, 0x79, 0x59, 0x53, 0x42, 0x55, 0x5a, 0x57, + 0x4e, 0x6f, 0x0a, 0x62, 0x6d, 0x39, 0x73, 0x62, 0x32, 0x64, 0x70, 0x5a, + 0x58, 0x4d, 0x67, 0x54, 0x47, 0x6c, 0x74, 0x61, 0x58, 0x52, 0x6c, 0x5a, + 0x44, 0x45, 0x67, 0x4d, 0x42, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, + 0x78, 0x4d, 0x58, 0x5a, 0x57, 0x31, 0x54, 0x61, 0x57, 0x64, 0x75, 0x49, + 0x45, 0x56, 0x44, 0x51, 0x79, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, + 0x45, 0x4e, 0x42, 0x49, 0x43, 0x30, 0x67, 0x0a, 0x52, 0x7a, 0x4d, 0x77, + 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x54, 0x67, 0x77, 0x4d, 0x6a, 0x45, 0x34, + 0x4d, 0x54, 0x67, 0x7a, 0x4d, 0x44, 0x41, 0x77, 0x57, 0x68, 0x63, 0x4e, + 0x4e, 0x44, 0x4d, 0x77, 0x4d, 0x6a, 0x45, 0x34, 0x4d, 0x54, 0x67, 0x7a, + 0x4d, 0x44, 0x41, 0x77, 0x57, 0x6a, 0x42, 0x72, 0x4d, 0x51, 0x73, 0x77, + 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x4a, + 0x0a, 0x54, 0x6a, 0x45, 0x54, 0x4d, 0x42, 0x45, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x78, 0x4d, 0x4b, 0x5a, 0x57, 0x31, 0x54, 0x61, 0x57, 0x64, + 0x75, 0x49, 0x46, 0x42, 0x4c, 0x53, 0x54, 0x45, 0x6c, 0x4d, 0x43, 0x4d, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x63, 0x5a, 0x55, 0x31, + 0x31, 0x5a, 0x47, 0x68, 0x79, 0x59, 0x53, 0x42, 0x55, 0x5a, 0x57, 0x4e, + 0x6f, 0x62, 0x6d, 0x39, 0x73, 0x0a, 0x62, 0x32, 0x64, 0x70, 0x5a, 0x58, + 0x4d, 0x67, 0x54, 0x47, 0x6c, 0x74, 0x61, 0x58, 0x52, 0x6c, 0x5a, 0x44, + 0x45, 0x67, 0x4d, 0x42, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, + 0x4d, 0x58, 0x5a, 0x57, 0x31, 0x54, 0x61, 0x57, 0x64, 0x75, 0x49, 0x45, + 0x56, 0x44, 0x51, 0x79, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, + 0x4e, 0x42, 0x49, 0x43, 0x30, 0x67, 0x52, 0x7a, 0x4d, 0x77, 0x0a, 0x64, + 0x6a, 0x41, 0x51, 0x42, 0x67, 0x63, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, + 0x51, 0x49, 0x42, 0x42, 0x67, 0x55, 0x72, 0x67, 0x51, 0x51, 0x41, 0x49, + 0x67, 0x4e, 0x69, 0x41, 0x41, 0x51, 0x6a, 0x70, 0x51, 0x79, 0x34, 0x4c, + 0x52, 0x4c, 0x31, 0x4b, 0x50, 0x4f, 0x78, 0x73, 0x74, 0x33, 0x69, 0x41, + 0x68, 0x4b, 0x41, 0x6e, 0x6a, 0x6c, 0x66, 0x53, 0x55, 0x32, 0x66, 0x79, + 0x53, 0x55, 0x30, 0x0a, 0x57, 0x58, 0x54, 0x73, 0x75, 0x77, 0x59, 0x63, + 0x35, 0x38, 0x42, 0x79, 0x72, 0x2b, 0x69, 0x75, 0x4c, 0x2b, 0x46, 0x42, + 0x56, 0x49, 0x63, 0x55, 0x71, 0x45, 0x71, 0x79, 0x36, 0x48, 0x79, 0x43, + 0x35, 0x6c, 0x74, 0x71, 0x74, 0x64, 0x79, 0x7a, 0x64, 0x63, 0x36, 0x4c, + 0x42, 0x74, 0x43, 0x47, 0x49, 0x37, 0x39, 0x47, 0x31, 0x59, 0x34, 0x50, + 0x50, 0x77, 0x54, 0x30, 0x31, 0x78, 0x79, 0x53, 0x0a, 0x66, 0x76, 0x61, + 0x6c, 0x59, 0x38, 0x4c, 0x31, 0x58, 0x34, 0x34, 0x75, 0x54, 0x36, 0x45, + 0x59, 0x47, 0x51, 0x49, 0x72, 0x4d, 0x67, 0x71, 0x43, 0x5a, 0x48, 0x30, + 0x57, 0x6b, 0x39, 0x47, 0x6a, 0x51, 0x6a, 0x42, 0x41, 0x4d, 0x42, 0x30, + 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x52, + 0x38, 0x58, 0x51, 0x4b, 0x45, 0x45, 0x39, 0x54, 0x4d, 0x69, 0x70, 0x75, + 0x42, 0x0a, 0x7a, 0x68, 0x63, 0x63, 0x4c, 0x69, 0x6b, 0x65, 0x6e, 0x45, + 0x68, 0x6a, 0x51, 0x6a, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, + 0x38, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x51, + 0x59, 0x77, 0x44, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x55, 0x77, 0x41, 0x77, 0x45, 0x42, 0x2f, 0x7a, + 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x0a, 0x68, 0x6b, 0x6a, 0x4f, 0x50, + 0x51, 0x51, 0x44, 0x41, 0x77, 0x4e, 0x70, 0x41, 0x44, 0x42, 0x6d, 0x41, + 0x6a, 0x45, 0x41, 0x76, 0x76, 0x4e, 0x68, 0x7a, 0x77, 0x49, 0x51, 0x48, + 0x57, 0x53, 0x56, 0x42, 0x37, 0x67, 0x59, 0x62, 0x6f, 0x69, 0x46, 0x42, + 0x53, 0x2b, 0x44, 0x43, 0x42, 0x65, 0x51, 0x79, 0x68, 0x2b, 0x4b, 0x54, + 0x4f, 0x67, 0x4e, 0x47, 0x33, 0x71, 0x78, 0x72, 0x64, 0x57, 0x42, 0x0a, + 0x43, 0x55, 0x66, 0x76, 0x4f, 0x36, 0x77, 0x49, 0x42, 0x48, 0x78, 0x63, + 0x6d, 0x62, 0x48, 0x74, 0x52, 0x77, 0x66, 0x53, 0x41, 0x6a, 0x45, 0x41, + 0x6e, 0x62, 0x70, 0x56, 0x2f, 0x4b, 0x6c, 0x4b, 0x36, 0x4f, 0x33, 0x74, + 0x35, 0x6e, 0x59, 0x42, 0x51, 0x6e, 0x76, 0x49, 0x2b, 0x47, 0x44, 0x5a, + 0x6a, 0x56, 0x47, 0x4c, 0x56, 0x54, 0x76, 0x37, 0x6a, 0x48, 0x76, 0x72, + 0x5a, 0x51, 0x6e, 0x44, 0x0a, 0x2b, 0x4a, 0x62, 0x4e, 0x52, 0x36, 0x69, + 0x43, 0x38, 0x68, 0x5a, 0x56, 0x64, 0x79, 0x52, 0x2b, 0x45, 0x68, 0x43, + 0x56, 0x42, 0x43, 0x79, 0x6a, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x65, 0x6d, + 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x20, 0x2d, 0x20, 0x43, 0x31, 0x20, 0x4f, 0x3d, 0x65, 0x4d, 0x75, 0x64, + 0x68, 0x72, 0x61, 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x65, + 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x50, 0x4b, 0x49, 0x0a, 0x23, 0x20, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x20, 0x2d, 0x20, 0x43, 0x31, 0x20, 0x4f, 0x3d, 0x65, 0x4d, + 0x75, 0x64, 0x68, 0x72, 0x61, 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, + 0x3d, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x50, 0x4b, 0x49, 0x0a, + 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x65, 0x6d, + 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x20, 0x2d, 0x20, 0x43, 0x31, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x38, 0x32, 0x35, 0x35, 0x31, 0x30, 0x32, + 0x39, 0x36, 0x36, 0x31, 0x33, 0x33, 0x31, 0x36, 0x30, 0x30, 0x34, 0x39, + 0x35, 0x35, 0x30, 0x35, 0x38, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x64, 0x38, 0x3a, 0x65, 0x33, 0x3a, 0x35, 0x64, 0x3a, 0x30, 0x31, + 0x3a, 0x32, 0x31, 0x3a, 0x66, 0x61, 0x3a, 0x37, 0x38, 0x3a, 0x35, 0x61, + 0x3a, 0x62, 0x30, 0x3a, 0x64, 0x66, 0x3a, 0x62, 0x61, 0x3a, 0x64, 0x32, + 0x3a, 0x65, 0x65, 0x3a, 0x32, 0x61, 0x3a, 0x35, 0x66, 0x3a, 0x36, 0x38, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x65, 0x37, 0x3a, + 0x32, 0x65, 0x3a, 0x66, 0x31, 0x3a, 0x64, 0x66, 0x3a, 0x66, 0x63, 0x3a, + 0x62, 0x32, 0x3a, 0x30, 0x39, 0x3a, 0x32, 0x38, 0x3a, 0x63, 0x66, 0x3a, + 0x35, 0x64, 0x3a, 0x64, 0x34, 0x3a, 0x64, 0x35, 0x3a, 0x36, 0x37, 0x3a, + 0x33, 0x37, 0x3a, 0x62, 0x31, 0x3a, 0x35, 0x31, 0x3a, 0x63, 0x62, 0x3a, + 0x38, 0x36, 0x3a, 0x34, 0x66, 0x3a, 0x30, 0x31, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x3a, 0x35, 0x36, + 0x3a, 0x30, 0x39, 0x3a, 0x61, 0x61, 0x3a, 0x33, 0x30, 0x3a, 0x31, 0x64, + 0x3a, 0x61, 0x30, 0x3a, 0x61, 0x32, 0x3a, 0x34, 0x39, 0x3a, 0x62, 0x39, + 0x3a, 0x37, 0x61, 0x3a, 0x38, 0x32, 0x3a, 0x33, 0x39, 0x3a, 0x63, 0x62, + 0x3a, 0x36, 0x61, 0x3a, 0x33, 0x34, 0x3a, 0x32, 0x31, 0x3a, 0x36, 0x66, + 0x3a, 0x34, 0x34, 0x3a, 0x64, 0x63, 0x3a, 0x61, 0x63, 0x3a, 0x39, 0x66, + 0x3a, 0x33, 0x39, 0x3a, 0x35, 0x34, 0x3a, 0x62, 0x31, 0x3a, 0x34, 0x32, + 0x3a, 0x39, 0x32, 0x3a, 0x66, 0x32, 0x3a, 0x65, 0x38, 0x3a, 0x63, 0x38, + 0x3a, 0x36, 0x30, 0x3a, 0x38, 0x66, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, + 0x49, 0x49, 0x44, 0x63, 0x7a, 0x43, 0x43, 0x41, 0x6c, 0x75, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x4c, 0x41, 0x4b, 0x37, 0x50, 0x41, + 0x4c, 0x72, 0x45, 0x7a, 0x7a, 0x4c, 0x34, 0x51, 0x37, 0x49, 0x77, 0x44, + 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, + 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x77, 0x56, 0x6a, 0x45, 0x4c, 0x4d, + 0x41, 0x6b, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, + 0x56, 0x56, 0x4d, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x73, 0x54, 0x43, 0x6d, 0x56, 0x74, 0x55, 0x32, 0x6c, 0x6e, + 0x62, 0x69, 0x42, 0x51, 0x53, 0x30, 0x6b, 0x78, 0x46, 0x44, 0x41, 0x53, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x43, 0x32, 0x56, 0x4e, + 0x64, 0x57, 0x52, 0x6f, 0x63, 0x6d, 0x45, 0x67, 0x0a, 0x53, 0x57, 0x35, + 0x6a, 0x4d, 0x52, 0x77, 0x77, 0x47, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x44, 0x45, 0x78, 0x4e, 0x6c, 0x62, 0x56, 0x4e, 0x70, 0x5a, 0x32, 0x34, + 0x67, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x53, 0x41, + 0x74, 0x49, 0x45, 0x4d, 0x78, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, + 0x34, 0x4d, 0x44, 0x49, 0x78, 0x4f, 0x44, 0x45, 0x34, 0x4d, 0x7a, 0x41, + 0x77, 0x0a, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x51, 0x7a, 0x4d, 0x44, + 0x49, 0x78, 0x4f, 0x44, 0x45, 0x34, 0x4d, 0x7a, 0x41, 0x77, 0x4d, 0x46, + 0x6f, 0x77, 0x56, 0x6a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x45, 0x7a, + 0x41, 0x52, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x43, 0x6d, + 0x56, 0x74, 0x55, 0x32, 0x6c, 0x6e, 0x0a, 0x62, 0x69, 0x42, 0x51, 0x53, + 0x30, 0x6b, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x6f, 0x54, 0x43, 0x32, 0x56, 0x4e, 0x64, 0x57, 0x52, 0x6f, 0x63, + 0x6d, 0x45, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4d, 0x52, 0x77, 0x77, 0x47, + 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x4e, 0x6c, 0x62, + 0x56, 0x4e, 0x70, 0x5a, 0x32, 0x34, 0x67, 0x55, 0x6d, 0x39, 0x76, 0x0a, + 0x64, 0x43, 0x42, 0x44, 0x51, 0x53, 0x41, 0x74, 0x49, 0x45, 0x4d, 0x78, + 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, + 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, + 0x41, 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, + 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x7a, 0x2b, 0x75, 0x70, + 0x75, 0x66, 0x47, 0x5a, 0x0a, 0x42, 0x63, 0x7a, 0x59, 0x4b, 0x43, 0x46, + 0x4b, 0x38, 0x33, 0x4d, 0x30, 0x55, 0x59, 0x52, 0x57, 0x45, 0x50, 0x57, + 0x67, 0x54, 0x79, 0x77, 0x53, 0x34, 0x2f, 0x6f, 0x54, 0x6d, 0x69, 0x66, + 0x51, 0x7a, 0x2f, 0x6c, 0x35, 0x47, 0x6e, 0x52, 0x66, 0x48, 0x58, 0x6b, + 0x35, 0x2f, 0x46, 0x76, 0x34, 0x63, 0x49, 0x37, 0x67, 0x6b, 0x6c, 0x4c, + 0x33, 0x35, 0x43, 0x58, 0x35, 0x56, 0x49, 0x50, 0x5a, 0x0a, 0x48, 0x64, + 0x50, 0x49, 0x57, 0x6f, 0x55, 0x2f, 0x58, 0x73, 0x65, 0x32, 0x42, 0x2b, + 0x34, 0x2b, 0x77, 0x4d, 0x36, 0x61, 0x72, 0x36, 0x78, 0x57, 0x51, 0x69, + 0x6f, 0x35, 0x4a, 0x58, 0x44, 0x57, 0x76, 0x37, 0x56, 0x37, 0x4e, 0x71, + 0x32, 0x73, 0x39, 0x6e, 0x50, 0x63, 0x7a, 0x64, 0x63, 0x64, 0x69, 0x6f, + 0x4f, 0x6c, 0x2b, 0x79, 0x75, 0x51, 0x46, 0x54, 0x64, 0x72, 0x48, 0x43, + 0x5a, 0x48, 0x0a, 0x33, 0x44, 0x73, 0x70, 0x56, 0x70, 0x4e, 0x71, 0x73, + 0x38, 0x46, 0x71, 0x4f, 0x70, 0x30, 0x39, 0x39, 0x63, 0x47, 0x58, 0x4f, + 0x46, 0x67, 0x46, 0x69, 0x78, 0x77, 0x52, 0x34, 0x2b, 0x53, 0x30, 0x75, + 0x46, 0x32, 0x46, 0x48, 0x59, 0x50, 0x2b, 0x65, 0x46, 0x38, 0x4c, 0x52, + 0x57, 0x67, 0x59, 0x53, 0x4b, 0x56, 0x47, 0x63, 0x7a, 0x51, 0x37, 0x2f, + 0x67, 0x2f, 0x49, 0x64, 0x72, 0x76, 0x48, 0x0a, 0x47, 0x50, 0x4d, 0x46, + 0x30, 0x59, 0x62, 0x7a, 0x68, 0x65, 0x33, 0x6e, 0x75, 0x64, 0x6b, 0x79, + 0x72, 0x56, 0x57, 0x49, 0x7a, 0x71, 0x61, 0x32, 0x6b, 0x62, 0x42, 0x50, + 0x72, 0x48, 0x34, 0x56, 0x49, 0x35, 0x62, 0x32, 0x50, 0x2f, 0x41, 0x67, + 0x4e, 0x42, 0x62, 0x65, 0x43, 0x73, 0x62, 0x45, 0x42, 0x45, 0x56, 0x35, + 0x66, 0x36, 0x66, 0x39, 0x76, 0x74, 0x4b, 0x70, 0x70, 0x61, 0x2b, 0x63, + 0x0a, 0x78, 0x53, 0x4d, 0x71, 0x39, 0x7a, 0x77, 0x68, 0x62, 0x4c, 0x32, + 0x76, 0x6a, 0x30, 0x37, 0x46, 0x4f, 0x72, 0x4c, 0x7a, 0x4e, 0x42, 0x4c, + 0x38, 0x33, 0x34, 0x41, 0x61, 0x53, 0x61, 0x54, 0x55, 0x71, 0x5a, 0x58, + 0x33, 0x6e, 0x6f, 0x6c, 0x65, 0x6f, 0x6f, 0x6d, 0x73, 0x6c, 0x4d, 0x75, + 0x6f, 0x61, 0x4a, 0x75, 0x76, 0x69, 0x6d, 0x55, 0x6e, 0x7a, 0x59, 0x6e, + 0x75, 0x33, 0x59, 0x79, 0x31, 0x0a, 0x61, 0x79, 0x6c, 0x77, 0x51, 0x36, + 0x42, 0x70, 0x43, 0x2b, 0x53, 0x35, 0x44, 0x77, 0x49, 0x44, 0x41, 0x51, + 0x41, 0x42, 0x6f, 0x30, 0x49, 0x77, 0x51, 0x44, 0x41, 0x64, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x2f, 0x71, + 0x48, 0x67, 0x63, 0x42, 0x34, 0x71, 0x41, 0x7a, 0x6c, 0x53, 0x57, 0x6b, + 0x4b, 0x2b, 0x58, 0x4a, 0x47, 0x46, 0x65, 0x68, 0x69, 0x71, 0x0a, 0x54, + 0x62, 0x55, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, + 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, + 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, + 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x77, 0x44, + 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, + 0x51, 0x45, 0x4c, 0x0a, 0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x42, + 0x41, 0x4d, 0x4a, 0x4b, 0x56, 0x76, 0x6f, 0x56, 0x49, 0x58, 0x73, 0x6f, + 0x6f, 0x75, 0x6e, 0x6c, 0x48, 0x66, 0x76, 0x34, 0x4c, 0x63, 0x51, 0x35, + 0x6c, 0x6b, 0x46, 0x4d, 0x4f, 0x79, 0x63, 0x73, 0x78, 0x47, 0x77, 0x59, + 0x46, 0x59, 0x44, 0x47, 0x72, 0x4b, 0x39, 0x48, 0x57, 0x53, 0x38, 0x6d, + 0x43, 0x2b, 0x4d, 0x32, 0x73, 0x4f, 0x38, 0x37, 0x0a, 0x2f, 0x6b, 0x4f, + 0x58, 0x53, 0x54, 0x4b, 0x5a, 0x45, 0x68, 0x56, 0x62, 0x33, 0x78, 0x45, + 0x70, 0x2f, 0x36, 0x74, 0x54, 0x2b, 0x4c, 0x76, 0x42, 0x65, 0x41, 0x2b, + 0x73, 0x6e, 0x46, 0x4f, 0x76, 0x56, 0x37, 0x31, 0x6f, 0x6a, 0x44, 0x31, + 0x70, 0x4d, 0x2f, 0x43, 0x6a, 0x6f, 0x43, 0x4e, 0x6a, 0x4f, 0x32, 0x52, + 0x6e, 0x49, 0x6b, 0x53, 0x74, 0x31, 0x58, 0x48, 0x4c, 0x56, 0x69, 0x70, + 0x34, 0x0a, 0x6b, 0x71, 0x4e, 0x50, 0x45, 0x6a, 0x45, 0x32, 0x4e, 0x75, + 0x4c, 0x65, 0x2f, 0x67, 0x44, 0x45, 0x6f, 0x32, 0x41, 0x50, 0x4a, 0x36, + 0x32, 0x67, 0x73, 0x49, 0x71, 0x31, 0x4e, 0x6e, 0x70, 0x53, 0x6f, 0x62, + 0x30, 0x6e, 0x39, 0x43, 0x41, 0x6e, 0x59, 0x75, 0x68, 0x4e, 0x6c, 0x43, + 0x51, 0x54, 0x35, 0x41, 0x6f, 0x45, 0x36, 0x54, 0x79, 0x72, 0x4c, 0x73, + 0x68, 0x44, 0x43, 0x55, 0x72, 0x47, 0x0a, 0x59, 0x51, 0x54, 0x6c, 0x53, + 0x54, 0x52, 0x2b, 0x30, 0x38, 0x54, 0x49, 0x39, 0x51, 0x2f, 0x41, 0x71, + 0x75, 0x6d, 0x36, 0x56, 0x46, 0x37, 0x7a, 0x59, 0x79, 0x74, 0x50, 0x54, + 0x31, 0x44, 0x55, 0x2f, 0x72, 0x6c, 0x37, 0x6d, 0x59, 0x77, 0x39, 0x77, + 0x43, 0x36, 0x38, 0x41, 0x69, 0x76, 0x54, 0x78, 0x45, 0x44, 0x6b, 0x69, + 0x67, 0x63, 0x78, 0x48, 0x70, 0x76, 0x4f, 0x4a, 0x70, 0x6b, 0x54, 0x0a, + 0x2b, 0x78, 0x48, 0x71, 0x6d, 0x69, 0x49, 0x4d, 0x45, 0x52, 0x6e, 0x48, + 0x58, 0x68, 0x75, 0x42, 0x55, 0x44, 0x44, 0x49, 0x6c, 0x68, 0x4a, 0x75, + 0x35, 0x38, 0x74, 0x42, 0x66, 0x35, 0x45, 0x37, 0x6f, 0x6b, 0x65, 0x33, + 0x56, 0x49, 0x41, 0x62, 0x33, 0x41, 0x44, 0x4d, 0x6d, 0x70, 0x44, 0x71, + 0x77, 0x38, 0x4e, 0x51, 0x42, 0x6d, 0x49, 0x4d, 0x4d, 0x4d, 0x41, 0x56, + 0x53, 0x4b, 0x65, 0x6f, 0x0a, 0x57, 0x58, 0x7a, 0x68, 0x72, 0x69, 0x4b, + 0x69, 0x34, 0x67, 0x70, 0x36, 0x44, 0x2f, 0x70, 0x69, 0x71, 0x31, 0x4a, + 0x4d, 0x34, 0x66, 0x48, 0x66, 0x79, 0x72, 0x36, 0x44, 0x44, 0x55, 0x49, + 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, + 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x20, 0x2d, 0x20, 0x43, 0x33, 0x20, 0x4f, 0x3d, 0x65, 0x4d, 0x75, 0x64, + 0x68, 0x72, 0x61, 0x20, 0x49, 0x6e, 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x65, + 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x50, 0x4b, 0x49, 0x0a, 0x23, 0x20, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, + 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x43, 0x33, 0x20, + 0x4f, 0x3d, 0x65, 0x4d, 0x75, 0x64, 0x68, 0x72, 0x61, 0x20, 0x49, 0x6e, + 0x63, 0x20, 0x4f, 0x55, 0x3d, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, + 0x50, 0x4b, 0x49, 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, + 0x20, 0x22, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x45, 0x43, 0x43, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x43, + 0x33, 0x22, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, + 0x20, 0x35, 0x38, 0x32, 0x39, 0x34, 0x38, 0x37, 0x31, 0x30, 0x36, 0x34, + 0x32, 0x35, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30, 0x31, 0x34, 0x35, 0x30, + 0x34, 0x0a, 0x23, 0x20, 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x33, 0x65, 0x3a, + 0x35, 0x33, 0x3a, 0x62, 0x33, 0x3a, 0x61, 0x33, 0x3a, 0x38, 0x31, 0x3a, + 0x65, 0x65, 0x3a, 0x64, 0x37, 0x3a, 0x31, 0x30, 0x3a, 0x66, 0x38, 0x3a, + 0x64, 0x33, 0x3a, 0x62, 0x30, 0x3a, 0x31, 0x64, 0x3a, 0x31, 0x37, 0x3a, + 0x39, 0x32, 0x3a, 0x66, 0x35, 0x3a, 0x64, 0x35, 0x0a, 0x23, 0x20, 0x53, + 0x48, 0x41, 0x31, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x62, 0x36, 0x3a, 0x61, 0x66, 0x3a, 0x34, + 0x33, 0x3a, 0x63, 0x32, 0x3a, 0x39, 0x62, 0x3a, 0x38, 0x31, 0x3a, 0x35, + 0x33, 0x3a, 0x37, 0x64, 0x3a, 0x66, 0x36, 0x3a, 0x65, 0x66, 0x3a, 0x36, + 0x62, 0x3a, 0x63, 0x33, 0x3a, 0x31, 0x66, 0x3a, 0x31, 0x66, 0x3a, 0x36, + 0x30, 0x3a, 0x31, 0x35, 0x3a, 0x30, 0x63, 0x3a, 0x65, 0x65, 0x3a, 0x34, + 0x38, 0x3a, 0x36, 0x36, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, + 0x36, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x3a, 0x20, 0x62, 0x63, 0x3a, 0x34, 0x64, 0x3a, 0x38, 0x30, 0x3a, + 0x39, 0x62, 0x3a, 0x31, 0x35, 0x3a, 0x31, 0x38, 0x3a, 0x39, 0x64, 0x3a, + 0x37, 0x38, 0x3a, 0x64, 0x62, 0x3a, 0x33, 0x65, 0x3a, 0x31, 0x64, 0x3a, + 0x38, 0x63, 0x3a, 0x66, 0x34, 0x3a, 0x66, 0x39, 0x3a, 0x37, 0x32, 0x3a, + 0x36, 0x61, 0x3a, 0x37, 0x39, 0x3a, 0x35, 0x64, 0x3a, 0x61, 0x31, 0x3a, + 0x36, 0x34, 0x3a, 0x33, 0x63, 0x3a, 0x61, 0x35, 0x3a, 0x66, 0x31, 0x3a, + 0x33, 0x35, 0x3a, 0x38, 0x65, 0x3a, 0x31, 0x64, 0x3a, 0x64, 0x62, 0x3a, + 0x30, 0x65, 0x3a, 0x64, 0x63, 0x3a, 0x30, 0x64, 0x3a, 0x37, 0x65, 0x3a, + 0x62, 0x33, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, + 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x4b, + 0x7a, 0x43, 0x43, 0x41, 0x62, 0x47, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, + 0x67, 0x49, 0x4b, 0x65, 0x33, 0x47, 0x32, 0x67, 0x6c, 0x61, 0x34, 0x45, + 0x6e, 0x79, 0x63, 0x71, 0x44, 0x41, 0x4b, 0x42, 0x67, 0x67, 0x71, 0x68, + 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x51, 0x44, 0x41, 0x7a, 0x42, 0x61, 0x4d, + 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x0a, + 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x45, 0x54, 0x4d, 0x42, 0x45, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4d, 0x4b, 0x5a, 0x57, 0x31, 0x54, + 0x61, 0x57, 0x64, 0x75, 0x49, 0x46, 0x42, 0x4c, 0x53, 0x54, 0x45, 0x55, + 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4c, + 0x5a, 0x55, 0x31, 0x31, 0x5a, 0x47, 0x68, 0x79, 0x59, 0x53, 0x42, 0x4a, + 0x62, 0x6d, 0x4d, 0x78, 0x0a, 0x49, 0x44, 0x41, 0x65, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x4d, 0x54, 0x46, 0x32, 0x56, 0x74, 0x55, 0x32, 0x6c, + 0x6e, 0x62, 0x69, 0x42, 0x46, 0x51, 0x30, 0x4d, 0x67, 0x55, 0x6d, 0x39, + 0x76, 0x64, 0x43, 0x42, 0x44, 0x51, 0x53, 0x41, 0x74, 0x49, 0x45, 0x4d, + 0x7a, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x34, 0x4d, 0x44, 0x49, + 0x78, 0x4f, 0x44, 0x45, 0x34, 0x4d, 0x7a, 0x41, 0x77, 0x0a, 0x4d, 0x46, + 0x6f, 0x58, 0x44, 0x54, 0x51, 0x7a, 0x4d, 0x44, 0x49, 0x78, 0x4f, 0x44, + 0x45, 0x34, 0x4d, 0x7a, 0x41, 0x77, 0x4d, 0x46, 0x6f, 0x77, 0x57, 0x6a, + 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, + 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x78, 0x45, 0x7a, 0x41, 0x52, 0x42, 0x67, + 0x4e, 0x56, 0x42, 0x41, 0x73, 0x54, 0x43, 0x6d, 0x56, 0x74, 0x55, 0x32, + 0x6c, 0x6e, 0x0a, 0x62, 0x69, 0x42, 0x51, 0x53, 0x30, 0x6b, 0x78, 0x46, + 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x54, 0x43, + 0x32, 0x56, 0x4e, 0x64, 0x57, 0x52, 0x6f, 0x63, 0x6d, 0x45, 0x67, 0x53, + 0x57, 0x35, 0x6a, 0x4d, 0x53, 0x41, 0x77, 0x48, 0x67, 0x59, 0x44, 0x56, + 0x51, 0x51, 0x44, 0x45, 0x78, 0x64, 0x6c, 0x62, 0x56, 0x4e, 0x70, 0x5a, + 0x32, 0x34, 0x67, 0x52, 0x55, 0x4e, 0x44, 0x0a, 0x49, 0x46, 0x4a, 0x76, + 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4c, 0x53, 0x42, 0x44, + 0x4d, 0x7a, 0x42, 0x32, 0x4d, 0x42, 0x41, 0x47, 0x42, 0x79, 0x71, 0x47, + 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x42, 0x53, 0x75, 0x42, + 0x42, 0x41, 0x41, 0x69, 0x41, 0x32, 0x49, 0x41, 0x42, 0x50, 0x32, 0x6c, + 0x59, 0x61, 0x35, 0x37, 0x4a, 0x68, 0x41, 0x64, 0x36, 0x62, 0x63, 0x69, + 0x0a, 0x4d, 0x4b, 0x34, 0x47, 0x39, 0x49, 0x47, 0x7a, 0x73, 0x55, 0x4a, + 0x78, 0x6c, 0x54, 0x6d, 0x38, 0x30, 0x31, 0x4c, 0x6a, 0x72, 0x36, 0x2f, + 0x35, 0x38, 0x70, 0x63, 0x31, 0x6b, 0x6a, 0x5a, 0x47, 0x44, 0x6f, 0x65, + 0x56, 0x6a, 0x62, 0x6b, 0x35, 0x57, 0x75, 0x6d, 0x37, 0x33, 0x39, 0x44, + 0x2b, 0x79, 0x41, 0x64, 0x42, 0x50, 0x4c, 0x74, 0x56, 0x62, 0x34, 0x4f, + 0x6a, 0x61, 0x76, 0x74, 0x69, 0x0a, 0x73, 0x49, 0x47, 0x4a, 0x41, 0x6e, + 0x42, 0x39, 0x53, 0x4d, 0x56, 0x4b, 0x34, 0x2b, 0x6b, 0x69, 0x56, 0x43, + 0x4a, 0x4e, 0x6b, 0x37, 0x74, 0x43, 0x44, 0x4b, 0x39, 0x33, 0x6e, 0x43, + 0x4f, 0x6d, 0x66, 0x64, 0x64, 0x68, 0x45, 0x63, 0x35, 0x6c, 0x78, 0x2f, + 0x68, 0x2f, 0x2f, 0x76, 0x58, 0x79, 0x71, 0x61, 0x4e, 0x43, 0x4d, 0x45, + 0x41, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x0a, 0x42, + 0x42, 0x59, 0x45, 0x46, 0x50, 0x74, 0x61, 0x53, 0x4e, 0x43, 0x41, 0x49, + 0x45, 0x44, 0x79, 0x71, 0x4f, 0x6b, 0x41, 0x42, 0x32, 0x6b, 0x5a, 0x64, + 0x36, 0x66, 0x6d, 0x77, 0x2f, 0x54, 0x50, 0x4d, 0x41, 0x34, 0x47, 0x41, + 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, + 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x50, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x52, 0x4d, 0x42, 0x0a, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, 0x44, + 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, 0x6f, 0x47, 0x43, 0x43, 0x71, 0x47, + 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x44, 0x41, 0x32, 0x67, 0x41, + 0x4d, 0x47, 0x55, 0x43, 0x4d, 0x51, 0x43, 0x30, 0x32, 0x43, 0x38, 0x43, + 0x69, 0x66, 0x32, 0x32, 0x54, 0x47, 0x4b, 0x36, 0x51, 0x30, 0x34, 0x54, + 0x68, 0x48, 0x4b, 0x31, 0x72, 0x74, 0x30, 0x63, 0x0a, 0x33, 0x74, 0x61, + 0x31, 0x33, 0x46, 0x61, 0x50, 0x57, 0x45, 0x42, 0x61, 0x4c, 0x64, 0x34, + 0x67, 0x54, 0x43, 0x4b, 0x44, 0x79, 0x70, 0x4f, 0x6f, 0x66, 0x75, 0x34, + 0x53, 0x51, 0x4d, 0x66, 0x57, 0x68, 0x30, 0x2f, 0x34, 0x33, 0x34, 0x55, + 0x43, 0x4d, 0x42, 0x77, 0x55, 0x5a, 0x4f, 0x52, 0x38, 0x6c, 0x6f, 0x4d, + 0x52, 0x6e, 0x4c, 0x44, 0x52, 0x57, 0x6d, 0x46, 0x4c, 0x70, 0x67, 0x39, + 0x4a, 0x0a, 0x30, 0x77, 0x44, 0x38, 0x6f, 0x66, 0x7a, 0x6b, 0x70, 0x66, + 0x39, 0x2f, 0x72, 0x64, 0x63, 0x77, 0x30, 0x4d, 0x64, 0x33, 0x66, 0x37, + 0x36, 0x42, 0x42, 0x31, 0x55, 0x77, 0x55, 0x43, 0x41, 0x55, 0x39, 0x56, + 0x63, 0x34, 0x43, 0x71, 0x67, 0x78, 0x55, 0x51, 0x3d, 0x3d, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, + 0x43, 0x4e, 0x3d, 0x48, 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x20, + 0x50, 0x6f, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x20, 0x33, 0x20, 0x4f, 0x3d, 0x48, 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, + 0x67, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, 0x43, 0x4e, 0x3d, 0x48, 0x6f, 0x6e, + 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, 0x20, 0x4f, 0x3d, 0x48, + 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x20, 0x50, 0x6f, 0x73, 0x74, + 0x0a, 0x23, 0x20, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x3a, 0x20, 0x22, 0x48, + 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x20, 0x50, 0x6f, 0x73, 0x74, + 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, 0x22, 0x0a, + 0x23, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x34, 0x36, + 0x31, 0x37, 0x30, 0x38, 0x36, 0x35, 0x32, 0x38, 0x38, 0x39, 0x37, 0x31, + 0x33, 0x38, 0x35, 0x35, 0x38, 0x38, 0x32, 0x38, 0x31, 0x31, 0x34, 0x34, + 0x31, 0x36, 0x32, 0x39, 0x37, 0x39, 0x33, 0x34, 0x37, 0x38, 0x37, 0x33, + 0x33, 0x37, 0x31, 0x32, 0x38, 0x32, 0x30, 0x38, 0x34, 0x0a, 0x23, 0x20, + 0x4d, 0x44, 0x35, 0x20, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x31, 0x31, 0x3a, 0x66, 0x63, 0x3a, 0x39, + 0x66, 0x3a, 0x62, 0x64, 0x3a, 0x37, 0x33, 0x3a, 0x33, 0x30, 0x3a, 0x30, + 0x32, 0x3a, 0x38, 0x61, 0x3a, 0x66, 0x64, 0x3a, 0x33, 0x66, 0x3a, 0x66, + 0x33, 0x3a, 0x35, 0x38, 0x3a, 0x62, 0x39, 0x3a, 0x63, 0x62, 0x3a, 0x32, + 0x30, 0x3a, 0x66, 0x30, 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x31, 0x20, + 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, + 0x20, 0x35, 0x38, 0x3a, 0x61, 0x32, 0x3a, 0x64, 0x30, 0x3a, 0x65, 0x63, + 0x3a, 0x32, 0x30, 0x3a, 0x35, 0x32, 0x3a, 0x38, 0x31, 0x3a, 0x35, 0x62, + 0x3a, 0x63, 0x31, 0x3a, 0x66, 0x33, 0x3a, 0x66, 0x38, 0x3a, 0x36, 0x34, + 0x3a, 0x30, 0x32, 0x3a, 0x32, 0x34, 0x3a, 0x34, 0x65, 0x3a, 0x63, 0x32, + 0x3a, 0x38, 0x65, 0x3a, 0x30, 0x32, 0x3a, 0x34, 0x62, 0x3a, 0x30, 0x32, + 0x0a, 0x23, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x46, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x3a, 0x20, 0x35, + 0x61, 0x3a, 0x32, 0x66, 0x3a, 0x63, 0x30, 0x3a, 0x33, 0x66, 0x3a, 0x30, + 0x63, 0x3a, 0x38, 0x33, 0x3a, 0x62, 0x30, 0x3a, 0x39, 0x30, 0x3a, 0x62, + 0x62, 0x3a, 0x66, 0x61, 0x3a, 0x34, 0x30, 0x3a, 0x36, 0x30, 0x3a, 0x34, + 0x62, 0x3a, 0x30, 0x39, 0x3a, 0x38, 0x38, 0x3a, 0x34, 0x34, 0x3a, 0x36, + 0x63, 0x3a, 0x37, 0x36, 0x3a, 0x33, 0x36, 0x3a, 0x31, 0x38, 0x3a, 0x33, + 0x64, 0x3a, 0x66, 0x39, 0x3a, 0x38, 0x34, 0x3a, 0x36, 0x65, 0x3a, 0x31, + 0x37, 0x3a, 0x31, 0x30, 0x3a, 0x31, 0x61, 0x3a, 0x34, 0x34, 0x3a, 0x37, + 0x66, 0x3a, 0x62, 0x38, 0x3a, 0x65, 0x66, 0x3a, 0x64, 0x36, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x46, 0x7a, 0x7a, 0x43, 0x43, 0x41, + 0x37, 0x65, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x43, + 0x42, 0x5a, 0x66, 0x69, 0x6b, 0x79, 0x6c, 0x37, 0x41, 0x44, 0x4a, 0x6b, + 0x30, 0x44, 0x66, 0x78, 0x4d, 0x61, 0x75, 0x49, 0x37, 0x67, 0x63, 0x57, + 0x71, 0x51, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x0a, 0x42, 0x51, 0x41, 0x77, + 0x62, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x42, 0x68, 0x4d, 0x43, 0x53, 0x45, 0x73, 0x78, 0x45, 0x6a, 0x41, 0x51, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x54, 0x43, 0x55, 0x68, 0x76, + 0x62, 0x6d, 0x63, 0x67, 0x53, 0x32, 0x39, 0x75, 0x5a, 0x7a, 0x45, 0x53, + 0x4d, 0x42, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x78, 0x4d, 0x4a, + 0x0a, 0x53, 0x47, 0x39, 0x75, 0x5a, 0x79, 0x42, 0x4c, 0x62, 0x32, 0x35, + 0x6e, 0x4d, 0x52, 0x59, 0x77, 0x46, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, + 0x4b, 0x45, 0x77, 0x31, 0x49, 0x62, 0x32, 0x35, 0x6e, 0x61, 0x32, 0x39, + 0x75, 0x5a, 0x79, 0x42, 0x51, 0x62, 0x33, 0x4e, 0x30, 0x4d, 0x53, 0x41, + 0x77, 0x48, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x78, 0x64, + 0x49, 0x62, 0x32, 0x35, 0x6e, 0x0a, 0x61, 0x32, 0x39, 0x75, 0x5a, 0x79, + 0x42, 0x51, 0x62, 0x33, 0x4e, 0x30, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, + 0x51, 0x67, 0x51, 0x30, 0x45, 0x67, 0x4d, 0x7a, 0x41, 0x65, 0x46, 0x77, + 0x30, 0x78, 0x4e, 0x7a, 0x41, 0x32, 0x4d, 0x44, 0x4d, 0x77, 0x4d, 0x6a, + 0x49, 0x35, 0x4e, 0x44, 0x5a, 0x61, 0x46, 0x77, 0x30, 0x30, 0x4d, 0x6a, + 0x41, 0x32, 0x4d, 0x44, 0x4d, 0x77, 0x4d, 0x6a, 0x49, 0x35, 0x0a, 0x4e, + 0x44, 0x5a, 0x61, 0x4d, 0x47, 0x38, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x68, 0x4c, 0x4d, + 0x52, 0x49, 0x77, 0x45, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, 0x45, + 0x77, 0x6c, 0x49, 0x62, 0x32, 0x35, 0x6e, 0x49, 0x45, 0x74, 0x76, 0x62, + 0x6d, 0x63, 0x78, 0x45, 0x6a, 0x41, 0x51, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x63, 0x54, 0x0a, 0x43, 0x55, 0x68, 0x76, 0x62, 0x6d, 0x63, 0x67, + 0x53, 0x32, 0x39, 0x75, 0x5a, 0x7a, 0x45, 0x57, 0x4d, 0x42, 0x51, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d, 0x4e, 0x53, 0x47, 0x39, 0x75, + 0x5a, 0x32, 0x74, 0x76, 0x62, 0x6d, 0x63, 0x67, 0x55, 0x47, 0x39, 0x7a, + 0x64, 0x44, 0x45, 0x67, 0x4d, 0x42, 0x34, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x41, 0x78, 0x4d, 0x58, 0x53, 0x47, 0x39, 0x75, 0x0a, 0x5a, 0x32, 0x74, + 0x76, 0x62, 0x6d, 0x63, 0x67, 0x55, 0x47, 0x39, 0x7a, 0x64, 0x43, 0x42, + 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x49, 0x44, 0x4d, + 0x77, 0x67, 0x67, 0x49, 0x69, 0x4d, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, + 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, + 0x41, 0x41, 0x34, 0x49, 0x43, 0x44, 0x77, 0x41, 0x77, 0x67, 0x67, 0x49, + 0x4b, 0x0a, 0x41, 0x6f, 0x49, 0x43, 0x41, 0x51, 0x43, 0x7a, 0x69, 0x4e, + 0x66, 0x71, 0x7a, 0x67, 0x38, 0x67, 0x54, 0x72, 0x37, 0x6d, 0x31, 0x67, + 0x4e, 0x74, 0x37, 0x6c, 0x6e, 0x38, 0x77, 0x6c, 0x66, 0x66, 0x4b, 0x57, + 0x69, 0x68, 0x67, 0x77, 0x34, 0x2b, 0x61, 0x4d, 0x64, 0x6f, 0x57, 0x4a, + 0x77, 0x63, 0x59, 0x45, 0x75, 0x4a, 0x51, 0x77, 0x79, 0x35, 0x31, 0x42, + 0x57, 0x79, 0x37, 0x73, 0x46, 0x4f, 0x0a, 0x64, 0x65, 0x6d, 0x31, 0x70, + 0x2b, 0x2f, 0x6c, 0x36, 0x54, 0x57, 0x5a, 0x35, 0x4d, 0x77, 0x63, 0x35, + 0x30, 0x74, 0x66, 0x6a, 0x54, 0x4d, 0x77, 0x49, 0x44, 0x4e, 0x54, 0x32, + 0x61, 0x61, 0x37, 0x31, 0x54, 0x34, 0x54, 0x6a, 0x75, 0x6b, 0x66, 0x68, + 0x30, 0x6d, 0x74, 0x55, 0x43, 0x31, 0x51, 0x79, 0x68, 0x69, 0x2b, 0x41, + 0x56, 0x69, 0x69, 0x45, 0x33, 0x43, 0x57, 0x75, 0x34, 0x6d, 0x49, 0x0a, + 0x56, 0x6f, 0x42, 0x63, 0x2b, 0x4c, 0x30, 0x73, 0x50, 0x4f, 0x46, 0x4d, + 0x56, 0x34, 0x69, 0x37, 0x30, 0x37, 0x6d, 0x56, 0x37, 0x38, 0x76, 0x48, + 0x39, 0x74, 0x6f, 0x78, 0x64, 0x43, 0x69, 0x6d, 0x35, 0x6c, 0x53, 0x4a, + 0x39, 0x55, 0x45, 0x78, 0x79, 0x75, 0x55, 0x6d, 0x47, 0x73, 0x32, 0x43, + 0x34, 0x48, 0x44, 0x61, 0x4f, 0x79, 0x6d, 0x37, 0x31, 0x51, 0x50, 0x31, + 0x6d, 0x62, 0x70, 0x56, 0x0a, 0x39, 0x57, 0x54, 0x52, 0x59, 0x41, 0x36, + 0x7a, 0x69, 0x55, 0x6d, 0x34, 0x69, 0x69, 0x38, 0x46, 0x30, 0x6f, 0x52, + 0x46, 0x4b, 0x48, 0x79, 0x50, 0x61, 0x46, 0x41, 0x53, 0x65, 0x50, 0x77, + 0x4c, 0x74, 0x56, 0x50, 0x4c, 0x77, 0x70, 0x67, 0x63, 0x68, 0x4b, 0x4f, + 0x65, 0x73, 0x4c, 0x34, 0x6a, 0x70, 0x4e, 0x72, 0x63, 0x79, 0x43, 0x73, + 0x65, 0x32, 0x6d, 0x35, 0x46, 0x48, 0x6f, 0x6d, 0x59, 0x0a, 0x32, 0x76, + 0x6b, 0x41, 0x4c, 0x67, 0x62, 0x70, 0x44, 0x44, 0x74, 0x77, 0x31, 0x56, + 0x41, 0x6c, 0x69, 0x4a, 0x6e, 0x4c, 0x7a, 0x58, 0x4e, 0x67, 0x39, 0x39, + 0x58, 0x2f, 0x4e, 0x57, 0x66, 0x46, 0x6f, 0x62, 0x78, 0x65, 0x71, 0x38, + 0x31, 0x4b, 0x75, 0x45, 0x58, 0x72, 0x79, 0x47, 0x67, 0x65, 0x44, 0x51, + 0x30, 0x55, 0x52, 0x68, 0x4c, 0x6a, 0x30, 0x6d, 0x52, 0x69, 0x69, 0x6b, + 0x4b, 0x59, 0x0a, 0x76, 0x4c, 0x54, 0x47, 0x43, 0x41, 0x6a, 0x34, 0x2f, + 0x61, 0x68, 0x4d, 0x5a, 0x4a, 0x78, 0x32, 0x41, 0x62, 0x30, 0x76, 0x71, + 0x57, 0x77, 0x7a, 0x44, 0x39, 0x67, 0x2f, 0x4b, 0x4c, 0x67, 0x38, 0x61, + 0x51, 0x46, 0x43, 0x68, 0x6e, 0x35, 0x70, 0x77, 0x63, 0x6b, 0x47, 0x79, + 0x75, 0x56, 0x36, 0x52, 0x6d, 0x58, 0x70, 0x77, 0x74, 0x5a, 0x51, 0x51, + 0x53, 0x34, 0x2f, 0x74, 0x2b, 0x54, 0x74, 0x0a, 0x62, 0x4e, 0x65, 0x2f, + 0x4a, 0x67, 0x45, 0x52, 0x6f, 0x68, 0x59, 0x70, 0x53, 0x6d, 0x73, 0x30, + 0x42, 0x70, 0x44, 0x73, 0x45, 0x39, 0x4b, 0x32, 0x2b, 0x32, 0x70, 0x32, + 0x30, 0x6a, 0x7a, 0x74, 0x38, 0x4e, 0x59, 0x74, 0x33, 0x65, 0x45, 0x56, + 0x37, 0x4b, 0x4f, 0x62, 0x4c, 0x79, 0x7a, 0x4a, 0x50, 0x69, 0x76, 0x6b, + 0x61, 0x54, 0x76, 0x2f, 0x63, 0x69, 0x57, 0x78, 0x4e, 0x6f, 0x5a, 0x62, + 0x0a, 0x78, 0x33, 0x39, 0x72, 0x69, 0x31, 0x55, 0x62, 0x53, 0x73, 0x55, + 0x67, 0x59, 0x54, 0x32, 0x75, 0x79, 0x31, 0x44, 0x68, 0x43, 0x44, 0x71, + 0x2b, 0x73, 0x49, 0x39, 0x6a, 0x51, 0x56, 0x4d, 0x77, 0x43, 0x46, 0x6b, + 0x38, 0x6d, 0x42, 0x31, 0x33, 0x75, 0x6d, 0x4f, 0x52, 0x65, 0x73, 0x6f, + 0x51, 0x55, 0x47, 0x43, 0x2f, 0x38, 0x4e, 0x65, 0x38, 0x6c, 0x59, 0x65, + 0x50, 0x6c, 0x38, 0x58, 0x2b, 0x0a, 0x6c, 0x32, 0x6f, 0x42, 0x6c, 0x4b, + 0x4e, 0x38, 0x57, 0x34, 0x55, 0x64, 0x4b, 0x6a, 0x6b, 0x36, 0x30, 0x46, + 0x53, 0x68, 0x30, 0x54, 0x6c, 0x78, 0x6e, 0x66, 0x30, 0x68, 0x2b, 0x62, + 0x56, 0x37, 0x38, 0x4f, 0x4c, 0x67, 0x41, 0x6f, 0x39, 0x75, 0x6c, 0x69, + 0x51, 0x6c, 0x4c, 0x4b, 0x41, 0x65, 0x4c, 0x4b, 0x6a, 0x45, 0x69, 0x61, + 0x66, 0x76, 0x37, 0x5a, 0x6b, 0x47, 0x4c, 0x37, 0x59, 0x4b, 0x0a, 0x54, + 0x45, 0x2f, 0x62, 0x6f, 0x73, 0x77, 0x33, 0x47, 0x71, 0x39, 0x48, 0x68, + 0x53, 0x32, 0x4b, 0x58, 0x38, 0x51, 0x30, 0x4e, 0x45, 0x77, 0x41, 0x2f, + 0x52, 0x69, 0x54, 0x5a, 0x78, 0x50, 0x52, 0x4e, 0x2b, 0x5a, 0x49, 0x74, + 0x49, 0x73, 0x47, 0x78, 0x56, 0x64, 0x37, 0x47, 0x59, 0x59, 0x4b, 0x65, + 0x63, 0x73, 0x41, 0x79, 0x56, 0x4b, 0x76, 0x51, 0x76, 0x38, 0x33, 0x6a, + 0x2b, 0x47, 0x6a, 0x0a, 0x48, 0x6e, 0x6f, 0x39, 0x55, 0x4b, 0x74, 0x6a, + 0x42, 0x75, 0x63, 0x56, 0x74, 0x54, 0x2b, 0x32, 0x52, 0x54, 0x65, 0x55, + 0x4e, 0x37, 0x46, 0x2b, 0x38, 0x6b, 0x6a, 0x44, 0x66, 0x38, 0x56, 0x31, + 0x2f, 0x70, 0x65, 0x4e, 0x52, 0x59, 0x38, 0x61, 0x70, 0x78, 0x70, 0x79, + 0x4b, 0x42, 0x70, 0x41, 0x44, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, + 0x6f, 0x32, 0x4d, 0x77, 0x59, 0x54, 0x41, 0x50, 0x0a, 0x42, 0x67, 0x4e, + 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x42, 0x54, 0x41, + 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, + 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, + 0x42, 0x42, 0x6a, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, + 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x51, 0x58, 0x6e, 0x63, 0x30, + 0x65, 0x0a, 0x69, 0x39, 0x59, 0x35, 0x4b, 0x33, 0x44, 0x54, 0x58, 0x4e, + 0x53, 0x67, 0x75, 0x42, 0x2b, 0x77, 0x41, 0x50, 0x7a, 0x46, 0x59, 0x54, + 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, + 0x51, 0x55, 0x46, 0x35, 0x33, 0x4e, 0x48, 0x6f, 0x76, 0x57, 0x4f, 0x53, + 0x74, 0x77, 0x30, 0x31, 0x7a, 0x55, 0x6f, 0x4c, 0x67, 0x66, 0x73, 0x41, + 0x44, 0x38, 0x78, 0x57, 0x45, 0x77, 0x0a, 0x44, 0x51, 0x59, 0x4a, 0x4b, + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, + 0x51, 0x41, 0x44, 0x67, 0x67, 0x49, 0x42, 0x41, 0x46, 0x62, 0x56, 0x65, + 0x32, 0x37, 0x6d, 0x49, 0x67, 0x48, 0x53, 0x51, 0x70, 0x73, 0x59, 0x31, + 0x51, 0x37, 0x58, 0x5a, 0x69, 0x4e, 0x63, 0x34, 0x2f, 0x36, 0x67, 0x78, + 0x35, 0x4c, 0x53, 0x36, 0x5a, 0x53, 0x74, 0x53, 0x36, 0x4c, 0x47, 0x0a, + 0x37, 0x42, 0x4a, 0x38, 0x64, 0x4e, 0x56, 0x49, 0x30, 0x6c, 0x6b, 0x55, + 0x6d, 0x63, 0x44, 0x72, 0x75, 0x64, 0x48, 0x72, 0x39, 0x45, 0x67, 0x77, + 0x57, 0x36, 0x32, 0x6e, 0x56, 0x33, 0x4f, 0x5a, 0x71, 0x64, 0x50, 0x6c, + 0x74, 0x39, 0x45, 0x75, 0x57, 0x53, 0x52, 0x59, 0x33, 0x47, 0x67, 0x75, + 0x4c, 0x6d, 0x4c, 0x59, 0x61, 0x75, 0x52, 0x77, 0x43, 0x79, 0x30, 0x67, + 0x55, 0x43, 0x43, 0x6b, 0x0a, 0x4d, 0x70, 0x58, 0x52, 0x41, 0x4a, 0x69, + 0x37, 0x30, 0x2f, 0x33, 0x33, 0x4d, 0x76, 0x4a, 0x4a, 0x72, 0x73, 0x5a, + 0x36, 0x34, 0x45, 0x65, 0x2b, 0x62, 0x73, 0x37, 0x4c, 0x6f, 0x33, 0x49, + 0x36, 0x4c, 0x57, 0x6c, 0x64, 0x79, 0x38, 0x6a, 0x6f, 0x52, 0x54, 0x6e, + 0x55, 0x2b, 0x6b, 0x4c, 0x42, 0x45, 0x55, 0x78, 0x33, 0x58, 0x5a, 0x4c, + 0x37, 0x61, 0x76, 0x39, 0x59, 0x52, 0x4f, 0x58, 0x72, 0x0a, 0x67, 0x5a, + 0x36, 0x76, 0x6f, 0x4a, 0x6d, 0x74, 0x76, 0x71, 0x6b, 0x42, 0x5a, 0x73, + 0x73, 0x34, 0x48, 0x54, 0x7a, 0x66, 0x51, 0x78, 0x2f, 0x30, 0x54, 0x57, + 0x36, 0x30, 0x75, 0x68, 0x64, 0x47, 0x2f, 0x48, 0x33, 0x39, 0x68, 0x34, + 0x46, 0x35, 0x61, 0x67, 0x30, 0x7a, 0x44, 0x2f, 0x6f, 0x76, 0x2b, 0x42, + 0x53, 0x35, 0x67, 0x4c, 0x4e, 0x64, 0x54, 0x61, 0x71, 0x58, 0x34, 0x66, + 0x6e, 0x6b, 0x0a, 0x47, 0x4d, 0x58, 0x34, 0x31, 0x54, 0x69, 0x4d, 0x4a, + 0x6a, 0x7a, 0x39, 0x38, 0x69, 0x6a, 0x69, 0x37, 0x6c, 0x70, 0x4a, 0x69, + 0x43, 0x7a, 0x66, 0x65, 0x54, 0x32, 0x4f, 0x6e, 0x70, 0x41, 0x38, 0x76, + 0x55, 0x46, 0x4b, 0x4f, 0x74, 0x31, 0x62, 0x39, 0x70, 0x71, 0x30, 0x7a, + 0x6a, 0x38, 0x6c, 0x4d, 0x48, 0x38, 0x79, 0x66, 0x61, 0x49, 0x44, 0x6c, + 0x4e, 0x44, 0x63, 0x65, 0x71, 0x46, 0x53, 0x0a, 0x33, 0x6d, 0x36, 0x54, + 0x6a, 0x52, 0x67, 0x6d, 0x2f, 0x56, 0x57, 0x73, 0x76, 0x59, 0x2b, 0x62, + 0x30, 0x73, 0x2b, 0x76, 0x35, 0x34, 0x59, 0x73, 0x79, 0x78, 0x38, 0x4a, + 0x62, 0x36, 0x4e, 0x76, 0x71, 0x59, 0x54, 0x55, 0x63, 0x37, 0x39, 0x4e, + 0x6f, 0x58, 0x51, 0x62, 0x54, 0x69, 0x4e, 0x67, 0x38, 0x73, 0x77, 0x4f, + 0x71, 0x6e, 0x2b, 0x6b, 0x6e, 0x45, 0x77, 0x6c, 0x71, 0x4c, 0x4a, 0x6d, + 0x0a, 0x4f, 0x7a, 0x6a, 0x2f, 0x32, 0x5a, 0x51, 0x77, 0x39, 0x6e, 0x4b, + 0x45, 0x76, 0x6d, 0x68, 0x56, 0x45, 0x41, 0x2f, 0x47, 0x63, 0x79, 0x77, + 0x57, 0x61, 0x5a, 0x4d, 0x48, 0x2f, 0x72, 0x46, 0x46, 0x37, 0x62, 0x75, + 0x69, 0x56, 0x57, 0x71, 0x77, 0x32, 0x72, 0x56, 0x4b, 0x41, 0x69, 0x55, + 0x6e, 0x68, 0x64, 0x65, 0x33, 0x74, 0x34, 0x5a, 0x45, 0x46, 0x6f, 0x6c, + 0x73, 0x67, 0x43, 0x73, 0x2b, 0x0a, 0x6c, 0x36, 0x6d, 0x63, 0x31, 0x58, + 0x35, 0x56, 0x54, 0x4d, 0x62, 0x65, 0x52, 0x52, 0x41, 0x63, 0x36, 0x75, + 0x6b, 0x37, 0x6e, 0x77, 0x4e, 0x54, 0x37, 0x75, 0x35, 0x36, 0x41, 0x51, + 0x49, 0x57, 0x65, 0x4e, 0x54, 0x6f, 0x77, 0x72, 0x35, 0x47, 0x64, 0x6f, + 0x67, 0x54, 0x50, 0x79, 0x4b, 0x37, 0x53, 0x42, 0x49, 0x64, 0x55, 0x67, + 0x43, 0x30, 0x41, 0x6e, 0x34, 0x68, 0x47, 0x68, 0x36, 0x63, 0x0a, 0x4a, + 0x66, 0x54, 0x7a, 0x50, 0x56, 0x34, 0x65, 0x30, 0x68, 0x7a, 0x35, 0x73, + 0x79, 0x32, 0x32, 0x39, 0x7a, 0x64, 0x63, 0x78, 0x73, 0x73, 0x68, 0x54, + 0x72, 0x44, 0x33, 0x6d, 0x55, 0x63, 0x59, 0x68, 0x63, 0x45, 0x72, 0x75, + 0x6c, 0x57, 0x75, 0x42, 0x75, 0x72, 0x51, 0x42, 0x37, 0x4c, 0x63, 0x71, + 0x39, 0x43, 0x43, 0x6c, 0x6e, 0x58, 0x4f, 0x30, 0x6c, 0x44, 0x2b, 0x6d, + 0x65, 0x66, 0x50, 0x0a, 0x4c, 0x35, 0x2f, 0x6e, 0x64, 0x74, 0x46, 0x68, + 0x4b, 0x76, 0x73, 0x68, 0x75, 0x7a, 0x48, 0x51, 0x71, 0x70, 0x39, 0x48, + 0x70, 0x4c, 0x49, 0x69, 0x79, 0x68, 0x59, 0x36, 0x55, 0x46, 0x66, 0x45, + 0x57, 0x30, 0x4e, 0x6e, 0x78, 0x57, 0x56, 0x69, 0x41, 0x30, 0x6b, 0x42, + 0x36, 0x30, 0x50, 0x5a, 0x32, 0x50, 0x69, 0x65, 0x72, 0x63, 0x2b, 0x78, + 0x59, 0x77, 0x35, 0x46, 0x39, 0x4b, 0x42, 0x61, 0x0a, 0x4c, 0x4a, 0x73, + 0x74, 0x78, 0x61, 0x62, 0x41, 0x72, 0x61, 0x68, 0x48, 0x39, 0x43, 0x64, + 0x4d, 0x4f, 0x41, 0x30, 0x75, 0x47, 0x30, 0x6b, 0x37, 0x55, 0x76, 0x54, + 0x6f, 0x69, 0x49, 0x4d, 0x72, 0x56, 0x43, 0x6a, 0x55, 0x38, 0x6a, 0x56, + 0x53, 0x74, 0x44, 0x4b, 0x44, 0x59, 0x6d, 0x6c, 0x6b, 0x44, 0x4a, 0x47, + 0x63, 0x6e, 0x35, 0x66, 0x71, 0x64, 0x42, 0x62, 0x39, 0x48, 0x78, 0x45, + 0x47, 0x0a, 0x6d, 0x70, 0x76, 0x30, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, + 0x00 // Extra \0 to make it a C string +}; + +const size_t grpc_root_certificates_generated_size = + sizeof(grpc_root_certificates_generated_data) - 1; + +const char roots_filename[] = "roots.pem"; + +} // namespace remote +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_root_certificates_generated.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_root_certificates_generated.h new file mode 100644 index 0000000..09b6fad --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_root_certificates_generated.h @@ -0,0 +1,20 @@ +// Copyright 2019 Google Inc. All Rights Reserved. + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_GRPC_ROOT_CERTIFICATES_GENERATED_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_GRPC_ROOT_CERTIFICATES_GENERATED_H_ + +#include + +namespace firebase { +namespace firestore { +namespace remote { + +extern const size_t grpc_root_certificates_generated_size; +extern const unsigned char grpc_root_certificates_generated_data[]; +extern const char roots_filename[]; + +} // namespace remote +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_GRPC_ROOT_CERTIFICATES_GENERATED_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_stream.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_stream.cc index 9656dfe..380382f 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_stream.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_stream.cc @@ -22,6 +22,7 @@ #include "Firestore/core/src/firebase/firestore/remote/grpc_connection.h" #include "Firestore/core/src/firebase/firestore/remote/grpc_util.h" #include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" namespace firebase { namespace firestore { @@ -85,7 +86,7 @@ using internal::BufferedWriter; GrpcStream::GrpcStream( std::unique_ptr context, std::unique_ptr call, - AsyncQueue* worker_queue, + const std::shared_ptr& worker_queue, GrpcConnection* grpc_connection, GrpcStreamObserver* observer) : context_{std::move(NOT_NULL(context))}, @@ -127,11 +128,11 @@ void GrpcStream::Read() { return; } - GrpcCompletion* completion = - NewCompletion(Type::Read, [this](const GrpcCompletion* completion) { + auto completion = NewCompletion( + Type::Read, [this](const std::shared_ptr& completion) { OnRead(*completion->message()); }); - call_->Read(completion->message(), completion); + call_->Read(completion->message(), completion.get()); } void GrpcStream::Write(grpc::ByteBuffer&& message) { @@ -150,11 +151,12 @@ void GrpcStream::MaybeWrite(absl::optional maybe_write) { } BufferedWrite write = std::move(maybe_write).value(); - GrpcCompletion* completion = - NewCompletion(Type::Write, [this](const GrpcCompletion*) { OnWrite(); }); + auto completion = NewCompletion( + Type::Write, + [this](const std::shared_ptr&) { OnWrite(); }); *completion->message() = write.message; - call_->Write(*completion->message(), write.options, completion); + call_->Write(*completion->message(), write.options, completion.get()); } void GrpcStream::FinishImmediately() { @@ -222,8 +224,8 @@ void GrpcStream::FinishGrpcCall(const OnSuccess& callback) { // All completions issued by this call must be taken off the queue before // finish operation can be enqueued. FastFinishCompletionsBlocking(); - GrpcCompletion* completion = NewCompletion(Type::Finish, callback); - call_->Finish(completion->status(), completion); + auto completion = NewCompletion(Type::Finish, callback); + call_->Finish(completion->status(), completion.get()); } void GrpcStream::FastFinishCompletionsBlocking() { @@ -233,16 +235,19 @@ void GrpcStream::FastFinishCompletionsBlocking() { // TODO(varconst): reset buffered_writer_? Should not be necessary, because it // should never be called again after a call to Finish. - for (auto completion : completions_) { + for (const auto& completion : completions_) { // `GrpcStream` cannot actually remove any of the completions that already // have been enqueued on the worker queue, so instead turn them into no-ops. completion->Cancel(); } - for (auto completion : completions_) { + for (const auto& completion : completions_) { // This is blocking. completion->WaitUntilOffQueue(); } + + // This will release all the shared pointers to GrpcCompletion, leaving it + // up to gRPC to actually call Complete and trigger deletion. completions_.clear(); } @@ -264,9 +269,10 @@ bool GrpcStream::TryLastWrite(grpc::ByteBuffer&& message) { } BufferedWrite last_write = std::move(maybe_write).value(); - GrpcCompletion* completion = NewCompletion(Type::Write, {}); + auto completion = NewCompletion(Type::Write, {}); *completion->message() = last_write.message; - call_->WriteLast(*completion->message(), grpc::WriteOptions{}, completion); + call_->WriteLast(*completion->message(), grpc::WriteOptions{}, + completion.get()); // Empirically, the write normally takes less than a millisecond to finish // (both with and without network connection), and never more than several @@ -310,23 +316,25 @@ void GrpcStream::OnOperationFailed() { return; } - FinishGrpcCall([this](const GrpcCompletion* completion) { + FinishGrpcCall([this](const std::shared_ptr& completion) { Status status = ConvertStatus(*completion->status()); FinishAndNotify(status); }); } -void GrpcStream::RemoveCompletion(const GrpcCompletion* to_remove) { +void GrpcStream::RemoveCompletion( + const std::shared_ptr& to_remove) { auto found = std::find(completions_.begin(), completions_.end(), to_remove); HARD_ASSERT(found != completions_.end(), "Missing GrpcCompletion"); completions_.erase(found); } -GrpcCompletion* GrpcStream::NewCompletion(Type tag, - const OnSuccess& on_success) { +std::shared_ptr GrpcStream::NewCompletion( + Type tag, const OnSuccess& on_success) { // Can't move into lambda until C++14. GrpcCompletion::Callback decorated = - [this, on_success](bool ok, const GrpcCompletion* completion) { + [this, on_success](bool ok, + const std::shared_ptr& completion) { RemoveCompletion(completion); if (ok) { @@ -343,8 +351,8 @@ GrpcCompletion* GrpcStream::NewCompletion(Type tag, }; // For lifetime details, see `GrpcCompletion` class comment. - auto* completion = - new GrpcCompletion{tag, worker_queue_, std::move(decorated)}; + auto completion = + GrpcCompletion::Create(tag, worker_queue_, std::move(decorated)); completions_.push_back(completion); return completion; } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_stream.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_stream.h index 9b0a528..ca1c497 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_stream.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_stream.h @@ -31,7 +31,7 @@ #include "Firestore/core/src/firebase/firestore/remote/grpc_completion.h" #include "Firestore/core/src/firebase/firestore/remote/grpc_stream_observer.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "absl/types/optional.h" #include "grpcpp/client_context.h" SUPPRESS_DOCUMENTATION_WARNINGS_BEGIN() @@ -124,10 +124,10 @@ class GrpcStream : public GrpcCall { public: GrpcStream(std::unique_ptr context, std::unique_ptr call, - util::AsyncQueue* worker_queue, + const std::shared_ptr& worker_queue, GrpcConnection* grpc_connection, GrpcStreamObserver* observer); - ~GrpcStream(); + ~GrpcStream() override; void Start(); @@ -196,11 +196,11 @@ class GrpcStream : public GrpcCall { void OnRead(const grpc::ByteBuffer& message); void OnWrite(); void OnOperationFailed(); - void RemoveCompletion(const GrpcCompletion* to_remove); + void RemoveCompletion(const std::shared_ptr& to_remove); - using OnSuccess = std::function; - GrpcCompletion* NewCompletion(GrpcCompletion::Type type, - const OnSuccess& callback); + using OnSuccess = std::function&)>; + std::shared_ptr NewCompletion(GrpcCompletion::Type type, + const OnSuccess& callback); // Finishes the underlying gRPC call. Must always be invoked on any call that // was started. Presumes that any pending completions will quickly come off // the queue and will block until they do, so this must only be invoked when @@ -229,13 +229,13 @@ class GrpcStream : public GrpcCall { std::unique_ptr context_; std::unique_ptr call_; - util::AsyncQueue* worker_queue_ = nullptr; + std::shared_ptr worker_queue_; GrpcConnection* grpc_connection_ = nullptr; GrpcStreamObserver* observer_ = nullptr; internal::BufferedWriter buffered_writer_; - std::vector completions_; + std::vector> completions_; // gRPC asserts that a call is finished exactly once. bool is_grpc_call_finished_ = false; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_stream_observer.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_stream_observer.h index 0b0980b..5298120 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_stream_observer.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_stream_observer.h @@ -17,7 +17,7 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_GRPC_STREAM_OBSERVER_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_GRPC_STREAM_OBSERVER_H_ -#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "grpcpp/support/byte_buffer.h" namespace firebase { diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_streaming_reader.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_streaming_reader.cc index 64dac1b..eab49ba 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_streaming_reader.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_streaming_reader.cc @@ -20,6 +20,9 @@ #include "Firestore/core/src/firebase/firestore/remote/grpc_connection.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/statusor.h" +#include "absl/memory/memory.h" namespace firebase { namespace firestore { @@ -32,7 +35,7 @@ using util::StatusOr; GrpcStreamingReader::GrpcStreamingReader( std::unique_ptr context, std::unique_ptr call, - util::AsyncQueue* worker_queue, + const std::shared_ptr& worker_queue, GrpcConnection* grpc_connection, const grpc::ByteBuffer& request) : stream_{absl::make_unique(std::move(context), diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_streaming_reader.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_streaming_reader.h index c31b096..ca66257 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_streaming_reader.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_streaming_reader.h @@ -26,8 +26,7 @@ #include "Firestore/core/src/firebase/firestore/remote/grpc_stream.h" #include "Firestore/core/src/firebase/firestore/remote/grpc_stream_observer.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" -#include "Firestore/core/src/firebase/firestore/util/statusor.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "grpcpp/client_context.h" SUPPRESS_DOCUMENTATION_WARNINGS_BEGIN() #include "grpcpp/generic/generic_stub.h" @@ -52,7 +51,7 @@ class GrpcStreamingReader : public GrpcCall, public GrpcStreamObserver { GrpcStreamingReader( std::unique_ptr context, std::unique_ptr call, - util::AsyncQueue* worker_queue, + const std::shared_ptr& worker_queue, GrpcConnection* grpc_connection, const grpc::ByteBuffer& request); diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_unary_call.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_unary_call.cc index 735ee1b..829f4fb 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_unary_call.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_unary_call.cc @@ -20,6 +20,7 @@ #include "Firestore/core/src/firebase/firestore/remote/grpc_connection.h" #include "Firestore/core/src/firebase/firestore/remote/grpc_util.h" +#include "Firestore/core/src/firebase/firestore/util/statusor.h" namespace firebase { namespace firestore { @@ -32,7 +33,7 @@ using Type = GrpcCompletion::Type; GrpcUnaryCall::GrpcUnaryCall( std::unique_ptr context, std::unique_ptr call, - AsyncQueue* worker_queue, + const std::shared_ptr& worker_queue, GrpcConnection* grpc_connection, const grpc::ByteBuffer& request) : context_{std::move(context)}, @@ -54,11 +55,12 @@ void GrpcUnaryCall::Start(Callback&& callback) { call_->StartCall(); // For lifetime details, see `GrpcCompletion` class comment. - finish_completion_ = new GrpcCompletion( + finish_completion_ = GrpcCompletion::Create( Type::Finish, worker_queue_, - [this](bool /*ignored_ok*/, const GrpcCompletion* completion) { + [this](bool /*ignored_ok*/, + const std::shared_ptr& completion) { // Ignoring ok, status should contain all the relevant information. - finish_completion_ = nullptr; + finish_completion_.reset(); Shutdown(); auto callback = std::move(callback_); @@ -72,7 +74,7 @@ void GrpcUnaryCall::Start(Callback&& callback) { }); call_->Finish(finish_completion_->message(), finish_completion_->status(), - finish_completion_); + finish_completion_.get()); } void GrpcUnaryCall::FinishImmediately() { @@ -98,7 +100,7 @@ void GrpcUnaryCall::Shutdown() { finish_completion_->Cancel(); // This function blocks. finish_completion_->WaitUntilOffQueue(); - finish_completion_ = nullptr; + finish_completion_.reset(); } void GrpcUnaryCall::MaybeUnregister() { diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_unary_call.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_unary_call.h index 3edb2bb..8d4f8aa 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_unary_call.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_unary_call.h @@ -26,8 +26,7 @@ #include "Firestore/core/src/firebase/firestore/remote/grpc_call.h" #include "Firestore/core/src/firebase/firestore/remote/grpc_completion.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" -#include "Firestore/core/src/firebase/firestore/util/statusor.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "grpcpp/client_context.h" SUPPRESS_DOCUMENTATION_WARNINGS_BEGIN() #include "grpcpp/generic/generic_stub.h" @@ -50,7 +49,7 @@ class GrpcUnaryCall : public GrpcCall { GrpcUnaryCall(std::unique_ptr context, std::unique_ptr call, - util::AsyncQueue* worker_queue, + const std::shared_ptr& worker_queue, GrpcConnection* grpc_connection, const grpc::ByteBuffer& request); ~GrpcUnaryCall(); @@ -100,10 +99,10 @@ class GrpcUnaryCall : public GrpcCall { // Stored to avoid lifetime issues with gRPC. grpc::ByteBuffer request_; - util::AsyncQueue* worker_queue_ = nullptr; + std::shared_ptr worker_queue_; GrpcConnection* grpc_connection_ = nullptr; - GrpcCompletion* finish_completion_ = nullptr; + std::shared_ptr finish_completion_; Callback callback_; }; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_util.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_util.cc index 12db198..a5f88f1 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_util.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_util.cc @@ -17,6 +17,7 @@ #include "Firestore/core/src/firebase/firestore/remote/grpc_util.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" namespace firebase { namespace firestore { @@ -39,7 +40,7 @@ Status ConvertStatus(const grpc::Status& from) { error_code >= grpc::CANCELLED && error_code <= grpc::UNAUTHENTICATED, "Unknown gRPC error code: %s", error_code); - return {static_cast(error_code), from.error_message()}; + return {static_cast(error_code), from.error_message()}; } } // namespace remote diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_util.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_util.h index 89b8c7f..2cba6e3 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_util.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/grpc_util.h @@ -17,7 +17,7 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_GRPC_UTIL_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_GRPC_UTIL_H_ -#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "grpcpp/support/status.h" namespace firebase { diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/online_state_tracker.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/online_state_tracker.cc index afdc69d..36e083b 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/online_state_tracker.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/online_state_tracker.cc @@ -21,6 +21,7 @@ #include "Firestore/core/src/firebase/firestore/util/executor.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" #include "Firestore/core/src/firebase/firestore/util/string_format.h" namespace chr = std::chrono; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h index a061745..b84ae15 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h @@ -18,11 +18,13 @@ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_ONLINE_STATE_TRACKER_H_ #include +#include #include +#include #include "Firestore/core/src/firebase/firestore/model/types.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" namespace firebase { namespace firestore { @@ -37,14 +39,14 @@ namespace remote { * up to `kMaxWatchStreamFailures` within `kOnlineStateTimeout` for a connection * to succeed. If we have too many failures or the timeout elapses, then we set * the `OnlineState` to `Offline`, and the client will behave as if it is - * offline (`getDocument()` calls will return cached data, etc.). + * offline (`GetDocument()` calls will return cached data, etc.). */ class OnlineStateTracker { public: OnlineStateTracker() = default; OnlineStateTracker( - util::AsyncQueue* worker_queue, + const std::shared_ptr& worker_queue, std::function online_state_handler) : worker_queue_{worker_queue}, online_state_handler_{online_state_handler} { @@ -55,7 +57,7 @@ class OnlineStateTracker { * each backoff attempt). * * If this is the first attempt, it sets the `OnlineState` to `Unknown` and - * starts the `onlineStateTimer`. + * starts the `online_state_timer_`. */ void HandleWatchStreamStart(); @@ -111,7 +113,7 @@ class OnlineStateTracker { * The worker queue to use for running timers (and to call * `online_state_handler_`). */ - util::AsyncQueue* worker_queue_ = nullptr; + std::shared_ptr worker_queue_; /** A callback to be notified on `OnlineState` changes. */ std::function online_state_handler_; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_event.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_event.cc new file mode 100644 index 0000000..49560ea --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_event.cc @@ -0,0 +1,427 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" + +#include + +#include "Firestore/core/src/firebase/firestore/local/target_data.h" +#include "Firestore/core/src/firebase/firestore/model/no_document.h" + +namespace firebase { +namespace firestore { +namespace remote { + +using core::DocumentViewChange; +using core::Target; +using local::QueryPurpose; +using local::TargetData; +using model::DocumentKey; +using model::DocumentKeySet; +using model::MaybeDocument; +using model::NoDocument; +using model::SnapshotVersion; +using model::TargetId; +using nanopb::ByteString; + +// TargetChange + +bool operator==(const TargetChange& lhs, const TargetChange& rhs) { + return lhs.resume_token() == rhs.resume_token() && + lhs.current() == rhs.current() && + lhs.added_documents() == rhs.added_documents() && + lhs.modified_documents() == rhs.modified_documents() && + lhs.removed_documents() == rhs.removed_documents(); +} + +// TargetState + +void TargetState::UpdateResumeToken(ByteString resume_token) { + if (!resume_token.empty()) { + has_pending_changes_ = true; + resume_token_ = std::move(resume_token); + } +} + +TargetChange TargetState::ToTargetChange() const { + DocumentKeySet added_documents; + DocumentKeySet modified_documents; + DocumentKeySet removed_documents; + + for (const auto& entry : document_changes_) { + const DocumentKey& document_key = entry.first; + DocumentViewChange::Type change_type = entry.second; + + switch (change_type) { + case DocumentViewChange::Type::Added: + added_documents = added_documents.insert(document_key); + break; + case DocumentViewChange::Type::Modified: + modified_documents = modified_documents.insert(document_key); + break; + case DocumentViewChange::Type::Removed: + removed_documents = removed_documents.insert(document_key); + break; + default: + HARD_FAIL("Encountered invalid change type: %s", change_type); + } + } + + return TargetChange{resume_token(), current(), std::move(added_documents), + std::move(modified_documents), + std::move(removed_documents)}; +} + +void TargetState::ClearPendingChanges() { + has_pending_changes_ = false; + document_changes_.clear(); +} + +void TargetState::RecordPendingTargetRequest() { + ++outstanding_responses_; +} + +void TargetState::RecordTargetResponse() { + --outstanding_responses_; +} + +void TargetState::MarkCurrent() { + has_pending_changes_ = true; + current_ = true; +} + +void TargetState::AddDocumentChange(const DocumentKey& document_key, + DocumentViewChange::Type type) { + has_pending_changes_ = true; + document_changes_[document_key] = type; +} + +void TargetState::RemoveDocumentChange(const DocumentKey& document_key) { + has_pending_changes_ = true; + document_changes_.erase(document_key); +} + +// WatchChangeAggregator + +WatchChangeAggregator::WatchChangeAggregator( + TargetMetadataProvider* target_metadata_provider) + : target_metadata_provider_{NOT_NULL(target_metadata_provider)} { +} + +void WatchChangeAggregator::HandleDocumentChange( + const DocumentWatchChange& document_change) { + for (TargetId target_id : document_change.updated_target_ids()) { + const auto& new_doc = document_change.new_document(); + if (new_doc && new_doc->is_document()) { + AddDocumentToTarget(target_id, *new_doc); + } else if (new_doc && new_doc->is_no_document()) { + RemoveDocumentFromTarget(target_id, document_change.document_key(), + document_change.new_document()); + } + } + + for (TargetId target_id : document_change.removed_target_ids()) { + RemoveDocumentFromTarget(target_id, document_change.document_key(), + document_change.new_document()); + } +} + +void WatchChangeAggregator::HandleTargetChange( + const WatchTargetChange& target_change) { + for (TargetId target_id : GetTargetIds(target_change)) { + TargetState& target_state = EnsureTargetState(target_id); + + switch (target_change.state()) { + case WatchTargetChangeState::NoChange: + if (IsActiveTarget(target_id)) { + target_state.UpdateResumeToken(target_change.resume_token()); + } + continue; + case WatchTargetChangeState::Added: + // We need to decrement the number of pending acks needed from watch for + // this target_id. + target_state.RecordTargetResponse(); + if (!target_state.IsPending()) { + // We have a freshly added target, so we need to reset any state that + // we had previously. This can happen e.g. when remove and add back a + // target for existence filter mismatches. + target_state.ClearPendingChanges(); + } + target_state.UpdateResumeToken(target_change.resume_token()); + continue; + case WatchTargetChangeState::Removed: + // We need to keep track of removed targets so we can post-filter and + // remove any target changes. We need to decrement the number of pending + // acks needed from watch for this target_id. + target_state.RecordTargetResponse(); + if (!target_state.IsPending()) { + RemoveTarget(target_id); + } + HARD_ASSERT(target_change.cause().ok(), + "WatchChangeAggregator does not handle errored targets"); + continue; + case WatchTargetChangeState::Current: + if (IsActiveTarget(target_id)) { + target_state.MarkCurrent(); + target_state.UpdateResumeToken(target_change.resume_token()); + } + continue; + case WatchTargetChangeState::Reset: + if (IsActiveTarget(target_id)) { + // Reset the target and synthesizes removes for all existing + // documents. The backend will re-add any documents that still match + // the target before it sends the next global snapshot. + ResetTarget(target_id); + target_state.UpdateResumeToken(target_change.resume_token()); + } + continue; + } + HARD_FAIL("Unknown target watch change state: %s", target_change.state()); + } +} + +std::vector WatchChangeAggregator::GetTargetIds( + const WatchTargetChange& target_change) const { + if (!target_change.target_ids().empty()) { + return target_change.target_ids(); + } + + std::vector result; + result.reserve(target_states_.size()); + for (const auto& entry : target_states_) { + result.push_back(entry.first); + } + + return result; +} + +void WatchChangeAggregator::HandleExistenceFilter( + const ExistenceFilterWatchChange& existence_filter) { + TargetId target_id = existence_filter.target_id(); + int expected_count = existence_filter.filter().count(); + + absl::optional target_data = TargetDataForActiveTarget(target_id); + if (target_data) { + const Target& target = target_data->target(); + if (target.IsDocumentQuery()) { + if (expected_count == 0) { + // The existence filter told us the document does not exist. We deduce + // that this document does not exist and apply a deleted document to our + // updates. Without applying this deleted document there might be + // another query that will raise this document as part of a snapshot + // until it is resolved, essentially exposing inconsistency between + // queries. + DocumentKey key{target.path()}; + RemoveDocumentFromTarget( + target_id, key, + NoDocument(key, SnapshotVersion::None(), + /* has_committed_mutations= */ false)); + } else { + HARD_ASSERT(expected_count == 1, + "Single document existence filter with count: %s", + expected_count); + } + } else { + int current_size = GetCurrentDocumentCountForTarget(target_id); + if (current_size != expected_count) { + // Existence filter mismatch: We reset the mapping and raise a new + // snapshot with `isFromCache:true`. + ResetTarget(target_id); + pending_target_resets_.insert(target_id); + } + } + } +} + +RemoteEvent WatchChangeAggregator::CreateRemoteEvent( + const SnapshotVersion& snapshot_version) { + std::unordered_map target_changes; + + for (auto& entry : target_states_) { + TargetId target_id = entry.first; + TargetState& target_state = entry.second; + + absl::optional target_data = + TargetDataForActiveTarget(target_id); + if (target_data) { + if (target_state.current() && target_data->target().IsDocumentQuery()) { + // Document queries for document that don't exist can produce an empty + // result set. To update our local cache, we synthesize a document + // delete if we have not previously received the document. This resolves + // the limbo state of the document, removing it from + // SyncEngine::limbo_document_refs_. + DocumentKey key{target_data->target().path()}; + if (pending_document_updates_.find(key) == + pending_document_updates_.end() && + !TargetContainsDocument(target_id, key)) { + RemoveDocumentFromTarget( + target_id, key, + NoDocument(key, snapshot_version, + /* has_committed_mutations= */ false)); + } + } + + if (target_state.HasPendingChanges()) { + target_changes[target_id] = target_state.ToTargetChange(); + target_state.ClearPendingChanges(); + } + } + } + + DocumentKeySet resolved_limbo_documents; + + // We extract the set of limbo-only document updates as the GC logic + // special-cases documents that do not appear in the target cache. + // + // TODO(gsoltis): Expand on this comment. + for (const auto& entry : pending_document_target_mappings_) { + bool is_only_limbo_target = true; + + for (TargetId target_id : entry.second) { + absl::optional target_data = + TargetDataForActiveTarget(target_id); + if (target_data && + target_data->purpose() != QueryPurpose::LimboResolution) { + is_only_limbo_target = false; + break; + } + } + + if (is_only_limbo_target) { + resolved_limbo_documents = resolved_limbo_documents.insert(entry.first); + } + } + + RemoteEvent remote_event{snapshot_version, std::move(target_changes), + std::move(pending_target_resets_), + std::move(pending_document_updates_), + std::move(resolved_limbo_documents)}; + + // Re-initialize the current state to ensure that we do not modify the + // generated `RemoteEvent`. + pending_document_updates_.clear(); + pending_document_target_mappings_.clear(); + pending_target_resets_.clear(); + + return remote_event; +} + +void WatchChangeAggregator::AddDocumentToTarget(TargetId target_id, + const MaybeDocument& document) { + if (!IsActiveTarget(target_id)) { + return; + } + + DocumentViewChange::Type change_type = + TargetContainsDocument(target_id, document.key()) + ? DocumentViewChange::Type::Modified + : DocumentViewChange::Type::Added; + + TargetState& target_state = EnsureTargetState(target_id); + target_state.AddDocumentChange(document.key(), change_type); + + pending_document_updates_[document.key()] = document; + pending_document_target_mappings_[document.key()].insert(target_id); +} + +void WatchChangeAggregator::RemoveDocumentFromTarget( + TargetId target_id, + const DocumentKey& key, + const absl::optional& updated_document) { + if (!IsActiveTarget(target_id)) { + return; + } + + TargetState& target_state = EnsureTargetState(target_id); + if (TargetContainsDocument(target_id, key)) { + target_state.AddDocumentChange(key, DocumentViewChange::Type::Removed); + } else { + // The document may have entered and left the target before we raised a + // snapshot, so we can just ignore the change. + target_state.RemoveDocumentChange(key); + } + pending_document_target_mappings_[key].insert(target_id); + + if (updated_document) { + pending_document_updates_[key] = *updated_document; + } +} + +void WatchChangeAggregator::RemoveTarget(TargetId target_id) { + target_states_.erase(target_id); +} + +int WatchChangeAggregator::GetCurrentDocumentCountForTarget( + TargetId target_id) { + TargetState& target_state = EnsureTargetState(target_id); + TargetChange target_change = target_state.ToTargetChange(); + return target_metadata_provider_->GetRemoteKeysForTarget(target_id).size() + + target_change.added_documents().size() - + target_change.removed_documents().size(); +} + +void WatchChangeAggregator::RecordPendingTargetRequest(TargetId target_id) { + // For each request we get we need to record we need a response for it. + TargetState& target_state = EnsureTargetState(target_id); + target_state.RecordPendingTargetRequest(); +} + +TargetState& WatchChangeAggregator::EnsureTargetState(TargetId target_id) { + return target_states_[target_id]; +} + +bool WatchChangeAggregator::IsActiveTarget(TargetId target_id) const { + return TargetDataForActiveTarget(target_id) != absl::nullopt; +} + +absl::optional WatchChangeAggregator::TargetDataForActiveTarget( + TargetId target_id) const { + auto target_state = target_states_.find(target_id); + return target_state != target_states_.end() && + target_state->second.IsPending() + ? absl::optional{} + : target_metadata_provider_->GetTargetDataForTarget(target_id); +} + +void WatchChangeAggregator::ResetTarget(TargetId target_id) { + auto current_target_state = target_states_.find(target_id); + HARD_ASSERT(current_target_state != target_states_.end() && + !(current_target_state->second.IsPending()), + "Should only reset active targets"); + + target_states_[target_id] = {}; + + // Trigger removal for any documents currently mapped to this target. These + // removals will be part of the initial snapshot if Watch does not resend + // these documents. + DocumentKeySet existing_keys = + target_metadata_provider_->GetRemoteKeysForTarget(target_id); + + for (const DocumentKey& key : existing_keys) { + RemoveDocumentFromTarget(target_id, key, absl::nullopt); + } +} + +bool WatchChangeAggregator::TargetContainsDocument(TargetId target_id, + const DocumentKey& key) { + const DocumentKeySet& existing_keys = + target_metadata_provider_->GetRemoteKeysForTarget(target_id); + return existing_keys.contains(key); +} + +} // namespace remote +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_event.h index 8ce1e38..0725210 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -17,14 +17,6 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_EVENT_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_EVENT_H_ -#if !defined(__OBJC__) -// TODO(varconst): the only dependencies are `FSTMaybeDocument` and `NSData` -// (the latter is used to represent the resume token). -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import - #include #include #include @@ -32,17 +24,15 @@ #include #include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" +#include "Firestore/core/src/firebase/firestore/local/target_data.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" -@class FSTMaybeDocument; -@class FSTQueryData; - -NS_ASSUME_NONNULL_BEGIN - namespace firebase { namespace firestore { namespace remote { @@ -64,10 +54,10 @@ class TargetMetadataProvider { model::TargetId target_id) const = 0; /** - * Returns the FSTQueryData for an active target ID or 'null' if this query - * has become inactive + * Returns the TargetData for an active target ID or `nullopt` if this query + * has become inactive. */ - virtual FSTQueryData* GetQueryDataForTarget( + virtual absl::optional GetTargetDataForTarget( model::TargetId target_id) const = 0; }; @@ -82,9 +72,13 @@ class TargetMetadataProvider { */ class TargetChange { public: + static TargetChange CreateSynthesizedTargetChange(bool current) { + return TargetChange(current); + } + TargetChange() = default; - TargetChange(NSData* resume_token, + TargetChange(nanopb::ByteString resume_token, bool current, model::DocumentKeySet added_documents, model::DocumentKeySet modified_documents, @@ -97,12 +91,12 @@ class TargetChange { } /** - * An opaque, server-assigned token that allows watching a query to be resumed - * after disconnecting without retransmitting all the data that matches the - * query. The resume token essentially identifies a point in time from which - * the server should resume sending results. + * An opaque, server-assigned token that allows watching a target to be + * resumed after disconnecting without retransmitting all the data that + * matches the target. The resume token essentially identifies a point in time + * from which the server should resume sending results. */ - NSData* resume_token() const { + const nanopb::ByteString& resume_token() const { return resume_token_; } @@ -140,7 +134,10 @@ class TargetChange { } private: - NSData* resume_token_ = nil; + explicit TargetChange(bool current) : current_{current} { + } + + nanopb::ByteString resume_token_; bool current_ = false; model::DocumentKeySet added_documents_; model::DocumentKeySet modified_documents_; @@ -152,8 +149,6 @@ bool operator==(const TargetChange& lhs, const TargetChange& rhs); /** Tracks the internal state of a Watch target. */ class TargetState { public: - TargetState(); - /** * Whether this target has been marked 'current'. * @@ -167,7 +162,7 @@ class TargetState { } /** The last resume token sent to us for this target. */ - NSData* resume_token() const { + const nanopb::ByteString& resume_token() const { return resume_token_; } @@ -185,7 +180,7 @@ class TargetState { * Applies the resume token to the `TargetChange`, but only when it has a new * value. Empty resume tokens are discarded. */ - void UpdateResumeToken(NSData* resume_token); + void UpdateResumeToken(nanopb::ByteString resume_token); /** * Creates a target change from the current set of changes. @@ -223,7 +218,7 @@ class TargetState { model::DocumentKeyHash> document_changes_; - NSData* resume_token_; + nanopb::ByteString resume_token_; bool current_ = false; @@ -242,12 +237,16 @@ class TargetState { */ class RemoteEvent { public: + using TargetChangeMap = std::unordered_map; + using TargetSet = std::unordered_set; + using DocumentUpdateMap = std::unordered_map; + RemoteEvent(model::SnapshotVersion snapshot_version, - std::unordered_map target_changes, - std::unordered_set target_mismatches, - std::unordered_map document_updates, + TargetChangeMap target_changes, + TargetSet target_mismatches, + DocumentUpdateMap document_updates, model::DocumentKeySet limbo_document_changes) : snapshot_version_{snapshot_version}, target_changes_{std::move(target_changes)}, @@ -262,8 +261,7 @@ class RemoteEvent { } /** A map from target to changes to the target. See `TargetChange`. */ - const std::unordered_map& target_changes() - const { + const TargetChangeMap& target_changes() const { return target_changes_; } @@ -271,7 +269,7 @@ class RemoteEvent { * A set of targets that is known to be inconsistent. Listens for these * targets should be re-established without resume tokens. */ - const std::unordered_set& target_mismatches() const { + const TargetSet& target_mismatches() const { return target_mismatches_; } @@ -279,10 +277,7 @@ class RemoteEvent { * A set of which documents have changed or been deleted, along with the doc's * new values (if not deleted). */ - const std::unordered_map& - document_updates() const { + const DocumentUpdateMap& document_updates() const { return document_updates_; } @@ -295,12 +290,9 @@ class RemoteEvent { private: model::SnapshotVersion snapshot_version_; - std::unordered_map target_changes_; - std::unordered_set target_mismatches_; - std::unordered_map - document_updates_; + TargetChangeMap target_changes_; + TargetSet target_mismatches_; + DocumentUpdateMap document_updates_; model::DocumentKeySet limbo_document_changes_; }; @@ -349,8 +341,8 @@ class WatchChangeAggregator { private: /** - * Returns all `targetId`s that the watch change applies to: either the - * `targetId`s explicitly listed in the change or the `targetId`s of all + * Returns all `TargetId`s that the watch change applies to: either the + * `TargetId`s explicitly listed in the change or the `TargetId`s of all * currently active targets. */ std::vector GetTargetIds( @@ -361,7 +353,7 @@ class WatchChangeAggregator { * document key to the given target's mapping. */ void AddDocumentToTarget(model::TargetId target_id, - FSTMaybeDocument* document); + const model::MaybeDocument& document); /** * Removes the provided document from the target mapping. If the document no @@ -370,9 +362,10 @@ class WatchChangeAggregator { * the filter mismatch), the new document can be provided to update the remote * document cache. */ - void RemoveDocumentFromTarget(model::TargetId target_id, - const model::DocumentKey& key, - FSTMaybeDocument* _Nullable updated_document); + void RemoveDocumentFromTarget( + model::TargetId target_id, + const model::DocumentKey& key, + const absl::optional& updated_document); /** * Returns the current count of documents in the target. This includes both @@ -397,11 +390,11 @@ class WatchChangeAggregator { bool IsActiveTarget(model::TargetId target_id) const; /** - * Returns the `FSTQueryData` for an active target (i.e., a target that the - * user is still interested in that has no outstanding target change - * requests). + * Returns the `TargetData` for an active target (i.e., a target that the user + * is still interested in that has no outstanding target change requests). */ - FSTQueryData* QueryDataForActiveTarget(model::TargetId target_id) const; + absl::optional TargetDataForActiveTarget( + model::TargetId target_id) const; /** * Resets the state of a Watch target to its initial state (e.g. sets @@ -419,10 +412,7 @@ class WatchChangeAggregator { std::unordered_map target_states_; /** Keeps track of the documents to update since the last raised snapshot. */ - std::unordered_map - pending_document_updates_; + RemoteEvent::DocumentUpdateMap pending_document_updates_; /** A mapping of document keys to their set of target IDs. */ std::unordered_map pending_target_resets_; + RemoteEvent::TargetSet pending_target_resets_; TargetMetadataProvider* target_metadata_provider_ = nullptr; }; @@ -444,6 +434,4 @@ class WatchChangeAggregator { } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_EVENT_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_event.mm deleted file mode 100644 index aa2fa33..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" - -#include - -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Local/FSTQueryData.h" -#import "Firestore/Source/Model/FSTDocument.h" - -using firebase::firestore::core::DocumentViewChange; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::DocumentKeySet; -using firebase::firestore::model::SnapshotVersion; -using firebase::firestore::model::TargetId; - -namespace firebase { -namespace firestore { -namespace remote { - -// TargetChange - -bool operator==(const TargetChange& lhs, const TargetChange& rhs) { - return [lhs.resume_token() isEqualToData:rhs.resume_token()] && - lhs.current() == rhs.current() && - lhs.added_documents() == rhs.added_documents() && - lhs.modified_documents() == rhs.modified_documents() && - lhs.removed_documents() == rhs.removed_documents(); -} - -// TargetState - -TargetState::TargetState() : resume_token_{[NSData data]} { -} - -void TargetState::UpdateResumeToken(NSData* resume_token) { - if (resume_token.length > 0) { - has_pending_changes_ = true; - resume_token_ = [resume_token copy]; - } -} - -TargetChange TargetState::ToTargetChange() const { - DocumentKeySet added_documents; - DocumentKeySet modified_documents; - DocumentKeySet removed_documents; - - for (const auto& entry : document_changes_) { - const DocumentKey& document_key = entry.first; - DocumentViewChange::Type change_type = entry.second; - - switch (change_type) { - case DocumentViewChange::Type::kAdded: - added_documents = added_documents.insert(document_key); - break; - case DocumentViewChange::Type::kModified: - modified_documents = modified_documents.insert(document_key); - break; - case DocumentViewChange::Type::kRemoved: - removed_documents = removed_documents.insert(document_key); - break; - default: - HARD_FAIL("Encountered invalid change type: %s", change_type); - } - } - - return TargetChange{resume_token(), current(), std::move(added_documents), - std::move(modified_documents), - std::move(removed_documents)}; -} - -void TargetState::ClearPendingChanges() { - has_pending_changes_ = false; - document_changes_.clear(); -} - -void TargetState::RecordPendingTargetRequest() { - ++outstanding_responses_; -} - -void TargetState::RecordTargetResponse() { - --outstanding_responses_; -} - -void TargetState::MarkCurrent() { - has_pending_changes_ = true; - current_ = true; -} - -void TargetState::AddDocumentChange(const DocumentKey& document_key, - DocumentViewChange::Type type) { - has_pending_changes_ = true; - document_changes_[document_key] = type; -} - -void TargetState::RemoveDocumentChange(const DocumentKey& document_key) { - has_pending_changes_ = true; - document_changes_.erase(document_key); -} - -// WatchChangeAggregator - -WatchChangeAggregator::WatchChangeAggregator( - TargetMetadataProvider* target_metadata_provider) - : target_metadata_provider_{NOT_NULL(target_metadata_provider)} { -} - -void WatchChangeAggregator::HandleDocumentChange( - const DocumentWatchChange& document_change) { - for (TargetId target_id : document_change.updated_target_ids()) { - if ([document_change.new_document() isKindOfClass:[FSTDocument class]]) { - AddDocumentToTarget(target_id, document_change.new_document()); - } else if ([document_change.new_document() - isKindOfClass:[FSTDeletedDocument class]]) { - RemoveDocumentFromTarget(target_id, document_change.document_key(), - document_change.new_document()); - } - } - - for (TargetId target_id : document_change.removed_target_ids()) { - RemoveDocumentFromTarget(target_id, document_change.document_key(), - document_change.new_document()); - } -} - -void WatchChangeAggregator::HandleTargetChange( - const WatchTargetChange& target_change) { - for (TargetId target_id : GetTargetIds(target_change)) { - TargetState& target_state = EnsureTargetState(target_id); - - switch (target_change.state()) { - case WatchTargetChangeState::NoChange: - if (IsActiveTarget(target_id)) { - target_state.UpdateResumeToken(target_change.resume_token()); - } - continue; - case WatchTargetChangeState::Added: - // We need to decrement the number of pending acks needed from watch for - // this target_id. - target_state.RecordTargetResponse(); - if (!target_state.IsPending()) { - // We have a freshly added target, so we need to reset any state that - // we had previously. This can happen e.g. when remove and add back a - // target for existence filter mismatches. - target_state.ClearPendingChanges(); - } - target_state.UpdateResumeToken(target_change.resume_token()); - continue; - case WatchTargetChangeState::Removed: - // We need to keep track of removed targets to we can post-filter and - // remove any target changes. - // We need to decrement the number of pending acks needed from watch for - // this targetId. - target_state.RecordTargetResponse(); - if (!target_state.IsPending()) { - RemoveTarget(target_id); - } - HARD_ASSERT(target_change.cause().ok(), - "WatchChangeAggregator does not handle errored targets"); - continue; - case WatchTargetChangeState::Current: - if (IsActiveTarget(target_id)) { - target_state.MarkCurrent(); - target_state.UpdateResumeToken(target_change.resume_token()); - } - continue; - case WatchTargetChangeState::Reset: - if (IsActiveTarget(target_id)) { - // Reset the target and synthesizes removes for all existing - // documents. The backend will re-add any documents that still match - // the target before it sends the next global snapshot. - ResetTarget(target_id); - target_state.UpdateResumeToken(target_change.resume_token()); - } - continue; - } - HARD_FAIL("Unknown target watch change state: %s", target_change.state()); - } -} - -std::vector WatchChangeAggregator::GetTargetIds( - const WatchTargetChange& target_change) const { - if (!target_change.target_ids().empty()) { - return target_change.target_ids(); - } - - std::vector result; - result.reserve(target_states_.size()); - for (const auto& entry : target_states_) { - result.push_back(entry.first); - } - - return result; -} - -void WatchChangeAggregator::HandleExistenceFilter( - const ExistenceFilterWatchChange& existence_filter) { - TargetId target_id = existence_filter.target_id(); - int expected_count = existence_filter.filter().count(); - - FSTQueryData* query_data = QueryDataForActiveTarget(target_id); - if (query_data) { - FSTQuery* query = query_data.query; - if ([query isDocumentQuery]) { - if (expected_count == 0) { - // The existence filter told us the document does not exist. We deduce - // that this document does not exist and apply a deleted document to our - // updates. Without applying this deleted document there might be - // another query that will raise this document as part of a snapshot - // until it is resolved, essentially exposing inconsistency between - // queries. - DocumentKey key{query.path}; - RemoveDocumentFromTarget( - target_id, key, - [FSTDeletedDocument documentWithKey:key - version:SnapshotVersion::None() - hasCommittedMutations:NO]); - } else { - HARD_ASSERT(expected_count == 1, - "Single document existence filter with count: %s", - expected_count); - } - } else { - int current_size = GetCurrentDocumentCountForTarget(target_id); - if (current_size != expected_count) { - // Existence filter mismatch: We reset the mapping and raise a new - // snapshot with `isFromCache:true`. - ResetTarget(target_id); - pending_target_resets_.insert(target_id); - } - } - } -} - -RemoteEvent WatchChangeAggregator::CreateRemoteEvent( - const SnapshotVersion& snapshot_version) { - std::unordered_map target_changes; - - for (auto& entry : target_states_) { - TargetId target_id = entry.first; - TargetState& target_state = entry.second; - - FSTQueryData* query_data = QueryDataForActiveTarget(target_id); - if (query_data) { - if (target_state.current() && [query_data.query isDocumentQuery]) { - // Document queries for document that don't exist can produce an empty - // result set. To update our local cache, we synthesize a document - // delete if we have not previously received the document. This resolves - // the limbo state of the document, removing it from limboDocumentRefs. - DocumentKey key{query_data.query.path}; - if (pending_document_updates_.find(key) == - pending_document_updates_.end() && - !TargetContainsDocument(target_id, key)) { - RemoveDocumentFromTarget( - target_id, key, - [FSTDeletedDocument documentWithKey:key - version:snapshot_version - hasCommittedMutations:NO]); - } - } - - if (target_state.HasPendingChanges()) { - target_changes[target_id] = target_state.ToTargetChange(); - target_state.ClearPendingChanges(); - } - } - } - - DocumentKeySet resolved_limbo_documents; - - // We extract the set of limbo-only document updates as the GC logic - // special-cases documents that do not appear in the query cache. - // - // TODO(gsoltis): Expand on this comment. - for (const auto& entry : pending_document_target_mappings_) { - bool is_only_limbo_target = true; - - for (TargetId target_id : entry.second) { - FSTQueryData* query_data = QueryDataForActiveTarget(target_id); - if (query_data && query_data.purpose != FSTQueryPurposeLimboResolution) { - is_only_limbo_target = false; - break; - } - } - - if (is_only_limbo_target) { - resolved_limbo_documents = resolved_limbo_documents.insert(entry.first); - } - } - - RemoteEvent remote_event{snapshot_version, std::move(target_changes), - std::move(pending_target_resets_), - std::move(pending_document_updates_), - std::move(resolved_limbo_documents)}; - - // Re-initialize the current state to ensure that we do not modify the - // generated `RemoteEvent`. - pending_document_updates_.clear(); - pending_document_target_mappings_.clear(); - pending_target_resets_.clear(); - - return remote_event; -} - -void WatchChangeAggregator::AddDocumentToTarget(TargetId target_id, - FSTMaybeDocument* document) { - if (!IsActiveTarget(target_id)) { - return; - } - - DocumentViewChange::Type change_type = - TargetContainsDocument(target_id, document.key) - ? DocumentViewChange::Type::kModified - : DocumentViewChange::Type::kAdded; - - TargetState& target_state = EnsureTargetState(target_id); - target_state.AddDocumentChange(document.key, change_type); - - pending_document_updates_[document.key] = document; - pending_document_target_mappings_[document.key].insert(target_id); -} - -void WatchChangeAggregator::RemoveDocumentFromTarget( - TargetId target_id, - const DocumentKey& key, - FSTMaybeDocument* _Nullable updated_document) { - if (!IsActiveTarget(target_id)) { - return; - } - - TargetState& target_state = EnsureTargetState(target_id); - if (TargetContainsDocument(target_id, key)) { - target_state.AddDocumentChange(key, DocumentViewChange::Type::kRemoved); - } else { - // The document may have entered and left the target before we raised a - // snapshot, so we can just ignore the change. - target_state.RemoveDocumentChange(key); - } - pending_document_target_mappings_[key].insert(target_id); - - if (updated_document) { - pending_document_updates_[key] = updated_document; - } -} - -void WatchChangeAggregator::RemoveTarget(TargetId target_id) { - target_states_.erase(target_id); -} - -int WatchChangeAggregator::GetCurrentDocumentCountForTarget( - TargetId target_id) { - TargetState& target_state = EnsureTargetState(target_id); - TargetChange target_change = target_state.ToTargetChange(); - return target_metadata_provider_->GetRemoteKeysForTarget(target_id).size() + - target_change.added_documents().size() - - target_change.removed_documents().size(); -} - -void WatchChangeAggregator::RecordPendingTargetRequest(TargetId target_id) { - // For each request we get we need to record we need a response for it. - TargetState& target_state = EnsureTargetState(target_id); - target_state.RecordPendingTargetRequest(); -} - -TargetState& WatchChangeAggregator::EnsureTargetState(TargetId target_id) { - return target_states_[target_id]; -} - -bool WatchChangeAggregator::IsActiveTarget(TargetId target_id) const { - return QueryDataForActiveTarget(target_id) != nil; -} - -FSTQueryData* WatchChangeAggregator::QueryDataForActiveTarget( - TargetId target_id) const { - auto target_state = target_states_.find(target_id); - return target_state != target_states_.end() && - target_state->second.IsPending() - ? nil - : target_metadata_provider_->GetQueryDataForTarget(target_id); -} - -void WatchChangeAggregator::ResetTarget(TargetId target_id) { - auto current_target_state = target_states_.find(target_id); - HARD_ASSERT(current_target_state != target_states_.end() && - !(current_target_state->second.IsPending()), - "Should only reset active targets"); - - target_states_[target_id] = {}; - - // Trigger removal for any documents currently mapped to this target. These - // removals will be part of the initial snapshot if Watch does not resend - // these documents. - DocumentKeySet existingKeys = - target_metadata_provider_->GetRemoteKeysForTarget(target_id); - - for (const DocumentKey& key : existingKeys) { - RemoveDocumentFromTarget(target_id, key, nil); - } -} - -bool WatchChangeAggregator::TargetContainsDocument(TargetId target_id, - const DocumentKey& key) { - const DocumentKeySet& existing_keys = - target_metadata_provider_->GetRemoteKeysForTarget(target_id); - return existing_keys.contains(key); -} - -} // namespace remote -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.cc new file mode 100644 index 0000000..e275249 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.cc @@ -0,0 +1,265 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h" + +#include + +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" +#include "Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h" +#include "Firestore/core/src/firebase/firestore/nanopb/writer.h" +#include "Firestore/core/src/firebase/firestore/remote/grpc_nanopb.h" +#include "Firestore/core/src/firebase/firestore/remote/grpc_util.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/statusor.h" +#include "grpcpp/support/status.h" + +namespace firebase { +namespace firestore { +namespace remote { + +using core::DatabaseInfo; +using local::TargetData; +using model::DocumentKey; +using model::MaybeDocument; +using model::Mutation; +using model::MutationResult; +using model::SnapshotVersion; +using model::TargetId; +using nanopb::ByteString; +using nanopb::ByteStringWriter; +using nanopb::MakeArray; +using nanopb::MakeByteString; +using nanopb::Message; +using nanopb::Reader; +using remote::ByteBufferReader; +using remote::Serializer; +using util::Status; +using util::StatusOr; +using util::StringFormat; + +// WatchStreamSerializer + +WatchStreamSerializer::WatchStreamSerializer(Serializer serializer) + : serializer_{std::move(serializer)} { +} + +Message +WatchStreamSerializer::EncodeWatchRequest(const TargetData& query) const { + Message result; + + result->database = serializer_.EncodeDatabaseName(); + result->which_target_change = + google_firestore_v1_ListenRequest_add_target_tag; + result->add_target = serializer_.EncodeTarget(query); + + auto labels = serializer_.EncodeListenRequestLabels(query); + if (!labels.empty()) { + result->labels_count = nanopb::CheckedSize(labels.size()); + result->labels = MakeArray( + result->labels_count); + + pb_size_t i = 0; + for (const auto& label : labels) { + result->labels[i] = label; + ++i; + } + } + + return result; +} + +Message +WatchStreamSerializer::EncodeUnwatchRequest(TargetId target_id) const { + Message result; + + result->database = serializer_.EncodeDatabaseName(); + result->which_target_change = + google_firestore_v1_ListenRequest_remove_target_tag; + result->remove_target = target_id; + + return result; +} + +Message +WatchStreamSerializer::ParseResponse(Reader* reader) const { + return Message::TryParse(reader); +} + +std::unique_ptr WatchStreamSerializer::DecodeWatchChange( + nanopb::Reader* reader, + const google_firestore_v1_ListenResponse& response) const { + return serializer_.DecodeWatchChange(reader, response); +} + +SnapshotVersion WatchStreamSerializer::DecodeSnapshotVersion( + nanopb::Reader* reader, + const google_firestore_v1_ListenResponse& response) const { + return serializer_.DecodeVersionFromListenResponse(reader, response); +} + +// WriteStreamSerializer + +WriteStreamSerializer::WriteStreamSerializer(Serializer serializer) + : serializer_{std::move(serializer)} { +} + +Message +WriteStreamSerializer::EncodeHandshake() const { + Message result; + + // The initial request cannot contain mutations, but must contain a project + // ID. + result->database = serializer_.EncodeDatabaseName(); + + return result; +} + +Message +WriteStreamSerializer::EncodeWriteMutationsRequest( + const std::vector& mutations, + const ByteString& last_stream_token) const { + Message result; + + if (!mutations.empty()) { + result->writes_count = nanopb::CheckedSize(mutations.size()); + result->writes = MakeArray(result->writes_count); + + for (pb_size_t i = 0; i != result->writes_count; ++i) { + result->writes[i] = serializer_.EncodeMutation(mutations[i]); + } + } + + result->stream_token = nanopb::CopyBytesArray(last_stream_token.get()); + + return result; +} + +Message WriteStreamSerializer::ParseResponse( + Reader* reader) const { + return Message::TryParse(reader); +} + +SnapshotVersion WriteStreamSerializer::DecodeCommitVersion( + nanopb::Reader* reader, + const google_firestore_v1_WriteResponse& proto) const { + return serializer_.DecodeVersion(reader, proto.commit_time); +} + +std::vector WriteStreamSerializer::DecodeMutationResults( + nanopb::Reader* reader, + const google_firestore_v1_WriteResponse& proto) const { + SnapshotVersion commit_version = DecodeCommitVersion(reader, proto); + if (!reader->ok()) { + return {}; + } + + const google_firestore_v1_WriteResult* writes = proto.write_results; + pb_size_t count = proto.write_results_count; + std::vector results; + results.reserve(count); + + for (pb_size_t i = 0; i != count; ++i) { + results.push_back( + serializer_.DecodeMutationResult(reader, writes[i], commit_version)); + } + + return results; +} + +// DatastoreSerializer + +DatastoreSerializer::DatastoreSerializer(const DatabaseInfo& database_info) + : serializer_{database_info.database_id()} { +} + +Message +DatastoreSerializer::EncodeCommitRequest( + const std::vector& mutations) const { + Message result; + + result->database = serializer_.EncodeDatabaseName(); + + if (!mutations.empty()) { + result->writes_count = nanopb::CheckedSize(mutations.size()); + result->writes = MakeArray(result->writes_count); + pb_size_t i = 0; + for (const Mutation& mutation : mutations) { + result->writes[i] = serializer_.EncodeMutation(mutation); + ++i; + } + } + + return result; +} + +Message +DatastoreSerializer::EncodeLookupRequest( + const std::vector& keys) const { + Message result; + + result->database = serializer_.EncodeDatabaseName(); + if (!keys.empty()) { + result->documents_count = nanopb::CheckedSize(keys.size()); + result->documents = MakeArray(result->documents_count); + pb_size_t i = 0; + for (const DocumentKey& key : keys) { + result->documents[i] = serializer_.EncodeKey(key); + ++i; + } + } + + return result; +} + +StatusOr> +DatastoreSerializer::MergeLookupResponses( + const std::vector& responses) const { + // Sort by key. + std::map results; + + for (const auto& response : responses) { + ByteBufferReader reader{response}; + auto message = + Message::TryParse( + &reader); + + MaybeDocument doc = serializer_.DecodeMaybeDocument(&reader, *message); + if (!reader.ok()) { + return reader.status(); + } + + results[doc.key()] = std::move(doc); + } + + std::vector docs; + docs.reserve(results.size()); + for (const auto& kv : results) { + docs.push_back(kv.second); + } + + StatusOr> result{std::move(docs)}; + return result; +} + +} // namespace remote +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h index e77b062..c25a5fb 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h @@ -17,161 +17,124 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_OBJC_BRIDGE_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_OBJC_BRIDGE_H_ -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import - #include #include +#include #include +#include "Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/local/target_data.h" #include "Firestore/core/src/firebase/firestore/model/types.h" -#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" +#include "Firestore/core/src/firebase/firestore/nanopb/message.h" +#include "Firestore/core/src/firebase/firestore/nanopb/reader.h" +#include "Firestore/core/src/firebase/firestore/remote/serializer.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "grpcpp/support/byte_buffer.h" -#import "Firestore/Protos/objc/google/firestore/v1/Firestore.pbobjc.h" -#import "Firestore/Source/Core/FSTTypes.h" -#import "Firestore/Source/Local/FSTQueryData.h" -#import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Remote/FSTSerializerBeta.h" - namespace firebase { namespace firestore { -namespace remote { -namespace bridge { -bool IsLoggingEnabled(); +namespace model { +class DocumentKey; +class MaybeDocument; +class SnapshotVersion; +} // namespace model -/** - * This file contains operations in remote/ folder that are still delegated to - * Objective-C: proto parsing and delegates. - * - * The principle is that the C++ implementation can only take Objective-C - * objects as parameters or return them, but never instantiate them or call any - * methods on them -- if that is necessary, it's delegated to one of the bridge - * classes. This allows easily identifying which parts of remote/ still rely on - * not-yet-ported code. - */ +namespace remote { + +class WatchChange; + +// TODO(varconst): remove this file? +// +// The original purpose of this file was to cleanly encapsulate the remaining +// Objective-C dependencies of `remote/` folder. These dependencies no longer +// exist (modulo pretty-printing), and this file makes C++ diverge from other +// platforms. +// +// On the other hand, stream classes are large, and having one easily +// separatable aspect of their implementation (serialization) refactored out is +// arguably a good thing. If this file were to stay (in some form, certainly +// under a different name), other platforms would have to follow suit. +// +// Note: return value optimization should make returning Nanopb messages from +// functions cheap (even though they may be large types that are relatively +// expensive to copy). -/** - * A C++ bridge to `FSTSerializerBeta` that allows creating - * `GCFSListenRequest`s and parsing `GCFSListenResponse`s. - */ class WatchStreamSerializer { public: - explicit WatchStreamSerializer(FSTSerializerBeta* serializer) - : serializer_{serializer} { - } - - GCFSListenRequest* CreateWatchRequest(FSTQueryData* query) const; - GCFSListenRequest* CreateUnwatchRequest(model::TargetId target_id) const; - static grpc::ByteBuffer ToByteBuffer(GCFSListenRequest* request); - - /** - * If parsing fails, will return nil and write information on the error to - * `out_status`. Otherwise, returns the parsed proto and sets `out_status` to - * ok. - */ - GCFSListenResponse* ParseResponse(const grpc::ByteBuffer& message, - util::Status* out_status) const; - std::unique_ptr ToWatchChange(GCFSListenResponse* proto) const; - model::SnapshotVersion ToSnapshotVersion(GCFSListenResponse* proto) const; - - /** Creates a pretty-printed description of the proto for debugging. */ - static NSString* Describe(GCFSListenRequest* request); - static NSString* Describe(GCFSListenResponse* request); + explicit WatchStreamSerializer(Serializer serializer); + + nanopb::Message EncodeWatchRequest( + const local::TargetData& query) const; + nanopb::Message EncodeUnwatchRequest( + model::TargetId target_id) const; + + nanopb::Message ParseResponse( + nanopb::Reader* reader) const; + std::unique_ptr DecodeWatchChange( + nanopb::Reader* reader, + const google_firestore_v1_ListenResponse& response) const; + model::SnapshotVersion DecodeSnapshotVersion( + nanopb::Reader* reader, + const google_firestore_v1_ListenResponse& response) const; private: - FSTSerializerBeta* serializer_; + Serializer serializer_; }; -/** - * A C++ bridge to `FSTSerializerBeta` that allows creating - * `GCFSWriteRequest`s and parsing `GCFSWriteResponse`s. - */ class WriteStreamSerializer { public: - explicit WriteStreamSerializer(FSTSerializerBeta* serializer) - : serializer_{serializer} { - } - - void UpdateLastStreamToken(GCFSWriteResponse* proto); - void SetLastStreamToken(NSData* token) { - last_stream_token_ = token; - } - NSData* GetLastStreamToken() const { - return last_stream_token_; + explicit WriteStreamSerializer(Serializer serializer); + + nanopb::Message EncodeHandshake() const; + nanopb::Message EncodeWriteMutationsRequest( + const std::vector& mutations, + const nanopb::ByteString& last_stream_token) const; + nanopb::Message EncodeEmptyMutationsList( + const nanopb::ByteString& last_stream_token) const { + return EncodeWriteMutationsRequest({}, last_stream_token); } - GCFSWriteRequest* CreateHandshake() const; - GCFSWriteRequest* CreateWriteMutationsRequest( - const std::vector& mutations) const; - GCFSWriteRequest* CreateEmptyMutationsList() { - return CreateWriteMutationsRequest({}); - } - static grpc::ByteBuffer ToByteBuffer(GCFSWriteRequest* request); - - /** - * If parsing fails, will return nil and write information on the error to - * `out_status`. Otherwise, returns the parsed proto and sets `out_status` to - * ok. - */ - GCFSWriteResponse* ParseResponse(const grpc::ByteBuffer& message, - util::Status* out_status) const; - model::SnapshotVersion ToCommitVersion(GCFSWriteResponse* proto) const; - std::vector ToMutationResults( - GCFSWriteResponse* proto) const; - - /** Creates a pretty-printed description of the proto for debugging. */ - static NSString* Describe(GCFSWriteRequest* request); - static NSString* Describe(GCFSWriteResponse* request); + nanopb::Message ParseResponse( + nanopb::Reader* reader) const; + model::SnapshotVersion DecodeCommitVersion( + nanopb::Reader* reader, + const google_firestore_v1_WriteResponse& proto) const; + std::vector DecodeMutationResults( + nanopb::Reader* reader, + const google_firestore_v1_WriteResponse& proto) const; private: - FSTSerializerBeta* serializer_; - NSData* last_stream_token_; + Serializer serializer_; }; -/** - * A C++ bridge to `FSTSerializerBeta` that allows creating - * `GCFSCommitRequest`s and `GCFSBatchGetDocumentsRequest`s and handling - * `GCFSBatchGetDocumentsResponse`s. - */ class DatastoreSerializer { public: explicit DatastoreSerializer(const core::DatabaseInfo& database_info); - GCFSCommitRequest* CreateCommitRequest( - const std::vector& mutations) const; - static grpc::ByteBuffer ToByteBuffer(GCFSCommitRequest* request); + nanopb::Message EncodeCommitRequest( + const std::vector& mutations) const; - GCFSBatchGetDocumentsRequest* CreateLookupRequest( - const std::vector& keys) const; - static grpc::ByteBuffer ToByteBuffer(GCFSBatchGetDocumentsRequest* request); + nanopb::Message + EncodeLookupRequest(const std::vector& keys) const; /** * Merges results of the streaming read together. The array is sorted by the * document key. */ - std::vector MergeLookupResponses( - const std::vector& responses, - util::Status* out_status) const; - FSTMaybeDocument* ToMaybeDocument( - GCFSBatchGetDocumentsResponse* response) const; + util::StatusOr> MergeLookupResponses( + const std::vector& responses) const; - FSTSerializerBeta* GetSerializer() { + const Serializer& serializer() const { return serializer_; } private: - FSTSerializerBeta* serializer_; + Serializer serializer_; }; -} // namespace bridge } // namespace remote } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm deleted file mode 100644 index a3f3f65..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h" - -#include -#include -#include -#include - -#import "Firestore/Source/API/FIRFirestore+Internal.h" - -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/util/error_apple.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" -#include "grpcpp/support/status.h" - -namespace firebase { -namespace firestore { -namespace remote { -namespace bridge { - -using core::DatabaseInfo; -using model::DocumentKey; -using model::TargetId; -using model::SnapshotVersion; -using util::MakeString; -using util::MakeNSError; -using util::Status; -using util::StringFormat; - -namespace { - -std::string ToHexString(const grpc::ByteBuffer& buffer) { - std::vector slices; - grpc::Status status = buffer.Dump(&slices); - - std::stringstream output; - // The output will look like "0x00 0x0a" - output << std::hex << std::setfill('0') << std::setw(2); - for (const auto& slice : slices) { - for (uint8_t c : slice) { - output << "0x" << static_cast(c) << " "; - } - } - - return output.str(); -} - -NSData* ConvertToNsData(const grpc::ByteBuffer& buffer, NSError** out_error) { - std::vector slices; - grpc::Status status = buffer.Dump(&slices); - if (!status.ok()) { - *out_error = - MakeNSError(Status{FirestoreErrorCode::Internal, - "Trying to convert an invalid grpc::ByteBuffer"}); - return nil; - } - - if (slices.size() == 1) { - return [NSData dataWithBytes:slices.front().begin() - length:slices.front().size()]; - } else { - NSMutableData* data = [NSMutableData dataWithCapacity:buffer.Length()]; - for (const auto& slice : slices) { - [data appendBytes:slice.begin() length:slice.size()]; - } - return data; - } -} - -grpc::ByteBuffer ConvertToByteBuffer(NSData* data) { - grpc::Slice slice{[data bytes], [data length]}; - return grpc::ByteBuffer{&slice, 1}; -} - -// Note: `StatusOr` cannot be used with ARC-managed objects. -template -Proto* ToProto(const grpc::ByteBuffer& message, Status* out_status) { - NSError* error = nil; - NSData* data = ConvertToNsData(message, &error); - if (!error) { - Proto* proto = [Proto parseFromData:data error:&error]; - if (!error) { - *out_status = Status::OK(); - return proto; - } - } - - std::string error_description = - StringFormat("Unable to parse response from the server.\n" - "Underlying error: %s\n" - "Expected class: %s\n" - "Received value: %s\n", - error, [Proto class], ToHexString(message)); - - *out_status = {FirestoreErrorCode::Internal, error_description}; - return nil; -} - -} // namespace - -bool IsLoggingEnabled() { - return [FIRFirestore isLoggingEnabled]; -} - -// WatchStreamSerializer - -GCFSListenRequest* WatchStreamSerializer::CreateWatchRequest( - FSTQueryData* query) const { - GCFSListenRequest* request = [GCFSListenRequest message]; - request.database = [serializer_ encodedDatabaseID]; - request.addTarget = [serializer_ encodedTarget:query]; - request.labels = [serializer_ encodedListenRequestLabelsForQueryData:query]; - return request; -} - -GCFSListenRequest* WatchStreamSerializer::CreateUnwatchRequest( - TargetId target_id) const { - GCFSListenRequest* request = [GCFSListenRequest message]; - request.database = [serializer_ encodedDatabaseID]; - request.removeTarget = target_id; - return request; -} - -grpc::ByteBuffer WatchStreamSerializer::ToByteBuffer( - GCFSListenRequest* request) { - return ConvertToByteBuffer([request data]); -} - -GCFSListenResponse* WatchStreamSerializer::ParseResponse( - const grpc::ByteBuffer& message, Status* out_status) const { - return ToProto(message, out_status); -} - -std::unique_ptr WatchStreamSerializer::ToWatchChange( - GCFSListenResponse* proto) const { - return [serializer_ decodedWatchChange:proto]; -} - -SnapshotVersion WatchStreamSerializer::ToSnapshotVersion( - GCFSListenResponse* proto) const { - return [serializer_ versionFromListenResponse:proto]; -} - -NSString* WatchStreamSerializer::Describe(GCFSListenRequest* request) { - return [request description]; -} - -NSString* WatchStreamSerializer::Describe(GCFSListenResponse* response) { - return [response description]; -} - -// WriteStreamSerializer - -void WriteStreamSerializer::UpdateLastStreamToken(GCFSWriteResponse* proto) { - last_stream_token_ = proto.streamToken; -} - -GCFSWriteRequest* WriteStreamSerializer::CreateHandshake() const { - // The initial request cannot contain mutations, but must contain a projectID. - GCFSWriteRequest* request = [GCFSWriteRequest message]; - request.database = [serializer_ encodedDatabaseID]; - return request; -} - -GCFSWriteRequest* WriteStreamSerializer::CreateWriteMutationsRequest( - const std::vector& mutations) const { - NSMutableArray* protos = - [NSMutableArray arrayWithCapacity:mutations.size()]; - for (FSTMutation* mutation : mutations) { - [protos addObject:[serializer_ encodedMutation:mutation]]; - }; - - GCFSWriteRequest* request = [GCFSWriteRequest message]; - request.writesArray = protos; - request.streamToken = last_stream_token_; - - return request; -} - -grpc::ByteBuffer WriteStreamSerializer::ToByteBuffer( - GCFSWriteRequest* request) { - return ConvertToByteBuffer([request data]); -} - -GCFSWriteResponse* WriteStreamSerializer::ParseResponse( - const grpc::ByteBuffer& message, Status* out_status) const { - return ToProto(message, out_status); -} - -model::SnapshotVersion WriteStreamSerializer::ToCommitVersion( - GCFSWriteResponse* proto) const { - return [serializer_ decodedVersion:proto.commitTime]; -} - -std::vector WriteStreamSerializer::ToMutationResults( - GCFSWriteResponse* response) const { - NSMutableArray* responses = response.writeResultsArray; - std::vector results; - results.reserve(responses.count); - - const model::SnapshotVersion commitVersion = ToCommitVersion(response); - for (GCFSWriteResult* proto in responses) { - results.push_back([serializer_ decodedMutationResult:proto - commitVersion:commitVersion]); - }; - return results; -} - -NSString* WriteStreamSerializer::Describe(GCFSWriteRequest* request) { - return [request description]; -} - -NSString* WriteStreamSerializer::Describe(GCFSWriteResponse* response) { - return [response description]; -} - -// DatastoreSerializer - -DatastoreSerializer::DatastoreSerializer(const DatabaseInfo& database_info) - : serializer_{[[FSTSerializerBeta alloc] - initWithDatabaseID:&database_info.database_id()]} { -} - -GCFSCommitRequest* DatastoreSerializer::CreateCommitRequest( - const std::vector& mutations) const { - GCFSCommitRequest* request = [GCFSCommitRequest message]; - request.database = [serializer_ encodedDatabaseID]; - - NSMutableArray* mutationProtos = [NSMutableArray array]; - for (FSTMutation* mutation : mutations) { - [mutationProtos addObject:[serializer_ encodedMutation:mutation]]; - } - request.writesArray = mutationProtos; - - return request; -} - -grpc::ByteBuffer DatastoreSerializer::ToByteBuffer(GCFSCommitRequest* request) { - return ConvertToByteBuffer([request data]); -} - -GCFSBatchGetDocumentsRequest* DatastoreSerializer::CreateLookupRequest( - const std::vector& keys) const { - GCFSBatchGetDocumentsRequest* request = - [GCFSBatchGetDocumentsRequest message]; - - request.database = [serializer_ encodedDatabaseID]; - for (const DocumentKey& key : keys) { - [request.documentsArray addObject:[serializer_ encodedDocumentKey:key]]; - } - - return request; -} - -grpc::ByteBuffer DatastoreSerializer::ToByteBuffer( - GCFSBatchGetDocumentsRequest* request) { - return ConvertToByteBuffer([request data]); -} - -std::vector DatastoreSerializer::MergeLookupResponses( - const std::vector& responses, Status* out_status) const { - // Sort by key. - std::map results; - - for (const auto& response : responses) { - auto* proto = ToProto(response, out_status); - if (!out_status->ok()) { - return {}; - } - FSTMaybeDocument* doc = [serializer_ decodedMaybeDocumentFromBatch:proto]; - results[doc.key] = doc; - } - - std::vector docs; - docs.reserve(results.size()); - for (const auto& kv : results) { - docs.push_back(kv.second); - } - return docs; -} - -FSTMaybeDocument* DatastoreSerializer::ToMaybeDocument( - GCFSBatchGetDocumentsResponse* response) const { - return [serializer_ decodedMaybeDocumentFromBatch:response]; -} - -} // namespace bridge -} // namespace remote -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_store.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_store.cc new file mode 100644 index 0000000..e920b9f --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_store.cc @@ -0,0 +1,544 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/remote/remote_store.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/core/transaction.h" +#include "Firestore/core/src/firebase/firestore/local/target_data.h" +#include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" +#include "Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h" +#include "Firestore/core/src/firebase/firestore/util/error_apple.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/to_string.h" +#include "absl/memory/memory.h" + +namespace firebase { +namespace firestore { +namespace remote { + +using core::Transaction; +using local::LocalStore; +using local::QueryPurpose; +using local::TargetData; +using model::BatchId; +using model::DocumentKeySet; +using model::kBatchIdUnknown; +using model::MutationBatch; +using model::MutationBatchResult; +using model::MutationResult; +using model::OnlineState; +using model::SnapshotVersion; +using model::TargetId; +using nanopb::ByteString; +using util::AsyncQueue; +using util::Status; + +/** + * The maximum number of pending writes to allow. + * TODO(b/35853402): Negotiate this value with the backend. + */ +constexpr int kMaxPendingWrites = 10; + +RemoteStore::RemoteStore( + LocalStore* local_store, + std::shared_ptr datastore, + const std::shared_ptr& worker_queue, + std::function online_state_handler) + : local_store_{local_store}, + datastore_{std::move(datastore)}, + online_state_tracker_{worker_queue, std::move(online_state_handler)} { + datastore_->Start(); + + // Create streams (but note they're not started yet) + watch_stream_ = datastore_->CreateWatchStream(this); + write_stream_ = datastore_->CreateWriteStream(this); +} + +void RemoteStore::Start() { + // For now, all setup is handled by `EnableNetwork`. We might expand on this + // in the future. + EnableNetwork(); +} + +void RemoteStore::EnableNetwork() { + is_network_enabled_ = true; + + if (CanUseNetwork()) { + // Load any saved stream token from persistent storage + write_stream_->set_last_stream_token(local_store_->GetLastStreamToken()); + + if (ShouldStartWatchStream()) { + StartWatchStream(); + } else { + online_state_tracker_.UpdateState(OnlineState::Unknown); + } + + // This will start the write stream if necessary. + FillWritePipeline(); + } +} + +void RemoteStore::DisableNetwork() { + is_network_enabled_ = false; + DisableNetworkInternal(); + + // Set the OnlineState to Offline so get()s return from cache, etc. + online_state_tracker_.UpdateState(OnlineState::Offline); +} + +void RemoteStore::DisableNetworkInternal() { + watch_stream_->Stop(); + write_stream_->Stop(); + + if (!write_pipeline_.empty()) { + LOG_DEBUG("Stopping write stream with %s pending writes", + write_pipeline_.size()); + write_pipeline_.clear(); + } + + CleanUpWatchStreamState(); +} + +void RemoteStore::Shutdown() { + LOG_DEBUG("RemoteStore %s shutting down", this); + is_network_enabled_ = false; + DisableNetworkInternal(); + + // Set the `OnlineState` to `Unknown` (rather than `Offline`) to avoid + // potentially triggering spurious listener events with cached data, etc. + online_state_tracker_.UpdateState(OnlineState::Unknown); + + datastore_->Shutdown(); +} + +// Watch Stream + +void RemoteStore::Listen(const TargetData& target_data) { + TargetId target_key = target_data.target_id(); + if (listen_targets_.find(target_key) != listen_targets_.end()) { + return; + } + + // Mark this as something the client is currently listening for. + listen_targets_[target_key] = target_data; + + if (ShouldStartWatchStream()) { + // The listen will be sent in `OnWatchStreamOpen` + StartWatchStream(); + } else if (watch_stream_->IsOpen()) { + SendWatchRequest(target_data); + } +} + +void RemoteStore::StopListening(TargetId target_id) { + size_t num_erased = listen_targets_.erase(target_id); + HARD_ASSERT(num_erased == 1, + "StopListening: target not currently watched: %s", target_id); + + // The watch stream might not be started if we're in a disconnected state + if (watch_stream_->IsOpen()) { + SendUnwatchRequest(target_id); + } + if (listen_targets_.empty()) { + if (watch_stream_->IsOpen()) { + watch_stream_->MarkIdle(); + } else if (CanUseNetwork()) { + // Revert to `OnlineState::Unknown` if the watch stream is not open and we + // have no listeners, since without any listens to send we cannot confirm + // if the stream is healthy and upgrade to `OnlineState::Online`. + online_state_tracker_.UpdateState(OnlineState::Unknown); + } + } +} + +void RemoteStore::SendWatchRequest(const TargetData& target_data) { + // We need to increment the the expected number of pending responses we're due + // from watch so we wait for the ack to process any messages from this target. + watch_change_aggregator_->RecordPendingTargetRequest(target_data.target_id()); + watch_stream_->WatchQuery(target_data); +} + +void RemoteStore::SendUnwatchRequest(TargetId target_id) { + // We need to increment the expected number of pending responses we're due + // from watch so we wait for the removal on the server before we process any + // messages from this target. + watch_change_aggregator_->RecordPendingTargetRequest(target_id); + watch_stream_->UnwatchTargetId(target_id); +} + +bool RemoteStore::ShouldStartWatchStream() const { + return CanUseNetwork() && !watch_stream_->IsStarted() && + !listen_targets_.empty(); +} + +void RemoteStore::StartWatchStream() { + HARD_ASSERT(ShouldStartWatchStream(), + "StartWatchStream called when ShouldStartWatchStream is false."); + watch_change_aggregator_ = absl::make_unique(this); + watch_stream_->Start(); + + online_state_tracker_.HandleWatchStreamStart(); +} + +void RemoteStore::CleanUpWatchStreamState() { + watch_change_aggregator_.reset(); +} + +void RemoteStore::OnWatchStreamOpen() { + // Restore any existing watches. + for (const auto& kv : listen_targets_) { + SendWatchRequest(kv.second); + } +} + +void RemoteStore::OnWatchStreamClose(const Status& status) { + if (status.ok()) { + // Graceful stop (due to Stop() or idle timeout). Make sure that's + // desirable. + HARD_ASSERT(!ShouldStartWatchStream(), + "Watch stream was stopped gracefully while still needed."); + } + + CleanUpWatchStreamState(); + + // If we still need the watch stream, retry the connection. + if (ShouldStartWatchStream()) { + online_state_tracker_.HandleWatchStreamFailure(status); + + StartWatchStream(); + } else { + // We don't need to restart the watch stream because there are no active + // targets. The online state is set to unknown because there is no active + // attempt at establishing a connection. + online_state_tracker_.UpdateState(OnlineState::Unknown); + } +} + +void RemoteStore::OnWatchStreamChange(const WatchChange& change, + const SnapshotVersion& snapshot_version) { + // Mark the connection as Online because we got a message from the server. + online_state_tracker_.UpdateState(OnlineState::Online); + + if (change.type() == WatchChange::Type::TargetChange) { + const WatchTargetChange& watch_target_change = + static_cast(change); + if (watch_target_change.state() == WatchTargetChangeState::Removed && + !watch_target_change.cause().ok()) { + // There was an error on a target, don't wait for a consistent snapshot to + // raise events + return ProcessTargetError(watch_target_change); + } else { + watch_change_aggregator_->HandleTargetChange(watch_target_change); + } + } else if (change.type() == WatchChange::Type::Document) { + watch_change_aggregator_->HandleDocumentChange( + static_cast(change)); + } else { + HARD_ASSERT( + change.type() == WatchChange::Type::ExistenceFilter, + "Expected WatchChange to be an instance of ExistenceFilterWatchChange"); + watch_change_aggregator_->HandleExistenceFilter( + static_cast(change)); + } + + if (snapshot_version != SnapshotVersion::None() && + snapshot_version >= local_store_->GetLastRemoteSnapshotVersion()) { + // We have received a target change with a global snapshot if the snapshot + // version is not equal to `SnapshotVersion::None()`. + RaiseWatchSnapshot(snapshot_version); + } +} + +void RemoteStore::RaiseWatchSnapshot(const SnapshotVersion& snapshot_version) { + HARD_ASSERT(snapshot_version != SnapshotVersion::None(), + "Can't raise event for unknown SnapshotVersion"); + + RemoteEvent remote_event = + watch_change_aggregator_->CreateRemoteEvent(snapshot_version); + + // Update in-memory resume tokens. `LocalStore` will update the persistent + // view of these when applying the completed `RemoteEvent`. + for (const auto& entry : remote_event.target_changes()) { + const TargetChange& target_change = entry.second; + const ByteString& resume_token = target_change.resume_token(); + + if (!resume_token.empty()) { + TargetId target_id = entry.first; + auto found = listen_targets_.find(target_id); + absl::optional target_data; + if (found != listen_targets_.end()) { + target_data = found->second; + } + + // A watched target might have been removed already. + if (target_data) { + listen_targets_[target_id] = + target_data->WithResumeToken(resume_token, snapshot_version); + } + } + } + + // Re-establish listens for the targets that have been invalidated by + // existence filter mismatches. + for (TargetId target_id : remote_event.target_mismatches()) { + auto found = listen_targets_.find(target_id); + if (found == listen_targets_.end()) { + // A watched target might have been removed already. + continue; + } + TargetData target_data = found->second; + + // Clear the resume token for the query, since we're in a known mismatch + // state. + target_data = + TargetData(target_data.target(), target_id, + target_data.sequence_number(), target_data.purpose()); + listen_targets_[target_id] = target_data; + + // Cause a hard reset by unwatching and rewatching immediately, but + // deliberately don't send a resume token so that we get a full update. + SendUnwatchRequest(target_id); + + // Mark the query we send as being on behalf of an existence filter + // mismatch, but don't actually retain that in listen_targets_. This ensures + // that we flag the first re-listen this way without impacting future + // listens of this target (that might happen e.g. on reconnect). + TargetData request_target_data(target_data.target(), target_id, + target_data.sequence_number(), + QueryPurpose::ExistenceFilterMismatch); + SendWatchRequest(request_target_data); + } + + // Finally handle remote event + sync_engine_->ApplyRemoteEvent(remote_event); +} + +void RemoteStore::ProcessTargetError(const WatchTargetChange& change) { + HARD_ASSERT(!change.cause().ok(), "Handling target error without a cause"); + + // Ignore targets that have been removed already. + for (TargetId target_id : change.target_ids()) { + auto found = listen_targets_.find(target_id); + if (found != listen_targets_.end()) { + listen_targets_.erase(found); + watch_change_aggregator_->RemoveTarget(target_id); + sync_engine_->HandleRejectedListen(target_id, change.cause()); + } + } +} + +// Write Stream + +void RemoteStore::FillWritePipeline() { + BatchId last_batch_id_retrieved = write_pipeline_.empty() + ? kBatchIdUnknown + : write_pipeline_.back().batch_id(); + while (CanAddToWritePipeline()) { + absl::optional batch = + local_store_->GetNextMutationBatch(last_batch_id_retrieved); + if (!batch) { + if (write_pipeline_.empty()) { + write_stream_->MarkIdle(); + } + break; + } + AddToWritePipeline(*batch); + last_batch_id_retrieved = batch->batch_id(); + } + + if (ShouldStartWriteStream()) { + StartWriteStream(); + } +} + +bool RemoteStore::CanAddToWritePipeline() const { + return CanUseNetwork() && write_pipeline_.size() < kMaxPendingWrites; +} + +void RemoteStore::AddToWritePipeline(const MutationBatch& batch) { + HARD_ASSERT(CanAddToWritePipeline(), + "AddToWritePipeline called when pipeline is full"); + + write_pipeline_.push_back(batch); + + if (write_stream_->IsOpen() && write_stream_->handshake_complete()) { + write_stream_->WriteMutations(batch.mutations()); + } +} + +bool RemoteStore::ShouldStartWriteStream() const { + return CanUseNetwork() && !write_stream_->IsStarted() && + !write_pipeline_.empty(); +} + +void RemoteStore::StartWriteStream() { + HARD_ASSERT(ShouldStartWriteStream(), + "StartWriteStream called when ShouldStartWriteStream is false."); + write_stream_->Start(); +} + +void RemoteStore::OnWriteStreamOpen() { + write_stream_->WriteHandshake(); +} + +void RemoteStore::OnWriteStreamHandshakeComplete() { + // Record the stream token. + local_store_->SetLastStreamToken(write_stream_->last_stream_token()); + + // Send the write pipeline now that the stream is established. + for (const MutationBatch& write : write_pipeline_) { + write_stream_->WriteMutations(write.mutations()); + } +} + +void RemoteStore::OnWriteStreamMutationResult( + SnapshotVersion commit_version, + std::vector mutation_results) { + // This is a response to a write containing mutations and should be correlated + // to the first write in our write pipeline. + HARD_ASSERT(!write_pipeline_.empty(), "Got result for empty write pipeline"); + + MutationBatch batch = write_pipeline_.front(); + write_pipeline_.erase(write_pipeline_.begin()); + + MutationBatchResult batch_result(std::move(batch), commit_version, + std::move(mutation_results), + write_stream_->last_stream_token()); + sync_engine_->HandleSuccessfulWrite(batch_result); + + // It's possible that with the completion of this mutation another slot has + // freed up. + FillWritePipeline(); +} + +void RemoteStore::OnWriteStreamClose(const Status& status) { + if (status.ok()) { + // Graceful stop (due to Stop() or idle timeout). Make sure that's + // desirable. + HARD_ASSERT(!ShouldStartWriteStream(), + "Write stream was stopped gracefully while still needed."); + } + + // If the write stream closed due to an error, invoke the error callbacks if + // there are pending writes. + if (!status.ok() && !write_pipeline_.empty()) { + // TODO(varconst): handle UNAUTHENTICATED status, see + // go/firestore-client-errors + if (write_stream_->handshake_complete()) { + // This error affects the actual writes. + HandleWriteError(status); + } else { + // If there was an error before the handshake finished, it's possible that + // the server is unable to process the stream token we're sending. + // (Perhaps it's too old?) + HandleHandshakeError(status); + } + } + + // The write stream might have been started by refilling the write pipeline + // for failed writes + if (ShouldStartWriteStream()) { + StartWriteStream(); + } +} + +void RemoteStore::HandleHandshakeError(const Status& status) { + HARD_ASSERT(!status.ok(), "Handling write error with status OK."); + + // Reset the token if it's a permanent error, signaling the write stream is + // no longer valid. Note that the handshake does not count as a write: see + // comments on `Datastore::IsPermanentWriteError` for details. + if (Datastore::IsPermanentError(status)) { + std::string token = util::ToString(write_stream_->last_stream_token()); + LOG_DEBUG( + "RemoteStore %s error before completed handshake; resetting " + "stream token %s: " + "error code: '%s', details: '%s'", + this, token, status.code(), status.error_message()); + write_stream_->set_last_stream_token({}); + local_store_->SetLastStreamToken({}); + } else { + // Some other error, don't reset stream token. Our stream logic will just + // retry with exponential backoff. + } +} + +void RemoteStore::HandleWriteError(const Status& status) { + HARD_ASSERT(!status.ok(), "Handling write error with status OK."); + + // Only handle permanent errors here. If it's transient, just let the retry + // logic kick in. + if (!Datastore::IsPermanentWriteError(status)) { + return; + } + + // If this was a permanent error, the request itself was the problem so it's + // not going to succeed if we resend it. + MutationBatch batch = write_pipeline_.front(); + write_pipeline_.erase(write_pipeline_.begin()); + + // In this case it's also unlikely that the server itself is melting + // down--this was just a bad request so inhibit backoff on the next restart. + write_stream_->InhibitBackoff(); + + sync_engine_->HandleRejectedWrite(batch.batch_id(), status); + + // It's possible that with the completion of this mutation another slot has + // freed up. + FillWritePipeline(); +} + +bool RemoteStore::CanUseNetwork() const { + // PORTING NOTE: This method exists mostly because web also has to take into + // account primary vs. secondary state. + return is_network_enabled_; +} + +std::shared_ptr RemoteStore::CreateTransaction() { + return std::make_shared(datastore_.get()); +} + +DocumentKeySet RemoteStore::GetRemoteKeysForTarget(TargetId target_id) const { + return sync_engine_->GetRemoteKeys(target_id); +} + +absl::optional RemoteStore::GetTargetDataForTarget( + TargetId target_id) const { + auto found = listen_targets_.find(target_id); + return found != listen_targets_.end() ? found->second + : absl::optional{}; +} + +void RemoteStore::HandleCredentialChange() { + if (CanUseNetwork()) { + // Tear down and re-create our network streams. This will ensure we get a + // fresh auth token for the new user and re-fill the write pipeline with new + // mutations from the `LocalStore` (since mutations are per-user). + LOG_DEBUG("RemoteStore %s restarting streams for new credential", this); + is_network_enabled_ = false; + DisableNetworkInternal(); + online_state_tracker_.UpdateState(OnlineState::Unknown); + EnableNetwork(); + } +} + +} // namespace remote +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_store.h index 6489f88..d272983 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -17,18 +17,15 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_STORE_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_STORE_H_ -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import - #include #include #include #include "Firestore/core/src/firebase/firestore/core/transaction.h" +#include "Firestore/core/src/firebase/firestore/local/local_store.h" #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" +#include "Firestore/core/src/firebase/firestore/model/mutation_batch_result.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" #include "Firestore/core/src/firebase/firestore/remote/datastore.h" @@ -38,93 +35,86 @@ #include "Firestore/core/src/firebase/firestore/remote/watch_stream.h" #include "Firestore/core/src/firebase/firestore/remote/write_stream.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" - -@class FSTLocalStore; -@class FSTMutationBatch; -@class FSTMutationBatchResult; -@class FSTQueryData; -@class FSTTransaction; +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" -NS_ASSUME_NONNULL_BEGIN - -/** - * A protocol that describes the actions the `RemoteStore` needs to perform on - * a cooperating synchronization engine. - */ -@protocol FSTRemoteSyncer +namespace firebase { +namespace firestore { +namespace remote { /** - * Applies one remote event to the sync engine, notifying any views of the - * changes, and releasing any pending mutation batches that would become visible - * because of the snapshot version the remote event contains. + * A callback interface for events from remote store. */ -- (void)applyRemoteEvent: - (const firebase::firestore::remote::RemoteEvent&)remoteEvent; +class RemoteStoreCallback { + public: + virtual ~RemoteStoreCallback() = default; -/** - * Rejects the listen for the given targetID. This can be triggered by the - * backend for any active target. - * - * @param targetID The targetID corresponding to a listen initiated via - * `RemoteStore::Listen`. - * @param error A description of the condition that has forced the rejection. - * Nearly always this will be an indication that the user is no longer - * authorized to see the data matching the target. - */ -- (void)rejectListenWithTargetID: - (const firebase::firestore::model::TargetId)targetID - error: - (NSError*)error; // NOLINT(readability/casting) + /** + * Applies a remote event to the sync engine, notifying any views of the + * changes, and releasing any pending mutation batches that would become + * visible because of the snapshot version the remote event contains. + */ + virtual void ApplyRemoteEvent(const RemoteEvent& remote_event) = 0; -/** - * Applies the result of a successful write of a mutation batch to the sync - * engine, emitting snapshots in any views that the mutation applies to, and - * removing the batch from the mutation queue. - */ -- (void)applySuccessfulWriteWithResult: - (FSTMutationBatchResult*)batchResult; // NOLINT(readability/casting) + /** + * Handles rejection of listen for the given target id. This can be triggered + * by the backend for any active target. + * + * @param target_id The target ID corresponding to a listen initiated via + * RemoteStore::Listen() + * @param error A description of the condition that has forced the rejection. + * Nearly always this will be an indication that the user is no longer + * authorized to see the data matching the target. + */ + virtual void HandleRejectedListen(model::TargetId target_id, + util::Status error) = 0; -/** - * Rejects the batch, removing the batch from the mutation queue, recomputing - * the local view of any documents affected by the batch and then, emitting - * snapshots with the reverted value. - */ -- (void) - rejectFailedWriteWithBatchID:(firebase::firestore::model::BatchId)batchID - error: - (NSError*)error; // NOLINT(readability/casting) + /** + * Applies the result of a successful write of a mutation batch to the sync + * engine, emitting snapshots in any views that the mutation applies to, and + * removing the batch from the mutation queue. + */ + virtual void HandleSuccessfulWrite( + const model::MutationBatchResult& batch_result) = 0; -/** - * Returns the set of remote document keys for the given target ID. This list - * includes the documents that were assigned to the target when we received the - * last snapshot. - */ -- (firebase::firestore::model::DocumentKeySet)remoteKeysForTarget: - (firebase::firestore::model::TargetId)targetId; + /** + * Rejects the batch, removing the batch from the mutation queue, recomputing + * the local view of any documents affected by the batch and then, emitting + * snapshots with the reverted value. + */ + virtual void HandleRejectedWrite(model::BatchId batch_id, + util::Status error) = 0; -@end + /** + * Applies an OnlineState change to the sync engine and notifies any views of + * the change. + */ + virtual void HandleOnlineStateChange(model::OnlineState online_state) = 0; -namespace firebase { -namespace firestore { -namespace remote { + /** + * Returns the set of remote document keys for the given target ID. This list + * includes the documents that were assigned to the target when we received + * the last snapshot. + */ + virtual model::DocumentKeySet GetRemoteKeys( + model::TargetId target_id) const = 0; +}; class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback, public WriteStreamCallback { public: - RemoteStore(FSTLocalStore* local_store, + RemoteStore(local::LocalStore* local_store, std::shared_ptr datastore, - util::AsyncQueue* worker_queue, + const std::shared_ptr& worker_queue, std::function online_state_handler); - void set_sync_engine(id sync_engine) { + void set_sync_engine(RemoteStoreCallback* sync_engine) { sync_engine_ = sync_engine; } /** * Starts up the remote store, creating streams, restoring state from - * `FSTLocalStore`, etc. + * `LocalStore`, etc. */ void Start(); @@ -146,6 +136,8 @@ class RemoteStore : public TargetMetadataProvider, */ void EnableNetwork(); + bool CanUseNetwork() const; + /** * Tells the `RemoteStore` that the currently authenticated user has changed. * @@ -155,17 +147,26 @@ class RemoteStore : public TargetMetadataProvider, */ void HandleCredentialChange(); - /** Listens to the target identified by the given `FSTQueryData`. */ - void Listen(FSTQueryData* query_data); + /** + * Listens to the target identified by the given `TargetData`. + * + * It is a no-op if the target of the given target data is already being + * listened to. + */ + void Listen(const local::TargetData& target_data); - /** Stops listening to the target with the given target ID. */ + /** + * Stops listening to the target with the given target ID. + * + * It is an error if the given target id is not being listened to. + */ void StopListening(model::TargetId target_id); /** - * Attempts to fill our write pipeline with writes from the `FSTLocalStore`. + * Attempts to fill our write pipeline with writes from the `LocalStore`. * * Called internally to bootstrap or refill the write pipeline and by - * `FSTSyncEngine` whenever there are new mutations to process. + * `SyncEngine` whenever there are new mutations to process. * * Starts the write stream if necessary. */ @@ -175,7 +176,7 @@ class RemoteStore : public TargetMetadataProvider, * Queues additional writes to be sent to the write stream, sending them * immediately if the write stream is established. */ - void AddToWritePipeline(FSTMutationBatch* batch); + void AddToWritePipeline(const model::MutationBatch& batch); /** Returns a new transaction backed by this remote store. */ // TODO(c++14): return a plain value when it becomes possible to move @@ -184,7 +185,8 @@ class RemoteStore : public TargetMetadataProvider, model::DocumentKeySet GetRemoteKeysForTarget( model::TargetId target_id) const override; - FSTQueryData* GetQueryDataForTarget(model::TargetId target_id) const override; + absl::optional GetTargetDataForTarget( + model::TargetId target_id) const override; void OnWatchStreamOpen() override; void OnWatchStreamChange( @@ -197,12 +199,12 @@ class RemoteStore : public TargetMetadataProvider, void OnWriteStreamClose(const util::Status& status) override; void OnWriteStreamMutationResult( model::SnapshotVersion commit_version, - std::vector mutation_results) override; + std::vector mutation_results) override; private: void DisableNetworkInternal(); - void SendWatchRequest(FSTQueryData* query_data); + void SendWatchRequest(const local::TargetData& target_data); void SendUnwatchRequest(model::TargetId target_id); /** @@ -231,8 +233,6 @@ class RemoteStore : public TargetMetadataProvider, void HandleHandshakeError(const util::Status& status); void HandleWriteError(const util::Status& status); - bool CanUseNetwork() const; - void StartWatchStream(); /** @@ -243,13 +243,13 @@ class RemoteStore : public TargetMetadataProvider, void CleanUpWatchStreamState(); - id sync_engine_ = nil; + RemoteStoreCallback* sync_engine_ = nullptr; /** * The local store, used to fill the write pipeline with outbound mutations * and resolve existence filter mismatches. */ - FSTLocalStore* local_store_ = nil; + local::LocalStore* local_store_ = nullptr; /** The client-side proxy for interacting with the backend. */ std::shared_ptr datastore_; @@ -263,7 +263,7 @@ class RemoteStore : public TargetMetadataProvider, * to the server. The targets removed with unlistens are removed eagerly * without waiting for confirmation from the listen stream. */ - std::unordered_map listen_targets_; + std::unordered_map listen_targets_; OnlineStateTracker online_state_tracker_; @@ -294,13 +294,11 @@ class RemoteStore : public TargetMetadataProvider, * purely based on order, and so we can just remove writes from the front of * the `write_pipeline_` as we receive responses. */ - std::vector write_pipeline_; + std::vector write_pipeline_; }; } // namespace remote } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_STORE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_store.mm deleted file mode 100644 index ce46f27..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/remote_store.mm +++ /dev/null @@ -1,552 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/remote/remote_store.h" - -#include - -#import "Firestore/Source/Local/FSTLocalStore.h" -#import "Firestore/Source/Local/FSTQueryData.h" -#import "Firestore/Source/Model/FSTMutationBatch.h" - -#include "Firestore/core/src/firebase/firestore/core/transaction.h" -#include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" -#include "Firestore/core/src/firebase/firestore/util/error_apple.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/log.h" -#include "absl/memory/memory.h" - -using firebase::firestore::core::Transaction; -using firebase::firestore::model::BatchId; -using firebase::firestore::model::DocumentKeySet; -using firebase::firestore::model::OnlineState; -using firebase::firestore::model::SnapshotVersion; -using firebase::firestore::model::TargetId; -using firebase::firestore::model::kBatchIdUnknown; -using firebase::firestore::remote::Datastore; -using firebase::firestore::remote::WatchStream; -using firebase::firestore::remote::DocumentWatchChange; -using firebase::firestore::remote::ExistenceFilterWatchChange; -using firebase::firestore::remote::OnlineStateTracker; -using firebase::firestore::remote::RemoteEvent; -using firebase::firestore::remote::TargetChange; -using firebase::firestore::remote::WatchChange; -using firebase::firestore::remote::WatchChangeAggregator; -using firebase::firestore::remote::WatchTargetChange; -using firebase::firestore::remote::WatchTargetChangeState; -using firebase::firestore::util::AsyncQueue; -using firebase::firestore::util::Status; - -namespace firebase { -namespace firestore { -namespace remote { - -/** - * The maximum number of pending writes to allow. - * TODO(b/35853402): Negotiate this value with the backend. - */ -constexpr int kMaxPendingWrites = 10; - -RemoteStore::RemoteStore( - FSTLocalStore* local_store, - std::shared_ptr datastore, - AsyncQueue* worker_queue, - std::function online_state_handler) - : local_store_{local_store}, - datastore_{std::move(datastore)}, - online_state_tracker_{worker_queue, std::move(online_state_handler)} { - datastore_->Start(); - - // Create streams (but note they're not started yet) - watch_stream_ = datastore_->CreateWatchStream(this); - write_stream_ = datastore_->CreateWriteStream(this); -} - -void RemoteStore::Start() { - // For now, all setup is handled by `EnableNetwork`. We might expand on this - // in the future. - EnableNetwork(); -} - -void RemoteStore::EnableNetwork() { - is_network_enabled_ = true; - - if (CanUseNetwork()) { - // Load any saved stream token from persistent storage - write_stream_->SetLastStreamToken([local_store_ lastStreamToken]); - - if (ShouldStartWatchStream()) { - StartWatchStream(); - } else { - online_state_tracker_.UpdateState(OnlineState::Unknown); - } - - // This will start the write stream if necessary. - FillWritePipeline(); - } -} - -void RemoteStore::DisableNetwork() { - is_network_enabled_ = false; - DisableNetworkInternal(); - - // Set the OnlineState to Offline so get()s return from cache, etc. - online_state_tracker_.UpdateState(OnlineState::Offline); -} - -void RemoteStore::DisableNetworkInternal() { - watch_stream_->Stop(); - write_stream_->Stop(); - - if (!write_pipeline_.empty()) { - LOG_DEBUG("Stopping write stream with %s pending writes", - write_pipeline_.size()); - write_pipeline_.clear(); - } - - CleanUpWatchStreamState(); -} - -void RemoteStore::Shutdown() { - LOG_DEBUG("RemoteStore %s shutting down", this); - is_network_enabled_ = false; - DisableNetworkInternal(); - - // Set the `OnlineState` to `Unknown` (rather than `Offline`) to avoid - // potentially triggering spurious listener events with cached data, etc. - online_state_tracker_.UpdateState(OnlineState::Unknown); - - datastore_->Shutdown(); -} - -// Watch Stream - -void RemoteStore::Listen(FSTQueryData* query_data) { - TargetId targetKey = query_data.targetID; - HARD_ASSERT(listen_targets_.find(targetKey) == listen_targets_.end(), - "Listen called with duplicate target id: %s", targetKey); - - // Mark this as something the client is currently listening for. - listen_targets_[targetKey] = query_data; - - if (ShouldStartWatchStream()) { - // The listen will be sent in `OnWatchStreamOpen` - StartWatchStream(); - } else if (watch_stream_->IsOpen()) { - SendWatchRequest(query_data); - } -} - -void RemoteStore::StopListening(TargetId target_id) { - size_t num_erased = listen_targets_.erase(target_id); - HARD_ASSERT(num_erased == 1, - "StopListening: target not currently watched: %s", target_id); - - // The watch stream might not be started if we're in a disconnected state - if (watch_stream_->IsOpen()) { - SendUnwatchRequest(target_id); - } - if (listen_targets_.empty()) { - if (watch_stream_->IsOpen()) { - watch_stream_->MarkIdle(); - } else if (CanUseNetwork()) { - // Revert to `OnlineState::Unknown` if the watch stream is not open and we - // have no listeners, since without any listens to send we cannot confirm - // if the stream is healthy and upgrade to `OnlineState::Online`. - online_state_tracker_.UpdateState(OnlineState::Unknown); - } - } -} - -void RemoteStore::SendWatchRequest(FSTQueryData* query_data) { - // We need to increment the the expected number of pending responses we're due - // from watch so we wait for the ack to process any messages from this target. - watch_change_aggregator_->RecordPendingTargetRequest(query_data.targetID); - watch_stream_->WatchQuery(query_data); -} - -void RemoteStore::SendUnwatchRequest(TargetId target_id) { - // We need to increment the expected number of pending responses we're due - // from watch so we wait for the removal on the server before we process any - // messages from this target. - watch_change_aggregator_->RecordPendingTargetRequest(target_id); - watch_stream_->UnwatchTargetId(target_id); -} - -bool RemoteStore::ShouldStartWatchStream() const { - return CanUseNetwork() && !watch_stream_->IsStarted() && - !listen_targets_.empty(); -} - -void RemoteStore::StartWatchStream() { - HARD_ASSERT(ShouldStartWatchStream(), - "StartWatchStream called when ShouldStartWatchStream is false."); - watch_change_aggregator_ = absl::make_unique(this); - watch_stream_->Start(); - - online_state_tracker_.HandleWatchStreamStart(); -} - -void RemoteStore::CleanUpWatchStreamState() { - watch_change_aggregator_.reset(); -} - -void RemoteStore::OnWatchStreamOpen() { - // Restore any existing watches. - for (const auto& kv : listen_targets_) { - SendWatchRequest(kv.second); - } -} - -void RemoteStore::OnWatchStreamClose(const Status& status) { - if (status.ok()) { - // Graceful stop (due to Stop() or idle timeout). Make sure that's - // desirable. - HARD_ASSERT(!ShouldStartWatchStream(), - "Watch stream was stopped gracefully while still needed."); - } - - CleanUpWatchStreamState(); - - // If we still need the watch stream, retry the connection. - if (ShouldStartWatchStream()) { - online_state_tracker_.HandleWatchStreamFailure(status); - - StartWatchStream(); - } else { - // We don't need to restart the watch stream because there are no active - // targets. The online state is set to unknown because there is no active - // attempt at establishing a connection. - online_state_tracker_.UpdateState(OnlineState::Unknown); - } -} - -void RemoteStore::OnWatchStreamChange(const WatchChange& change, - const SnapshotVersion& snapshot_version) { - // Mark the connection as Online because we got a message from the server. - online_state_tracker_.UpdateState(OnlineState::Online); - - if (change.type() == WatchChange::Type::TargetChange) { - const WatchTargetChange& watch_target_change = - static_cast(change); - if (watch_target_change.state() == WatchTargetChangeState::Removed && - !watch_target_change.cause().ok()) { - // There was an error on a target, don't wait for a consistent snapshot to - // raise events - return ProcessTargetError(watch_target_change); - } else { - watch_change_aggregator_->HandleTargetChange(watch_target_change); - } - } else if (change.type() == WatchChange::Type::Document) { - watch_change_aggregator_->HandleDocumentChange( - static_cast(change)); - } else { - HARD_ASSERT( - change.type() == WatchChange::Type::ExistenceFilter, - "Expected watchChange to be an instance of ExistenceFilterWatchChange"); - watch_change_aggregator_->HandleExistenceFilter( - static_cast(change)); - } - - if (snapshot_version != SnapshotVersion::None() && - snapshot_version >= [local_store_ lastRemoteSnapshotVersion]) { - // We have received a target change with a global snapshot if the snapshot - // version is not equal to `SnapshotVersion::None()`. - RaiseWatchSnapshot(snapshot_version); - } -} - -void RemoteStore::RaiseWatchSnapshot(const SnapshotVersion& snapshot_version) { - HARD_ASSERT(snapshot_version != SnapshotVersion::None(), - "Can't raise event for unknown SnapshotVersion"); - - RemoteEvent remote_event = - watch_change_aggregator_->CreateRemoteEvent(snapshot_version); - - // Update in-memory resume tokens. `FSTLocalStore` will update the persistent - // view of these when applying the completed `RemoteEvent`. - for (const auto& entry : remote_event.target_changes()) { - const TargetChange& target_change = entry.second; - NSData* resumeToken = target_change.resume_token(); - - if (resumeToken.length > 0) { - TargetId target_id = entry.first; - auto found = listen_targets_.find(target_id); - FSTQueryData* query_data = - found != listen_targets_.end() ? found->second : nil; - - // A watched target might have been removed already. - if (query_data) { - listen_targets_[target_id] = [query_data - queryDataByReplacingSnapshotVersion:snapshot_version - resumeToken:resumeToken - sequenceNumber:query_data.sequenceNumber]; - } - } - } - - // Re-establish listens for the targets that have been invalidated by - // existence filter mismatches. - for (TargetId target_id : remote_event.target_mismatches()) { - auto found = listen_targets_.find(target_id); - if (found == listen_targets_.end()) { - // A watched target might have been removed already. - continue; - } - FSTQueryData* query_data = found->second; - - // Clear the resume token for the query, since we're in a known mismatch - // state. - query_data = [[FSTQueryData alloc] initWithQuery:query_data.query - targetID:target_id - listenSequenceNumber:query_data.sequenceNumber - purpose:query_data.purpose]; - listen_targets_[target_id] = query_data; - - // Cause a hard reset by unwatching and rewatching immediately, but - // deliberately don't send a resume token so that we get a full update. - SendUnwatchRequest(target_id); - - // Mark the query we send as being on behalf of an existence filter - // mismatch, but don't actually retain that in listen_targets_. This ensures - // that we flag the first re-listen this way without impacting future - // listens of this target (that might happen e.g. on reconnect). - FSTQueryData* request_query_data = [[FSTQueryData alloc] - initWithQuery:query_data.query - targetID:target_id - listenSequenceNumber:query_data.sequenceNumber - purpose:FSTQueryPurposeExistenceFilterMismatch]; - SendWatchRequest(request_query_data); - } - - // Finally handle remote event - [sync_engine_ applyRemoteEvent:remote_event]; -} - -void RemoteStore::ProcessTargetError(const WatchTargetChange& change) { - HARD_ASSERT(!change.cause().ok(), "Handling target error without a cause"); - - // Ignore targets that have been removed already. - for (TargetId target_id : change.target_ids()) { - auto found = listen_targets_.find(target_id); - if (found != listen_targets_.end()) { - listen_targets_.erase(found); - watch_change_aggregator_->RemoveTarget(target_id); - [sync_engine_ rejectListenWithTargetID:target_id - error:util::MakeNSError(change.cause())]; - } - } -} - -// Write Stream - -void RemoteStore::FillWritePipeline() { - BatchId last_batch_id_retrieved = write_pipeline_.empty() - ? kBatchIdUnknown - : write_pipeline_.back().batchID; - while (CanAddToWritePipeline()) { - FSTMutationBatch* batch = - [local_store_ nextMutationBatchAfterBatchID:last_batch_id_retrieved]; - if (!batch) { - if (write_pipeline_.empty()) { - write_stream_->MarkIdle(); - } - break; - } - AddToWritePipeline(batch); - last_batch_id_retrieved = batch.batchID; - } - - if (ShouldStartWriteStream()) { - StartWriteStream(); - } -} - -bool RemoteStore::CanAddToWritePipeline() const { - return CanUseNetwork() && write_pipeline_.size() < kMaxPendingWrites; -} - -void RemoteStore::AddToWritePipeline(FSTMutationBatch* batch) { - HARD_ASSERT(CanAddToWritePipeline(), - "AddToWritePipeline called when pipeline is full"); - - write_pipeline_.push_back(batch); - - if (write_stream_->IsOpen() && write_stream_->handshake_complete()) { - write_stream_->WriteMutations(batch.mutations); - } -} - -bool RemoteStore::ShouldStartWriteStream() const { - return CanUseNetwork() && !write_stream_->IsStarted() && - !write_pipeline_.empty(); -} - -void RemoteStore::StartWriteStream() { - HARD_ASSERT(ShouldStartWriteStream(), "StartWriteStream called when " - "ShouldStartWriteStream is false."); - write_stream_->Start(); -} - -void RemoteStore::OnWriteStreamOpen() { - write_stream_->WriteHandshake(); -} - -void RemoteStore::OnWriteStreamHandshakeComplete() { - // Record the stream token. - [local_store_ setLastStreamToken:write_stream_->GetLastStreamToken()]; - - // Send the write pipeline now that the stream is established. - for (FSTMutationBatch* write : write_pipeline_) { - write_stream_->WriteMutations(write.mutations); - } -} - -void RemoteStore::OnWriteStreamMutationResult( - SnapshotVersion commit_version, - std::vector mutation_results) { - // This is a response to a write containing mutations and should be correlated - // to the first write in our write pipeline. - HARD_ASSERT(!write_pipeline_.empty(), "Got result for empty write pipeline"); - - FSTMutationBatch* batch = write_pipeline_.front(); - write_pipeline_.erase(write_pipeline_.begin()); - - FSTMutationBatchResult* batchResult = [FSTMutationBatchResult - resultWithBatch:batch - commitVersion:commit_version - mutationResults:std::move(mutation_results) - streamToken:write_stream_->GetLastStreamToken()]; - [sync_engine_ applySuccessfulWriteWithResult:batchResult]; - - // It's possible that with the completion of this mutation another slot has - // freed up. - FillWritePipeline(); -} - -void RemoteStore::OnWriteStreamClose(const Status& status) { - if (status.ok()) { - // Graceful stop (due to Stop() or idle timeout). Make sure that's - // desirable. - HARD_ASSERT(!ShouldStartWriteStream(), - "Write stream was stopped gracefully while still needed."); - } - - // If the write stream closed due to an error, invoke the error callbacks if - // there are pending writes. - if (!status.ok() && !write_pipeline_.empty()) { - // TODO(varconst): handle UNAUTHENTICATED status, see - // go/firestore-client-errors - if (write_stream_->handshake_complete()) { - // This error affects the actual writes. - HandleWriteError(status); - } else { - // If there was an error before the handshake finished, it's possible that - // the server is unable to process the stream token we're sending. - // (Perhaps it's too old?) - HandleHandshakeError(status); - } - } - - // The write stream might have been started by refilling the write pipeline - // for failed writes - if (ShouldStartWriteStream()) { - StartWriteStream(); - } -} - -void RemoteStore::HandleHandshakeError(const Status& status) { - HARD_ASSERT(!status.ok(), "Handling write error with status OK."); - - // Reset the token if it's a permanent error, signaling the write stream is - // no longer valid. Note that the handshake does not count as a write: see - // comments on `Datastore::IsPermanentWriteError` for details. - if (Datastore::IsPermanentError(status)) { - NSString* token = - [write_stream_->GetLastStreamToken() base64EncodedStringWithOptions:0]; - LOG_DEBUG("RemoteStore %s error before completed handshake; resetting " - "stream token %s: " - "error code: '%s', details: '%s'", - this, token, status.code(), status.error_message()); - write_stream_->SetLastStreamToken(nil); - [local_store_ setLastStreamToken:nil]; - } else { - // Some other error, don't reset stream token. Our stream logic will just - // retry with exponential backoff. - } -} - -void RemoteStore::HandleWriteError(const Status& status) { - HARD_ASSERT(!status.ok(), "Handling write error with status OK."); - - // Only handle permanent errors here. If it's transient, just let the retry - // logic kick in. - if (!Datastore::IsPermanentWriteError(status)) { - return; - } - - // If this was a permanent error, the request itself was the problem so it's - // not going to succeed if we resend it. - FSTMutationBatch* batch = write_pipeline_.front(); - write_pipeline_.erase(write_pipeline_.begin()); - - // In this case it's also unlikely that the server itself is melting - // down--this was just a bad request so inhibit backoff on the next restart. - write_stream_->InhibitBackoff(); - - [sync_engine_ rejectFailedWriteWithBatchID:batch.batchID - error:util::MakeNSError(status)]; - - // It's possible that with the completion of this mutation another slot has - // freed up. - FillWritePipeline(); -} - -bool RemoteStore::CanUseNetwork() const { - // PORTING NOTE: This method exists mostly because web also has to take into - // account primary vs. secondary state. - return is_network_enabled_; -} - -std::shared_ptr RemoteStore::CreateTransaction() { - return std::make_shared(datastore_.get()); -} - -DocumentKeySet RemoteStore::GetRemoteKeysForTarget(TargetId target_id) const { - return [sync_engine_ remoteKeysForTarget:target_id]; -} - -FSTQueryData* RemoteStore::GetQueryDataForTarget(TargetId target_id) const { - auto found = listen_targets_.find(target_id); - return found != listen_targets_.end() ? found->second : nil; -} - -void RemoteStore::HandleCredentialChange() { - if (CanUseNetwork()) { - // Tear down and re-create our network streams. This will ensure we get a - // fresh auth token for the new user and re-fill the write pipeline with new - // mutations from the `FSTLocalStore` (since mutations are per-user). - LOG_DEBUG("RemoteStore %s restarting streams for new credential", this); - is_network_enabled_ = false; - DisableNetworkInternal(); - online_state_tracker_.UpdateState(OnlineState::Unknown); - EnableNetwork(); - } -} - -} // namespace remote -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/serializer.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/serializer.cc index cd0b9a1..3d1f2cb 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/serializer.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/serializer.cc @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -30,183 +31,102 @@ #include "Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.h" #include "Firestore/core/include/firebase/firestore/firestore_errors.h" #include "Firestore/core/include/firebase/firestore/timestamp.h" +#include "Firestore/core/src/firebase/firestore/core/query.h" +#include "Firestore/core/src/firebase/firestore/model/delete_mutation.h" #include "Firestore/core/src/firebase/firestore/model/document.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" #include "Firestore/core/src/firebase/firestore/model/field_value.h" #include "Firestore/core/src/firebase/firestore/model/no_document.h" +#include "Firestore/core/src/firebase/firestore/model/patch_mutation.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" +#include "Firestore/core/src/firebase/firestore/model/set_mutation.h" +#include "Firestore/core/src/firebase/firestore/model/transform_mutation.h" +#include "Firestore/core/src/firebase/firestore/model/verify_mutation.h" +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" #include "Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h" #include "Firestore/core/src/firebase/firestore/nanopb/reader.h" #include "Firestore/core/src/firebase/firestore/nanopb/writer.h" #include "Firestore/core/src/firebase/firestore/timestamp_internal.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_format.h" -#include "absl/base/casts.h" -#include "absl/memory/memory.h" +#include "absl/algorithm/container.h" namespace firebase { namespace firestore { namespace remote { -using firebase::Timestamp; -using firebase::TimestampInternal; -using firebase::firestore::core::Query; -using firebase::firestore::model::DatabaseId; -using firebase::firestore::model::DeleteMutation; -using firebase::firestore::model::Document; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::DocumentState; -using firebase::firestore::model::FieldMask; -using firebase::firestore::model::FieldPath; -using firebase::firestore::model::FieldValue; -using firebase::firestore::model::MaybeDocument; -using firebase::firestore::model::Mutation; -using firebase::firestore::model::NoDocument; -using firebase::firestore::model::ObjectValue; -using firebase::firestore::model::PatchMutation; -using firebase::firestore::model::Precondition; -using firebase::firestore::model::ResourcePath; -using firebase::firestore::model::SetMutation; -using firebase::firestore::model::SnapshotVersion; -using firebase::firestore::nanopb::CheckedSize; -using firebase::firestore::nanopb::Reader; -using firebase::firestore::nanopb::Writer; -using firebase::firestore::util::Status; -using firebase::firestore::util::StringFormat; +using core::Bound; +using core::CollectionGroupId; +using core::Direction; +using core::FieldFilter; +using core::Filter; +using core::FilterList; +using core::LimitType; +using core::OrderBy; +using core::OrderByList; +using core::Query; +using core::Target; +using local::QueryPurpose; +using local::TargetData; +using model::ArrayTransform; +using model::DatabaseId; +using model::DeleteMutation; +using model::Document; +using model::DocumentKey; +using model::DocumentState; +using model::FieldMask; +using model::FieldPath; +using model::FieldTransform; +using model::FieldValue; +using model::MaybeDocument; +using model::Mutation; +using model::MutationResult; +using model::NoDocument; +using model::NumericIncrementTransform; +using model::ObjectValue; +using model::PatchMutation; +using model::Precondition; +using model::ResourcePath; +using model::ServerTimestampTransform; +using model::SetMutation; +using model::SnapshotVersion; +using model::TargetId; +using model::TransformMutation; +using model::TransformOperation; +using model::VerifyMutation; +using nanopb::ByteString; +using nanopb::CheckedSize; +using nanopb::MakeArray; +using nanopb::MakeStringView; +using nanopb::Reader; +using nanopb::SafeReadBoolean; +using nanopb::Writer; +using remote::WatchChange; +using util::Status; +using util::StringFormat; pb_bytes_array_t* Serializer::EncodeString(const std::string& str) { - pb_size_t size = CheckedSize(str.size()); - auto result = - static_cast(malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size))); - result->size = size; - memcpy(result->bytes, str.c_str(), size); - return result; + return nanopb::MakeBytesArray(str); } std::string Serializer::DecodeString(const pb_bytes_array_t* str) { - if (str == nullptr) return ""; - size_t size = static_cast(str->size); - return std::string{reinterpret_cast(str->bytes), size}; -} - -pb_bytes_array_t* Serializer::EncodeBytes(const std::vector& bytes) { - pb_size_t size = CheckedSize(bytes.size()); - auto result = - static_cast(malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size))); - result->size = size; - memcpy(result->bytes, bytes.data(), size); - return result; -} - -std::vector Serializer::DecodeBytes(const pb_bytes_array_t* bytes) { - if (bytes == nullptr) return {}; - return std::vector(bytes->bytes, bytes->bytes + bytes->size); + return nanopb::MakeString(str); } namespace { -FieldValue::Map DecodeMapValue(Reader* reader, - const google_firestore_v1_MapValue& map_value); - -// There's no f:f::model equivalent of StructuredQuery, so we'll create our -// own struct for decoding. We could use nanopb's struct, but it's slightly -// inconvenient since it's a fixed size (so uses callbacks to represent -// strings, repeated fields, etc.) -struct StructuredQuery { - struct CollectionSelector { - std::string collection_id; - bool all_descendants; - }; - // TODO(rsgowman): other submessages - - std::vector from; - // TODO(rsgowman): other fields -}; - -FieldValue::Map::value_type DecodeFieldsEntry( - Reader* reader, const google_firestore_v1_Document_FieldsEntry& fields) { - std::string key = Serializer::DecodeString(fields.key); - FieldValue value = Serializer::DecodeFieldValue(reader, fields.value); - - if (key.empty()) { - reader->Fail( - "Invalid message: Empty key while decoding a Map field value."); - return {}; - } - - return FieldValue::Map::value_type{std::move(key), std::move(value)}; -} - -FieldValue::Map DecodeFields( - Reader* reader, - size_t count, - const google_firestore_v1_Document_FieldsEntry* fields) { - FieldValue::Map result; - for (size_t i = 0; i < count; i++) { - FieldValue::Map::value_type kv = DecodeFieldsEntry(reader, fields[i]); - result = result.insert(std::move(kv.first), std::move(kv.second)); - } - - return result; -} - -google_firestore_v1_MapValue EncodeMapValue(const ObjectValue& object_value) { - google_firestore_v1_MapValue result{}; - - pb_size_t count = CheckedSize(object_value.GetInternalValue().size()); - - result.fields_count = count; - result.fields = MakeArray(count); - - int i = 0; - for (const auto& kv : object_value.GetInternalValue()) { - result.fields[i].key = Serializer::EncodeString(kv.first); - result.fields[i].value = Serializer::EncodeFieldValue(kv.second); - i++; - } - - return result; -} - -FieldValue::Map DecodeMapValue(Reader* reader, - const google_firestore_v1_MapValue& map_value) { - FieldValue::Map result; - - for (size_t i = 0; i < map_value.fields_count; i++) { - std::string key = Serializer::DecodeString(map_value.fields[i].key); - FieldValue value = - Serializer::DecodeFieldValue(reader, map_value.fields[i].value); - - result = result.insert(key, value); - } - - return result; -} - /** * Creates the prefix for a fully qualified resource path, without a local path * on the end. */ -ResourcePath EncodeDatabaseId(const DatabaseId& database_id) { +ResourcePath DatabaseName(const DatabaseId& database_id) { return ResourcePath{"projects", database_id.project_id(), "databases", database_id.database_id()}; } -/** - * Encodes a databaseId and resource path into the following form: - * /projects/$projectId/database/$databaseId/documents/$path - */ -std::string EncodeResourceName(const DatabaseId& database_id, - const ResourcePath& path) { - return EncodeDatabaseId(database_id) - .Append("documents") - .Append(path) - .CanonicalString(); -} - /** * Validates that a path has a prefix that looks like a valid encoded - * databaseId. + * database ID. */ bool IsValidResourceName(const ResourcePath& path) { // Resource names have at least 4 components (project ID, database ID) @@ -214,20 +134,6 @@ bool IsValidResourceName(const ResourcePath& path) { return path.size() >= 4 && path[0] == "projects" && path[2] == "databases"; } -/** - * Decodes a fully qualified resource name into a resource path and validates - * that there is a project and database encoded in the path. There are no - * guarantees that a local path is also encoded in this resource name. - */ -ResourcePath DecodeResourceName(Reader* reader, absl::string_view encoded) { - ResourcePath resource = ResourcePath::FromString(encoded); - if (!IsValidResourceName(resource)) { - reader->Fail(StringFormat("Tried to deserialize an invalid key %s", - resource.CanonicalString())); - } - return resource; -} - /** * Decodes a fully qualified resource name into a resource path and validates * that there is a project and database encoded in the path along with a local @@ -243,112 +149,197 @@ ResourcePath ExtractLocalPathFromResourceName( return resource_name.PopFirst(5); } -StructuredQuery::CollectionSelector DecodeCollectionSelector( - const google_firestore_v1_StructuredQuery_CollectionSelector& proto) { - StructuredQuery::CollectionSelector collection_selector{}; - - collection_selector.collection_id = - Serializer::DecodeString(proto.collection_id); - collection_selector.all_descendants = proto.all_descendants; - - return collection_selector; -} - -StructuredQuery DecodeStructuredQuery( - const google_firestore_v1_StructuredQuery& proto) { - StructuredQuery query{}; - - for (size_t i = 0; i < proto.from_count; i++) { - query.from.push_back(DecodeCollectionSelector(proto.from[i])); - } - - // TODO(rsgowman): decode other fields - - return query; +Filter InvalidFilter() { + // The exact value doesn't matter. Note that there's no way to create the base + // class `Filter`, so it has to be one of the derived classes. + return FieldFilter::Create({}, {}, {}); } } // namespace -Serializer::Serializer( - const firebase::firestore::model::DatabaseId& database_id) - : database_id_(database_id), - database_name_(EncodeDatabaseId(database_id).CanonicalString()) { +Serializer::Serializer(DatabaseId database_id) + : database_id_(std::move(database_id)) { } -void Serializer::FreeNanopbMessage(const pb_field_t fields[], - void* dest_struct) { - pb_release(fields, dest_struct); +pb_bytes_array_t* Serializer::EncodeDatabaseName() const { + return EncodeString(DatabaseName(database_id_).CanonicalString()); } google_firestore_v1_Value Serializer::EncodeFieldValue( - const FieldValue& field_value) { - // TODO(rsgowman): some refactoring is in order... but will wait until after a - // non-varint, non-fixed-size (i.e. string) type is present before doing so. - google_firestore_v1_Value result{}; + const FieldValue& field_value) const { switch (field_value.type()) { case FieldValue::Type::Null: - result.which_value_type = google_firestore_v1_Value_null_value_tag; - result.null_value = google_protobuf_NullValue_NULL_VALUE; - return result; + return EncodeNull(); case FieldValue::Type::Boolean: - result.which_value_type = google_firestore_v1_Value_boolean_value_tag; - result.boolean_value = field_value.boolean_value(); - return result; + return EncodeBoolean(field_value.boolean_value()); case FieldValue::Type::Integer: - result.which_value_type = google_firestore_v1_Value_integer_value_tag; - result.integer_value = field_value.integer_value(); - return result; + return EncodeInteger(field_value.integer_value()); case FieldValue::Type::Double: - result.which_value_type = google_firestore_v1_Value_double_value_tag; - result.double_value = field_value.double_value(); - return result; + return EncodeDouble(field_value.double_value()); case FieldValue::Type::Timestamp: - result.which_value_type = google_firestore_v1_Value_timestamp_value_tag; - result.timestamp_value = EncodeTimestamp(field_value.timestamp_value()); - return result; - - case FieldValue::Type::ServerTimestamp: - // TODO(rsgowman): Implement - abort(); + return EncodeTimestampValue(field_value.timestamp_value()); case FieldValue::Type::String: - result.which_value_type = google_firestore_v1_Value_string_value_tag; - result.string_value = EncodeString(field_value.string_value()); - return result; + return EncodeStringValue(field_value.string_value()); case FieldValue::Type::Blob: - result.which_value_type = google_firestore_v1_Value_bytes_value_tag; - result.bytes_value = EncodeBytes(field_value.blob_value()); - return result; + return EncodeBlob(field_value.blob_value()); case FieldValue::Type::Reference: - // TODO(rsgowman): Implement - abort(); + return EncodeReference(field_value.reference_value()); case FieldValue::Type::GeoPoint: - result.which_value_type = google_firestore_v1_Value_geo_point_value_tag; - result.geo_point_value = EncodeGeoPoint(field_value.geo_point_value()); - return result; + return EncodeGeoPoint(field_value.geo_point_value()); - case FieldValue::Type::Array: + case FieldValue::Type::Array: { + google_firestore_v1_Value result{}; result.which_value_type = google_firestore_v1_Value_array_value_tag; result.array_value = EncodeArray(field_value.array_value()); return result; + } - case FieldValue::Type::Object: + case FieldValue::Type::Object: { + google_firestore_v1_Value result{}; result.which_value_type = google_firestore_v1_Value_map_value_tag; result.map_value = EncodeMapValue(ObjectValue(field_value)); return result; + } + + case FieldValue::Type::ServerTimestamp: + HARD_FAIL("Unhandled type %s on %s", field_value.type(), + field_value.ToString()); } UNREACHABLE(); } -FieldValue Serializer::DecodeFieldValue(Reader* reader, - const google_firestore_v1_Value& msg) { +google_firestore_v1_Value Serializer::EncodeNull() const { + google_firestore_v1_Value result{}; + result.which_value_type = google_firestore_v1_Value_null_value_tag; + result.null_value = google_protobuf_NullValue_NULL_VALUE; + return result; +} + +google_firestore_v1_Value Serializer::EncodeBoolean(bool value) const { + google_firestore_v1_Value result{}; + result.which_value_type = google_firestore_v1_Value_boolean_value_tag; + result.boolean_value = value; + return result; +} + +google_firestore_v1_Value Serializer::EncodeInteger(int64_t value) const { + google_firestore_v1_Value result{}; + result.which_value_type = google_firestore_v1_Value_integer_value_tag; + result.integer_value = value; + return result; +} + +google_firestore_v1_Value Serializer::EncodeDouble(double value) const { + google_firestore_v1_Value result{}; + result.which_value_type = google_firestore_v1_Value_double_value_tag; + result.double_value = value; + return result; +} + +google_firestore_v1_Value Serializer::EncodeTimestampValue( + Timestamp value) const { + google_firestore_v1_Value result{}; + result.which_value_type = google_firestore_v1_Value_timestamp_value_tag; + result.timestamp_value = EncodeTimestamp(value); + return result; +} + +google_firestore_v1_Value Serializer::EncodeStringValue( + const std::string& value) const { + google_firestore_v1_Value result{}; + result.which_value_type = google_firestore_v1_Value_string_value_tag; + result.string_value = EncodeString(value); + return result; +} + +google_firestore_v1_Value Serializer::EncodeBlob( + const nanopb::ByteString& value) const { + google_firestore_v1_Value result{}; + result.which_value_type = google_firestore_v1_Value_bytes_value_tag; + // Copy the blob so that pb_release can do the right thing. + result.bytes_value = nanopb::CopyBytesArray(value.get()); + return result; +} + +google_firestore_v1_Value Serializer::EncodeReference( + const FieldValue::Reference& value) const { + HARD_ASSERT(database_id_ == value.database_id(), + "Database %s cannot encode reference from %s", + database_id_.ToString(), value.database_id().ToString()); + + google_firestore_v1_Value result{}; + result.which_value_type = google_firestore_v1_Value_reference_value_tag; + result.reference_value = + EncodeResourceName(value.database_id(), value.key().path()); + + return result; +} + +google_firestore_v1_Value Serializer::EncodeGeoPoint( + const GeoPoint& value) const { + google_firestore_v1_Value result{}; + result.which_value_type = google_firestore_v1_Value_geo_point_value_tag; + + google_type_LatLng geo_point{}; + geo_point.latitude = value.latitude(); + geo_point.longitude = value.longitude(); + result.geo_point_value = geo_point; + + return result; +} + +FieldValue::Map::value_type Serializer::DecodeFieldsEntry( + Reader* reader, + const google_firestore_v1_Document_FieldsEntry& fields) const { + std::string key = DecodeString(fields.key); + FieldValue value = DecodeFieldValue(reader, fields.value); + + if (key.empty()) { + reader->Fail( + "Invalid message: Empty key while decoding a Map field value."); + return {}; + } + + return FieldValue::Map::value_type{std::move(key), std::move(value)}; +} + +ObjectValue Serializer::DecodeFields( + Reader* reader, + size_t count, + const google_firestore_v1_Document_FieldsEntry* fields) const { + FieldValue::Map result; + for (size_t i = 0; i < count; i++) { + FieldValue::Map::value_type kv = DecodeFieldsEntry(reader, fields[i]); + result = result.insert(std::move(kv.first), std::move(kv.second)); + } + + return ObjectValue::FromMap(result); +} + +FieldValue::Map Serializer::DecodeMapValue( + Reader* reader, const google_firestore_v1_MapValue& map_value) const { + FieldValue::Map result; + + for (size_t i = 0; i < map_value.fields_count; i++) { + std::string key = DecodeString(map_value.fields[i].key); + FieldValue value = DecodeFieldValue(reader, map_value.fields[i].value); + + result = result.insert(key, value); + } + + return result; +} + +FieldValue Serializer::DecodeFieldValue( + Reader* reader, const google_firestore_v1_Value& msg) const { switch (msg.which_value_type) { case google_firestore_v1_Value_null_value_tag: if (msg.null_value != google_protobuf_NullValue_NULL_VALUE) { @@ -357,13 +348,7 @@ FieldValue Serializer::DecodeFieldValue(Reader* reader, return FieldValue::Null(); case google_firestore_v1_Value_boolean_value_tag: { - // Due to the nanopb implementation, msg.boolean_value could be an integer - // other than 0 or 1, (such as 2). This leads to undefined behaviour when - // it's read as a boolean. eg. on at least gcc, the value is treated as - // both true *and* false. So we'll instead memcpy to an integer (via - // absl::bit_cast) and compare with 0. - int bool_as_int = absl::bit_cast(msg.boolean_value); - return FieldValue::FromBoolean(bool_as_int != 0); + return FieldValue::FromBoolean(SafeReadBoolean(msg.boolean_value)); } case google_firestore_v1_Value_integer_value_tag: @@ -380,15 +365,11 @@ FieldValue Serializer::DecodeFieldValue(Reader* reader, case google_firestore_v1_Value_string_value_tag: return FieldValue::FromString(DecodeString(msg.string_value)); - case google_firestore_v1_Value_bytes_value_tag: { - std::vector bytes = DecodeBytes(msg.bytes_value); - return FieldValue::FromBlob(bytes.data(), bytes.size()); - } + case google_firestore_v1_Value_bytes_value_tag: + return FieldValue::FromBlob(ByteString(msg.bytes_value)); case google_firestore_v1_Value_reference_value_tag: - // TODO(b/74243929): Implement remaining types. - HARD_FAIL("Unhandled message field number (tag): %i.", - msg.which_value_type); + return DecodeReference(reader, msg.reference_value); case google_firestore_v1_Value_geo_point_value_tag: return FieldValue::FromGeoPoint( @@ -410,31 +391,44 @@ FieldValue Serializer::DecodeFieldValue(Reader* reader, UNREACHABLE(); } -std::string Serializer::EncodeKey(const DocumentKey& key) const { +pb_bytes_array_t* Serializer::EncodeKey(const DocumentKey& key) const { return EncodeResourceName(database_id_, key.path()); } -DocumentKey Serializer::DecodeKey(Reader* reader, - absl::string_view name) const { - ResourcePath resource = DecodeResourceName(reader, name); - if (resource.size() < 5) { +void Serializer::ValidateDocumentKeyPath( + Reader* reader, const ResourcePath& resource_name) const { + if (resource_name.size() < 5) { reader->Fail( StringFormat("Attempted to decode invalid key: '%s'. Should have at " "least 5 segments.", - name)); - } else if (resource[1] != database_id_.project_id()) { + resource_name.CanonicalString())); + } else if (resource_name[1] != database_id_.project_id()) { reader->Fail( StringFormat("Tried to deserialize key from different project. " "Expected: '%s'. Found: '%s'. (Full key: '%s')", - database_id_.project_id(), resource[1], name)); - } else if (resource[3] != database_id_.database_id()) { + database_id_.project_id(), resource_name[1], + resource_name.CanonicalString())); + } else if (resource_name[3] != database_id_.database_id()) { reader->Fail( StringFormat("Tried to deserialize key from different database. " "Expected: '%s'. Found: '%s'. (Full key: '%s')", - database_id_.database_id(), resource[3], name)); + database_id_.database_id(), resource_name[3], + resource_name.CanonicalString())); } +} + +DocumentKey Serializer::DecodeKey(Reader* reader, + const pb_bytes_array_t* name) const { + ResourcePath resource_name = DecodeResourceName(reader, MakeStringView(name)); + ValidateDocumentKeyPath(reader, resource_name); + + return DecodeKey(reader, resource_name); +} - ResourcePath local_path = ExtractLocalPathFromResourceName(reader, resource); +DocumentKey Serializer::DecodeKey(Reader* reader, + const ResourcePath& resource_name) const { + ResourcePath local_path = + ExtractLocalPathFromResourceName(reader, resource_name); if (!DocumentKey::IsDocumentKey(local_path)) { reader->Fail(StringFormat("Invalid document key path: %s", @@ -446,11 +440,60 @@ DocumentKey Serializer::DecodeKey(Reader* reader, return DocumentKey{std::move(local_path)}; } +pb_bytes_array_t* Serializer::EncodeQueryPath(const ResourcePath& path) const { + return EncodeResourceName(database_id_, path); +} + +ResourcePath Serializer::DecodeQueryPath(Reader* reader, + absl::string_view name) const { + ResourcePath resource = DecodeResourceName(reader, name); + if (resource.size() == 4) { + // In v1beta1 queries for collections at the root did not have a trailing + // "/documents". In v1 all resource paths contain "/documents". Preserve the + // ability to read the v1beta1 form for compatibility with queries persisted + // in the local target cache. + return ResourcePath::Empty(); + } else { + return ExtractLocalPathFromResourceName(reader, resource); + } +} + +pb_bytes_array_t* Serializer::EncodeResourceName( + const DatabaseId& database_id, const ResourcePath& path) const { + return Serializer::EncodeString(DatabaseName(database_id) + .Append("documents") + .Append(path) + .CanonicalString()); +} + +ResourcePath Serializer::DecodeResourceName(Reader* reader, + absl::string_view encoded) const { + ResourcePath resource = ResourcePath::FromStringView(encoded); + if (!IsValidResourceName(resource)) { + reader->Fail(StringFormat("Tried to deserialize an invalid key %s", + resource.CanonicalString())); + } + return resource; +} + +DatabaseId Serializer::DecodeDatabaseId( + Reader* reader, const ResourcePath& resource_name) const { + if (resource_name.size() < 4) { + reader->Fail(StringFormat("Tried to deserialize invalid key %s", + resource_name.CanonicalString())); + return DatabaseId{}; + } + + const std::string& project_id = resource_name[1]; + const std::string& database_id = resource_name[3]; + return DatabaseId{project_id, database_id}; +} + google_firestore_v1_Document Serializer::EncodeDocument( const DocumentKey& key, const ObjectValue& object_value) const { google_firestore_v1_Document result{}; - result.name = EncodeString(EncodeKey(key)); + result.name = EncodeKey(key); // Encode Document.fields (unless it's empty) pb_size_t count = CheckedSize(object_value.GetInternalValue().size()); @@ -469,7 +512,7 @@ google_firestore_v1_Document Serializer::EncodeDocument( return result; } -std::unique_ptr Serializer::DecodeMaybeDocument( +MaybeDocument Serializer::DecodeMaybeDocument( Reader* reader, const google_firestore_v1_BatchGetDocumentsResponse& response) const { switch (response.which_result) { @@ -480,111 +523,119 @@ std::unique_ptr Serializer::DecodeMaybeDocument( default: reader->Fail( StringFormat("Unknown result case: %s", response.which_result)); - return nullptr; + return {}; } UNREACHABLE(); } -std::unique_ptr Serializer::DecodeFoundDocument( +Document Serializer::DecodeFoundDocument( Reader* reader, const google_firestore_v1_BatchGetDocumentsResponse& response) const { HARD_ASSERT(response.which_result == google_firestore_v1_BatchGetDocumentsResponse_found_tag, "Tried to deserialize a found document from a missing document."); - DocumentKey key = DecodeKey(reader, DecodeString(response.found.name)); - FieldValue::Map value = + DocumentKey key = DecodeKey(reader, response.found.name); + ObjectValue value = DecodeFields(reader, response.found.fields_count, response.found.fields); - SnapshotVersion version = - DecodeSnapshotVersion(reader, response.found.update_time); + SnapshotVersion version = DecodeVersion(reader, response.found.update_time); if (version == SnapshotVersion::None()) { reader->Fail("Got a document response with no snapshot version"); } - return absl::make_unique(ObjectValue::FromMap(std::move(value)), - std::move(key), std::move(version), - DocumentState::kSynced); + return Document(std::move(value), std::move(key), version, + DocumentState::kSynced); } -std::unique_ptr Serializer::DecodeMissingDocument( +NoDocument Serializer::DecodeMissingDocument( Reader* reader, const google_firestore_v1_BatchGetDocumentsResponse& response) const { HARD_ASSERT(response.which_result == google_firestore_v1_BatchGetDocumentsResponse_missing_tag, "Tried to deserialize a missing document from a found document."); - DocumentKey key = DecodeKey(reader, DecodeString(response.missing)); - SnapshotVersion version = DecodeSnapshotVersion(reader, response.read_time); + DocumentKey key = DecodeKey(reader, response.missing); + SnapshotVersion version = DecodeVersion(reader, response.read_time); if (version == SnapshotVersion::None()) { reader->Fail("Got a no document response with no snapshot version"); - return nullptr; + return {}; } - return absl::make_unique(std::move(key), std::move(version), - /*hasCommittedMutations=*/false); -} - -std::unique_ptr Serializer::DecodeDocument( - Reader* reader, const google_firestore_v1_Document& proto) const { - FieldValue::Map fields_internal = - DecodeFields(reader, proto.fields_count, proto.fields); - SnapshotVersion version = DecodeSnapshotVersion(reader, proto.update_time); - - return absl::make_unique( - ObjectValue::FromMap(std::move(fields_internal)), - DecodeKey(reader, DecodeString(proto.name)), std::move(version), - DocumentState::kSynced); + return NoDocument(std::move(key), version, + /*has_committed_mutations=*/false); } google_firestore_v1_Write Serializer::EncodeMutation( - const model::Mutation& mutation) const { + const Mutation& mutation) const { + HARD_ASSERT(mutation.is_valid(), "Invalid mutation encountered."); google_firestore_v1_Write result{}; - if (!mutation.precondition().IsNone()) { + if (!mutation.precondition().is_none()) { + result.has_current_document = true; result.current_document = EncodePrecondition(mutation.precondition()); } switch (mutation.type()) { - case Mutation::Type::kSet: { + case Mutation::Type::Set: { result.which_operation = google_firestore_v1_Write_update_tag; result.update = EncodeDocument( mutation.key(), static_cast(mutation).value()); return result; } - case Mutation::Type::kPatch: { + case Mutation::Type::Patch: { result.which_operation = google_firestore_v1_Write_update_tag; auto patch_mutation = static_cast(mutation); result.update = EncodeDocument(mutation.key(), patch_mutation.value()); - result.update_mask = EncodeDocumentMask(patch_mutation.mask()); + // Note: the fact that this field is set (even if the mask is empty) is + // what makes the backend treat this as a patch mutation, not a set + // mutation. + result.has_update_mask = true; + if (patch_mutation.mask().size() != 0) { + result.update_mask = EncodeFieldMask(patch_mutation.mask()); + } + return result; + } + + case Mutation::Type::Transform: { + result.which_operation = google_firestore_v1_Write_transform_tag; + auto transform = static_cast(mutation); + result.transform.document = EncodeKey(transform.key()); + + pb_size_t count = CheckedSize(transform.field_transforms().size()); + result.transform.field_transforms_count = count; + result.transform.field_transforms = + MakeArray( + count); + int i = 0; + for (const FieldTransform& field_transform : + transform.field_transforms()) { + result.transform.field_transforms[i] = + EncodeFieldTransform(field_transform); + i++; + } + + // NOTE: We set a precondition of exists: true as a safety-check, since we + // always combine TransformMutations with a SetMutation or PatchMutation + // which (if successful) should end up with an existing document. + result.has_current_document = true; + result.current_document = EncodePrecondition(Precondition::Exists(true)); + return result; } - // TODO(rsgowman): Implement transform mutations. Probably like this: - /* - case Mutation::Type::kTransform: - result.which_operation = google_firestore_v1_Write_transform_tag; - auto transform = static_cast(mutation); - result.transform.document = EncodeKey(transform.key()); - - size_t count = transform.field_transforms.size(); - result.transform.field_transforms_count = count; - result.transform.field_transforms = - MakeArray(count); - int i = 0; - for (const FieldTransform& field_transform : - transform.field_transforms()) { result.transform.field_transforms[i] = - EncodeFieldTransform(field_transform); i++; - } - return result; - */ - - case Mutation::Type::kDelete: { + case Mutation::Type::Delete: { result.which_operation = google_firestore_v1_Write_delete_tag; - result.delete_ = EncodeString(EncodeKey(mutation.key())); + result.delete_ = EncodeKey(mutation.key()); + return result; + } + + case Mutation::Type::Verify: { + result.which_operation = google_firestore_v1_Write_verify_tag; + result.verify = EncodeKey(mutation.key()); return result; } } @@ -592,54 +643,56 @@ google_firestore_v1_Write Serializer::EncodeMutation( UNREACHABLE(); } -std::unique_ptr Serializer::DecodeMutation( +Mutation Serializer::DecodeMutation( nanopb::Reader* reader, const google_firestore_v1_Write& mutation) const { - Precondition precondition = - DecodePrecondition(reader, mutation.current_document); + auto precondition = Precondition::None(); + if (mutation.has_current_document) { + precondition = DecodePrecondition(reader, mutation.current_document); + } switch (mutation.which_operation) { case google_firestore_v1_Write_update_tag: { - DocumentKey key = DecodeKey(reader, DecodeString(mutation.update.name)); - ObjectValue value = ObjectValue::FromMap(DecodeFields( - reader, mutation.update.fields_count, mutation.update.fields)); - FieldMask mask = DecodeDocumentMask(mutation.update_mask); - if (mask.size() > 0) { - return absl::make_unique( - std::move(key), std::move(value), std::move(mask), - std::move(precondition)); + DocumentKey key = DecodeKey(reader, mutation.update.name); + ObjectValue value = DecodeFields(reader, mutation.update.fields_count, + mutation.update.fields); + if (mutation.has_update_mask) { + FieldMask mask = DecodeFieldMask(mutation.update_mask); + return PatchMutation(std::move(key), std::move(value), std::move(mask), + std::move(precondition)); } else { - return absl::make_unique(std::move(key), std::move(value), - std::move(precondition)); + return SetMutation(std::move(key), std::move(value), + std::move(precondition)); } - UNREACHABLE(); } case google_firestore_v1_Write_delete_tag: - return absl::make_unique( - DecodeKey(reader, DecodeString(mutation.delete_)), - std::move(precondition)); - - // TODO(rsgowman): Implement transform. Probably like this: - /* - case google_firestore_v1_Write_transform_tag: - std::vector field_transforms; - for (size_t i = 0; i( - DecodeKey(reader, mutation.transform.document), - field_transforms); - */ + return DeleteMutation(DecodeKey(reader, mutation.delete_), + std::move(precondition)); + + case google_firestore_v1_Write_transform_tag: { + std::vector field_transforms; + for (size_t i = 0; i < mutation.transform.field_transforms_count; i++) { + field_transforms.push_back(DecodeFieldTransform( + reader, mutation.transform.field_transforms[i])); + } + + HARD_ASSERT(precondition.type() == Precondition::Type::Exists && + precondition.exists(), + "Transforms only support precondition \"exists == true\""); + + return TransformMutation(DecodeKey(reader, mutation.transform.document), + field_transforms); + } + + case google_firestore_v1_Write_verify_tag: { + return VerifyMutation(DecodeKey(reader, mutation.verify), + std::move(precondition)); + } default: reader->Fail(StringFormat("Unknown mutation operation: %s", mutation.which_operation)); - return nullptr; + return {}; } UNREACHABLE(); @@ -691,7 +744,7 @@ Precondition Serializer::DecodePrecondition( } case google_firestore_v1_Precondition_update_time_tag: return Precondition::UpdateTime( - DecodeSnapshotVersion(reader, precondition.update_time)); + DecodeVersion(reader, precondition.update_time)); } reader->Fail(StringFormat("Unknown Precondition type: %s", @@ -700,7 +753,7 @@ Precondition Serializer::DecodePrecondition( } /* static */ -google_firestore_v1_DocumentMask Serializer::EncodeDocumentMask( +google_firestore_v1_DocumentMask Serializer::EncodeFieldMask( const FieldMask& mask) { google_firestore_v1_DocumentMask result{}; @@ -710,7 +763,7 @@ google_firestore_v1_DocumentMask Serializer::EncodeDocumentMask( int i = 0; for (const FieldPath& path : mask) { - result.field_paths[i] = EncodeString(path.CanonicalString()); + result.field_paths[i] = EncodeFieldPath(path); i++; } @@ -718,114 +771,610 @@ google_firestore_v1_DocumentMask Serializer::EncodeDocumentMask( } /* static */ -model::FieldMask Serializer::DecodeDocumentMask( +FieldMask Serializer::DecodeFieldMask( const google_firestore_v1_DocumentMask& mask) { std::set fields; for (size_t i = 0; i < mask.field_paths_count; i++) { - auto path = DecodeString(mask.field_paths[i]); - fields.insert(FieldPath::FromServerFormat(path)); + fields.insert(DecodeFieldPath(mask.field_paths[i])); } - return model::FieldMask(std::move(fields)); + return FieldMask(std::move(fields)); } -google_firestore_v1_Target_QueryTarget Serializer::EncodeQueryTarget( - const core::Query& query) const { - google_firestore_v1_Target_QueryTarget result{}; +google_firestore_v1_DocumentTransform_FieldTransform +Serializer::EncodeFieldTransform(const FieldTransform& field_transform) const { + using Type = TransformOperation::Type; + + google_firestore_v1_DocumentTransform_FieldTransform proto{}; + proto.field_path = EncodeFieldPath(field_transform.path()); + + switch (field_transform.transformation().type()) { + case Type::ServerTimestamp: + proto.which_transform_type = + google_firestore_v1_DocumentTransform_FieldTransform_set_to_server_value_tag; // NOLINT + proto.set_to_server_value = + google_firestore_v1_DocumentTransform_FieldTransform_ServerValue_REQUEST_TIME; // NOLINT + return proto; + + case Type::ArrayUnion: + proto.which_transform_type = + google_firestore_v1_DocumentTransform_FieldTransform_append_missing_elements_tag; // NOLINT + proto.append_missing_elements = EncodeArray( + ArrayTransform(field_transform.transformation()).elements()); + return proto; + + case Type::ArrayRemove: + proto.which_transform_type = + google_firestore_v1_DocumentTransform_FieldTransform_remove_all_from_array_tag; // NOLINT + proto.remove_all_from_array = EncodeArray( + ArrayTransform(field_transform.transformation()).elements()); + return proto; + + case Type::Increment: { + proto.which_transform_type = + google_firestore_v1_DocumentTransform_FieldTransform_increment_tag; + const auto& increment = static_cast( + field_transform.transformation()); + proto.increment = EncodeFieldValue(increment.operand()); + return proto; + } + } - // Dissect the path into parent, collection_id and optional key filter. - std::string collection_id; - // TODO(rsgowman): Port Collection Group Queries logic. - if (query.path().empty()) { - result.parent = EncodeString(EncodeQueryPath(ResourcePath::Empty())); + UNREACHABLE(); +} + +FieldTransform Serializer::DecodeFieldTransform( + nanopb::Reader* reader, + const google_firestore_v1_DocumentTransform_FieldTransform& proto) const { + switch (proto.which_transform_type) { + case google_firestore_v1_DocumentTransform_FieldTransform_set_to_server_value_tag: { // NOLINT + HARD_ASSERT( + proto.set_to_server_value == + google_firestore_v1_DocumentTransform_FieldTransform_ServerValue_REQUEST_TIME, // NOLINT + "Unknown transform setToServerValue: %s", proto.set_to_server_value); + + return FieldTransform(DecodeFieldPath(proto.field_path), + ServerTimestampTransform()); + } + + case google_firestore_v1_DocumentTransform_FieldTransform_append_missing_elements_tag: { // NOLINT + std::vector elements = + DecodeArray(reader, proto.append_missing_elements); + return FieldTransform(DecodeFieldPath(proto.field_path), + ArrayTransform(TransformOperation::Type::ArrayUnion, + std::move(elements))); + } + + case google_firestore_v1_DocumentTransform_FieldTransform_remove_all_from_array_tag: { // NOLINT + std::vector elements = + DecodeArray(reader, proto.remove_all_from_array); + return FieldTransform( + DecodeFieldPath(proto.field_path), + ArrayTransform(TransformOperation::Type::ArrayRemove, + std::move(elements))); + } + + case google_firestore_v1_DocumentTransform_FieldTransform_increment_tag: { + FieldValue operand = DecodeFieldValue(reader, proto.increment); + return FieldTransform(DecodeFieldPath(proto.field_path), + NumericIncrementTransform(std::move(operand))); + } + } + + UNREACHABLE(); +} + +google_firestore_v1_Target Serializer::EncodeTarget( + const TargetData& target_data) const { + google_firestore_v1_Target result{}; + const Target& target = target_data.target(); + + if (target.IsDocumentQuery()) { + result.which_target_type = google_firestore_v1_Target_documents_tag; + result.target_type.documents = EncodeDocumentsTarget(target); } else { - ResourcePath path = query.path(); - HARD_ASSERT(path.size() % 2 != 0, - "Document queries with filters are not supported."); - result.parent = EncodeString(EncodeQueryPath(path.PopLast())); - collection_id = path.last_segment(); + result.which_target_type = google_firestore_v1_Target_query_tag; + result.target_type.query = EncodeQueryTarget(target); } + result.target_id = target_data.target_id(); + if (!target_data.resume_token().empty()) { + result.which_resume_type = google_firestore_v1_Target_resume_token_tag; + result.resume_type.resume_token = + nanopb::CopyBytesArray(target_data.resume_token().get()); + } + + return result; +} + +google_firestore_v1_Target_DocumentsTarget Serializer::EncodeDocumentsTarget( + const core::Target& target) const { + google_firestore_v1_Target_DocumentsTarget result{}; + + result.documents_count = 1; + result.documents = MakeArray(result.documents_count); + result.documents[0] = EncodeQueryPath(target.path()); + + return result; +} + +Target Serializer::DecodeDocumentsTarget( + nanopb::Reader* reader, + const google_firestore_v1_Target_DocumentsTarget& proto) const { + if (proto.documents_count != 1) { + reader->Fail( + StringFormat("DocumentsTarget contained other than 1 document %s", + proto.documents_count)); + return {}; + } + + ResourcePath path = DecodeQueryPath(reader, DecodeString(proto.documents[0])); + return Query(std::move(path)).ToTarget(); +} + +google_firestore_v1_Target_QueryTarget Serializer::EncodeQueryTarget( + const core::Target& target) const { + google_firestore_v1_Target_QueryTarget result{}; result.which_query_type = google_firestore_v1_Target_QueryTarget_structured_query_tag; - if (!collection_id.empty()) { - pb_size_t count = 1; - result.structured_query.from_count = count; - result.structured_query.from = - MakeArray( - count); - result.structured_query.from[0].collection_id = EncodeString(collection_id); + pb_size_t from_count = 1; + result.structured_query.from_count = from_count; + result.structured_query.from = + MakeArray( + from_count); + google_firestore_v1_StructuredQuery_CollectionSelector& from = + result.structured_query.from[0]; + + // Dissect the path into parent, collection_id and optional key filter. + const ResourcePath& path = target.path(); + if (target.collection_group()) { + HARD_ASSERT( + path.size() % 2 == 0, + "Collection group queries should be within a document path or root."); + result.parent = EncodeQueryPath(path); + + from.collection_id = EncodeString(*target.collection_group()); + from.all_descendants = true; + } else { - result.structured_query.from_count = 0; + HARD_ASSERT(path.size() % 2 != 0, + "Document queries with filters are not supported."); + result.parent = EncodeQueryPath(path.PopLast()); + from.collection_id = EncodeString(path.last_segment()); } // Encode the filters. - if (!query.filters().empty()) { - // TODO(rsgowman): Implement - abort(); + const auto& filters = target.filters(); + if (!filters.empty()) { + result.structured_query.where = EncodeFilters(filters); } - // TODO(rsgowman): Encode the orders. - // TODO(rsgowman): Encode the limit. - // TODO(rsgowman): Encode the startat. - // TODO(rsgowman): Encode the endat. + const auto& orders = target.order_bys(); + if (!orders.empty()) { + result.structured_query.order_by_count = CheckedSize(orders.size()); + result.structured_query.order_by = EncodeOrderBys(orders); + } - return result; -} + if (target.limit() != Target::kNoLimit) { + result.structured_query.has_limit = true; + result.structured_query.limit.value = target.limit(); + } -ResourcePath DecodeQueryPath(Reader* reader, absl::string_view name) { - ResourcePath resource = DecodeResourceName(reader, name); - if (resource.size() == 4) { - // In v1beta1 queries for collections at the root did not have a trailing - // "/documents". In v1 all resource paths contain "/documents". Preserve the - // ability to read the v1beta1 form for compatibility with queries persisted - // in the local query cache. - return ResourcePath::Empty(); - } else { - return ExtractLocalPathFromResourceName(reader, resource); + if (target.start_at()) { + result.structured_query.start_at = EncodeBound(*target.start_at()); + } + + if (target.end_at()) { + result.structured_query.end_at = EncodeBound(*target.end_at()); } + + return result; } -Query Serializer::DecodeQueryTarget( +Target Serializer::DecodeQueryTarget( nanopb::Reader* reader, - const google_firestore_v1_Target_QueryTarget& proto) { + const google_firestore_v1_Target_QueryTarget& proto) const { // The QueryTarget oneof only has a single valid value. if (proto.which_query_type != google_firestore_v1_Target_QueryTarget_structured_query_tag) { reader->Fail( StringFormat("Unknown query_type: %s", proto.which_query_type)); - return Query::Invalid(); + return {}; } ResourcePath path = DecodeQueryPath(reader, DecodeString(proto.parent)); - StructuredQuery query = DecodeStructuredQuery(proto.structured_query); + const google_firestore_v1_StructuredQuery& query = proto.structured_query; - size_t from_count = query.from.size(); + CollectionGroupId collection_group; + size_t from_count = query.from_count; if (from_count > 0) { if (from_count != 1) { reader->Fail( "StructuredQuery.from with more than one collection is not " "supported."); + return {}; + } + + google_firestore_v1_StructuredQuery_CollectionSelector& from = + query.from[0]; + auto collection_id = DecodeString(from.collection_id); + if (from.all_descendants) { + collection_group = std::make_shared(collection_id); + } else { + path = path.Append(collection_id); } + } + + FilterList filter_by; + if (query.where.which_filter_type != 0) { + filter_by = DecodeFilters(reader, query.where); + } - path = path.Append(query.from[0].collection_id); + OrderByList order_by; + if (query.order_by_count > 0) { + order_by = DecodeOrderBys(reader, query.order_by, query.order_by_count); } - // TODO(rsgowman): Dencode the filters. - // TODO(rsgowman): Dencode the orders. - // TODO(rsgowman): Dencode the limit. - // TODO(rsgowman): Dencode the startat. - // TODO(rsgowman): Dencode the endat. + int32_t limit = Target::kNoLimit; + if (query.has_limit) { + limit = query.limit.value; + } + + std::shared_ptr start_at; + if (query.start_at.values_count > 0) { + start_at = DecodeBound(reader, query.start_at); + } - return Query(path, {}); + std::shared_ptr end_at; + if (query.end_at.values_count > 0) { + end_at = DecodeBound(reader, query.end_at); + } + + return Query(std::move(path), std::move(collection_group), + std::move(filter_by), std::move(order_by), limit, + LimitType::First, std::move(start_at), std::move(end_at)) + .ToTarget(); } -std::string Serializer::EncodeQueryPath(const ResourcePath& path) const { - return EncodeResourceName(database_id_, path); +google_firestore_v1_StructuredQuery_Filter Serializer::EncodeFilters( + const FilterList& filters) const { + google_firestore_v1_StructuredQuery_Filter result{}; + + auto is_field_filter = [](const Filter& f) { return f.IsAFieldFilter(); }; + size_t filters_count = absl::c_count_if(filters, is_field_filter); + if (filters_count == 1) { + auto first = absl::c_find_if(filters, is_field_filter); + // Special case: no existing filters and we only need to add one filter. + // This can be made the single root filter without a composite filter. + FieldFilter filter{*first}; + return EncodeSingularFilter(filter); + } + + result.which_filter_type = + google_firestore_v1_StructuredQuery_Filter_composite_filter_tag; + google_firestore_v1_StructuredQuery_CompositeFilter& composite = + result.composite_filter; + composite.op = + google_firestore_v1_StructuredQuery_CompositeFilter_Operator_AND; + + auto count = CheckedSize(filters_count); + composite.filters_count = count; + composite.filters = + MakeArray(count); + pb_size_t i = 0; + for (const auto& filter : filters) { + if (filter.IsAFieldFilter()) { + HARD_ASSERT(i < count, "Index out of bounds"); + composite.filters[i] = EncodeSingularFilter(FieldFilter{filter}); + ++i; + } + } + + return result; +} + +FilterList Serializer::DecodeFilters( + nanopb::Reader* reader, + const google_firestore_v1_StructuredQuery_Filter& proto) const { + FilterList result; + + switch (proto.which_filter_type) { + case google_firestore_v1_StructuredQuery_Filter_composite_filter_tag: + return DecodeCompositeFilter(reader, proto.composite_filter); + + case google_firestore_v1_StructuredQuery_Filter_unary_filter_tag: + return result.push_back(DecodeUnaryFilter(reader, proto.unary_filter)); + + case google_firestore_v1_StructuredQuery_Filter_field_filter_tag: + return result.push_back(DecodeFieldFilter(reader, proto.field_filter)); + + default: + reader->Fail(StringFormat("Unrecognized Filter.which_filter_type %s", + proto.which_filter_type)); + return result; + } +} + +google_firestore_v1_StructuredQuery_Filter Serializer::EncodeSingularFilter( + const FieldFilter& filter) const { + google_firestore_v1_StructuredQuery_Filter result{}; + + if (filter.op() == Filter::Operator::Equal) { + if (filter.value().is_null() || filter.value().is_nan()) { + result.which_filter_type = + google_firestore_v1_StructuredQuery_Filter_unary_filter_tag; + result.unary_filter.which_operand_type = + google_firestore_v1_StructuredQuery_UnaryFilter_field_tag; + result.unary_filter.field.field_path = EncodeFieldPath(filter.field()); + + auto op = + filter.value().is_null() + ? google_firestore_v1_StructuredQuery_UnaryFilter_Operator_IS_NULL + : google_firestore_v1_StructuredQuery_UnaryFilter_Operator_IS_NAN; + result.unary_filter.op = op; + + return result; + } + } + + result.which_filter_type = + google_firestore_v1_StructuredQuery_Filter_field_filter_tag; + + result.field_filter.field.field_path = EncodeFieldPath(filter.field()); + result.field_filter.op = EncodeFieldFilterOperator(filter.op()); + result.field_filter.value = EncodeFieldValue(filter.value()); + + return result; +} + +Filter Serializer::DecodeFieldFilter( + nanopb::Reader* reader, + const google_firestore_v1_StructuredQuery_FieldFilter& field_filter) const { + FieldPath field_path = + FieldPath::FromServerFormat(DecodeString(field_filter.field.field_path)); + Filter::Operator op = DecodeFieldFilterOperator(reader, field_filter.op); + FieldValue value = DecodeFieldValue(reader, field_filter.value); + + return FieldFilter::Create(std::move(field_path), op, std::move(value)); +} + +Filter Serializer::DecodeUnaryFilter( + nanopb::Reader* reader, + const google_firestore_v1_StructuredQuery_UnaryFilter& unary) const { + HARD_ASSERT(unary.which_operand_type == + google_firestore_v1_StructuredQuery_UnaryFilter_field_tag, + "Unexpected UnaryFilter.which_operand_type: %s", + unary.which_operand_type); + + auto field = + FieldPath::FromServerFormat(DecodeString(unary.field.field_path)); + + switch (unary.op) { + case google_firestore_v1_StructuredQuery_UnaryFilter_Operator_IS_NULL: + return FieldFilter::Create(std::move(field), Filter::Operator::Equal, + FieldValue::Null()); + + case google_firestore_v1_StructuredQuery_UnaryFilter_Operator_IS_NAN: + return FieldFilter::Create(std::move(field), Filter::Operator::Equal, + FieldValue::Nan()); + + default: + reader->Fail(StringFormat("Unrecognized UnaryFilter.op %s", unary.op)); + return InvalidFilter(); + } +} + +FilterList Serializer::DecodeCompositeFilter( + nanopb::Reader* reader, + const google_firestore_v1_StructuredQuery_CompositeFilter& composite) + const { + if (composite.op != + google_firestore_v1_StructuredQuery_CompositeFilter_Operator_AND) { + reader->Fail(StringFormat( + "Only AND-type composite filters are supported, got %s", composite.op)); + return FilterList{}; + } + + FilterList result; + result = result.reserve(composite.filters_count); + + for (pb_size_t i = 0; i != composite.filters_count; ++i) { + auto& filter = composite.filters[i]; + switch (filter.which_filter_type) { + case google_firestore_v1_StructuredQuery_Filter_composite_filter_tag: + reader->Fail("Nested composite filters are not supported"); + return FilterList{}; + + case google_firestore_v1_StructuredQuery_Filter_unary_filter_tag: + result = + result.push_back(DecodeUnaryFilter(reader, filter.unary_filter)); + break; + + case google_firestore_v1_StructuredQuery_Filter_field_filter_tag: + result = + result.push_back(DecodeFieldFilter(reader, filter.field_filter)); + break; + + default: + reader->Fail(StringFormat("Unrecognized Filter.which_filter_type %s", + filter.which_filter_type)); + return FilterList{}; + } + } + + return result; +} + +google_firestore_v1_StructuredQuery_FieldFilter_Operator +Serializer::EncodeFieldFilterOperator(Filter::Operator op) const { + switch (op) { + case Filter::Operator::LessThan: + return google_firestore_v1_StructuredQuery_FieldFilter_Operator_LESS_THAN; + + case Filter::Operator::LessThanOrEqual: + return google_firestore_v1_StructuredQuery_FieldFilter_Operator_LESS_THAN_OR_EQUAL; // NOLINT + + case Filter::Operator::GreaterThan: + return google_firestore_v1_StructuredQuery_FieldFilter_Operator_GREATER_THAN; // NOLINT + + case Filter::Operator::GreaterThanOrEqual: + return google_firestore_v1_StructuredQuery_FieldFilter_Operator_GREATER_THAN_OR_EQUAL; // NOLINT + + case Filter::Operator::Equal: + return google_firestore_v1_StructuredQuery_FieldFilter_Operator_EQUAL; + + case Filter::Operator::ArrayContains: + return google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAY_CONTAINS; // NOLINT + + case Filter::Operator::In: + return google_firestore_v1_StructuredQuery_FieldFilter_Operator_IN; + + case Filter::Operator::ArrayContainsAny: + return google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAY_CONTAINS_ANY; // NOLINT + + default: + HARD_FAIL("Unhandled Filter::Operator: %s", op); + } +} + +Filter::Operator Serializer::DecodeFieldFilterOperator( + nanopb::Reader* reader, + google_firestore_v1_StructuredQuery_FieldFilter_Operator op) const { + switch (op) { + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_LESS_THAN: + return Filter::Operator::LessThan; + + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_LESS_THAN_OR_EQUAL: // NOLINT + return Filter::Operator::LessThanOrEqual; + + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_GREATER_THAN: + return Filter::Operator::GreaterThan; + + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_GREATER_THAN_OR_EQUAL: // NOLINT + return Filter::Operator::GreaterThanOrEqual; + + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_EQUAL: + return Filter::Operator::Equal; + + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAY_CONTAINS: // NOLINT + return Filter::Operator::ArrayContains; + + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_IN: + return Filter::Operator::In; + + case google_firestore_v1_StructuredQuery_FieldFilter_Operator_ARRAY_CONTAINS_ANY: // NOLINT + return Filter::Operator::ArrayContainsAny; + + default: + reader->Fail(StringFormat("Unhandled FieldFilter.op: %s", op)); + return Filter::Operator{}; + } +} + +google_firestore_v1_StructuredQuery_Order* Serializer::EncodeOrderBys( + const OrderByList& orders) const { + auto* result = MakeArray( + CheckedSize(orders.size())); + + int i = 0; + for (const OrderBy& order : orders) { + auto& encoded_order = result[i]; + + encoded_order.field.field_path = EncodeFieldPath(order.field()); + auto dir = order.ascending() + ? google_firestore_v1_StructuredQuery_Direction_ASCENDING + : google_firestore_v1_StructuredQuery_Direction_DESCENDING; + encoded_order.direction = dir; + + ++i; + } + + return result; +} + +OrderByList Serializer::DecodeOrderBys( + nanopb::Reader* reader, + google_firestore_v1_StructuredQuery_Order* order_bys, + pb_size_t size) const { + OrderByList result; + result = result.reserve(size); + + for (pb_size_t i = 0; i != size; ++i) { + result = result.push_back(DecodeOrderBy(reader, order_bys[i])); + } + + return result; +} + +OrderBy Serializer::DecodeOrderBy( + nanopb::Reader* reader, + const google_firestore_v1_StructuredQuery_Order& order_by) const { + auto field_path = + FieldPath::FromServerFormat(DecodeString(order_by.field.field_path)); + + Direction direction; + switch (order_by.direction) { + case google_firestore_v1_StructuredQuery_Direction_ASCENDING: + direction = Direction::Ascending; + break; + + case google_firestore_v1_StructuredQuery_Direction_DESCENDING: + direction = Direction::Descending; + break; + + default: + reader->Fail(StringFormat( + "Unrecognized google_firestore_v1_StructuredQuery_Direction %s", + order_by.direction)); + return OrderBy{}; + } + + return OrderBy(std::move(field_path), direction); +} + +google_firestore_v1_Cursor Serializer::EncodeBound(const Bound& bound) const { + google_firestore_v1_Cursor result{}; + result.before = bound.before(); + + auto count = CheckedSize(bound.position().size()); + result.values_count = count; + result.values = MakeArray(count); + + int i = 0; + for (const FieldValue& field_value : bound.position()) { + result.values[i] = EncodeFieldValue(field_value); + ++i; + } + + return result; +} + +std::shared_ptr Serializer::DecodeBound( + nanopb::Reader* reader, const google_firestore_v1_Cursor& cursor) const { + std::vector index_components; + index_components.reserve(cursor.values_count); + + for (pb_size_t i = 0; i != cursor.values_count; ++i) { + FieldValue value = DecodeFieldValue(reader, cursor.values[i]); + index_components.push_back(std::move(value)); + } + + return std::make_shared(std::move(index_components), cursor.before); +} + +/* static */ +pb_bytes_array_t* Serializer::EncodeFieldPath(const FieldPath& field_path) { + return EncodeString(field_path.CanonicalString()); +} + +/* static */ +FieldPath Serializer::DecodeFieldPath(const pb_bytes_array_t* field_path) { + absl::string_view str = MakeStringView(field_path); + return FieldPath::FromServerFormatView(str); } google_protobuf_Timestamp Serializer::EncodeVersion( - const model::SnapshotVersion& version) { + const SnapshotVersion& version) { return EncodeTimestamp(version.timestamp()); } @@ -837,7 +1386,7 @@ google_protobuf_Timestamp Serializer::EncodeTimestamp( return result; } -SnapshotVersion Serializer::DecodeSnapshotVersion( +SnapshotVersion Serializer::DecodeVersion( nanopb::Reader* reader, const google_protobuf_Timestamp& proto) { return SnapshotVersion{DecodeTimestamp(reader, proto)}; } @@ -862,12 +1411,15 @@ Timestamp Serializer::DecodeTimestamp( return Timestamp{timestamp_proto.seconds, timestamp_proto.nanos}; } -/* static */ -google_type_LatLng Serializer::EncodeGeoPoint(const GeoPoint& geo_point_value) { - google_type_LatLng result{}; - result.latitude = geo_point_value.latitude(); - result.longitude = geo_point_value.longitude(); - return result; +FieldValue Serializer::DecodeReference( + Reader* reader, const pb_bytes_array_t* resource_name_raw) const { + ResourcePath resource_name = + DecodeResourceName(reader, MakeStringView(resource_name_raw)); + ValidateDocumentKeyPath(reader, resource_name); + DatabaseId database_id = DecodeDatabaseId(reader, resource_name); + DocumentKey key = DecodeKey(reader, resource_name); + + return FieldValue::FromReference(std::move(database_id), std::move(key)); } /* static */ @@ -890,9 +1442,8 @@ GeoPoint Serializer::DecodeGeoPoint(nanopb::Reader* reader, return GeoPoint(latitude, longitude); } -/* static */ google_firestore_v1_ArrayValue Serializer::EncodeArray( - const std::vector& array_value) { + const std::vector& array_value) const { google_firestore_v1_ArrayValue result{}; pb_size_t count = CheckedSize(array_value.size()); @@ -907,9 +1458,9 @@ google_firestore_v1_ArrayValue Serializer::EncodeArray( return result; } -/* static */ std::vector Serializer::DecodeArray( - nanopb::Reader* reader, const google_firestore_v1_ArrayValue& array_proto) { + nanopb::Reader* reader, + const google_firestore_v1_ArrayValue& array_proto) const { std::vector result; result.reserve(array_proto.values_count); @@ -920,6 +1471,220 @@ std::vector Serializer::DecodeArray( return result; } +google_firestore_v1_MapValue Serializer::EncodeMapValue( + const ObjectValue& object_value) const { + google_firestore_v1_MapValue result{}; + + pb_size_t count = CheckedSize(object_value.GetInternalValue().size()); + + result.fields_count = count; + result.fields = MakeArray(count); + + int i = 0; + for (const auto& kv : object_value.GetInternalValue()) { + result.fields[i].key = EncodeString(kv.first); + result.fields[i].value = EncodeFieldValue(kv.second); + i++; + } + + return result; +} + +MutationResult Serializer::DecodeMutationResult( + nanopb::Reader* reader, + const google_firestore_v1_WriteResult& write_result, + const SnapshotVersion& commit_version) const { + // NOTE: Deletes don't have an update_time, use commit_version instead. + SnapshotVersion version = + write_result.has_update_time + ? DecodeVersion(reader, write_result.update_time) + : commit_version; + + absl::optional> transform_results; + if (write_result.transform_results_count > 0) { + transform_results = std::vector{}; + for (pb_size_t i = 0; i < write_result.transform_results_count; i++) { + transform_results->push_back( + DecodeFieldValue(reader, write_result.transform_results[i])); + } + } + + return MutationResult(version, std::move(transform_results)); +} + +std::vector +Serializer::EncodeListenRequestLabels(const TargetData& target_data) const { + std::vector result; + auto value = EncodeLabel(target_data.purpose()); + if (value.empty()) { + return result; + } + + result.push_back({/* key */ EncodeString("goog-listen-tags"), + /* value */ EncodeString(value)}); + + return result; +} + +std::string Serializer::EncodeLabel(QueryPurpose purpose) const { + switch (purpose) { + case QueryPurpose::Listen: + return ""; + case QueryPurpose::ExistenceFilterMismatch: + return "existence-filter-mismatch"; + case QueryPurpose::LimboResolution: + return "limbo-document"; + } + UNREACHABLE(); +} + +std::unique_ptr Serializer::DecodeWatchChange( + nanopb::Reader* reader, + const google_firestore_v1_ListenResponse& watch_change) const { + switch (watch_change.which_response_type) { + case google_firestore_v1_ListenResponse_target_change_tag: + return DecodeTargetChange(reader, watch_change.target_change); + + case google_firestore_v1_ListenResponse_document_change_tag: + return DecodeDocumentChange(reader, watch_change.document_change); + + case google_firestore_v1_ListenResponse_document_delete_tag: + return DecodeDocumentDelete(reader, watch_change.document_delete); + + case google_firestore_v1_ListenResponse_document_remove_tag: + return DecodeDocumentRemove(reader, watch_change.document_remove); + + case google_firestore_v1_ListenResponse_filter_tag: + return DecodeExistenceFilterWatchChange(reader, watch_change.filter); + } + UNREACHABLE(); +} + +SnapshotVersion Serializer::DecodeVersionFromListenResponse( + nanopb::Reader* reader, + const google_firestore_v1_ListenResponse& listen_response) const { + // We have only reached a consistent snapshot for the entire stream if there + // is a read_time set and it applies to all targets (i.e. the list of targets + // is empty). The backend is guaranteed to send such responses. + if (listen_response.which_response_type != + google_firestore_v1_ListenResponse_target_change_tag) { + return SnapshotVersion::None(); + } + if (listen_response.target_change.target_ids_count != 0) { + return SnapshotVersion::None(); + } + + return DecodeVersion(reader, listen_response.target_change.read_time); +} + +std::unique_ptr Serializer::DecodeTargetChange( + nanopb::Reader* reader, + const google_firestore_v1_TargetChange& change) const { + WatchTargetChangeState state = + DecodeTargetChangeState(reader, change.target_change_type); + std::vector target_ids(change.target_ids, + change.target_ids + change.target_ids_count); + ByteString resume_token(change.resume_token); + + util::Status cause; + if (change.has_cause) { + cause = util::Status{static_cast(change.cause.code), + DecodeString(change.cause.message)}; + } + + return absl::make_unique( + state, std::move(target_ids), std::move(resume_token), std::move(cause)); +} + +WatchTargetChangeState Serializer::DecodeTargetChangeState( + nanopb::Reader* reader, + const google_firestore_v1_TargetChange_TargetChangeType state) { + switch (state) { + case google_firestore_v1_TargetChange_TargetChangeType_NO_CHANGE: + return WatchTargetChangeState::NoChange; + case google_firestore_v1_TargetChange_TargetChangeType_ADD: + return WatchTargetChangeState::Added; + case google_firestore_v1_TargetChange_TargetChangeType_REMOVE: + return WatchTargetChangeState::Removed; + case google_firestore_v1_TargetChange_TargetChangeType_CURRENT: + return WatchTargetChangeState::Current; + case google_firestore_v1_TargetChange_TargetChangeType_RESET: + return WatchTargetChangeState::Reset; + } + UNREACHABLE(); +} + +std::unique_ptr Serializer::DecodeDocumentChange( + nanopb::Reader* reader, + const google_firestore_v1_DocumentChange& change) const { + ObjectValue value = DecodeFields(reader, change.document.fields_count, + change.document.fields); + DocumentKey key = DecodeKey(reader, change.document.name); + + HARD_ASSERT(change.document.has_update_time, + "Got a document change with no snapshot version"); + SnapshotVersion version = DecodeVersion(reader, change.document.update_time); + + // TODO(b/142956770): other platforms memoize `change.document` inside the + // `Document`. This currently cannot be implemented efficiently because it + // would require a reference-counted ownership model for the proto (copying it + // would defeat the purpose). Note, however, that even without this + // optimization C++ implementation is on par with the preceding Objective-C + // implementation. + Document document(std::move(value), key, version, DocumentState::kSynced); + + std::vector updated_target_ids( + change.target_ids, change.target_ids + change.target_ids_count); + std::vector removed_target_ids( + change.removed_target_ids, + change.removed_target_ids + change.removed_target_ids_count); + + return absl::make_unique( + std::move(updated_target_ids), std::move(removed_target_ids), + std::move(key), std::move(document)); +} + +std::unique_ptr Serializer::DecodeDocumentDelete( + nanopb::Reader* reader, + const google_firestore_v1_DocumentDelete& change) const { + DocumentKey key = DecodeKey(reader, change.document); + // Note that version might be unset in which case we use + // SnapshotVersion::None(). + SnapshotVersion version = change.has_read_time + ? DecodeVersion(reader, change.read_time) + : SnapshotVersion::None(); + NoDocument document(key, version, /* has_committed_mutations= */ false); + + std::vector removed_target_ids( + change.removed_target_ids, + change.removed_target_ids + change.removed_target_ids_count); + + return absl::make_unique( + std::vector{}, std::move(removed_target_ids), std::move(key), + std::move(document)); +} + +std::unique_ptr Serializer::DecodeDocumentRemove( + nanopb::Reader* reader, + const google_firestore_v1_DocumentRemove& change) const { + DocumentKey key = DecodeKey(reader, change.document); + std::vector removed_target_ids( + change.removed_target_ids, + change.removed_target_ids + change.removed_target_ids_count); + + return absl::make_unique(std::vector{}, + std::move(removed_target_ids), + std::move(key), absl::nullopt); +} + +std::unique_ptr Serializer::DecodeExistenceFilterWatchChange( + nanopb::Reader* reader, + const google_firestore_v1_ExistenceFilter& filter) const { + ExistenceFilter existence_filter{filter.count}; + return absl::make_unique(existence_filter, + filter.target_id); +} + } // namespace remote } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/serializer.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/serializer.h index ae011b3..b3d7e5d 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/serializer.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/serializer.h @@ -21,25 +21,34 @@ #include #include #include +#include #include #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h" #include "Firestore/Protos/nanopb/google/firestore/v1/firestore.nanopb.h" #include "Firestore/Protos/nanopb/google/type/latlng.nanopb.h" -#include "Firestore/core/src/firebase/firestore/core/query.h" +#include "Firestore/core/src/firebase/firestore/core/bound.h" +#include "Firestore/core/src/firebase/firestore/core/field_filter.h" +#include "Firestore/core/src/firebase/firestore/core/filter.h" +#include "Firestore/core/src/firebase/firestore/core/order_by.h" +#include "Firestore/core/src/firebase/firestore/core/target.h" +#include "Firestore/core/src/firebase/firestore/local/target_data.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/field_mask.h" +#include "Firestore/core/src/firebase/firestore/model/field_transform.h" #include "Firestore/core/src/firebase/firestore/model/field_value.h" #include "Firestore/core/src/firebase/firestore/model/maybe_document.h" #include "Firestore/core/src/firebase/firestore/model/mutation.h" #include "Firestore/core/src/firebase/firestore/model/no_document.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" #include "Firestore/core/src/firebase/firestore/nanopb/reader.h" #include "Firestore/core/src/firebase/firestore/nanopb/writer.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "absl/base/attributes.h" #include "absl/strings/string_view.h" @@ -52,10 +61,7 @@ class LocalSerializer; namespace remote { -template -T* MakeArray(pb_size_t count) { - return reinterpret_cast(calloc(count, sizeof(T))); -} +core::Target InvalidTarget(); /** * @brief Converts internal model objects to their equivalent protocol buffer @@ -63,10 +69,10 @@ T* MakeArray(pb_size_t count) { * * Methods starting with "Encode" convert from a model object to a nanopb * protocol buffer, and methods starting with "Decode" convert from a nanopb - * protocol buffer to a model object + * protocol buffer to a model object. * - * For encoded messages, FreeNanopbMessage() must be called on the returned - * nanopb proto buffer or a memory leak will occur. + * For encoded messages, `nanopb::FreeNanopbMessage()` must be called on the + * returned nanopb proto buffer or a memory leak will occur. * * All errors that occur during serialization are fatal. * @@ -83,8 +89,7 @@ class Serializer { * @param database_id Must remain valid for the lifetime of this Serializer * object. */ - explicit Serializer( - const firebase::firestore::model::DatabaseId& database_id); + explicit Serializer(model::DatabaseId database_id); /** * Encodes the string to nanopb bytes. @@ -115,23 +120,16 @@ class Serializer { static pb_bytes_array_t* EncodeBytes(const std::vector& bytes); /** - * Decodes the nanopb bytes to a std::vector. If the input pointer is null, - * then this method will return an empty vector. - */ - static std::vector DecodeBytes(const pb_bytes_array_t* bytes); - - /** - * Release memory allocated by the Encode* methods that return protos. - * - * This essentially wraps calls to nanopb's pb_release() method. + * Returns the database ID, such as + * `projects/{project_id}/databases/{database_id}`. */ - static void FreeNanopbMessage(const pb_field_t fields[], void* dest_struct); + pb_bytes_array_t* EncodeDatabaseName() const; /** * @brief Converts the FieldValue model passed into bytes. */ - static google_firestore_v1_Value EncodeFieldValue( - const model::FieldValue& field_value); + google_firestore_v1_Value EncodeFieldValue( + const model::FieldValue& field_value) const; /** * @brief Converts from nanopb proto to the model FieldValue format. @@ -140,21 +138,21 @@ class Serializer { // used for is error handling. This seems questionable. We probably need to // rework error handling. Again. But we'll defer that for now and continue // just passing the reader object. - static model::FieldValue DecodeFieldValue( - nanopb::Reader* reader, const google_firestore_v1_Value& proto); + model::FieldValue DecodeFieldValue( + nanopb::Reader* reader, const google_firestore_v1_Value& proto) const; /** * Encodes the given document key as a fully qualified name. This includes the - * databaseId associated with this Serializer and the key path. + * DatabaseId associated with this Serializer and the key path. */ - std::string EncodeKey( + pb_bytes_array_t* EncodeKey( const firebase::firestore::model::DocumentKey& key) const; /** * Decodes the given document key from a fully qualified name. */ firebase::firestore::model::DocumentKey DecodeKey( - nanopb::Reader* reader, absl::string_view name) const; + nanopb::Reader* reader, const pb_bytes_array_t* name) const; /** * @brief Converts the Document (i.e. key/value) into bytes. @@ -165,13 +163,13 @@ class Serializer { /** * @brief Converts from nanopb proto to the model Document format. */ - std::unique_ptr DecodeMaybeDocument( + model::MaybeDocument DecodeMaybeDocument( nanopb::Reader* reader, const google_firestore_v1_BatchGetDocumentsResponse& response) const; google_firestore_v1_Write EncodeMutation( const model::Mutation& mutation) const; - std::unique_ptr DecodeMutation( + model::Mutation DecodeMutation( nanopb::Reader* reader, const google_firestore_v1_Write& mutation) const; static google_firestore_v1_Precondition EncodePrecondition( @@ -180,20 +178,27 @@ class Serializer { nanopb::Reader* reader, const google_firestore_v1_Precondition& precondition); - static google_firestore_v1_DocumentMask EncodeDocumentMask( + static google_firestore_v1_DocumentMask EncodeFieldMask( const model::FieldMask& mask); - static model::FieldMask DecodeDocumentMask( + static model::FieldMask DecodeFieldMask( const google_firestore_v1_DocumentMask& mask); - /** - * @brief Converts the Query into bytes, representing a - * firestore::v1::Target::QueryTarget. - */ - google_firestore_v1_Target_QueryTarget EncodeQueryTarget( - const core::Query& query) const; + google_firestore_v1_DocumentTransform_FieldTransform EncodeFieldTransform( + const model::FieldTransform& field_transform) const; + model::FieldTransform DecodeFieldTransform( + nanopb::Reader* reader, + const google_firestore_v1_DocumentTransform_FieldTransform& proto) const; + + model::MutationResult DecodeMutationResult( + nanopb::Reader* reader, + const google_firestore_v1_WriteResult& write_result, + const model::SnapshotVersion& commit_version) const; + + std::vector + EncodeListenRequestLabels(const local::TargetData& target_data) const; - std::unique_ptr DecodeDocument( - nanopb::Reader* reader, const google_firestore_v1_Document& proto) const; + static pb_bytes_array_t* EncodeFieldPath(const model::FieldPath& field_path); + static model::FieldPath DecodeFieldPath(const pb_bytes_array_t* field_path); static google_protobuf_Timestamp EncodeVersion( const model::SnapshotVersion& version); @@ -201,38 +206,172 @@ class Serializer { static google_protobuf_Timestamp EncodeTimestamp( const Timestamp& timestamp_value); - static model::SnapshotVersion DecodeSnapshotVersion( + static model::SnapshotVersion DecodeVersion( nanopb::Reader* reader, const google_protobuf_Timestamp& proto); static Timestamp DecodeTimestamp( nanopb::Reader* reader, const google_protobuf_Timestamp& timestamp_proto); - static core::Query DecodeQueryTarget( - nanopb::Reader* reader, - const google_firestore_v1_Target_QueryTarget& proto); - - static google_type_LatLng EncodeGeoPoint(const GeoPoint& geo_point_value); static GeoPoint DecodeGeoPoint(nanopb::Reader* reader, const google_type_LatLng& latlng_proto); - static google_firestore_v1_ArrayValue EncodeArray( - const std::vector& array_value); - static std::vector DecodeArray( + google_firestore_v1_ArrayValue EncodeArray( + const std::vector& array_value) const; + std::vector DecodeArray( nanopb::Reader* reader, - const google_firestore_v1_ArrayValue& array_proto); + const google_firestore_v1_ArrayValue& array_proto) const; + + google_firestore_v1_MapValue EncodeMapValue( + const model::ObjectValue& object_value) const; + + google_firestore_v1_Target EncodeTarget( + const local::TargetData& target_data) const; + google_firestore_v1_Target_DocumentsTarget EncodeDocumentsTarget( + const core::Target& target) const; + core::Target DecodeDocumentsTarget( + nanopb::Reader* reader, + const google_firestore_v1_Target_DocumentsTarget& proto) const; + google_firestore_v1_Target_QueryTarget EncodeQueryTarget( + const core::Target& target) const; + core::Target DecodeQueryTarget( + nanopb::Reader* reader, + const google_firestore_v1_Target_QueryTarget& proto) const; + + std::unique_ptr DecodeWatchChange( + nanopb::Reader* reader, + const google_firestore_v1_ListenResponse& watch_change) const; + + model::SnapshotVersion DecodeVersionFromListenResponse( + nanopb::Reader* reader, + const google_firestore_v1_ListenResponse& listen_response) const; + + model::ObjectValue DecodeFields( + nanopb::Reader* reader, + size_t count, + const google_firestore_v1_Document_FieldsEntry* fields) const; + + // Public for the sake of tests. + google_firestore_v1_StructuredQuery_Filter EncodeFilters( + const core::FilterList& filters) const; + core::FilterList DecodeFilters( + nanopb::Reader* reader, + const google_firestore_v1_StructuredQuery_Filter& proto) const; private: - std::unique_ptr DecodeFoundDocument( + google_firestore_v1_Value EncodeNull() const; + google_firestore_v1_Value EncodeBoolean(bool value) const; + google_firestore_v1_Value EncodeInteger(int64_t value) const; + google_firestore_v1_Value EncodeDouble(double value) const; + google_firestore_v1_Value EncodeTimestampValue(Timestamp value) const; + google_firestore_v1_Value EncodeStringValue(const std::string& value) const; + google_firestore_v1_Value EncodeBlob(const nanopb::ByteString& value) const; + google_firestore_v1_Value EncodeReference( + const model::FieldValue::Reference& value) const; + google_firestore_v1_Value EncodeGeoPoint(const GeoPoint& value) const; + + model::Document DecodeFoundDocument( nanopb::Reader* reader, const google_firestore_v1_BatchGetDocumentsResponse& response) const; - std::unique_ptr DecodeMissingDocument( + model::NoDocument DecodeMissingDocument( nanopb::Reader* reader, const google_firestore_v1_BatchGetDocumentsResponse& response) const; - std::string EncodeQueryPath(const model::ResourcePath& path) const; + pb_bytes_array_t* EncodeQueryPath(const model::ResourcePath& path) const; + model::ResourcePath DecodeQueryPath(nanopb::Reader* reader, + absl::string_view name) const; + + /** + * Encodes a database ID and resource path into the following form: + * /projects/$project_id/database/$database_id/documents/$path + */ + pb_bytes_array_t* EncodeResourceName(const model::DatabaseId& database_id, + const model::ResourcePath& path) const; + + /** + * Decodes a fully qualified resource name into a resource path and validates + * that there is a project and database encoded in the path. There are no + * guarantees that a local path is also encoded in this resource name. + */ + model::ResourcePath DecodeResourceName(nanopb::Reader* reader, + absl::string_view encoded) const; + + void ValidateDocumentKeyPath(nanopb::Reader* reader, + const model::ResourcePath& resource_name) const; + model::DocumentKey DecodeKey(nanopb::Reader* reader, + const model::ResourcePath& resource_name) const; + + model::FieldValue::Map::value_type DecodeFieldsEntry( + nanopb::Reader* reader, + const google_firestore_v1_Document_FieldsEntry& fields) const; + + model::FieldValue::Map DecodeMapValue( + nanopb::Reader* reader, + const google_firestore_v1_MapValue& map_value) const; + + model::DatabaseId DecodeDatabaseId( + nanopb::Reader* reader, const model::ResourcePath& resource_name) const; + model::FieldValue DecodeReference( + nanopb::Reader* reader, const pb_bytes_array_t* resource_name_raw) const; + + std::string EncodeLabel(local::QueryPurpose purpose) const; + + google_firestore_v1_StructuredQuery_Filter EncodeSingularFilter( + const core::FieldFilter& filter) const; + core::Filter DecodeFieldFilter( + nanopb::Reader* reader, + const google_firestore_v1_StructuredQuery_FieldFilter& field_filter) + const; + core::Filter DecodeUnaryFilter( + nanopb::Reader* reader, + const google_firestore_v1_StructuredQuery_UnaryFilter& unary) const; + core::FilterList DecodeCompositeFilter( + nanopb::Reader* reader, + const google_firestore_v1_StructuredQuery_CompositeFilter& composite) + const; + + google_firestore_v1_StructuredQuery_FieldFilter_Operator + EncodeFieldFilterOperator(core::Filter::Operator op) const; + core::Filter::Operator DecodeFieldFilterOperator( + nanopb::Reader* reader, + google_firestore_v1_StructuredQuery_FieldFilter_Operator op) const; + + google_firestore_v1_StructuredQuery_Order* EncodeOrderBys( + const core::OrderByList& orders) const; + core::OrderByList DecodeOrderBys( + nanopb::Reader* reader, + google_firestore_v1_StructuredQuery_Order* order_bys, + pb_size_t size) const; + core::OrderBy DecodeOrderBy( + nanopb::Reader* reader, + const google_firestore_v1_StructuredQuery_Order& order_by) const; + + google_firestore_v1_Cursor EncodeBound(const core::Bound& bound) const; + std::shared_ptr DecodeBound( + nanopb::Reader* reader, const google_firestore_v1_Cursor& cursor) const; + + std::unique_ptr DecodeTargetChange( + nanopb::Reader* reader, + const google_firestore_v1_TargetChange& change) const; + static remote::WatchTargetChangeState DecodeTargetChangeState( + nanopb::Reader* reader, + const google_firestore_v1_TargetChange_TargetChangeType state); + + std::unique_ptr DecodeDocumentChange( + nanopb::Reader* reader, + const google_firestore_v1_DocumentChange& change) const; + std::unique_ptr DecodeDocumentDelete( + nanopb::Reader* reader, + const google_firestore_v1_DocumentDelete& change) const; + std::unique_ptr DecodeDocumentRemove( + nanopb::Reader* reader, + const google_firestore_v1_DocumentRemove& change) const; + std::unique_ptr DecodeExistenceFilterWatchChange( + nanopb::Reader* reader, + const google_firestore_v1_ExistenceFilter& filter) const; - const model::DatabaseId& database_id_; - const std::string database_name_; + model::DatabaseId database_id_; + // TODO(varconst): Android caches the result of calling `EncodeDatabaseName` + // as well, consider implementing that. }; } // namespace remote diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/stream.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/stream.cc new file mode 100644 index 0000000..7d3ec65 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/stream.cc @@ -0,0 +1,323 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/remote/stream.h" + +#include // NOLINT(build/c++11) +#include + +#include "Firestore/core/include/firebase/firestore/firestore_errors.h" +#include "Firestore/core/src/firebase/firestore/remote/datastore.h" +#include "Firestore/core/src/firebase/firestore/util/error_apple.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/string_format.h" + +namespace firebase { +namespace firestore { +namespace remote { + +using auth::CredentialsProvider; +using auth::Token; +using util::AsyncQueue; +using util::LogIsDebugEnabled; +using util::Status; +using util::StatusOr; +using util::StringFormat; +using util::TimerId; + +namespace { + +/** + * Initial backoff time after an error. + * Set to 1s according to https://cloud.google.com/apis/design/errors. + */ +const double kBackoffFactor = 1.5; +const AsyncQueue::Milliseconds kBackoffInitialDelay{std::chrono::seconds(1)}; +const AsyncQueue::Milliseconds kBackoffMaxDelay{std::chrono::seconds(60)}; +/** The time a stream stays open after it is marked idle. */ +const AsyncQueue::Milliseconds kIdleTimeout{std::chrono::seconds(60)}; + +} // namespace + +Stream::Stream(const std::shared_ptr& worker_queue, + std::shared_ptr credentials_provider, + GrpcConnection* grpc_connection, + TimerId backoff_timer_id, + TimerId idle_timer_id) + : backoff_{worker_queue, backoff_timer_id, kBackoffFactor, + kBackoffInitialDelay, kBackoffMaxDelay}, + credentials_provider_{std::move(credentials_provider)}, + worker_queue_{worker_queue}, + grpc_connection_{grpc_connection}, + idle_timer_id_{idle_timer_id} { +} + +// Check state + +bool Stream::IsOpen() const { + EnsureOnQueue(); + return state_ == State::Open; +} + +bool Stream::IsStarted() const { + EnsureOnQueue(); + return state_ == State::Starting || state_ == State::Backoff || IsOpen(); +} + +// Starting + +void Stream::Start() { + EnsureOnQueue(); + + if (state_ == State::Error) { + BackoffAndTryRestarting(); + return; + } + + LOG_DEBUG("%s start", GetDebugDescription()); + + HARD_ASSERT(state_ == State::Initial, "Already started"); + state_ = State::Starting; + + RequestCredentials(); +} + +void Stream::RequestCredentials() { + EnsureOnQueue(); + + // Auth may outlive the stream, so make sure it doesn't try to access a + // deleted object. + std::weak_ptr weak_this{shared_from_this()}; + int initial_close_count = close_count_; + credentials_provider_->GetToken([weak_this, initial_close_count]( + const StatusOr& maybe_token) { + auto strong_this = weak_this.lock(); + if (!strong_this) { + return; + } + + strong_this->worker_queue_->EnqueueRelaxed([maybe_token, weak_this, + initial_close_count] { + auto strong_this = weak_this.lock(); + // Streams can be stopped while waiting for authorization, so need + // to check the close count. + if (!strong_this || strong_this->close_count_ != initial_close_count) { + return; + } + strong_this->ResumeStartWithCredentials(maybe_token); + }); + }); +} + +void Stream::ResumeStartWithCredentials(const StatusOr& maybe_token) { + EnsureOnQueue(); + + HARD_ASSERT(state_ == State::Starting, + "State should still be 'Starting' (was %s)", state_); + + if (!maybe_token.ok()) { + OnStreamFinish(maybe_token.status()); + return; + } + + grpc_stream_ = CreateGrpcStream(grpc_connection_, maybe_token.ValueOrDie()); + grpc_stream_->Start(); +} + +void Stream::OnStreamStart() { + EnsureOnQueue(); + + state_ = State::Open; + NotifyStreamOpen(); +} + +// Backoff + +void Stream::BackoffAndTryRestarting() { + EnsureOnQueue(); + + LOG_DEBUG("%s backoff", GetDebugDescription()); + + HARD_ASSERT(state_ == State::Error, + "Should only perform backoff in an error case"); + + state_ = State::Backoff; + backoff_.BackoffAndRun([this] { + HARD_ASSERT(state_ == State::Backoff, + "Backoff elapsed but state is now: %s", state_); + + state_ = State::Initial; + Start(); + HARD_ASSERT(IsStarted(), "Stream should have started."); + }); +} + +void Stream::InhibitBackoff() { + EnsureOnQueue(); + + HARD_ASSERT(!IsStarted(), + "Can only cancel backoff in a stopped state (was %s)", state_); + + // Clear the error condition. + state_ = State::Initial; + backoff_.Reset(); +} + +// Idleness + +void Stream::MarkIdle() { + EnsureOnQueue(); + + if (IsOpen() && !idleness_timer_) { + idleness_timer_ = worker_queue_->EnqueueAfterDelay( + kIdleTimeout, idle_timer_id_, [this] { Stop(); }); + } +} + +void Stream::CancelIdleCheck() { + EnsureOnQueue(); + idleness_timer_.Cancel(); +} + +// Read/write + +void Stream::OnStreamRead(const grpc::ByteBuffer& message) { + EnsureOnQueue(); + + HARD_ASSERT(IsStarted(), "OnStreamRead called for a stopped stream."); + + if (LogIsDebugEnabled()) { + LOG_DEBUG("%s headers (whitelisted): %s", GetDebugDescription(), + Datastore::GetWhitelistedHeadersAsString( + grpc_stream_->GetResponseHeaders())); + } + + Status read_status = NotifyStreamResponse(message); + if (!read_status.ok()) { + grpc_stream_->FinishImmediately(); + // Don't expect gRPC to produce status -- since the error happened on the + // client, we have all the information we need. + OnStreamFinish(read_status); + return; + } +} + +// Stopping + +void Stream::Stop() { + EnsureOnQueue(); + LOG_DEBUG("%s stop", GetDebugDescription()); + + Close(Status::OK()); +} + +void Stream::Close(const Status& status) { + // This function ensures that both graceful stop and stop due to error go + // through the same sequence of steps. While it leads to more conditional + // logic, the benefit is reducing the chance of divergence across the two + // cases. + + EnsureOnQueue(); + bool graceful_stop = status.ok(); + + // Step 1 (both): check current state. + if (graceful_stop && !IsStarted()) { + // Graceful stop is idempotent. + return; + } + HARD_ASSERT(IsStarted(), "Trying to close a non-started stream"); + + // Step 2 (both): cancel any outstanding timers (they're guaranteed not to + // execute). + CancelIdleCheck(); + backoff_.Cancel(); + + // Step 3 (both): increment close count, which invalidates long-lived + // callbacks, guaranteeing they won't execute against a new instance of the + // stream or when the stream has been destroyed. + ++close_count_; + + // Step 4 (both): make small adjustments (to backoff/etc.) based on the + // status. + if (graceful_stop) { + // If this is an intentional close, ensure we don't delay our next + // connection attempt. + backoff_.Reset(); + } else { + HandleErrorStatus(status); + } + + // Step 5 (graceful stop only): give subclasses a chance to send final + // messages. + if (graceful_stop && grpc_stream_) { + // If the stream is in the auth stage, gRPC stream might not have been + // created yet. + LOG_DEBUG("%s Finishing gRPC stream", GetDebugDescription()); + TearDown(grpc_stream_.get()); + } + // Step 6 (both): destroy the underlying stream. + grpc_stream_.reset(); + + // Step 7 (both): update the state machine and notify the listener. + // State must be updated before calling the delegate. + state_ = graceful_stop ? State::Initial : State::Error; + NotifyStreamClose(status); +} + +void Stream::HandleErrorStatus(const Status& status) { + if (status.code() == Error::ResourceExhausted) { + LOG_DEBUG( + "%s Using maximum backoff delay to prevent overloading the backend.", + GetDebugDescription()); + backoff_.ResetToMax(); + } else if (status.code() == Error::Unauthenticated) { + // "unauthenticated" error means the token was rejected. Try force + // refreshing it in case it just expired. + credentials_provider_->InvalidateToken(); + } +} + +void Stream::OnStreamFinish(const Status& status) { + EnsureOnQueue(); + + LOG_DEBUG("%s Stream error: '%s'", GetDebugDescription(), status.ToString()); + Close(status); +} + +// Protected helpers + +void Stream::EnsureOnQueue() const { + worker_queue_->VerifyIsCurrentQueue(); +} + +void Stream::Write(grpc::ByteBuffer&& message) { + EnsureOnQueue(); + + HARD_ASSERT(IsOpen(), "Cannot write when the stream is not open."); + + CancelIdleCheck(); + grpc_stream_->Write(std::move(message)); +} + +std::string Stream::GetDebugDescription() const { + EnsureOnQueue(); + return StringFormat("%s (%s)", GetDebugName(), this); +} + +} // namespace remote +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/stream.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/stream.h index 669c381..60ae470 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/stream.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/stream.h @@ -28,8 +28,7 @@ #include "Firestore/core/src/firebase/firestore/remote/grpc_stream.h" #include "Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" -#include "Firestore/core/src/firebase/firestore/util/statusor.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "absl/strings/string_view.h" #include "grpcpp/support/byte_buffer.h" @@ -119,8 +118,8 @@ class Stream : public GrpcStreamObserver, Backoff }; - Stream(util::AsyncQueue* async_queue, - auth::CredentialsProvider* credentials_provider, + Stream(const std::shared_ptr& worker_queue, + std::shared_ptr credentials_provider, GrpcConnection* grpc_connection, util::TimerId backoff_timer_id, util::TimerId idle_timer_id); @@ -227,8 +226,8 @@ class Stream : public GrpcStreamObserver, std::unique_ptr grpc_stream_; - auth::CredentialsProvider* credentials_provider_ = nullptr; - util::AsyncQueue* worker_queue_ = nullptr; + std::shared_ptr credentials_provider_; + std::shared_ptr worker_queue_; GrpcConnection* grpc_connection_ = nullptr; util::TimerId idle_timer_id_{}; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/stream.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/stream.mm deleted file mode 100644 index f03375d..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/stream.mm +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/remote/stream.h" - -#include // NOLINT(build/c++11) -#include - -#include "Firestore/core/include/firebase/firestore/firestore_errors.h" -#include "Firestore/core/src/firebase/firestore/remote/datastore.h" -#include "Firestore/core/src/firebase/firestore/util/error_apple.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/log.h" -#include "Firestore/core/src/firebase/firestore/util/string_format.h" - -namespace firebase { -namespace firestore { -namespace remote { - -using auth::CredentialsProvider; -using auth::Token; -using util::AsyncQueue; -using util::TimerId; -using util::Status; -using util::StatusOr; -using util::StringFormat; - -namespace { - -/** - * Initial backoff time after an error. - * Set to 1s according to https://cloud.google.com/apis/design/errors. - */ -const double kBackoffFactor = 1.5; -const AsyncQueue::Milliseconds kBackoffInitialDelay{std::chrono::seconds(1)}; -const AsyncQueue::Milliseconds kBackoffMaxDelay{std::chrono::seconds(60)}; -/** The time a stream stays open after it is marked idle. */ -const AsyncQueue::Milliseconds kIdleTimeout{std::chrono::seconds(60)}; - -} // namespace - -Stream::Stream(AsyncQueue* worker_queue, - CredentialsProvider* credentials_provider, - GrpcConnection* grpc_connection, - TimerId backoff_timer_id, - TimerId idle_timer_id) - : backoff_{worker_queue, backoff_timer_id, kBackoffFactor, - kBackoffInitialDelay, kBackoffMaxDelay}, - credentials_provider_{credentials_provider}, - worker_queue_{worker_queue}, - grpc_connection_{grpc_connection}, - idle_timer_id_{idle_timer_id} { -} - -// Check state - -bool Stream::IsOpen() const { - EnsureOnQueue(); - return state_ == State::Open; -} - -bool Stream::IsStarted() const { - EnsureOnQueue(); - return state_ == State::Starting || state_ == State::Backoff || IsOpen(); -} - -// Starting - -void Stream::Start() { - EnsureOnQueue(); - - if (state_ == State::Error) { - BackoffAndTryRestarting(); - return; - } - - LOG_DEBUG("%s start", GetDebugDescription()); - - HARD_ASSERT(state_ == State::Initial, "Already started"); - state_ = State::Starting; - - RequestCredentials(); -} - -void Stream::RequestCredentials() { - EnsureOnQueue(); - - // Auth may outlive the stream, so make sure it doesn't try to access a - // deleted object. - std::weak_ptr weak_this{shared_from_this()}; - int initial_close_count = close_count_; - credentials_provider_->GetToken([weak_this, initial_close_count]( - const StatusOr& maybe_token) { - auto strong_this = weak_this.lock(); - if (!strong_this) { - return; - } - - strong_this->worker_queue_->EnqueueRelaxed([maybe_token, weak_this, - initial_close_count] { - auto strong_this = weak_this.lock(); - // Streams can be stopped while waiting for authorization, so need - // to check the close count. - if (!strong_this || strong_this->close_count_ != initial_close_count) { - return; - } - strong_this->ResumeStartWithCredentials(maybe_token); - }); - }); -} - -void Stream::ResumeStartWithCredentials(const StatusOr& maybe_token) { - EnsureOnQueue(); - - HARD_ASSERT(state_ == State::Starting, - "State should still be 'Starting' (was %s)", state_); - - if (!maybe_token.ok()) { - OnStreamFinish(maybe_token.status()); - return; - } - - grpc_stream_ = CreateGrpcStream(grpc_connection_, maybe_token.ValueOrDie()); - grpc_stream_->Start(); -} - -void Stream::OnStreamStart() { - EnsureOnQueue(); - - state_ = State::Open; - NotifyStreamOpen(); -} - -// Backoff - -void Stream::BackoffAndTryRestarting() { - EnsureOnQueue(); - - LOG_DEBUG("%s backoff", GetDebugDescription()); - - HARD_ASSERT(state_ == State::Error, - "Should only perform backoff in an error case"); - - state_ = State::Backoff; - backoff_.BackoffAndRun([this] { - HARD_ASSERT(state_ == State::Backoff, - "Backoff elapsed but state is now: %s", state_); - - state_ = State::Initial; - Start(); - HARD_ASSERT(IsStarted(), "Stream should have started."); - }); -} - -void Stream::InhibitBackoff() { - EnsureOnQueue(); - - HARD_ASSERT(!IsStarted(), - "Can only cancel backoff in a stopped state (was %s)", state_); - - // Clear the error condition. - state_ = State::Initial; - backoff_.Reset(); -} - -// Idleness - -void Stream::MarkIdle() { - EnsureOnQueue(); - - if (IsOpen() && !idleness_timer_) { - idleness_timer_ = worker_queue_->EnqueueAfterDelay( - kIdleTimeout, idle_timer_id_, [this] { Stop(); }); - } -} - -void Stream::CancelIdleCheck() { - EnsureOnQueue(); - idleness_timer_.Cancel(); -} - -// Read/write - -void Stream::OnStreamRead(const grpc::ByteBuffer& message) { - EnsureOnQueue(); - - HARD_ASSERT(IsStarted(), "OnStreamRead called for a stopped stream."); - - if (bridge::IsLoggingEnabled()) { - LOG_DEBUG("%s headers (whitelisted): %s", GetDebugDescription(), - Datastore::GetWhitelistedHeadersAsString( - grpc_stream_->GetResponseHeaders())); - } - - Status read_status = NotifyStreamResponse(message); - if (!read_status.ok()) { - grpc_stream_->FinishImmediately(); - // Don't expect gRPC to produce status -- since the error happened on the - // client, we have all the information we need. - OnStreamFinish(read_status); - return; - } -} - -// Stopping - -void Stream::Stop() { - EnsureOnQueue(); - LOG_DEBUG("%s stop", GetDebugDescription()); - - Close(Status::OK()); -} - -void Stream::Close(const Status& status) { - // This function ensures that both graceful stop and stop due to error go - // through the same sequence of steps. While it leads to more conditional - // logic, the benefit is reducing the chance of divergence across the two - // cases. - - EnsureOnQueue(); - bool graceful_stop = status.ok(); - - // Step 1 (both): check current state. - if (graceful_stop && !IsStarted()) { - // Graceful stop is idempotent. - return; - } - HARD_ASSERT(IsStarted(), "Trying to close a non-started stream"); - - // Step 2 (both): cancel any outstanding timers (they're guaranteed not to - // execute). - CancelIdleCheck(); - backoff_.Cancel(); - - // Step 3 (both): increment close count, which invalidates long-lived - // callbacks, guaranteeing they won't execute against a new instance of the - // stream or when the stream has been destroyed. - ++close_count_; - - // Step 4 (both): make small adjustments (to backoff/etc.) based on the - // status. - if (graceful_stop) { - // If this is an intentional close, ensure we don't delay our next - // connection attempt. - backoff_.Reset(); - } else { - HandleErrorStatus(status); - } - - // Step 5 (graceful stop only): give subclasses a chance to send final - // messages. - if (graceful_stop && grpc_stream_) { - // If the stream is in the auth stage, gRPC stream might not have been - // created yet. - LOG_DEBUG("%s Finishing gRPC stream", GetDebugDescription()); - TearDown(grpc_stream_.get()); - } - // Step 6 (both): destroy the underlying stream. - grpc_stream_.reset(); - - // Step 7 (both): update the state machine and notify the listener. - // State must be updated before calling the delegate. - state_ = graceful_stop ? State::Initial : State::Error; - NotifyStreamClose(status); -} - -void Stream::HandleErrorStatus(const Status& status) { - if (status.code() == FirestoreErrorCode::ResourceExhausted) { - LOG_DEBUG( - "%s Using maximum backoff delay to prevent overloading the backend.", - GetDebugDescription()); - backoff_.ResetToMax(); - } else if (status.code() == FirestoreErrorCode::Unauthenticated) { - // "unauthenticated" error means the token was rejected. Try force - // refreshing it in case it just expired. - credentials_provider_->InvalidateToken(); - } -} - -void Stream::OnStreamFinish(const Status& status) { - EnsureOnQueue(); - // TODO(varconst): log error here? - LOG_DEBUG("%s Stream error", GetDebugDescription()); - - Close(status); -} - -// Protected helpers - -void Stream::EnsureOnQueue() const { - worker_queue_->VerifyIsCurrentQueue(); -} - -void Stream::Write(grpc::ByteBuffer&& message) { - EnsureOnQueue(); - - HARD_ASSERT(IsOpen(), "Cannot write when the stream is not open."); - - CancelIdleCheck(); - grpc_stream_->Write(std::move(message)); -} - -std::string Stream::GetDebugDescription() const { - EnsureOnQueue(); - return StringFormat("%s (%s)", GetDebugName(), this); -} - -} // namespace remote -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_change.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_change.cc new file mode 100644 index 0000000..ad08c67 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_change.cc @@ -0,0 +1,69 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" + +namespace firebase { +namespace firestore { +namespace remote { + +namespace { + +template +bool Equals(const WatchChange& lhs, const WatchChange& rhs) { + return static_cast(lhs) == static_cast(rhs); +} + +} // namespace + +// Compares two `WatchChange`s taking into account their actual derived type. +bool operator==(const WatchChange& lhs, const WatchChange& rhs) { + if (lhs.type() != rhs.type()) { + return false; + } + + switch (lhs.type()) { + case WatchChange::Type::Document: + return Equals(lhs, rhs); + case WatchChange::Type::ExistenceFilter: + return Equals(lhs, rhs); + case WatchChange::Type::TargetChange: + return Equals(lhs, rhs); + } + UNREACHABLE(); +} + +bool operator==(const DocumentWatchChange& lhs, + const DocumentWatchChange& rhs) { + return lhs.updated_target_ids() == rhs.updated_target_ids() && + lhs.removed_target_ids() == rhs.removed_target_ids() && + lhs.document_key() == rhs.document_key() && + lhs.new_document() == rhs.new_document(); +} + +bool operator==(const ExistenceFilterWatchChange& lhs, + const ExistenceFilterWatchChange& rhs) { + return lhs.filter() == rhs.filter() && lhs.target_id() == rhs.target_id(); +} + +bool operator==(const WatchTargetChange& lhs, const WatchTargetChange& rhs) { + return lhs.state() == rhs.state() && lhs.target_ids() == rhs.target_ids() && + lhs.resume_token() == rhs.resume_token() && lhs.cause() == rhs.cause(); +} + +} // namespace remote +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_change.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_change.h index 885110c..78cce77 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_change.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_change.h @@ -17,24 +17,16 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_WATCH_CHANGE_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_WATCH_CHANGE_H_ -#if !defined(__OBJC__) -// TODO(varconst): the only dependencies are `FSTMaybeDocument` and `NSData` -// (the latter is used to represent the resume token). -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import - #include #include #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/maybe_document.h" #include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h" #include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" #include "Firestore/core/src/firebase/firestore/util/status.h" -@class FSTMaybeDocument; - namespace firebase { namespace firestore { namespace remote { @@ -60,6 +52,8 @@ class WatchChange { virtual Type type() const = 0; }; +bool operator==(const WatchChange& lhs, const WatchChange& rhs); + /** * `DocumentWatchChange` represents a changed document and a list of target ids * to which this change applies. @@ -71,11 +65,11 @@ class DocumentWatchChange : public WatchChange { DocumentWatchChange(std::vector updated_target_ids, std::vector removed_target_ids, model::DocumentKey document_key, - FSTMaybeDocument* new_document) + absl::optional new_document) : updated_target_ids_{std::move(updated_target_ids)}, removed_target_ids_{std::move(removed_target_ids)}, document_key_{std::move(document_key)}, - new_document_{new_document} { + new_document_{std::move(new_document)} { } Type type() const override { @@ -96,7 +90,7 @@ class DocumentWatchChange : public WatchChange { * The new document, or `DeletedDocument` if it was deleted. Is null if the * document went out of view without the server sending a new document. */ - FSTMaybeDocument* new_document() const { + const absl::optional& new_document() const { return new_document_; } @@ -109,7 +103,7 @@ class DocumentWatchChange : public WatchChange { std::vector updated_target_ids_; std::vector removed_target_ids_; model::DocumentKey document_key_; - FSTMaybeDocument* new_document_; + absl::optional new_document_; }; bool operator==(const DocumentWatchChange& lhs, const DocumentWatchChange& rhs); @@ -149,30 +143,31 @@ class WatchTargetChange : public WatchChange { public: WatchTargetChange(WatchTargetChangeState state, std::vector target_ids) - : WatchTargetChange{state, std::move(target_ids), [NSData data], + : WatchTargetChange{state, std::move(target_ids), nanopb::ByteString(), util::Status::OK()} { } WatchTargetChange(WatchTargetChangeState state, std::vector target_ids, - NSData* resume_token) - : WatchTargetChange{state, std::move(target_ids), resume_token, + nanopb::ByteString resume_token) + : WatchTargetChange{state, std::move(target_ids), std::move(resume_token), util::Status::OK()} { } WatchTargetChange(WatchTargetChangeState state, std::vector target_ids, util::Status cause) - : WatchTargetChange{state, std::move(target_ids), [NSData data], cause} { + : WatchTargetChange{state, std::move(target_ids), nanopb::ByteString(), + cause} { } WatchTargetChange(WatchTargetChangeState state, std::vector target_ids, - NSData* resume_token, + nanopb::ByteString resume_token, util::Status cause) : state_{state}, target_ids_{std::move(target_ids)}, - resume_token_{resume_token}, + resume_token_{std::move(resume_token)}, cause_{std::move(cause)} { } @@ -196,7 +191,7 @@ class WatchTargetChange : public WatchChange { * matches the query. The resume token essentially identifies a point in * time from which the server should resume sending results. */ - NSData* resume_token() const { + const nanopb::ByteString& resume_token() const { return resume_token_; } @@ -211,7 +206,7 @@ class WatchTargetChange : public WatchChange { private: WatchTargetChangeState state_; std::vector target_ids_; - NSData* resume_token_; + nanopb::ByteString resume_token_; util::Status cause_; }; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_change.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_change.mm deleted file mode 100644 index e56d974..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_change.mm +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" - -#import "Firestore/Source/Model/FSTDocument.h" - -#include "Firestore/core/src/firebase/firestore/util/objc_compatibility.h" - -namespace objc = firebase::firestore::util::objc; - -namespace firebase { -namespace firestore { -namespace remote { - -bool operator==(const DocumentWatchChange& lhs, - const DocumentWatchChange& rhs) { - return lhs.updated_target_ids() == rhs.updated_target_ids() && - lhs.removed_target_ids() == rhs.removed_target_ids() && - lhs.document_key() == rhs.document_key() && - objc::Equals(lhs.new_document(), rhs.new_document()); -} - -bool operator==(const ExistenceFilterWatchChange& lhs, - const ExistenceFilterWatchChange& rhs) { - return lhs.filter() == rhs.filter() && lhs.target_id() == rhs.target_id(); -} - -bool operator==(const WatchTargetChange& lhs, const WatchTargetChange& rhs) { - return lhs.state() == rhs.state() && lhs.target_ids() == rhs.target_ids() && - objc::Equals(lhs.resume_token(), rhs.resume_token()) && - lhs.cause() == rhs.cause(); -} - -} // namespace remote -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_stream.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_stream.cc new file mode 100644 index 0000000..5ce9801 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_stream.cc @@ -0,0 +1,114 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#include + +#include "Firestore/core/src/firebase/firestore/remote/watch_stream.h" + +#include "Firestore/core/src/firebase/firestore/nanopb/message.h" +#include "Firestore/core/src/firebase/firestore/nanopb/reader.h" +#include "Firestore/core/src/firebase/firestore/remote/grpc_nanopb.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" + +namespace firebase { +namespace firestore { +namespace remote { + +using auth::CredentialsProvider; +using auth::Token; +using local::TargetData; +using model::TargetId; +using nanopb::Message; +using remote::ByteBufferReader; +using util::AsyncQueue; +using util::Status; +using util::TimerId; + +WatchStream::WatchStream( + const std::shared_ptr& async_queue, + std::shared_ptr credentials_provider, + Serializer serializer, + GrpcConnection* grpc_connection, + WatchStreamCallback* callback) + : Stream{async_queue, std::move(credentials_provider), grpc_connection, + TimerId::ListenStreamConnectionBackoff, TimerId::ListenStreamIdle}, + watch_serializer_{std::move(serializer)}, + callback_{NOT_NULL(callback)} { +} + +void WatchStream::WatchQuery(const TargetData& query) { + EnsureOnQueue(); + + auto request = watch_serializer_.EncodeWatchRequest(query); + LOG_DEBUG("%s watch: %s", GetDebugDescription(), request.ToString()); + Write(MakeByteBuffer(request)); +} + +void WatchStream::UnwatchTargetId(TargetId target_id) { + EnsureOnQueue(); + + auto request = watch_serializer_.EncodeUnwatchRequest(target_id); + + LOG_DEBUG("%s unwatch: %s", GetDebugDescription(), request.ToString()); + Write(MakeByteBuffer(request)); +} + +std::unique_ptr WatchStream::CreateGrpcStream( + GrpcConnection* grpc_connection, const Token& token) { + return grpc_connection->CreateStream("/google.firestore.v1.Firestore/Listen", + token, this); +} + +void WatchStream::TearDown(GrpcStream* grpc_stream) { + grpc_stream->FinishImmediately(); +} + +void WatchStream::NotifyStreamOpen() { + callback_->OnWatchStreamOpen(); +} + +Status WatchStream::NotifyStreamResponse(const grpc::ByteBuffer& message) { + ByteBufferReader reader{message}; + auto response = watch_serializer_.ParseResponse(&reader); + if (!reader.ok()) { + return reader.status(); + } + + LOG_DEBUG("%s response: %s", GetDebugDescription(), response.ToString()); + + // A successful response means the stream is healthy. + backoff_.Reset(); + + auto watch_change = watch_serializer_.DecodeWatchChange(&reader, *response); + auto version = watch_serializer_.DecodeSnapshotVersion(&reader, *response); + if (!reader.ok()) { + return reader.status(); + } + + callback_->OnWatchStreamChange(*watch_change, version); + + return Status::OK(); +} + +void WatchStream::NotifyStreamClose(const Status& status) { + callback_->OnWatchStreamClose(status); +} + +} // namespace remote +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_stream.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_stream.h index b6136cf..cd77934 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_stream.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_stream.h @@ -17,13 +17,10 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_WATCH_STREAM_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_WATCH_STREAM_H_ -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - #include #include +#include "Firestore/core/src/firebase/firestore/local/target_data.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" #include "Firestore/core/src/firebase/firestore/remote/grpc_connection.h" @@ -31,25 +28,27 @@ #include "Firestore/core/src/firebase/firestore/remote/stream.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "absl/strings/string_view.h" #include "grpcpp/support/byte_buffer.h" -#import "Firestore/Source/Core/FSTTypes.h" -#import "Firestore/Source/Local/FSTQueryData.h" -#import "Firestore/Source/Remote/FSTSerializerBeta.h" - namespace firebase { namespace firestore { namespace remote { +class Serializer; + /** * An interface defining the events that can be emitted by the `WatchStream`. */ class WatchStreamCallback { public: - /** Called by the `WatchStream` when it is ready to accept outbound request - * messages. */ + virtual ~WatchStreamCallback() = default; + + /** + * Called by the `WatchStream` when it is ready to accept outbound request + * messages. + */ virtual void OnWatchStreamOpen() = 0; /** @@ -81,9 +80,9 @@ class WatchStreamCallback { */ class WatchStream : public Stream { public: - WatchStream(util::AsyncQueue* async_queue, - auth::CredentialsProvider* credentials_provider, - FSTSerializerBeta* serializer, + WatchStream(const std::shared_ptr& async_queue, + std::shared_ptr credentials_provider, + Serializer serializer, GrpcConnection* grpc_connection, WatchStreamCallback* callback); @@ -93,7 +92,8 @@ class WatchStream : public Stream { * query will be streamed back as WatchChange messages that reference the * target ID included in `query`. */ - virtual /*virtual for tests only*/ void WatchQuery(FSTQueryData* query); + virtual /*virtual for tests only*/ void WatchQuery( + const local::TargetData& query); /** * Unregisters interest in the results of the query associated with the given @@ -115,7 +115,7 @@ class WatchStream : public Stream { return "WatchStream"; } - bridge::WatchStreamSerializer serializer_bridge_; + WatchStreamSerializer watch_serializer_; WatchStreamCallback* callback_; }; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_stream.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_stream.mm deleted file mode 100644 index 0066809..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/watch_stream.mm +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/remote/watch_stream.h" - -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/log.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" - -#import "Firestore/Protos/objc/google/firestore/v1/Firestore.pbobjc.h" - -namespace firebase { -namespace firestore { -namespace remote { - -using auth::CredentialsProvider; -using auth::Token; -using model::TargetId; -using util::AsyncQueue; -using util::TimerId; -using util::Status; - -WatchStream::WatchStream(AsyncQueue* async_queue, - CredentialsProvider* credentials_provider, - FSTSerializerBeta* serializer, - GrpcConnection* grpc_connection, - WatchStreamCallback* callback) - : Stream{async_queue, credentials_provider, grpc_connection, - TimerId::ListenStreamConnectionBackoff, TimerId::ListenStreamIdle}, - serializer_bridge_{serializer}, - callback_{NOT_NULL(callback)} { -} - -void WatchStream::WatchQuery(FSTQueryData* query) { - EnsureOnQueue(); - - GCFSListenRequest* request = serializer_bridge_.CreateWatchRequest(query); - LOG_DEBUG("%s watch: %s", GetDebugDescription(), - serializer_bridge_.Describe(request)); - Write(serializer_bridge_.ToByteBuffer(request)); -} - -void WatchStream::UnwatchTargetId(TargetId target_id) { - EnsureOnQueue(); - - GCFSListenRequest* request = - serializer_bridge_.CreateUnwatchRequest(target_id); - LOG_DEBUG("%s unwatch: %s", GetDebugDescription(), - serializer_bridge_.Describe(request)); - Write(serializer_bridge_.ToByteBuffer(request)); -} - -std::unique_ptr WatchStream::CreateGrpcStream( - GrpcConnection* grpc_connection, const Token& token) { - return grpc_connection->CreateStream("/google.firestore.v1.Firestore/Listen", - token, this); -} - -void WatchStream::TearDown(GrpcStream* grpc_stream) { - grpc_stream->FinishImmediately(); -} - -void WatchStream::NotifyStreamOpen() { - callback_->OnWatchStreamOpen(); -} - -Status WatchStream::NotifyStreamResponse(const grpc::ByteBuffer& message) { - Status status; - GCFSListenResponse* response = - serializer_bridge_.ParseResponse(message, &status); - if (!status.ok()) { - return status; - } - - if (bridge::IsLoggingEnabled()) { - LOG_DEBUG("%s response: %s", GetDebugDescription(), - serializer_bridge_.Describe(response)); - } - - // A successful response means the stream is healthy. - backoff_.Reset(); - - callback_->OnWatchStreamChange( - *serializer_bridge_.ToWatchChange(response), - serializer_bridge_.ToSnapshotVersion(response)); - return Status::OK(); -} - -void WatchStream::NotifyStreamClose(const Status& status) { - callback_->OnWatchStreamClose(status); -} - -} // namespace remote -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/write_stream.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/write_stream.cc new file mode 100644 index 0000000..dedbf3d --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/write_stream.cc @@ -0,0 +1,156 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#include + +#include "Firestore/core/src/firebase/firestore/remote/write_stream.h" + +#include "Firestore/core/src/firebase/firestore/nanopb/message.h" +#include "Firestore/core/src/firebase/firestore/nanopb/reader.h" +#include "Firestore/core/src/firebase/firestore/remote/grpc_nanopb.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" + +namespace firebase { +namespace firestore { +namespace remote { + +using auth::CredentialsProvider; +using auth::Token; +using model::Mutation; +using nanopb::ByteString; +using nanopb::Message; +using remote::ByteBufferReader; +using util::AsyncQueue; +using util::Status; +using util::TimerId; + +WriteStream::WriteStream( + const std::shared_ptr& async_queue, + std::shared_ptr credentials_provider, + Serializer serializer, + GrpcConnection* grpc_connection, + WriteStreamCallback* callback) + : Stream{async_queue, std::move(credentials_provider), grpc_connection, + TimerId::WriteStreamConnectionBackoff, TimerId::WriteStreamIdle}, + write_serializer_{std::move(serializer)}, + callback_{NOT_NULL(callback)} { +} + +void WriteStream::set_last_stream_token(ByteString token) { + last_stream_token_ = std::move(token); +} + +const ByteString& WriteStream::last_stream_token() const { + return last_stream_token_; +} + +void WriteStream::WriteHandshake() { + EnsureOnQueue(); + HARD_ASSERT(IsOpen(), "Writing handshake requires an opened stream"); + HARD_ASSERT(!handshake_complete(), "Handshake already completed"); + + auto request = write_serializer_.EncodeHandshake(); + LOG_DEBUG("%s initial request: %s", GetDebugDescription(), + request.ToString()); + Write(MakeByteBuffer(request)); + + // TODO(dimond): Support stream resumption. We intentionally do not set the + // stream token on the handshake, ignoring any stream token we might have. +} + +void WriteStream::WriteMutations(const std::vector& mutations) { + EnsureOnQueue(); + HARD_ASSERT(IsOpen(), "Writing mutations requires an opened stream"); + HARD_ASSERT(handshake_complete(), + "Handshake must be complete before writing mutations"); + + auto request = write_serializer_.EncodeWriteMutationsRequest( + mutations, last_stream_token()); + LOG_DEBUG("%s write request: %s", GetDebugDescription(), request.ToString()); + Write(MakeByteBuffer(request)); +} + +std::unique_ptr WriteStream::CreateGrpcStream( + GrpcConnection* grpc_connection, const Token& token) { + return grpc_connection->CreateStream("/google.firestore.v1.Firestore/Write", + token, this); +} + +void WriteStream::TearDown(GrpcStream* grpc_stream) { + if (handshake_complete()) { + // Send an empty write request to the backend to indicate imminent stream + // closure. This isn't mandatory, but it allows the backend to clean up + // resources. + auto request = + write_serializer_.EncodeEmptyMutationsList(last_stream_token()); + grpc_stream->WriteAndFinish(MakeByteBuffer(request)); + } else { + grpc_stream->FinishImmediately(); + } +} + +void WriteStream::NotifyStreamOpen() { + callback_->OnWriteStreamOpen(); +} + +void WriteStream::NotifyStreamClose(const Status& status) { + callback_->OnWriteStreamClose(status); + // Delegate's logic might depend on whether handshake was completed, so only + // reset it after notifying. + handshake_complete_ = false; +} + +Status WriteStream::NotifyStreamResponse(const grpc::ByteBuffer& message) { + ByteBufferReader reader{message}; + Message response = + write_serializer_.ParseResponse(&reader); + if (!reader.ok()) { + return reader.status(); + } + + LOG_DEBUG("%s response: %s", GetDebugDescription(), response.ToString()); + + // Always capture the last stream token. + set_last_stream_token(ByteString::Take(response->stream_token)); + response->stream_token = nullptr; + + if (!handshake_complete()) { + // The first response is the handshake response + handshake_complete_ = true; + callback_->OnWriteStreamHandshakeComplete(); + } else { + // A successful first write response means the stream is healthy. + // Note that we could consider a successful handshake healthy, however, the + // write itself might be causing an error we want to back off from. + backoff_.Reset(); + + auto version = write_serializer_.DecodeCommitVersion(&reader, *response); + auto results = write_serializer_.DecodeMutationResults(&reader, *response); + if (!reader.ok()) { + return reader.status(); + } + + callback_->OnWriteStreamMutationResult(version, results); + } + + return Status::OK(); +} + +} // namespace remote +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/write_stream.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/write_stream.h index bfa7530..39c6174 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/write_stream.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/write_stream.h @@ -17,11 +17,6 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_WRITE_STREAM_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_WRITE_STREAM_H_ -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import #include #include #include @@ -31,22 +26,20 @@ #include "Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h" #include "Firestore/core/src/firebase/firestore/remote/stream.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "absl/strings/string_view.h" #include "grpcpp/support/byte_buffer.h" -#import "Firestore/Source/Core/FSTTypes.h" -#import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Remote/FSTSerializerBeta.h" - -@class FSTMutationResult; - namespace firebase { namespace firestore { namespace remote { +class Serializer; + class WriteStreamCallback { public: + virtual ~WriteStreamCallback() = default; + /** * Called by the `WriteStream` when it is ready to accept outbound request * messages. @@ -65,7 +58,7 @@ class WriteStreamCallback { */ virtual void OnWriteStreamMutationResult( model::SnapshotVersion commit_version, - std::vector results) = 0; + std::vector results) = 0; /** * Called when the `WriteStream`'s underlying RPC is interrupted for whatever @@ -99,13 +92,13 @@ class WriteStreamCallback { */ class WriteStream : public Stream { public: - WriteStream(util::AsyncQueue* async_queue, - auth::CredentialsProvider* credentials_provider, - FSTSerializerBeta* serializer, + WriteStream(const std::shared_ptr& async_queue, + std::shared_ptr credentials_provider, + Serializer serializer, GrpcConnection* grpc_connection, WriteStreamCallback* callback); - void SetLastStreamToken(NSData* token); + void set_last_stream_token(nanopb::ByteString token); /** * The last received stream token from the server, used to acknowledge which * responses the client has processed. Stream tokens are opaque checkpoint @@ -114,7 +107,7 @@ class WriteStream : public Stream { * `WriteStream` manages propagating this value from responses to the * next request. */ - NSData* GetLastStreamToken() const; + const nanopb::ByteString& last_stream_token() const; /** * Tracks whether or not a handshake has been successfully exchanged and @@ -131,7 +124,7 @@ class WriteStream : public Stream { virtual void WriteHandshake(); /** Sends a group of mutations to the Firestore backend to apply. */ - virtual void WriteMutations(const std::vector& mutations); + virtual void WriteMutations(const std::vector& mutations); protected: // For tests only @@ -152,9 +145,10 @@ class WriteStream : public Stream { return "WriteStream"; } - bridge::WriteStreamSerializer serializer_bridge_; + WriteStreamSerializer write_serializer_; WriteStreamCallback* callback_ = nullptr; bool handshake_complete_ = false; + nanopb::ByteString last_stream_token_; }; } // namespace remote diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/write_stream.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/write_stream.mm deleted file mode 100644 index 7e0513a..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/remote/write_stream.mm +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/remote/write_stream.h" - -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/log.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" - -#import "Firestore/Protos/objc/google/firestore/v1/Firestore.pbobjc.h" - -namespace firebase { -namespace firestore { -namespace remote { - -using auth::CredentialsProvider; -using auth::Token; -using util::AsyncQueue; -using util::TimerId; -using util::Status; - -WriteStream::WriteStream(AsyncQueue* async_queue, - CredentialsProvider* credentials_provider, - FSTSerializerBeta* serializer, - GrpcConnection* grpc_connection, - WriteStreamCallback* callback) - : Stream{async_queue, credentials_provider, grpc_connection, - TimerId::WriteStreamConnectionBackoff, TimerId::WriteStreamIdle}, - serializer_bridge_{serializer}, - callback_{NOT_NULL(callback)} { -} - -void WriteStream::SetLastStreamToken(NSData* token) { - serializer_bridge_.SetLastStreamToken(token); -} - -NSData* WriteStream::GetLastStreamToken() const { - return serializer_bridge_.GetLastStreamToken(); -} - -void WriteStream::WriteHandshake() { - EnsureOnQueue(); - HARD_ASSERT(IsOpen(), "Writing handshake requires an opened stream"); - HARD_ASSERT(!handshake_complete(), "Handshake already completed"); - - GCFSWriteRequest* request = serializer_bridge_.CreateHandshake(); - LOG_DEBUG("%s initial request: %s", GetDebugDescription(), - serializer_bridge_.Describe(request)); - Write(serializer_bridge_.ToByteBuffer(request)); - - // TODO(dimond): Support stream resumption. We intentionally do not set the - // stream token on the handshake, ignoring any stream token we might have. -} - -void WriteStream::WriteMutations(const std::vector& mutations) { - EnsureOnQueue(); - HARD_ASSERT(IsOpen(), "Writing mutations requires an opened stream"); - HARD_ASSERT(handshake_complete(), - "Handshake must be complete before writing mutations"); - - GCFSWriteRequest* request = - serializer_bridge_.CreateWriteMutationsRequest(mutations); - LOG_DEBUG("%s write request: %s", GetDebugDescription(), - serializer_bridge_.Describe(request)); - Write(serializer_bridge_.ToByteBuffer(request)); -} - -std::unique_ptr WriteStream::CreateGrpcStream( - GrpcConnection* grpc_connection, const Token& token) { - return grpc_connection->CreateStream("/google.firestore.v1.Firestore/Write", - token, this); -} - -void WriteStream::TearDown(GrpcStream* grpc_stream) { - if (handshake_complete()) { - // Send an empty write request to the backend to indicate imminent stream - // closure. This isn't mandatory, but it allows the backend to clean up - // resources. - GCFSWriteRequest* request = serializer_bridge_.CreateEmptyMutationsList(); - grpc_stream->WriteAndFinish(serializer_bridge_.ToByteBuffer(request)); - } else { - grpc_stream->FinishImmediately(); - } -} - -void WriteStream::NotifyStreamOpen() { - callback_->OnWriteStreamOpen(); -} - -void WriteStream::NotifyStreamClose(const Status& status) { - callback_->OnWriteStreamClose(status); - // Delegate's logic might depend on whether handshake was completed, so only - // reset it after notifying. - handshake_complete_ = false; -} - -Status WriteStream::NotifyStreamResponse(const grpc::ByteBuffer& message) { - Status status; - GCFSWriteResponse* response = - serializer_bridge_.ParseResponse(message, &status); - if (!status.ok()) { - return status; - } - - LOG_DEBUG("%s response: %s", GetDebugDescription(), - serializer_bridge_.Describe(response)); - - // Always capture the last stream token. - serializer_bridge_.UpdateLastStreamToken(response); - - if (!handshake_complete()) { - // The first response is the handshake response - handshake_complete_ = true; - callback_->OnWriteStreamHandshakeComplete(); - } else { - // A successful first write response means the stream is healthy. - // Note that we could consider a successful handshake healthy, however, the - // write itself might be causing an error we want to back off from. - backoff_.Reset(); - - callback_->OnWriteStreamMutationResult( - serializer_bridge_.ToCommitVersion(response), - serializer_bridge_.ToMutationResults(response)); - } - - return Status::OK(); -} - -} // namespace remote -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/timestamp.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/timestamp.cc index 50ddec6..2ba3d88 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/timestamp.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/timestamp.cc @@ -18,27 +18,72 @@ #include +#if defined(__APPLE__) +#import +#elif defined(_STLPORT_VERSION) +#include +#endif + #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "absl/strings/str_cat.h" namespace firebase { -Timestamp::Timestamp() { +namespace { + +constexpr int32_t kNanosPerSecond = 1000 * 1000 * 1000; + +/** + * Creates a `Timestamp` from the given non-normalized inputs. + * + * Timestamp protos require `Timestamp` to always has a positive number of + * nanoseconds that is counting forward. For negative time, we need to adjust + * representations with negative nanoseconds. That is, make (negative seconds s1 + * + negative nanoseconds ns1) into (negative seconds s2 + positive nanoseconds + * ns2). Since nanosecond part is always less than 1 second in our + * representation, instead of starting at s1 and going back ns1 nanoseconds, + * start at (s1 minus one second) and go *forward* ns2 = (1 second + ns1, ns1 < + * 0) nanoseconds. + */ +Timestamp MakeNormalizedTimestamp(int64_t seconds, int64_t nanos) { + if (nanos < 0) { + // Note: if nanoseconds are negative, it must mean that seconds are + // non-positive, but the formula would still be valid, so no need to check. + seconds = seconds - 1; + nanos = kNanosPerSecond + nanos; + } + + HARD_ASSERT(nanos < kNanosPerSecond); + + return {seconds, static_cast(nanos)}; } -Timestamp::Timestamp(const int64_t seconds, const int32_t nanoseconds) +} // namespace + +Timestamp::Timestamp(int64_t seconds, int32_t nanoseconds) : seconds_(seconds), nanoseconds_(nanoseconds) { ValidateBounds(); } Timestamp Timestamp::Now() { -#if !defined(_STLPORT_VERSION) +#if defined(__APPLE__) + // Originally, FIRTimestamp used NSDate to get current time. This method + // preserves the lower accuracy of that method. + CFAbsoluteTime now = + CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970; + double seconds_double; + double fraction = modf(now, &seconds_double); + auto seconds = static_cast(seconds_double); + auto nanos = static_cast(fraction * kNanosPerSecond); + return MakeNormalizedTimestamp(seconds, nanos); + +#elif !defined(_STLPORT_VERSION) // Use the standard library from C++11 if possible. return FromTimePoint(std::chrono::system_clock::now()); #else - // If is unavailable, use clock_gettime from POSIX, which supports up - // to nanosecond resolution. Note that it's a non-standard function contained - // in . + // If is unavailable, use clock_gettime from POSIX, which supports + // up to nanosecond resolution. Note that it's a non-standard function + // contained in . // // Note: it's possible to check for availability of POSIX clock_gettime using // macros (see "Availability" at https://linux.die.net/man/3/clock_gettime). @@ -46,7 +91,7 @@ Timestamp Timestamp::Now() { // STLPort standard library, where clock_gettime is known to be available. timespec now; clock_gettime(CLOCK_REALTIME, &now); - return Timestamp(now.tv_sec, now.tv_nsec); + return MakeNormalizedTimestamp(now.tv_sec, now.tv_nsec); #endif // !defined(_STLPORT_VERSION) } @@ -60,26 +105,9 @@ Timestamp Timestamp::FromTimePoint( namespace chr = std::chrono; const auto epoch_time = time_point.time_since_epoch(); auto seconds = chr::duration_cast>(epoch_time); - auto nanoseconds = chr::duration_cast(epoch_time - seconds); - HARD_ASSERT(nanoseconds.count() < 1 * 1000 * 1000 * 1000); - - if (nanoseconds.count() < 0) { - // Timestamp format always has a positive number of nanoseconds that is - // counting forward. For negative time, we need to transform chrono - // representation of (negative seconds s1 + negative nanoseconds ns1) to - // (negative seconds s2 + positive nanoseconds ns2). Since nanosecond part - // is always less than 1 second in our representation, instead of starting - // at s1 and going back ns1 nanoseconds, start at (s1 minus one second) and - // go *forward* ns2 = (1 second + ns1, ns1 < 0) nanoseconds. - // - // Note: if nanoseconds are negative, it must mean that seconds are - // non-positive, but the formula would still be valid, so no need to check. - seconds = seconds - chr::seconds(1); - nanoseconds = chr::seconds(1) + nanoseconds; - } + auto nanos = chr::duration_cast(epoch_time - seconds); - const Timestamp result{seconds.count(), - static_cast(nanoseconds.count())}; + Timestamp result = MakeNormalizedTimestamp(seconds.count(), nanos.count()); result.ValidateBounds(); return result; } @@ -98,8 +126,8 @@ std::ostream& operator<<(std::ostream& out, const Timestamp& timestamp) { void Timestamp::ValidateBounds() const { HARD_ASSERT(nanoseconds_ >= 0, "Timestamp nanoseconds out of range: %s", nanoseconds_); - HARD_ASSERT(nanoseconds_ < 1e9, "Timestamp nanoseconds out of range: %s", - nanoseconds_); + HARD_ASSERT(nanoseconds_ < kNanosPerSecond, + "Timestamp nanoseconds out of range: %s", nanoseconds_); // Midnight at the beginning of 1/1/1 is the earliest timestamp Firestore // supports. HARD_ASSERT(seconds_ >= -62135596800L, "Timestamp seconds out of range: %s", @@ -110,13 +138,3 @@ void Timestamp::ValidateBounds() const { } } // namespace firebase - -namespace std { -size_t hash::operator()( - const firebase::Timestamp& timestamp) const { - // Note: if sizeof(size_t) == 4, this discards high-order bits of seconds. - return 37 * static_cast(timestamp.seconds()) + - static_cast(timestamp.nanoseconds()); -} - -} // namespace std diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/timestamp_internal.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/timestamp_internal.cc new file mode 100644 index 0000000..478498b --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/timestamp_internal.cc @@ -0,0 +1,34 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/timestamp_internal.h" + +#include "Firestore/core/src/firebase/firestore/util/hashing.h" + +namespace util = firebase::firestore::util; + +namespace firebase { + +size_t TimestampInternal::Hash(const Timestamp& timestamp) { + return util::Hash(timestamp.seconds(), timestamp.nanoseconds()); +} + +Timestamp TimestampInternal::Truncate(const Timestamp& timestamp) { + int32_t truncated_nanos = timestamp.nanoseconds() / 1000 * 1000; + return Timestamp(timestamp.seconds(), truncated_nanos); +} + +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/timestamp_internal.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/timestamp_internal.h index 3516176..3130ccd 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/timestamp_internal.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/timestamp_internal.h @@ -42,6 +42,14 @@ class TimestampInternal { static firebase::Timestamp Min() { return {-62135596800L, 0}; } + + static size_t Hash(const Timestamp& timestamp); + + /** + * Truncates the input timestamp to microsecond precision to match backend + * behavior. + */ + static Timestamp Truncate(const Timestamp& timestamp); }; } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/async_queue.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/async_queue.cc index 3b8c3c8..d75be36 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/async_queue.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/async_queue.cc @@ -19,12 +19,20 @@ #include #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "absl/algorithm/container.h" #include "absl/memory/memory.h" namespace firebase { namespace firestore { namespace util { +std::shared_ptr AsyncQueue::Create( + std::unique_ptr executor) { + // Use new because make_shared cannot access a private constructor. + auto queue = new AsyncQueue(std::move(executor)); + return std::shared_ptr(queue); +} + AsyncQueue::AsyncQueue(std::unique_ptr executor) : executor_{std::move(executor)} { is_operation_in_progress_ = false; @@ -49,6 +57,10 @@ void AsyncQueue::VerifyIsCurrentQueue() const { } void AsyncQueue::ExecuteBlocking(const Operation& operation) { + // This is not guarded by `is_shutting_down_` because it is the execution + // of the operation, not scheduling. Checking `is_shutting_down_` here + // would mean *all* operations will not run after shutdown, which is not + // intended. VerifyIsCurrentExecutor(); HARD_ASSERT(!is_operation_in_progress_, "ExecuteBlocking may not be called " @@ -64,20 +76,48 @@ void AsyncQueue::Enqueue(const Operation& operation) { EnqueueRelaxed(operation); } +void AsyncQueue::EnqueueAndInitiateShutdown(const Operation& operation) { + std::lock_guard lock{shut_down_mutex_}; + VerifySequentialOrder(); + + is_shutting_down_ = true; + executor_->Execute(Wrap(operation)); +} + +void AsyncQueue::EnqueueEvenAfterShutdown(const Operation& operation) { + // Still guarding the lock to ensure sequential scheduling. + std::lock_guard lock{shut_down_mutex_}; + VerifySequentialOrder(); + executor_->Execute(Wrap(operation)); +} + +bool AsyncQueue::is_shutting_down() const { + std::lock_guard lock{shut_down_mutex_}; + return is_shutting_down_; +} + void AsyncQueue::EnqueueRelaxed(const Operation& operation) { + std::lock_guard lock{shut_down_mutex_}; + if (is_shutting_down_) { + return; + } executor_->Execute(Wrap(operation)); } -DelayedOperation AsyncQueue::EnqueueAfterDelay(const Milliseconds delay, +DelayedOperation AsyncQueue::EnqueueAfterDelay(Milliseconds delay, const TimerId timer_id, const Operation& operation) { + std::lock_guard lock{shut_down_mutex_}; VerifyIsCurrentExecutor(); - // While not necessarily harmful, we currently don't expect to have multiple - // callbacks with the same timer_id in the queue, so defensively reject - // them. - HARD_ASSERT(!IsScheduled(timer_id), - "Attempted to schedule multiple operations with id %s", timer_id); + if (is_shutting_down_) { + return DelayedOperation(); + } + + // Skip delays for timer_ids that have been overridden + if (absl::c_linear_search(timer_ids_to_skip_, timer_id)) { + delay = Milliseconds(0); + } Executor::TaggedOperation tagged{static_cast(timer_id), Wrap(operation)}; return executor_->Schedule(delay, std::move(tagged)); @@ -88,7 +128,8 @@ AsyncQueue::Operation AsyncQueue::Wrap(const Operation& operation) { // ensure that it doesn't spawn any nested operations. // Note: can't move `operation` into lambda until C++14. - return [this, operation] { ExecuteBlocking(operation); }; + auto shared_this = shared_from_this(); + return [shared_this, operation] { shared_this->ExecuteBlocking(operation); }; } void AsyncQueue::VerifySequentialOrder() const { @@ -131,6 +172,10 @@ void AsyncQueue::RunScheduledOperationsUntil(const TimerId last_timer_id) { }); } +void AsyncQueue::SkipDelaysForTimerId(TimerId timer_id) { + timer_ids_to_skip_.push_back(timer_id); +} + } // namespace util } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/async_queue.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/async_queue.h index e3971ee..a68a8c0 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/async_queue.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/async_queue.h @@ -21,6 +21,8 @@ #include // NOLINT(build/c++11) #include #include +#include // NOLINT(build/c++11) +#include #include "Firestore/core/src/firebase/firestore/util/executor.h" @@ -54,10 +56,17 @@ enum class TimerId { * indefinitely for success or failure. */ OnlineStateTimeout, + /** * A timer used to periodically attempt LRU Garbage collection */ - GarbageCollectionDelay + GarbageCollectionDelay, + + /** + * A timer used to retry transactions. Since there can be multiple concurrent + * transactions, multiple of these may be in the queue at a given time. + */ + RetryTransaction }; // A serial queue that executes given operations asynchronously, one at a time. @@ -75,12 +84,12 @@ enum class TimerId { // // A significant portion of `AsyncQueue` interface only exists for test purposes // and must *not* be used in regular code. -class AsyncQueue { +class AsyncQueue : public std::enable_shared_from_this { public: using Operation = Executor::Operation; using Milliseconds = Executor::Milliseconds; - explicit AsyncQueue(std::unique_ptr executor); + static std::shared_ptr Create(std::unique_ptr executor); // Asserts for the caller that it is being invoked as part of an operation on // the `AsyncQueue`. @@ -95,11 +104,28 @@ class AsyncQueue { // be called by a previously enqueued operation when it is run (as a special // case, destructors invoked when an enqueued operation has run and is being // destroyed may invoke `Enqueue`). + // + // After the shutdown process has initiated (`is_shutting_down()` is true), + // calling `Enqueue` is a no-op. void Enqueue(const Operation& operation); + // Like `Enqueue`, but also starts the shutdown process. Once the shutdown + // process has started, calling any Enqueue* methods becomes a no-op + // + // The exception is `EnqueueEvenAfterShutdown`, operations requsted via + // this will still be scheduled. + void EnqueueAndInitiateShutdown(const Operation& operation); + + // Like `Enqueue`, but it will proceed scheduling the requested operation + // regardless of whether the queue is shut down or not. + void EnqueueEvenAfterShutdown(const Operation& operation); + // Like `Enqueue`, but without applying any prerequisite checks. void EnqueueRelaxed(const Operation& operation); + // Whether the queue has initiated its shutdown process. + bool is_shutting_down() const; + // Puts the `operation` on the queue to be executed `delay` milliseconds from // now, and returns a handle that allows to cancel the operation (provided it // hasn't run already). @@ -155,7 +181,13 @@ class AsyncQueue { // queue. void RunScheduledOperationsUntil(TimerId last_timer_id); + // For tests: Skip all subsequent delays for a specific TimerId. + // NOTE: This does not work with TimerId::All. + void SkipDelaysForTimerId(TimerId timer_id); + private: + explicit AsyncQueue(std::unique_ptr executor); + Operation Wrap(const Operation& operation); // Asserts that the current invocation happens asynchronously on the queue. @@ -164,6 +196,11 @@ class AsyncQueue { std::atomic is_operation_in_progress_; std::unique_ptr executor_; + + bool is_shutting_down_ = false; + mutable std::mutex shut_down_mutex_; + + std::vector timer_ids_to_skip_; }; } // namespace util diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/bits.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/bits.h index 591c306..2ed4f6c 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/bits.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/bits.h @@ -24,6 +24,24 @@ #include +#if _MSC_VER +// The Microsoft implementation of iso646.h defines alternative operator names +// as macros and this interferes with the inline assembly, below, which uses the +// `and` and `xor` instructions. Defining these as macros is conforming behavior +// for C but not C++, where these are keywords. +// +// Unfortunately, fixing this by undefining the macros can't be enabled +// everywhere because other compilers (e.g. Clang) specifically prevent the use +// of these keywords as macro names. +#ifdef and +#undef and +#endif + +#ifdef xor +#undef xor +#endif +#endif // _MSC_VER + namespace firebase { namespace firestore { namespace util { diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/comparator_holder.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/comparator_holder.h deleted file mode 100644 index 3147117..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/comparator_holder.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_COMPARATOR_HOLDER_H_ -#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_COMPARATOR_HOLDER_H_ - -#include - -namespace firebase { -namespace firestore { -namespace util { - -/** - * A holder of some comparator (e.g. std::less or util::Comparator) that - * implements the empty base optimization for the common case where the - * comparator occupies no storage. - */ -template ::value> -class ComparatorHolder { - protected: - explicit ComparatorHolder(const C& comparator) noexcept - : comparator_(comparator) { - } - - public: - const C& comparator() const noexcept { - return comparator_; - } - - private: - C comparator_; -}; - -// Implementation to use when C is empty. -template -class ComparatorHolder : private C { - protected: - explicit ComparatorHolder(const C& /* comparator */) noexcept { - } - - public: - const C& comparator() const noexcept { - return *this; - } -}; - -} // namespace util -} // namespace firestore -} // namespace firebase - -#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_COMPARATOR_HOLDER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/comparison.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/comparison.cc index 0e7fe25..e0bba2c 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/comparison.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/comparison.cc @@ -16,35 +16,60 @@ #include "Firestore/core/src/firebase/firestore/util/comparison.h" +#include #include +#include #include +#include "absl/base/casts.h" + namespace firebase { namespace firestore { namespace util { using std::isnan; -bool Comparator::operator()(absl::string_view left, - absl::string_view right) const { - // TODO(wilhuff): truncation aware comparison - return left < right; +/** + * Creates a ComparisonResult from a typical integer return value, where + * 0 means "same", less than zero means "ascending", and greater than zero + * means "descending". + */ +constexpr ComparisonResult ComparisonResultFromInt(int value) { + // TODO(c++14): convert this to an if statement. + return value < 0 ? ComparisonResult::Ascending + : (value > 0 ? ComparisonResult::Descending + : ComparisonResult::Same); +} + +ComparisonResult Comparator::Compare( + absl::string_view left, absl::string_view right) const { + return ComparisonResultFromInt(left.compare(right)); } -bool Comparator::operator()(const std::string& left, - const std::string& right) const { - // TODO(wilhuff): truncation aware comparison - return left < right; +ComparisonResult Comparator::Compare( + const std::string& left, const std::string& right) const { + return ComparisonResultFromInt(left.compare(right)); } -bool Comparator::operator()(double left, double right) const { +ComparisonResult Comparator::Compare(double left, double right) const { // NaN sorts equal to itself and before any other number. if (left < right) { - return true; - } else if (left >= right) { - return false; + return ComparisonResult::Ascending; + } else if (left > right) { + return ComparisonResult::Descending; + } else if (left == right) { + return ComparisonResult::Same; } else { // One or both left and right is NaN. - return isnan(left) && !isnan(right); + if (!isnan(right)) { + // Only left is NaN. + return ComparisonResult::Ascending; + } else if (!isnan(left)) { + // Only right is NaN. + return ComparisonResult::Descending; + } else { + // Both are NaN. + return ComparisonResult::Same; + } } } @@ -93,13 +118,7 @@ uint64_t DoubleBits(double d) { d = NAN; } - // Unlike C, C++ does not define type punning through a union type. - - // TODO(wilhuff): replace with absl::bit_cast - static_assert(sizeof(double) == sizeof(uint64_t), "doubles must be 8 bytes"); - uint64_t bits; - memcpy(&bits, &d, sizeof(bits)); - return bits; + return absl::bit_cast(d); } bool DoubleBitwiseEquals(double left, double right) { diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/comparison.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/comparison.h index 98262fc..62aced9 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/comparison.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/comparison.h @@ -26,9 +26,10 @@ #include #include #include +#include #include -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" +#include "absl/meta/type_traits.h" #include "absl/strings/string_view.h" namespace firebase { @@ -59,6 +60,18 @@ enum class ComparisonResult { Descending = 1 }; +constexpr bool Ascending(ComparisonResult result) noexcept { + return result == ComparisonResult::Ascending; +} + +constexpr bool Same(ComparisonResult result) noexcept { + return result == ComparisonResult::Same; +} + +constexpr bool Descending(ComparisonResult result) noexcept { + return result == ComparisonResult::Descending; +} + /** * Returns the reverse order (i.e. Ascending => Descending) etc. */ @@ -66,80 +79,120 @@ constexpr ComparisonResult ReverseOrder(ComparisonResult result) { return static_cast(-static_cast(result)); } +#if __OBJC__ +/** + * Returns true if the given ComparisonResult and NSComparisonResult have the + * same integer values (at compile time). + */ +constexpr bool EqualValue(ComparisonResult lhs, NSComparisonResult rhs) { + return static_cast(lhs) == static_cast(rhs); +} + +static_assert(EqualValue(ComparisonResult::Ascending, NSOrderedAscending), + "Ascending invalid"); +static_assert(EqualValue(ComparisonResult::Same, NSOrderedSame), + "Same invalid"); +static_assert(EqualValue(ComparisonResult::Descending, NSOrderedDescending), + "Descending invalid"); + +/** Converts NSComparisonResult to ComparisonResult. */ +constexpr ComparisonResult MakeComparisonResult(NSComparisonResult value) { + return static_cast(value); +} + +/** Converts ComparisonResult to NSComparisonResult. */ +constexpr NSComparisonResult MakeNSComparisonResult(ComparisonResult value) { + return static_cast(value); +} +#endif // __OBJC__ + /** * A generalized comparator for types in Firestore, with ordering defined - * according to Firestore's semantics. This is useful as argument to e.g. - * std::sort. + * according to Firestore's semantics. * - * Comparators are only defined for the limited set of types for which - * Firestore defines an ordering. + * How a given type is compared depends on the type itself: + * + * - (Objective-C++-only) If T* is an Objective-C object pointer then + * invokes the `-compare:` member. Note that if T does not actually define + * `-compare:` this will fail. This is unconditional this way because no + * other alternative is valid for pointer types. + * + * - If T defines a `CompareTo(T) const` member function, then Compare will + * invoke `lhs.CompareTo(rhs)`. + * + * - Otherwise, invokes `DefaultCompare(lhs, rhs)`. */ template -struct Comparator { - // By default comparison is not defined +struct Comparator; + +template +struct DefaultComparator { + ComparisonResult Compare(const T& left, const T& right) const { + if (left < right) { + return ComparisonResult::Ascending; + } else if (right < left) { + return ComparisonResult::Descending; + } else { + return ComparisonResult::Same; + } + } }; /** Compares two strings. */ template <> struct Comparator { - bool operator()(absl::string_view left, absl::string_view right) const; + ComparisonResult Compare(absl::string_view left, + absl::string_view right) const; }; template <> struct Comparator { - bool operator()(const std::string& left, const std::string& right) const; + Comparator() = default; + // GCC 4.8.5 has trouble implicitly generating copy operations (`=default` + // doesn't work as well). + Comparator(const Comparator&) { + } + Comparator& operator=(const Comparator&) { + return *this; + } + + ComparisonResult Compare(const std::string& left, + const std::string& right) const; }; /** Compares two bools: false < true. */ template <> -struct Comparator : public std::less {}; +struct Comparator : public DefaultComparator {}; /** Compares two int32_t. */ template <> -struct Comparator : public std::less {}; +struct Comparator : public DefaultComparator {}; /** Compares two int64_t. */ template <> -struct Comparator : public std::less {}; +struct Comparator : public DefaultComparator {}; /** Compares two doubles (using Firestore semantics for NaN). */ template <> struct Comparator { - bool operator()(double left, double right) const; + ComparisonResult Compare(double left, double right) const; }; -/** Compare two byte sequences. */ -// TODO(wilhuff): perhaps absl::Span would be better? -template <> -struct Comparator> - : public std::less> {}; - /** * Perform a three-way comparison between the left and right values using * the appropriate Comparator for the values based on their type. + * + * Essentially a shortcut for Comparator().Compare(left, right), where + * Comparator is default constructible. */ template > ComparisonResult Compare(const T& left, const T& right, - const C& less_than = C()) { - if (less_than(left, right)) { - return ComparisonResult::Ascending; - } else if (less_than(right, left)) { - return ComparisonResult::Descending; - } else { - return ComparisonResult::Same; - } + const C& comparator = C()) { + return comparator.Compare(left, right); } #if __OBJC__ -/** - * Returns true if the given ComparisonResult and NSComparisonResult have the - * same integer values (at compile time). - */ -constexpr bool EqualValue(ComparisonResult lhs, NSComparisonResult rhs) { - return static_cast(lhs) == static_cast(rhs); -} - /** * Performs a three-way comparison, identically to Compare, but converts the * result to an NSComparisonResult. @@ -149,19 +202,98 @@ constexpr bool EqualValue(ComparisonResult lhs, NSComparisonResult rhs) { */ template inline NSComparisonResult WrapCompare(const T& left, const T& right) { - static_assert(EqualValue(ComparisonResult::Ascending, NSOrderedAscending), - "Ascending invalid"); - static_assert(EqualValue(ComparisonResult::Same, NSOrderedSame), - "Same invalid"); - static_assert(EqualValue(ComparisonResult::Descending, NSOrderedDescending), - "Descending invalid"); - - return static_cast(Compare(left, right)); + return MakeNSComparisonResult(Compare(left, right)); +} +#endif // __OBJC__ + +namespace impl { + +/** + * Checks wither the type T has a `CompareTo` member. + */ +template > +struct has_compare_to : public std::false_type {}; + +template +struct has_compare_to< + T, + absl::void_t().CompareTo(std::declval()))>> + : public std::true_type {}; + +/** + * Implements ranked choice among overloads below. + */ +template +struct CompareChoice : CompareChoice {}; + +template <> +struct CompareChoice<2> {}; + +// Use a `CompareTo` member, if available +template ::value>> +ComparisonResult CompareImpl(const T& lhs, const T& rhs, CompareChoice<1>) { + return lhs.CompareTo(rhs); +} + +// Otherwise, fall back on less than. +template +ComparisonResult CompareImpl(const T& lhs, const T& rhs, CompareChoice<2>) { + DefaultComparator comparator; + return comparator.Compare(lhs, rhs); +} + +} // namespace impl + +template +struct Comparator { + ComparisonResult Compare(const T& lhs, const T& rhs) const { + return impl::CompareImpl(lhs, rhs, impl::CompareChoice<0>{}); + } +}; + +/** + * A Comparator whose behavior is defined by a std::function. + */ +template +class FunctionComparator { + public: + using ComparisonFunction = + std::function; + + explicit FunctionComparator(ComparisonFunction&& function) + : function_(std::move(function)) { + } + + ComparisonResult Compare(const T& lhs, const T& rhs) const { + return function_(lhs, rhs); + } + + private: + ComparisonFunction function_; +}; + +template +ComparisonResult CompareContainer(const T& lhs, const T& rhs) { + auto lhs_iter = lhs.begin(); + auto lhs_end = lhs.end(); + auto rhs_iter = rhs.begin(); + auto rhs_end = rhs.end(); + + while (lhs_iter != lhs_end && rhs_iter != rhs_end) { + ComparisonResult cmp = Compare(*lhs_iter, *rhs_iter); + if (!Same(cmp)) return cmp; + + ++lhs_iter; + ++rhs_iter; + } + + if (rhs_iter != rhs_end) return ComparisonResult::Ascending; + if (lhs_iter != lhs_end) return ComparisonResult::Descending; + return ComparisonResult::Same; } -#endif /** Compares a double and an int64_t. */ -ComparisonResult CompareMixedNumber(double doubleValue, int64_t longValue); +ComparisonResult CompareMixedNumber(double double_value, int64_t long_value); /** Normalizes a double and then return the raw bits as a uint64_t. */ uint64_t DoubleBits(double d); @@ -175,23 +307,57 @@ bool DoubleBitwiseEquals(double left, double right); /** * Computes a bitwise hash of a double, but normalizes NaN values, suitable for - * use when using FSTDoublesAreBitwiseEqual for equality. + * use when using DoubleBitwiseEquals for equality. */ size_t DoubleBitwiseHash(double d); +/** + * A mixin that defines all six relational operators for a type T in terms of a + * CompareTo() member. + * + * @tparam T The type that should get comparison operators. + */ template -class Equatable { +class Comparable { public: + friend bool operator==(const T& lhs, const T& rhs) { + return Same(lhs.CompareTo(rhs)); + } friend bool operator!=(const T& lhs, const T& rhs) { return !(lhs == rhs); } + friend bool operator<(const T& lhs, const T& rhs) { + return Ascending(lhs.CompareTo(rhs)); + } + friend bool operator>(const T& lhs, const T& rhs) { + return Descending(lhs.CompareTo(rhs)); + } + friend bool operator<=(const T& lhs, const T& rhs) { + return !(rhs < lhs); + } + friend bool operator>=(const T& lhs, const T& rhs) { + return !(lhs < rhs); + } }; +/** + * Same as `Comparable`, but deliberately not defining `operator==`, which + * instead is left for the class inheriting from this mixin to implement. This + * is an optimization that avoids doing an extra comparison when comparing for + * equality (`Comparable` would have to check for both "less-than" and + * "greater-than" to determine whether two values are equal). + */ template -class Comparable : public Equatable { +class InequalityComparable { public: + friend bool operator!=(const T& lhs, const T& rhs) { + return !(lhs == rhs); + } + friend bool operator<(const T& lhs, const T& rhs) { + return Ascending(lhs.CompareTo(rhs)); + } friend bool operator>(const T& lhs, const T& rhs) { - return rhs < lhs; + return Descending(lhs.CompareTo(rhs)); } friend bool operator<=(const T& lhs, const T& rhs) { return !(rhs < lhs); diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/compressed_member.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/compressed_member.h new file mode 100644 index 0000000..916b6b3 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/compressed_member.h @@ -0,0 +1,79 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_COMPRESSED_MEMBER_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_COMPRESSED_MEMBER_H_ + +#include +#include + +namespace firebase { +namespace firestore { +namespace util { + +/** + * A numbered member of some other class that implements the empty + * base optimization. This makes it possible to hold a value of an + * empty type without using any space. + * + * Use by inheriting privately from CompressedMember. + */ +template ::value> +class CompressedMember : private T { + public: + CompressedMember() = default; + explicit CompressedMember(const T& t) : T(t) { + } + explicit CompressedMember(T&& t) : T(std::move(t)) { + } + + T& get() noexcept { + return *this; + } + const T& get() const noexcept { + return *this; + } +}; + +/** + * Specialization of CompressedMember for the case where the type T + * is non-empty. + */ +template +class CompressedMember { + public: + CompressedMember() = default; + explicit CompressedMember(const T& t) : value_(t) { + } + explicit CompressedMember(T&& t) : value_(std::move(t)) { + } + + T& get() noexcept { + return value_; + } + const T& get() const noexcept { + return value_; + } + + private: + T value_; +}; + +} // namespace util +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_COMPRESSED_MEMBER_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/delayed_constructor.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/delayed_constructor.h index 9c00e51..c45b186 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/delayed_constructor.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/delayed_constructor.h @@ -62,11 +62,7 @@ class DelayedConstructor { public: typedef T element_type; - /** - * Default constructor does nothing. - */ - DelayedConstructor() { - } + DelayedConstructor() = default; /** * Forwards arguments to the T's constructor: calls T(args...). @@ -79,27 +75,23 @@ class DelayedConstructor { void(DelayedConstructor)>::value, int>::type = 0> void Init(Ts&&... args) { - new (&space_) T(std::forward(args)...); + new (&space_.value) T(std::forward(args)...); } /** * Forwards copy and move construction for T. */ void Init(const T& x) { - new (&space_) T(x); + new (&space_.value) T(x); } void Init(T&& x) { - new (&space_) T(std::move(x)); + new (&space_.value) T(std::move(x)); } // No copying. DelayedConstructor(const DelayedConstructor&) = delete; DelayedConstructor& operator=(const DelayedConstructor&) = delete; - ~DelayedConstructor() { - get()->~T(); - } - // Pretend to be a smart pointer to T. T& operator*() { return *get(); @@ -108,7 +100,7 @@ class DelayedConstructor { return get(); } T* get() { - return reinterpret_cast(&space_); + return &space_.value; } const T& operator*() const { return *get(); @@ -117,11 +109,20 @@ class DelayedConstructor { return get(); } const T* get() const { - return reinterpret_cast(&space_); + return &space_.value; } private: - typename std::aligned_storage::type space_; + union Space { + /** Default constructor does nothing. */ + Space() { + } + ~Space() { + value.~T(); + } + char empty; + T value; + } space_; }; } // namespace util diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/empty.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/empty.h new file mode 100644 index 0000000..8e1abfd --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/empty.h @@ -0,0 +1,37 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_EMPTY_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_EMPTY_H_ + +namespace firebase { +namespace firestore { +namespace util { + +/** + * Used to represent an empty value. + */ +struct Empty { + friend bool operator==(Empty /* left */, Empty /* right */) { + return true; + } +}; + +} // namespace util +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_EMPTY_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/equality.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/equality.h new file mode 100644 index 0000000..386b616 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/equality.h @@ -0,0 +1,40 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_EQUALITY_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_EQUALITY_H_ + +#include +#include + +namespace firebase { +namespace firestore { +namespace util { + +/** + * Checks if the values pointed to by two C++ pointers are equal. Two null + * pointers are also considered equal. + */ +template +bool Equals(const T& lhs, const T& rhs) { + return lhs == nullptr ? rhs == nullptr : rhs != nullptr && *lhs == *rhs; +} + +} // namespace util +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_EQUALITY_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/error_apple.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/error_apple.h index a091840..ee900ad 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/error_apple.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/error_apple.h @@ -22,52 +22,63 @@ #import -#import // for FIRFirestoreErrorDomain +#include +#include #include "Firestore/core/include/firebase/firestore/firestore_errors.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "absl/strings/string_view.h" +NS_ASSUME_NONNULL_BEGIN + +// The Cloud Firestore error domain. Keep in sync with FIRFirestoreErrors.h. +// Exposed here to make it possible to build in CMake without bringing in the +// sources under Firestore/Source. +FOUNDATION_EXPORT NSString* const FIRFirestoreErrorDomain + NS_SWIFT_NAME(FirestoreErrorDomain); + namespace firebase { namespace firestore { namespace util { // Translates a set of error_code and error_msg to an NSError. -inline NSError* MakeNSError(const int64_t error_code, - const absl::string_view error_msg) { - if (error_code == FirestoreErrorCode::Ok) { - return nil; - } - return [NSError - errorWithDomain:FIRFirestoreErrorDomain - code:static_cast(error_code) - userInfo:@{NSLocalizedDescriptionKey : WrapNSString(error_msg)}]; -} +NSError* MakeNSError(int64_t error_code, + const absl::string_view error_msg, + NSError* cause = nil); -inline NSError* MakeNSError(const util::Status& status) { - return MakeNSError(status.code(), status.error_message()); -} +NSError* MakeNSError(const util::Status& status); -inline Status MakeStatus(NSError* error) { - if (!error) { - return Status::OK(); - } +Status MakeStatus(NSError* error); - HARD_ASSERT(error.domain == FIRFirestoreErrorDomain, - "Can only translate a Firestore error to a status"); - auto error_code = static_cast(error.code); - HARD_ASSERT(error_code >= FirestoreErrorCode::Cancelled && - error_code <= FirestoreErrorCode::Unauthenticated, - "Unknown error code"); - return Status{static_cast(error_code), - MakeString(error.localizedDescription)}; +using VoidErrorBlock = void (^)(NSError* _Nullable error); + +util::StatusCallback MakeCallback(VoidErrorBlock _Nullable block); + +template +using VoidValueErrorBlock = void (^)(T _Nullable value, + NSError* _Nullable error); + +template +util::StatusOrCallback MakeCallback(VoidValueErrorBlock _Nullable block) { + if (block) { + return [block](StatusOr maybe_value) { + if (maybe_value.ok()) { + block(std::move(maybe_value).ValueOrDie(), nil); + } else { + block(nil, MakeNSError(std::move(maybe_value).status())); + } + }; + } else { + return [](StatusOr maybe_value) { (void)maybe_value; }; + } } } // namespace util } // namespace firestore } // namespace firebase +NS_ASSUME_NONNULL_END + #endif // __OBJC__ #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_ERROR_APPLE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/error_apple.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/error_apple.mm new file mode 100644 index 0000000..0d80a03 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/error_apple.mm @@ -0,0 +1,67 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/util/error_apple.h" + +#include "Firestore/core/include/firebase/firestore/firestore_errors.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" + +// NB: This is also declared in Firestore/Source/Public/FIRFirestoreErrors.h +// NOLINTNEXTLINE: public constant +FOUNDATION_EXPORT NSString* const FIRFirestoreErrorDomain = + @"FIRFirestoreErrorDomain"; + +namespace firebase { +namespace firestore { +namespace util { + +// Translates a set of error_code and error_msg to an NSError. +NSError* MakeNSError(int64_t error_code, + absl::string_view error_msg, + NSError* cause) { + if (error_code == Error::Ok) { + return nil; + } + + NSMutableDictionary* user_info = + [NSMutableDictionary dictionary]; + user_info[NSLocalizedDescriptionKey] = MakeNSString(error_msg); + if (cause) { + user_info[NSUnderlyingErrorKey] = cause; + } + + return [NSError errorWithDomain:FIRFirestoreErrorDomain + code:static_cast(error_code) + userInfo:user_info]; +} + +NSError* MakeNSError(const util::Status& status) { + return status.ToNSError(); +} + +util::StatusCallback MakeCallback(VoidErrorBlock _Nullable block) { + if (block) { + return [block](Status status) { block(MakeNSError(status)); }; + } else { + return [](Status status) { (void)status; }; + } +} + +} // namespace util +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/exception.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/exception.cc new file mode 100644 index 0000000..c406f98 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/exception.cc @@ -0,0 +1,95 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/util/exception.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" +#include "absl/strings/str_cat.h" + +namespace firebase { +namespace firestore { +namespace util { +namespace { + +const char* ExceptionName(ExceptionType exception) { + switch (exception) { + case ExceptionType::AssertionFailure: + return "FIRESTORE INTERNAL ASSERTION FAILED"; + case ExceptionType::IllegalState: + return "Illegal state"; + case ExceptionType::InvalidArgument: + return "Invalid argument"; + } + UNREACHABLE(); +} + +ABSL_ATTRIBUTE_NORETURN void DefaultThrowHandler(ExceptionType type, + const char* file, + const char* func, + int line, + const std::string& message) { + std::string what = absl::StrCat(ExceptionName(type), ": "); + if (file && func) { + absl::StrAppend(&what, file, "(", line, ") ", func, ": "); + } + absl::StrAppend(&what, message); + +#if ABSL_HAVE_EXCEPTIONS + switch (type) { + case ExceptionType::AssertionFailure: + throw FirestoreInternalError(what); + case ExceptionType::IllegalState: + throw std::logic_error(what); + case ExceptionType::InvalidArgument: + throw std::invalid_argument(what); + } +#else + LOG_ERROR("%s", what); + std::terminate(); +#endif + + UNREACHABLE(); +} + +ThrowHandler throw_handler = DefaultThrowHandler; + +} // namespace + +ThrowHandler SetThrowHandler(ThrowHandler handler) { + ThrowHandler previous = throw_handler; + throw_handler = handler; + return previous; +} + +ABSL_ATTRIBUTE_NORETURN void Throw(ExceptionType exception, + const char* file, + const char* func, + int line, + const std::string& message) { + throw_handler(exception, file, func, line, message); + + // It's expected that the throw handler above does not return. If it does, + // just terminate. + std::terminate(); +} + +} // namespace util +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/exception.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/exception.h new file mode 100644 index 0000000..bf1552e --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/exception.h @@ -0,0 +1,127 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_EXCEPTION_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_EXCEPTION_H_ + +// Routines in this file are used to throw an exception (or crash, depending on +// platform) in response to API usage errors. Exceptions should only be used +// for programmer errors made by consumers of the SDK, e.g. invalid method +// arguments. +// +// These routines avoid conditional compilation in the caller and avoids lint +// warnings around actually throwing exceptions in source. The implementation +// chooses the best way to surface a logic error to the developer. +// +// For recoverable runtime errors, use util::Status, or in pure Objective-C +// code use an NSError** out-parameter. +// +// For internal programming errors, including internal argument checking, use +// HARD_ASSERT or HARD_FAIL(). + +#include +#include + +#include "Firestore/core/src/firebase/firestore/util/string_format.h" +#include "absl/base/attributes.h" + +namespace firebase { +namespace firestore { +namespace util { + +#if ABSL_HAVE_EXCEPTIONS +/** + * An exception thrown if Firestore encounters an internal error. + */ +class FirestoreInternalError : public std::logic_error { + public: + using std::logic_error::logic_error; +}; +#endif // ABSL_HAVE_EXCEPTIONS + +/** + * An enumeration of logical exception types mapping to common user visible + * exceptions we might throw in response do some invalid action in an + * interaction with the Firestore API. + */ +enum class ExceptionType { + AssertionFailure, + IllegalState, + InvalidArgument, +}; + +using ThrowHandler = void (*)(ExceptionType type, + const char* file, + const char* func, + int line, + const std::string& message); + +/** + * Overrides the default exception throw handler. + * + * The default essentially just calls std::terminate. While reasonable for C++ + * with exceptions disabled, this isn't optimal for platforms that merely use + * the C++ core as their implementation and would otherwise be expected to throw + * a platform specific exception. + * + * @param callback A function that will handle the exception. This function is + * expected not to return. (If it does, std::terminate() will be called + * immediately after it does so.) + * @return A pointer to the previous failure handler. + */ +ThrowHandler SetThrowHandler(ThrowHandler callback); + +ABSL_ATTRIBUTE_NORETURN void Throw(ExceptionType type, + const char* file, + const char* func, + int line, + const std::string& message); + +/** + * Throws an exception indicating that the user passed an invalid argument. + * + * Invalid argument is interpreted pretty broadly and can mean that the user + * made an incompatible chained method call while building up a larger + * structure, like a query. + */ +template +ABSL_ATTRIBUTE_NORETURN void ThrowInvalidArgument(const char* format, + const FA&... args) { + Throw(ExceptionType::InvalidArgument, nullptr, nullptr, 0, + StringFormat(format, args...)); +} + +/** + * Throws an exception that indicates the user has attempted to use an API + * that's in an illegal state, usually by violating a precondition of the API + * call. + * + * Good uses of these are things like using a write batch after committing or + * trying to use Firestore without initializing FIRApp. Builder-style APIs that + * haven't done anything yet should likely just stick to ThrowInvalidArgument. + */ +template +ABSL_ATTRIBUTE_NORETURN void ThrowIllegalState(const char* format, + const FA&... args) { + Throw(ExceptionType::IllegalState, nullptr, nullptr, 0, + StringFormat(format, args...)); +} + +} // namespace util +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_EXCEPTION_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/exception_apple.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/exception_apple.h new file mode 100644 index 0000000..736a0ef --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/exception_apple.h @@ -0,0 +1,42 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_EXCEPTION_APPLE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_EXCEPTION_APPLE_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/util/exception.h" +#include "absl/base/attributes.h" + +namespace firebase { +namespace firestore { +namespace util { + +/** + * Default throw handler for ObjC/Swift. Typically shouldn't be used directly. + */ +ABSL_ATTRIBUTE_NORETURN void ObjcThrowHandler(ExceptionType type, + const char* file, + const char* func, + int line, + const std::string& message); + +} // namespace util +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_EXCEPTION_APPLE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/exception_apple.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/exception_apple.mm new file mode 100644 index 0000000..c956369 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/exception_apple.mm @@ -0,0 +1,75 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/util/exception_apple.h" + +#import + +#include + +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" + +NS_ASSUME_NONNULL_BEGIN + +namespace firebase { +namespace firestore { +namespace util { +namespace { + +NSString* ExceptionName(ExceptionType exception) { + switch (exception) { + case ExceptionType::AssertionFailure: + return @"FIRESTORE INTERNAL ASSERTION FAILED"; + case ExceptionType::IllegalState: + return @"FIRIllegalStateException"; + case ExceptionType::InvalidArgument: + return @"FIRInvalidArgumentException"; + } + UNREACHABLE(); +} + +NSException* MakeException(ExceptionType type, const std::string& message) { + return [[NSException alloc] initWithName:ExceptionName(type) + reason:MakeNSString(message) + userInfo:nil]; +} + +} // namespace + +ABSL_ATTRIBUTE_NORETURN void ObjcThrowHandler(ExceptionType type, + const char* file, + const char* func, + int line, + const std::string& message) { + if (type == ExceptionType::AssertionFailure) { + [[NSAssertionHandler currentHandler] + handleFailureInFunction:MakeNSString(func) + file:MakeNSString(file) + lineNumber:line + description:@"%@: %s", ExceptionName(type), + message.c_str()]; + std::terminate(); + } else { + @throw MakeException(type, message); // NOLINT + } +} + +} // namespace util +} // namespace firestore +} // namespace firebase + +NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor.h index 6299ae7..10ed4b8 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor.h @@ -19,6 +19,7 @@ #include // NOLINT(build/c++11) #include +#include #include #include @@ -90,8 +91,21 @@ class Executor { Operation operation; }; - virtual ~Executor() { - } + // Creates a new serial Executor of the platform-appropriate type, and gives + // it the given label, if the implementation supports it. + // + // Note that this method has multiple definitions, depending on the platform. + static std::unique_ptr CreateSerial(const char* label); + + // Creates a new concurrent Executor of the platform-appropriate type, with + // at least the given number of threads, and gives it the given label, if the + // implementation supports it. + // + // Note that this method has multiple definitions, depending on the platform. + static std::unique_ptr CreateConcurrent(const char* label, + int threads); + + virtual ~Executor() = default; // Schedules the `operation` to be asynchronously executed as soon as // possible, in FIFO order. diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_libdispatch.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_libdispatch.h index 459fa4e..b66de5a 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_libdispatch.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_libdispatch.h @@ -17,13 +17,14 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_EXECUTOR_LIBDISPATCH_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_EXECUTOR_LIBDISPATCH_H_ +#include + #include // NOLINT(build/c++11) #include #include #include +#include #include -#include -#include "dispatch/dispatch.h" #include "Firestore/core/src/firebase/firestore/util/executor.h" #include "absl/strings/string_view.h" @@ -57,8 +58,12 @@ class TimeSlot; // a dedicated serial dispatch queue. class ExecutorLibdispatch : public Executor { public: + // An opaque, monotonically increasing identifier for TimeSlots that does + // not depend on their address. + using TimeSlotId = uint32_t; + explicit ExecutorLibdispatch(dispatch_queue_t dispatch_queue); - ~ExecutorLibdispatch(); + ~ExecutorLibdispatch() override; bool IsCurrentExecutor() const override; std::string CurrentExecutorName() const override; @@ -69,7 +74,7 @@ class ExecutorLibdispatch : public Executor { DelayedOperation Schedule(Milliseconds delay, TaggedOperation&& operation) override; - void RemoveFromSchedule(const TimeSlot* to_remove); + void RemoveFromSchedule(TimeSlotId to_remove); bool IsScheduled(Tag tag) const override; absl::optional PopFromSchedule() override; @@ -79,10 +84,16 @@ class ExecutorLibdispatch : public Executor { } private: + using ScheduleMap = std::unordered_map; + using ScheduleEntry = ScheduleMap::value_type; + + TimeSlotId NextId(); + dispatch_queue_t dispatch_queue_; // Stores non-owned pointers to `TimeSlot`s. // Invariant: if a `TimeSlot` is in `schedule_`, it's a valid pointer. - std::vector schedule_; + ScheduleMap schedule_; + TimeSlotId current_id_ = 0; }; } // namespace util diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_libdispatch.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_libdispatch.mm index 0b16827..4e0ef0a 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_libdispatch.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_libdispatch.mm @@ -90,6 +90,8 @@ void RunSynchronized(const ExecutorLibdispatch* const executor, Work&& work) { } // namespace +// MARK: - TimeSlot + // Represents a "busy" time slot on the schedule. // // Since libdispatch doesn't provide a way to cancel a scheduled operation, once @@ -114,16 +116,27 @@ void RunSynchronized(const ExecutorLibdispatch* const executor, Work&& work) { class TimeSlot { public: + using TimeSlotId = ExecutorLibdispatch::TimeSlotId; + TimeSlot(ExecutorLibdispatch* executor, Executor::Milliseconds delay, - Executor::TaggedOperation&& operation); + Executor::TaggedOperation&& operation, + TimeSlotId slot_id); // Returns the operation that was scheduled for this time slot and turns the // slot into a no-op. Executor::TaggedOperation Unschedule(); bool operator<(const TimeSlot& rhs) const { - return target_time_ < rhs.target_time_; + // Order by target time, then by the order in which entries were created. + if (target_time_ < rhs.target_time_) { + return true; + } + if (target_time_ > rhs.target_time_) { + return false; + } + + return time_slot_id_ < rhs.time_slot_id_; } bool operator==(const Executor::Tag tag) const { return tagged_.tag == tag; @@ -133,7 +146,7 @@ void MarkDone() { done_ = true; } - static void InvokedByLibdispatch(void* const raw_self); + static void InvokedByLibdispatch(void* raw_self); private: void Execute(); @@ -145,6 +158,7 @@ void MarkDone() { ExecutorLibdispatch* const executor_; const TimePoint target_time_; // Used for sorting Executor::TaggedOperation tagged_; + TimeSlotId time_slot_id_ = 0; // True if the operation has either been run or canceled. // @@ -155,12 +169,14 @@ void MarkDone() { TimeSlot::TimeSlot(ExecutorLibdispatch* const executor, const Executor::Milliseconds delay, - Executor::TaggedOperation&& operation) + Executor::TaggedOperation&& operation, + TimeSlotId slot_id) : executor_{executor}, target_time_{std::chrono::time_point_cast( std::chrono::steady_clock::now()) + delay}, - tagged_{std::move(operation)} { + tagged_{std::move(operation)}, + time_slot_id_{slot_id} { // Only assignment of std::atomic is atomic; initialization in its constructor // isn't done_ = false; @@ -173,7 +189,7 @@ void MarkDone() { return std::move(tagged_); } -void TimeSlot::InvokedByLibdispatch(void* const raw_self) { +void TimeSlot::InvokedByLibdispatch(void* raw_self) { auto const self = static_cast(raw_self); self->Execute(); delete self; @@ -194,10 +210,10 @@ void MarkDone() { } void TimeSlot::RemoveFromSchedule() { - executor_->RemoveFromSchedule(this); + executor_->RemoveFromSchedule(time_slot_id_); } -// ExecutorLibdispatch +// MARK: - ExecutorLibdispatch ExecutorLibdispatch::ExecutorLibdispatch(const dispatch_queue_t dispatch_queue) : dispatch_queue_{dispatch_queue} { @@ -211,8 +227,8 @@ void MarkDone() { // already finished. // Note: this is thread-safe, because the underlying variable `done_` is // atomic. `RunSynchronized` may result in a deadlock. - for (auto slot : schedule_) { - slot->MarkDone(); + for (const auto& entry : schedule_) { + entry.second->MarkDone(); } } @@ -244,28 +260,34 @@ void MarkDone() { // guaranteed to outlive the executor, and it's possible for work to be // invoked by libdispatch after the executor is destroyed. Executor only // stores an observer pointer to the operation. + TimeSlot* time_slot = nullptr; + TimeSlotId time_slot_id = 0; + RunSynchronized(this, [this, delay, &operation, &time_slot, &time_slot_id] { + time_slot_id = NextId(); + time_slot = new TimeSlot{this, delay, std::move(operation), time_slot_id}; + schedule_[time_slot_id] = time_slot; + }); - auto const time_slot = new TimeSlot{this, delay, std::move(operation)}; dispatch_after_f(delay_ns, dispatch_queue(), time_slot, TimeSlot::InvokedByLibdispatch); - RunSynchronized(this, [this, time_slot] { schedule_.push_back(time_slot); }); - return DelayedOperation{[this, time_slot] { - // `time_slot` might be destroyed by the time cancellation function runs. - // Therefore, don't access any methods on `time_slot`, only use it as - // a handle to remove from `schedule_`. - RemoveFromSchedule(time_slot); + + return DelayedOperation{[this, time_slot_id] { + // `time_slot` might have been destroyed by the time cancellation function + // runs, in which case it's guaranteed to have been removed from the + // `schedule_`. If the `time_slot_id` refers to a slot that has been + // removed, the call to `RemoveFromSchedule` will be a no-op. + RemoveFromSchedule(time_slot_id); }}; } -void ExecutorLibdispatch::RemoveFromSchedule(const TimeSlot* const to_remove) { +void ExecutorLibdispatch::RemoveFromSchedule(TimeSlotId to_remove) { RunSynchronized(this, [this, to_remove] { - const auto found = std::find_if( - schedule_.begin(), schedule_.end(), - [to_remove](const TimeSlot* op) { return op == to_remove; }); + const auto found = schedule_.find(to_remove); + // It's possible for the operation to be missing if libdispatch gets to run // it after it was force-run, for example. if (found != schedule_.end()) { - (*found)->MarkDone(); + found->second->MarkDone(); schedule_.erase(found); } }); @@ -276,9 +298,10 @@ void MarkDone() { bool ExecutorLibdispatch::IsScheduled(const Tag tag) const { bool result = false; RunSynchronized(this, [this, tag, &result] { - result = std::any_of( - schedule_.begin(), schedule_.end(), - [&tag](const TimeSlot* const operation) { return *operation == tag; }); + result = std::any_of(schedule_.begin(), schedule_.end(), + [&tag](const ScheduleEntry& operation) { + return *operation.second == tag; + }); }); return result; } @@ -287,22 +310,49 @@ void MarkDone() { ExecutorLibdispatch::PopFromSchedule() { absl::optional result; - RunSynchronized(this, [this, &result] { + RunSynchronized(this, [this, &result]() -> void { if (schedule_.empty()) { return; } - // Sorting upon each call to `PopFromSchedule` is inefficient, which is - // consciously ignored because this function is only ever called from tests. - std::sort( + + const auto nearest = std::min_element( schedule_.begin(), schedule_.end(), - [](const TimeSlot* lhs, const TimeSlot* rhs) { return *lhs < *rhs; }); - const auto nearest = schedule_.begin(); - result = (*nearest)->Unschedule(); + [](const ScheduleEntry& lhs, const ScheduleEntry& rhs) { + return *lhs.second < *rhs.second; + }); + + result = nearest->second->Unschedule(); }); return result; } +ExecutorLibdispatch::TimeSlotId ExecutorLibdispatch::NextId() { + // The wrap around after ~4 billion operations is explicitly ignored. Even if + // an instance of `ExecutorLibdispatch` runs long enough to get `current_id_` + // to overflow, it's extremely unlikely that any object still holds a + // reference that is old enough to cause a conflict. + return current_id_++; +} + +// MARK: - Executor + +std::unique_ptr Executor::CreateSerial(const char* label) { + dispatch_queue_t queue = dispatch_queue_create(label, DISPATCH_QUEUE_SERIAL); + return absl::make_unique(queue); +} + +std::unique_ptr Executor::CreateConcurrent(const char* label, + int threads) { + HARD_ASSERT(threads > 1); + + // Concurrent queues auto-create enough threads to avoid deadlock so there's + // no need to honor the threads argument. + dispatch_queue_t queue = + dispatch_queue_create(label, DISPATCH_QUEUE_CONCURRENT); + return absl::make_unique(queue); +} + } // namespace util } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_std.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_std.cc index bfc47fe..913f2d9 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_std.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_std.cc @@ -17,8 +17,11 @@ #include "Firestore/core/src/firebase/firestore/util/executor_std.h" #include // NOLINT(build/c++11) +#include #include +#include "absl/memory/memory.h" + namespace firebase { namespace firestore { namespace util { @@ -35,23 +38,44 @@ std::string ThreadIdToString(const std::thread::id thread_id) { } // namespace -ExecutorStd::ExecutorStd() { +// MARK: - ExecutorStd + +ExecutorStd::ExecutorStd(int threads) + : shutting_down_(std::make_shared>()) { + HARD_ASSERT(threads > 0); + // Somewhat counter-intuitively, constructor of `std::atomic` assigns the // value non-atomically, so the atomic initialization must be provided here, // before the worker thread is started. // See [this thread](https://stackoverflow.com/questions/25609858) for context // on the constructor. current_id_ = 0; - shutting_down_ = false; - worker_thread_ = std::thread{&ExecutorStd::PollingThread, this}; + *shutting_down_ = false; + for (int i = 0; i < threads; ++i) { + worker_thread_pool_.emplace_back(&ExecutorStd::PollingThread, this); + } } ExecutorStd::~ExecutorStd() { - shutting_down_ = true; - // Make sure the worker thread is not blocked, so that the call to `join` - // doesn't hang. - UnblockQueue(); - worker_thread_.join(); + *shutting_down_ = true; + + // Make sure the worker threads are not blocked, so that the call to `join` + // doesn't hang. It's not deterministic which thread will pick up an entry, + // so add an entry for each thread before attempting to join. + for (size_t i = 0; i < worker_thread_pool_.size(); ++i) { + UnblockQueue(); + } + + for (std::thread& thread : worker_thread_pool_) { + // If the current thread is running this destructor, we can't join the + // thread. Instead detach it and rely on PollingThread to notice that + // *shutting_down_ is now true. + if (std::this_thread::get_id() == thread.get_id()) { + thread.detach(); + } else { + thread.join(); + } + } } void ExecutorStd::Execute(Operation&& operation) { @@ -89,7 +113,10 @@ ExecutorStd::Id ExecutorStd::PushOnSchedule(Operation&& operation, } void ExecutorStd::PollingThread() { - while (!shutting_down_) { + // Keep a local shared_ptr here to ensure that the atomic pointed to by + // shutting_down_ remains valid even after the destruction of the executor. + std::shared_ptr> local_shutting_down = shutting_down_; + while (!*local_shutting_down) { Entry entry = schedule_.PopBlocking(); if (entry.tagged.operation) { entry.tagged.operation(); @@ -113,15 +140,25 @@ ExecutorStd::Id ExecutorStd::NextId() { } bool ExecutorStd::IsCurrentExecutor() const { - return std::this_thread::get_id() == worker_thread_.get_id(); + auto current_id = std::this_thread::get_id(); + for (const std::thread& thread : worker_thread_pool_) { + if (thread.get_id() == current_id) { + return true; + } + } + return false; } std::string ExecutorStd::CurrentExecutorName() const { - return ThreadIdToString(std::this_thread::get_id()); + if (IsCurrentExecutor()) { + return Name(); + } else { + return ThreadIdToString(std::this_thread::get_id()); + } } std::string ExecutorStd::Name() const { - return ThreadIdToString(worker_thread_.get_id()); + return ThreadIdToString(worker_thread_pool_.front().get_id()); } void ExecutorStd::ExecuteBlocking(Operation&& operation) { @@ -147,6 +184,22 @@ absl::optional ExecutorStd::PopFromSchedule() { return {std::move(removed.value().tagged)}; } +// MARK: - Executor + +// Only defined on non-Apple platforms. On Apple platforms, see the alternative +// definition in executor_libdispatch.mm. +#if !__APPLE__ + +std::unique_ptr Executor::CreateSerial(const char*) { + return absl::make_unique(/*threads=*/1); +} + +std::unique_ptr Executor::CreateConcurrent(const char*, int threads) { + return absl::make_unique(threads); +} + +#endif // !__APPLE__ + } // namespace util } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_std.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_std.h index 2550036..7ed3266 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_std.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/executor_std.h @@ -21,10 +21,12 @@ #include #include // NOLINT(build/c++11) #include +#include #include // NOLINT(build/c++11) #include #include // NOLINT(build/c++11) #include +#include #include "Firestore/core/src/firebase/firestore/util/executor.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" @@ -92,7 +94,12 @@ class Schedule { // To minimize busy waiting, sleep until either the nearest entry in the // future either changes, or else becomes due. - const auto until = scheduled_.front().due; + + // Workaround for Visual Studio 2015: cast to a time point with resolution + // that's at least as fine-grained as the clock on which `wait_until` is + // parametrized. + const auto until = + std::chrono::time_point_cast(scheduled_.front().due); cv_.wait_until(lock, until, [this, until] { return scheduled_.empty() || scheduled_.front().due != until; }); @@ -204,7 +211,7 @@ class Schedule { // thread, using C++11 standard library functionality. class ExecutorStd : public Executor { public: - ExecutorStd(); + explicit ExecutorStd(int threads); ~ExecutorStd(); void Execute(Operation&& operation) override; @@ -265,9 +272,9 @@ class ExecutorStd : public Executor { // (with due time set to `Immediate`). async::Schedule schedule_; - std::thread worker_thread_; + std::vector worker_thread_pool_; // Used to stop the worker thread. - std::atomic shutting_down_{false}; + std::shared_ptr> shutting_down_; std::atomic current_id_{0}; }; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem.h index 532c954..bbbc7d5 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem.h @@ -20,71 +20,188 @@ #include #include -#include "Firestore/core/src/firebase/firestore/util/path.h" #include "Firestore/core/src/firebase/firestore/util/status.h" -#include "Firestore/core/src/firebase/firestore/util/statusor.h" +#include "absl/strings/string_view.h" namespace firebase { namespace firestore { namespace util { -// High-level routines for the manipulating the filesystem. All filesystems -// are required to implement these routines. +class Path; -/** - * Answers the question "is this path a directory? The path is not required to - * have a trailing slash. - * - * Typical return codes include: - * * Ok - The path exists and is a directory. - * * FailedPrecondition - Some component of the path is not a directory. This - * does not necessarily imply that the path exists and is a file. - * * NotFound - The path does not exist - * * PermissionDenied - Insufficient permissions to access the path. - */ -Status IsDirectory(const Path& path); +template +class StatusOr; /** - * Recursively creates all the directories in the path name if they don't - * exist. - * - * @return Ok if the directory was created or already existed. + * A high-level interface describing filesystem operations. */ -Status RecursivelyCreateDir(const Path& path); +class Filesystem { + public: + virtual ~Filesystem() = default; -/** - * Recursively deletes the contents of the given pathname. If the pathname is - * a file, deletes just that file. The the pathname is a directory, deletes - * everything within the directory. - * - * @return Ok if the directory was deleted or did not exist. - */ -Status RecursivelyDelete(const Path& path); + Filesystem(const Filesystem&) = delete; + Filesystem& operator=(const Filesystem&) = delete; -/** - * Returns system-defined best directory in which to create temporary files. - * Typical return values are like `/tmp` on UNIX systems. Clients should create - * randomly named directories or files within this location to avoid collisions. - * Absent any changes that might affect the underlying calls, the value returned - * from TempDir will be stable over time. - * - * Note: the returned path is just where the system thinks temporary files - * should be stored, but TempDir does not actually guarantee that this path - * exists. - */ -Path TempDir(); + /** + * Returns a singleton default filesystem implementation for the current + * operating system. + */ + static Filesystem* Default(); -/** - * On success, returns the size in bytes of the file specified by - * `path`. - */ -StatusOr FileSize(const Path& path); + /** + * Returns a system-defined best directory in which to create application + * data. Values vary wildly across platforms. They include: + * + * * iOS: $container/Library/Application Support/$app_name + * * Linux: $HOME/.local/share/$app_name + * * macOS: $container/Library/Application Support/$app_name + * * Other UNIX: $HOME/.$app_name + * * tvOS: $container/Library/Caches/$app_name + * * Windows: %USERPROFILE%/AppData/Local + * + * On iOS, tvOS, and macOS (when running sandboxed), these locations are + * relative to the data container for the current application. On macOS when + * the application is not sandboxed, the returned value will be relative to + * $HOME instead. See "About the iOS File System" in the Apple "File System + * Programming Guide" at https://apple.co/2Nn7Bsb. + * + * Note: the returned path is just where the system thinks the application + * data should be stored, but AppDataDir does not actually guarantee that this + * path exists. + * + * @param app_name The name of the application. + */ + virtual StatusOr AppDataDir(absl::string_view app_name); + + /** + * Returns the Documents directory in which Firestore used to store + * application data. Values vary wildly across platforms. They include: + * + * * iOS: $container/Documents/$app_name + * * macOS: $HOME/.$app_name + * + * On iOS, the Documents folder is relative to the data container for the + * current application. See "About the iOS File System" in the Apple "File + * System Programming Guide" at https://apple.co/2Nn7Bsb. + * + * Note: the returned path is just where the system thinks the documents + * directory should be stored, but LegacyDocumentsDir does not actually + * guarantee that this path exists. + * + * @param app_name The name of the application. + * + * @returns The documents directory path or a status with Error::Unimplemented + * if the current platform does not have a legacy documents directory. + */ + virtual StatusOr LegacyDocumentsDir(absl::string_view app_name); + + /** + * Returns system-defined best directory in which to create temporary files. + * Typical return values are like `/tmp` on UNIX systems. Clients should + * create randomly named directories or files within this location to avoid + * collisions. Absent any changes that might affect the underlying calls, the + * value returned from TempDir will be stable over time. + * + * Note: the returned path is just where the system thinks temporary files + * should be stored, but TempDir does not actually guarantee that this path + * exists. + */ + virtual Path TempDir(); + + /** + * Answers the question "is this path a directory? The path is not required to + * have a trailing slash. + * + * Typical return codes include: + * * Ok - The path exists and is a directory. + * * FailedPrecondition - Some component of the path is not a directory. + * This does not necessarily imply that the path exists and is a file. + * * NotFound - The path does not exist + * * PermissionDenied - Insufficient permissions to access the path. + */ + virtual Status IsDirectory(const Path& path); + + /** + * On success, returns the size in bytes of the file specified by + * `path`. + */ + virtual StatusOr FileSize(const Path& path); + + /** + * Recursively creates all the directories in the path name if they don't + * exist. + * + * @return Ok if the directory was created or already existed. + */ + virtual Status RecursivelyCreateDir(const Path& path); + + /** + * Recursively deletes the contents of the given pathname. If the pathname is + * a file, deletes just that file. The the pathname is a directory, deletes + * everything within the directory. + * + * @return Ok if the directory was deleted or did not exist. + */ + virtual Status RecursivelyRemove(const Path& path); + + /** + * Creates the given directory. The immediate parent directory must already + * exist and not already be a file. + * + * @return Ok if the directory was created or already existed. On some systems + * this may also return Ok if a regular file exists at the given path. + */ + virtual Status CreateDir(const Path& path); + + /** + * Deletes the given directory if it exists. + * + * @return Ok if the directory was deleted or did not exist. Returns a + * system-defined error if the path is not a directory or the directory is + * non-empty. + */ + virtual Status RemoveDir(const Path& path); + + /** + * Deletes the given file if it exists. + * + * @return Ok if the file was deleted or did not exist. Returns a + * system-defined error if the path exists but is not a regular file. + */ + virtual Status RemoveFile(const Path& path); + + /** + * Recursively deletes the contents of the given pathname that is known to be + * a directory. + * + * @return Ok if the directory was deleted or did not exist. Returns a + * system-defined error if the path exists but is not a directory. + * + */ + virtual Status RecursivelyRemoveDir(const Path& path); + + virtual Status Rename(const Path& from_path, const Path& to_path); + + /** + * Marks the given directory as excluded from platform-specific backup schemes + * like iCloud backup. + */ + virtual Status ExcludeFromBackups(const Path& dir); + + /** + * On success, opens the file at the given `path` and returns its contents as + * a string. + */ + virtual StatusOr ReadFile(const Path& path); + + protected: + Filesystem() = default; +}; /** - * On success, opens the file at the given `path` and returns its contents as - * a string. + * Returns true if the path is an accessible directory and is empty. */ -StatusOr ReadFile(const Path& path); +bool IsEmptyDir(const Path& path); /** * Implements an iterator over the contents of a directory. Initializes to the @@ -100,8 +217,7 @@ class DirectoryIterator { */ static std::unique_ptr Create(const Path& path); - virtual ~DirectoryIterator() { - } + virtual ~DirectoryIterator() = default; /** * Advances the iterator. diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_apple.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_apple.mm index 07c755e..3bfe5db 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_apple.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_apple.mm @@ -16,15 +16,64 @@ #include "Firestore/core/src/firebase/firestore/util/filesystem.h" -#if defined(__APPLE__) +#if __APPLE__ #import +#include "Firestore/core/src/firebase/firestore/util/path.h" +#include "Firestore/core/src/firebase/firestore/util/statusor.h" + namespace firebase { namespace firestore { namespace util { -Path TempDir() { +Status Filesystem::ExcludeFromBackups(const Path& dir) { + NSURL* dir_url = [NSURL fileURLWithPath:dir.ToNSString()]; + NSError* error = nil; + if (![dir_url setResourceValue:@YES + forKey:NSURLIsExcludedFromBackupKey + error:&error]) { + return Status{ + Error::Internal, + "Failed to mark persistence directory as excluded from backups"} + .CausedBy(Status::FromNSError(error)); + } + + return Status::OK(); +} + +StatusOr Filesystem::AppDataDir(absl::string_view app_name) { +#if TARGET_OS_IOS || TARGET_OS_OSX + NSArray* directories = NSSearchPathForDirectoriesInDomains( + NSApplicationSupportDirectory, NSUserDomainMask, YES); + return Path::FromNSString(directories[0]).AppendUtf8(app_name); + +#elif TARGET_OS_TV + NSArray* directories = NSSearchPathForDirectoriesInDomains( + NSCachesDirectory, NSUserDomainMask, YES); + return Path::FromNSString(directories[0]).AppendUtf8(app_name); + +#else +#error "Don't know where to store documents on this platform." +#endif +} + +StatusOr Filesystem::LegacyDocumentsDir(absl::string_view app_name) { +#if TARGET_OS_IOS + NSArray* directories = NSSearchPathForDirectoriesInDomains( + NSDocumentDirectory, NSUserDomainMask, YES); + return Path::FromNSString(directories[0]).AppendUtf8(app_name); + +#elif TARGET_OS_OSX + std::string dot_prefixed = absl::StrCat(".", app_name); + return Path::FromNSString(NSHomeDirectory()).AppendUtf8(dot_prefixed); + +#else + return Status(Error::Unimplemented, "No legacy storage on this platform."); +#endif +} + +Path Filesystem::TempDir() { const char* env_tmpdir = getenv("TMPDIR"); if (env_tmpdir) { return Path::FromUtf8(env_tmpdir); @@ -42,4 +91,4 @@ Path TempDir() { } // namespace firestore } // namespace firebase -#endif // defined(__APPLE__) +#endif // __APPLE__ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_common.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_common.cc index 656eaf2..9c65381 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_common.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_common.cc @@ -14,43 +14,26 @@ * limitations under the License. */ -#include "Firestore/core/src/firebase/firestore/util/filesystem_detail.h" - #include #include #include "Firestore/core/src/firebase/firestore/util/filesystem.h" +#include "Firestore/core/src/firebase/firestore/util/path.h" +#include "Firestore/core/src/firebase/firestore/util/statusor.h" #include "Firestore/core/src/firebase/firestore/util/string_format.h" -using firebase::firestore::util::Path; - namespace firebase { namespace firestore { namespace util { -namespace detail { -Status RecursivelyDeleteDir(const Path& parent) { - std::unique_ptr iter = DirectoryIterator::Create(parent); - for (; iter->Valid(); iter->Next()) { - Status status = RecursivelyDelete(iter->file()); - if (!status.ok()) { - return status; - } - } - if (!iter->status().ok()) { - if (iter->status().code() == FirestoreErrorCode::NotFound) { - return Status::OK(); - } - return iter->status(); - } - return detail::DeleteDir(parent); +Filesystem* Filesystem::Default() { + static Filesystem filesystem; + return &filesystem; } -} // namespace detail - -Status RecursivelyCreateDir(const Path& path) { - Status result = detail::CreateDir(path); - if (result.ok() || result.code() != FirestoreErrorCode::NotFound) { +Status Filesystem::RecursivelyCreateDir(const Path& path) { + Status result = CreateDir(path); + if (result.ok() || result.code() != Error::NotFound) { // Successfully created the directory, it already existed, or some other // unrecoverable error. return result; @@ -64,21 +47,21 @@ Status RecursivelyCreateDir(const Path& path) { } // Successfully created the parent so try again. - return detail::CreateDir(path); + return CreateDir(path); } -Status RecursivelyDelete(const Path& path) { +Status Filesystem::RecursivelyRemove(const Path& path) { Status status = IsDirectory(path); switch (status.code()) { - case FirestoreErrorCode::Ok: - return detail::RecursivelyDeleteDir(path); + case Error::Ok: + return RecursivelyRemoveDir(path); - case FirestoreErrorCode::FailedPrecondition: + case Error::FailedPrecondition: // Could be a file or something else. Attempt to delete it as a file // but otherwise allow that to fail if it's not a file. - return detail::DeleteFile(path); + return RemoveFile(path); - case FirestoreErrorCode::NotFound: + case Error::NotFound: return Status::OK(); default: @@ -86,12 +69,37 @@ Status RecursivelyDelete(const Path& path) { } } -StatusOr ReadFile(const Path& path) { +Status Filesystem::RecursivelyRemoveDir(const Path& parent) { + std::unique_ptr iter = DirectoryIterator::Create(parent); + for (; iter->Valid(); iter->Next()) { + Status status = RecursivelyRemove(iter->file()); + if (!status.ok()) { + return status; + } + } + + if (!iter->status().ok()) { + if (iter->status().code() == Error::NotFound) { + return Status::OK(); + } + return iter->status(); + } + return RemoveDir(parent); +} + +#if !__APPLE__ +Status Filesystem::ExcludeFromBackups(const Path&) { + // Non-Apple platforms don't yet implement exclusion from backups. + return Status::OK(); +} +#endif // !__APPLE__ + +StatusOr Filesystem::ReadFile(const Path& path) { std::ifstream file{path.native_value()}; if (!file) { // TODO(varconst): more error details. This will require platform-specific // code, because `` may not update `errno`. - return Status{FirestoreErrorCode::Unknown, + return Status{Error::Unknown, StringFormat("File at path '%s' cannot be opened", path.ToUtf8String())}; } @@ -101,6 +109,12 @@ StatusOr ReadFile(const Path& path) { return buffer.str(); } +bool IsEmptyDir(const Path& path) { + // If the DirectoryIterator is valid there's at least one entry. + auto iter = DirectoryIterator::Create(path); + return iter->status().ok() && !iter->Valid(); +} + } // namespace util } // namespace firestore } // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_detail.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_detail.h deleted file mode 100644 index f2b344d..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_detail.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_FILESYSTEM_DETAIL_H_ -#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_FILESYSTEM_DETAIL_H_ - -#include "Firestore/core/src/firebase/firestore/util/path.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" - -namespace firebase { -namespace firestore { -namespace util { -namespace detail { - -// Additional routines for filesystem implementations that are not based on -// high-level mechanisms like NSFileManager. - -/** - * Creates the given directory. The immediate parent directory must already - * exist and not already be a file. - * - * @return Ok if the directory was created or already existed. On some systems - * this may also return Ok if a regular file exists at the given path. - */ -Status CreateDir(const Path& path); - -/** - * Deletes the given directory if it exists. - * - * @return Ok if the directory was deleted or did not exist. Returns a - * system-defined error if the path is not a directory or the directory is - * non-empty. - */ -Status DeleteDir(const Path& path); - -/** - * Deletes the given file if it exists. - * - * @return Ok if the file was deleted or did not exist. Returns a system-defined - * error if the path exists but is not a regular file. - */ -Status DeleteFile(const Path& path); - -/** - * Recursively deletes the contents of the given pathname that is known to be - * a directory. - * - * @return Ok if the directory was deleted or did not exist. Returns a - * system-defined error if the path exists but is not a directory. - * - */ -Status RecursivelyDeleteDir(const Path& path); - -} // namespace detail -} // namespace util -} // namespace firestore -} // namespace firebase - -#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_FILESYSTEM_DETAIL_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_posix.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_posix.cc index 650b821..9df961d 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_posix.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/filesystem_posix.cc @@ -17,16 +17,18 @@ #include "Firestore/core/src/firebase/firestore/util/filesystem.h" #include +#include #include #include #include #include +#include #include #include -#include "Firestore/core/src/firebase/firestore/util/filesystem_detail.h" #include "Firestore/core/src/firebase/firestore/util/path.h" +#include "Firestore/core/src/firebase/firestore/util/statusor.h" #include "Firestore/core/src/firebase/firestore/util/string_format.h" #include "absl/memory/memory.h" @@ -34,12 +36,104 @@ namespace firebase { namespace firestore { namespace util { -Status IsDirectory(const Path& path) { +#if !__APPLE__ && !_WIN32 +// See filesystem_apple.mm and filesystem_win.cc for other implementations. + +namespace { + +StatusOr HomeDir() { + const char* home_dir = getenv("HOME"); + if (home_dir) return Path::FromUtf8(home_dir); + + passwd pwd; + passwd* result; + auto buffer_size = static_cast(sysconf(_SC_GETPW_R_SIZE_MAX)); + std::string buffer(buffer_size, '\0'); + uid_t uid = getuid(); + int rc; + do { + rc = getpwuid_r(uid, &pwd, &buffer[0], buffer_size, &result); + } while (rc == EINTR); + + if (rc != 0) { + return Status::FromErrno( + rc, "Failed to find the home directory for the current user"); + } + + return Path::FromUtf8(pwd.pw_dir); +} + +#if __linux__ && !__ANDROID__ +StatusOr XdgDataHomeDir() { + const char* data_home = getenv("XDG_DATA_HOME"); + if (data_home) return Path::FromUtf8(data_home); + + StatusOr maybe_home_dir = HomeDir(); + if (!maybe_home_dir.ok()) return maybe_home_dir; + + const Path& home_dir = maybe_home_dir.ValueOrDie(); + return home_dir.AppendUtf8(".local/share"); +} +#endif // __linux__ && !__ANDROID__ + +} // namespace + +StatusOr Filesystem::AppDataDir(absl::string_view app_name) { +#if __linux__ && !__ANDROID__ + // On Linux, use XDG data home, usually $HOME/.local/share/$app_name + StatusOr maybe_data_home = XdgDataHomeDir(); + if (!maybe_data_home.ok()) return maybe_data_home; + + return maybe_data_home.ValueOrDie().AppendUtf8(app_name); + +#elif !__ANDROID__ + // On any other UNIX, use an old school dotted directory in $HOME. + StatusOr maybe_home = HomeDir(); + if (!maybe_home.ok()) return maybe_home; + + std::string dot_prefixed = absl::StrCat(".", app_name); + return maybe_home.ValueOrDie().AppendUtf8(dot_prefixed); + +#else + // TODO(wilhuff): On Android, use internal storage +#error "Don't know where to store documents on this platform." + +#endif // __linux__ && !__ANDROID__ +} + +StatusOr Filesystem::LegacyDocumentsDir(absl::string_view) { + return Status(Error::Unimplemented, "No legacy storage on this platform."); +} + +Path Filesystem::TempDir() { + const char* env_tmpdir = getenv("TMPDIR"); + if (env_tmpdir) { + return Path::FromUtf8(env_tmpdir); + } + +#if __ANDROID__ + // The /tmp directory doesn't exist as a fallback; each application is + // supposed to keep its own temporary files. Previously /data/local/tmp may + // have been reasonable, but current lore points to this being unreliable for + // writing at higher API levels or certain phone models because default + // permissions on this directory no longer permit writing. + // + // TODO(wilhuff): Validate on recent Android. +#error "Not yet sure about temporary file locations on Android." + return Path::FromUtf8("/data/local/tmp"); + +#else + return Path::FromUtf8("/tmp"); +#endif // __ANDROID__ +} +#endif // !__APPLE__ && !_WIN32 + +Status Filesystem::IsDirectory(const Path& path) { struct stat buffer {}; if (::stat(path.c_str(), &buffer)) { if (errno == ENOENT) { // Expected common error case. - return Status{FirestoreErrorCode::NotFound, path.ToUtf8String()}; + return Status{Error::NotFound, path.ToUtf8String()}; } else if (errno == ENOTDIR) { // This is a case where POSIX and Windows differ in behavior in a way @@ -55,14 +149,14 @@ Status IsDirectory(const Path& path) { // // Since we really don't care about this distinction it's easier to // resolve this by returning NotFound here. - return Status{FirestoreErrorCode::NotFound, path.ToUtf8String()}; + return Status{Error::NotFound, path.ToUtf8String()}; } else { return Status::FromErrno(errno, path.ToUtf8String()); } } if (!S_ISDIR(buffer.st_mode)) { - return Status{FirestoreErrorCode::FailedPrecondition, + return Status{Error::FailedPrecondition, StringFormat("Path %s exists but is not a directory", path.ToUtf8String())}; } @@ -70,32 +164,7 @@ Status IsDirectory(const Path& path) { return Status::OK(); } -#if !defined(__APPLE__) -// See filesystem_apple.mm for an alternative implementation. -Path TempDir() { - const char* env_tmpdir = getenv("TMPDIR"); - if (env_tmpdir) { - return Path::FromUtf8(env_tmpdir); - } - -#if defined(__ANDROID__) - // The /tmp directory doesn't exist as a fallback; each application is - // supposed to keep its own temporary files. Previously /data/local/tmp may - // have been reasonable, but current lore points to this being unreliable for - // writing at higher API levels or certain phone models because default - // permissions on this directory no longer permit writing. - // - // TODO(wilhuff): Validate on recent Android. -#error "Not yet sure about temporary file locations on Android." - return Path::FromUtf8("/data/local/tmp"); - -#else - return Path::FromUtf8("/tmp"); -#endif // defined(__ANDROID__) -} -#endif // !defined(__APPLE__) - -StatusOr FileSize(const Path& path) { +StatusOr Filesystem::FileSize(const Path& path) { struct stat st {}; if (stat(path.c_str(), &st) == 0) { return st.st_size; @@ -105,9 +174,7 @@ StatusOr FileSize(const Path& path) { } } -namespace detail { - -Status CreateDir(const Path& path) { +Status Filesystem::CreateDir(const Path& path) { if (::mkdir(path.c_str(), 0777)) { if (errno != EEXIST) { return Status::FromErrno( @@ -119,7 +186,7 @@ Status CreateDir(const Path& path) { return Status::OK(); } -Status DeleteDir(const Path& path) { +Status Filesystem::RemoveDir(const Path& path) { if (::rmdir(path.c_str())) { if (errno != ENOENT) { return Status::FromErrno( @@ -130,7 +197,7 @@ Status DeleteDir(const Path& path) { return Status::OK(); } -Status DeleteFile(const Path& path) { +Status Filesystem::RemoveFile(const Path& path) { if (::unlink(path.c_str())) { if (errno != ENOENT) { return Status::FromErrno( @@ -140,14 +207,21 @@ Status DeleteFile(const Path& path) { return Status::OK(); } -} // namespace detail +Status Filesystem::Rename(const Path& from_path, const Path& to_path) { + if (::rename(from_path.ToUtf8String().c_str(), + to_path.ToUtf8String().c_str())) { + return Status::FromErrno(errno, from_path.ToUtf8String()); + } + + return Status::OK(); +} namespace { -class DirectoryIteratorPosix : public DirectoryIterator { +class PosixDirectoryIterator : public DirectoryIterator { public: - explicit DirectoryIteratorPosix(const util::Path& path); - virtual ~DirectoryIteratorPosix(); + explicit PosixDirectoryIterator(const util::Path& path); + virtual ~PosixDirectoryIterator(); void Next() override; bool Valid() const override; @@ -160,7 +234,7 @@ class DirectoryIteratorPosix : public DirectoryIterator { struct dirent* entry_ = nullptr; }; -DirectoryIteratorPosix::DirectoryIteratorPosix(const util::Path& path) +PosixDirectoryIterator::PosixDirectoryIterator(const util::Path& path) : DirectoryIterator{path} { dir_ = ::opendir(parent_.c_str()); if (!dir_) { @@ -172,7 +246,7 @@ DirectoryIteratorPosix::DirectoryIteratorPosix(const util::Path& path) Advance(); } -DirectoryIteratorPosix::~DirectoryIteratorPosix() { +PosixDirectoryIterator::~PosixDirectoryIterator() { if (dir_) { if (::closedir(dir_) != 0) { HARD_FAIL("Could not close directory %s", parent_.ToUtf8String()); @@ -180,7 +254,7 @@ DirectoryIteratorPosix::~DirectoryIteratorPosix() { } } -void DirectoryIteratorPosix::Advance() { +void PosixDirectoryIterator::Advance() { HARD_ASSERT(status_.ok(), "Advancing an errored iterator"); errno = 0; entry_ = ::readdir(dir_); @@ -198,16 +272,16 @@ void DirectoryIteratorPosix::Advance() { } } -void DirectoryIteratorPosix::Next() { +void PosixDirectoryIterator::Next() { HARD_ASSERT(Valid(), "Next() called on invalid iterator"); Advance(); } -bool DirectoryIteratorPosix::Valid() const { +bool PosixDirectoryIterator::Valid() const { return status_.ok() && entry_ != nullptr; } -Path DirectoryIteratorPosix::file() const { +Path PosixDirectoryIterator::file() const { HARD_ASSERT(Valid(), "file() called on invalid iterator"); return parent_.AppendUtf8(entry_->d_name, strlen(entry_->d_name)); } @@ -216,7 +290,7 @@ Path DirectoryIteratorPosix::file() const { std::unique_ptr DirectoryIterator::Create( const util::Path& path) { - return absl::make_unique(path); + return absl::make_unique(path); } } // namespace util diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/hard_assert.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/hard_assert.cc new file mode 100644 index 0000000..b0b5323 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/hard_assert.cc @@ -0,0 +1,55 @@ +/* + * Copyright 2018 Google + * + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" + +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/util/string_format.h" +#include "absl/base/config.h" + +namespace firebase { +namespace firestore { +namespace util { +namespace internal { + +void FailAssertion(const char* file, + const char* func, + const int line, + const std::string& message) { + Throw(ExceptionType::AssertionFailure, file, func, line, message); +} + +void FailAssertion(const char* file, + const char* func, + const int line, + const std::string& message, + const char* condition) { + std::string failure; + if (message.empty()) { + failure = condition; + } else { + failure = StringFormat("%s (expected %s)", message, condition); + } + FailAssertion(file, func, line, failure); +} + +} // namespace internal +} // namespace util +} // namespace firestore +} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/hard_assert.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/hard_assert.h index 6cea147..19b4d56 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/hard_assert.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/hard_assert.h @@ -20,7 +20,9 @@ #include #include +#include "Firestore/core/src/firebase/firestore/util/exception.h" #include "Firestore/core/src/firebase/firestore/util/string_format.h" +#include "absl/base/optimization.h" #if defined(_MSC_VER) #define FIRESTORE_FUNCTION_NAME __FUNCSIG__ @@ -28,6 +30,17 @@ #define FIRESTORE_FUNCTION_NAME __PRETTY_FUNCTION__ #endif +/** + * Invokes the internal Fail function below with all the required contextual + * information and passes additional arguments. + * + * @param message The failure message. + * @param condition The string form of the expression that failed (optional) + */ +#define INVOKE_INTERNAL_FAIL(...) \ + firebase::firestore::util::internal::FailAssertion( \ + __FILE__, FIRESTORE_FUNCTION_NAME, __LINE__, __VA_ARGS__) + /** * Fails the current function if the given condition is false. * @@ -37,14 +50,13 @@ * @param format (optional) A format string suitable for util::StringFormat. * @param ... format arguments to pass to util::StringFormat. */ -#define HARD_ASSERT(condition, ...) \ - do { \ - if (!(condition)) { \ - std::string _message = \ - firebase::firestore::util::StringFormat(__VA_ARGS__); \ - firebase::firestore::util::internal::Fail( \ - __FILE__, FIRESTORE_FUNCTION_NAME, __LINE__, _message, #condition); \ - } \ +#define HARD_ASSERT(condition, ...) \ + do { \ + if (!ABSL_PREDICT_TRUE(condition)) { \ + std::string _message = \ + firebase::firestore::util::StringFormat(__VA_ARGS__); \ + INVOKE_INTERNAL_FAIL(_message, #condition); \ + } \ } while (0) /** @@ -55,12 +67,11 @@ * @param format A format string suitable for util::StringFormat. * @param ... format arguments to pass to util::StringFormat. */ -#define HARD_FAIL(...) \ - do { \ - std::string _failure = \ - firebase::firestore::util::StringFormat(__VA_ARGS__); \ - firebase::firestore::util::internal::Fail( \ - __FILE__, FIRESTORE_FUNCTION_NAME, __LINE__, _failure); \ +#define HARD_FAIL(...) \ + do { \ + std::string _failure = \ + firebase::firestore::util::StringFormat(__VA_ARGS__); \ + INVOKE_INTERNAL_FAIL(_failure); \ } while (0) /** @@ -82,10 +93,11 @@ * * @param ptr The pointer to check and return. Can be a smart pointer. */ -#define NOT_NULL(ptr) \ - firebase::firestore::util::internal::NotNull( \ - __FILE__, FIRESTORE_FUNCTION_NAME, __LINE__, "Expected non-null " #ptr, \ - ptr) +#define NOT_NULL(ptr) \ + (static_cast(ABSL_PREDICT_FALSE((ptr) == nullptr) \ + ? INVOKE_INTERNAL_FAIL("Expected non-null " #ptr) \ + : static_cast(0)), \ + (ptr)) // NOLINT(whitespace/indent) namespace firebase { namespace firestore { @@ -93,28 +105,16 @@ namespace util { namespace internal { // A no-return helper function. To raise an assertion, use Macro instead. -ABSL_ATTRIBUTE_NORETURN void Fail(const char* file, - const char* func, - int line, - const std::string& message); - -ABSL_ATTRIBUTE_NORETURN void Fail(const char* file, - const char* func, - int line, - const std::string& message, - const char* condition); +ABSL_ATTRIBUTE_NORETURN void FailAssertion(const char* file, + const char* func, + int line, + const std::string& message); -template -T NotNull(const char* file, - const char* func, - int line, - const std::string& message, - T&& ptr) { - if (ptr == nullptr) { - Fail(file, func, line, message); - } - return std::forward(ptr); -} +ABSL_ATTRIBUTE_NORETURN void FailAssertion(const char* file, + const char* func, + int line, + const std::string& message, + const char* condition); } // namespace internal } // namespace util diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/hard_assert_apple.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/hard_assert_apple.mm deleted file mode 100644 index 6abd324..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/hard_assert_apple.mm +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2018 Google - * - * 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. - */ - -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" - -#import - -#include - -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" - -namespace firebase { -namespace firestore { -namespace util { -namespace internal { - -void Fail(const char* file, - const char* func, - const int line, - const std::string& message) { - [[NSAssertionHandler currentHandler] - handleFailureInFunction:WrapNSString(func) - file:WrapNSString(file) - lineNumber:line - description:@"FIRESTORE INTERNAL ASSERTION FAILED: %s", - message.c_str()]; - abort(); -} - -void Fail(const char* file, - const char* func, - const int line, - const std::string& message, - const char* condition) { - std::string failure; - if (message.empty()) { - failure = condition; - } else { - failure = StringFormat("%s (expected %s)", message, condition); - } - Fail(file, func, line, failure); -} - -} // namespace internal -} // namespace util -} // namespace firestore -} // namespace firebase diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/hashing.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/hashing.h index 4d8462a..c709609 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/hashing.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/hashing.h @@ -22,8 +22,10 @@ #include #include +#include "Firestore/core/src/firebase/firestore/objc/objc_type_traits.h" #include "Firestore/core/src/firebase/firestore/util/type_traits.h" #include "absl/meta/type_traits.h" +#include "absl/types/optional.h" namespace firebase { namespace firestore { @@ -92,7 +94,7 @@ using std_hash_type = /** * Combines a hash_value with whatever accumulated state there is so far. */ -inline size_t Combine(size_t state, size_t hash_value) { +constexpr size_t Combine(size_t state, size_t hash_value) { return 31 * state + hash_value; } @@ -121,7 +123,7 @@ template struct HashChoice : HashChoice {}; template <> -struct HashChoice<3> {}; +struct HashChoice<5> {}; template size_t InvokeHash(const K& value); @@ -145,7 +147,7 @@ auto RankedInvokeHash(const K& value, HashChoice<0>) -> decltype(value.Hash()) { * @return The result of `[value hash]`, converted to `size_t`. */ template ::value>> + typename = absl::enable_if_t::value>> size_t RankedInvokeHash(const K& value, HashChoice<1>) { return static_cast([value hash]); } @@ -168,7 +170,7 @@ std_hash_type RankedInvokeHash(const K& value, HashChoice<2>) { */ template auto RankedInvokeHash(const Range& range, HashChoice<3>) - -> decltype(impl::InvokeHash(*std::begin(range))) { + -> decltype(InvokeHash(*std::begin(range))) { size_t result = 0; size_t size = 0; for (auto&& element : range) { @@ -181,6 +183,22 @@ auto RankedInvokeHash(const Range& range, HashChoice<3>) return result; } +/** + * Hashes the contents of the given optional value, only if the underlying + * value can itself be hashed. + */ +template +auto RankedInvokeHash(const absl::optional& option, HashChoice<4>) + -> decltype(InvokeHash(*option)) { + return option ? InvokeHash(*option) : -1171; +} + +template ::value>> +size_t RankedInvokeHash(K value, HashChoice<5>) { + auto underlying = static_cast::type>(value); + return InvokeHash(underlying); +} + template size_t InvokeHash(const K& value) { return RankedInvokeHash(value, HashChoice<0>{}); diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/log.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/log.h index 248d434..7034ec6 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/log.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/log.h @@ -29,8 +29,12 @@ namespace util { enum LogLevel { // Debug Log Level kLogLevelDebug, + // Notice Log Level + kLogLevelNotice, // Warning Log Level kLogLevelWarning, + // Error Log Level + kLogLevelError, }; // Log a message if kLogLevelDebug is enabled. Arguments are not evaluated if @@ -63,6 +67,21 @@ enum LogLevel { } \ } while (0) +// Log a message if kLogLevelError is enabled (it is by default). Arguments are +// not evaluated if logging is disabled. +// +// @param format A format string suitable for use with `util::StringFormat` +// @param ... C++ variadic arguments that match the format string. Not C +// varargs. +#define LOG_ERROR(...) \ + do { \ + namespace _util = firebase::firestore::util; \ + if (_util::LogIsLoggable(_util::kLogLevelError)) { \ + std::string _message = _util::StringFormat(__VA_ARGS__); \ + _util::LogMessage(_util::kLogLevelError, _message); \ + } \ + } while (0) + // Tests to see if the given log level is loggable. bool LogIsLoggable(LogLevel level); diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/log_apple.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/log_apple.mm index e173b47..09d1851 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/log_apple.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/log_apple.mm @@ -32,13 +32,19 @@ namespace { +const FIRLoggerService kFIRLoggerFirestore = @"[Firebase/Firestore]"; + // Translates a C++ LogLevel to the equivalent Objective-C FIRLoggerLevel FIRLoggerLevel ToFIRLoggerLevel(LogLevel level) { switch (level) { case kLogLevelDebug: return FIRLoggerLevelDebug; + case kLogLevelNotice: + return FIRLoggerLevelNotice; case kLogLevelWarning: return FIRLoggerLevelWarning; + case kLogLevelError: + return FIRLoggerLevelError; default: // Unsupported log level. FIRSetLoggerLevel will deal with it. return static_cast(-1); @@ -64,7 +70,7 @@ void LogSetLevel(LogLevel level) { } bool LogIsLoggable(LogLevel level) { - return FIRIsLoggableLevel(ToFIRLoggerLevel(level), NO); + return FIRIsLoggableLevel(ToFIRLoggerLevel(level), false); } void LogMessage(LogLevel level, const std::string& message) { diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/nullability.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/nullability.h new file mode 100644 index 0000000..4313f26 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/nullability.h @@ -0,0 +1,44 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_NULLABILITY_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_NULLABILITY_H_ + +namespace firebase { +namespace firestore { +namespace util { + +// Define NS_ASSUME_NONNULL_BEGIN for straight C++ so that everything gets the +// correct nullability specifier. +#if !defined(NS_ASSUME_NONNULL_BEGIN) +#if __clang__ +#define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin") +#define NS_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end") + +#else // !__clang__ +#define NS_ASSUME_NONNULL_BEGIN +#define NS_ASSUME_NONNULL_END +#define _Nonnull +#define _Nullable + +#endif // __clang__ +#endif // !defined(NS_ASSUME_NONNULL_BEGIN) + +} // namespace util +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_NULLABILITY_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/objc_compatibility.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/objc_compatibility.h deleted file mode 100644 index 5745d77..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/objc_compatibility.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_OBJC_COMPATIBILITY_H_ -#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_OBJC_COMPATIBILITY_H_ - -#if !defined(__OBJC__) -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import - -#include -#include -#include -#include - -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" -#include "Firestore/core/src/firebase/firestore/util/to_string.h" -#include "Firestore/core/src/firebase/firestore/util/type_traits.h" -#include "absl/meta/type_traits.h" - -/** - * Utility functions that help C++ code interoperate with Objective-C while - * migration is in progress - */ - -namespace firebase { -namespace firestore { -namespace util { -namespace objc { - -namespace internal { - -template -using is_container_of_objc = - absl::conjunction, - is_objective_c_pointer>; - -} - -/** - * Checks two Objective-C objects for equality using `isEqual`. Two nil objects - * are considered equal, unlike the behavior of `isEqual`. - */ -template ::value>> -bool Equals(T* lhs, T* rhs) { - return (lhs == nil && rhs == nil) || [lhs isEqual:rhs]; -} - -/** Checks two C++ containers of Objective-C objects for "deep" equality. */ -template < - typename T, - typename = absl::enable_if_t::value>> -bool Equals(const T& lhs, const T& rhs) { - using Ptr = typename T::value_type; - - return lhs.size() == rhs.size() && - std::equal(lhs.begin(), lhs.end(), rhs.begin(), - [](Ptr o1, Ptr o2) { return Equals(o1, o2); }); -} - -/** - * A function object that implements equality for an Objective-C pointer by - * delegating to -isEqual:. This is useful for using Objective-C objects as - * keys in STL associative containers. - */ -template ::value>> -class EqualTo { - public: - bool operator()(T lhs, T rhs) const { - return [lhs isEqual:rhs]; - } -}; - -/** - * A function object that implements STL-compatible hash code for an Objective-C - * pointer by delegating to -hash. This is useful for using Objective-C objects - * as keys in std::unordered_map. - */ -template ::value>> -class Hash { - public: - size_t operator()(T value) const { - return static_cast([value hash]); - } -}; - -/** - * The equivalent of std::unordered_map, where the Key type is an Objective-C - * class. - */ -template ::value>> -using unordered_map = std::unordered_map, EqualTo>; - -/** - * Creates a debug description of the given `value` by calling `ToString` on it, - * converting the result to an `NSString`. Exists mainly to simplify writing - * `description:` methods for Objective-C classes. - */ -template -NSString* Description(const T& value) { - return WrapNSString(ToString(value)); -} - -} // namespace objc -} // namespace util -} // namespace firestore -} // namespace firebase - -#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_OBJC_COMPATIBILITY_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/ordered_code.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/ordered_code.cc index 03da08d..76c8f1e 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/ordered_code.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/ordered_code.cc @@ -22,6 +22,12 @@ #include "absl/base/internal/unaligned_access.h" #include "absl/base/port.h" +#if !defined(ABSL_IS_LITTLE_ENDIAN) && !defined(ABSL_IS_BIG_ENDIAN) +#error \ + "Unsupported byte order: Either ABSL_IS_BIG_ENDIAN or " \ + "ABSL_IS_LITTLE_ENDIAN must be defined" +#endif + #define UNALIGNED_LOAD32 ABSL_INTERNAL_UNALIGNED_LOAD32 #define UNALIGNED_LOAD64 ABSL_INTERNAL_UNALIGNED_LOAD64 #define UNALIGNED_STORE32 ABSL_INTERNAL_UNALIGNED_STORE32 @@ -125,8 +131,8 @@ inline static int AdvanceIfNoSpecialBytes(uint32_t v_32, const char* p) { inline static const char* SkipToNextSpecialByte(const char* start, const char* limit) { // If these constants were ever changed, this routine needs to change - HARD_ASSERT(kEscape1 == 0); - HARD_ASSERT((kEscape2 & 0xff) == 255); + static_assert(kEscape1 == 0, "bit fiddling needs readjusting"); + static_assert((kEscape2 & 0xff) == 255, "bit fiddling needs readjusting"); const char* p = start; while (p + 8 <= limit) { // Find out if any of the next 8 bytes are either 0 or 255 (our @@ -153,7 +159,7 @@ inline static const char* SkipToNextSpecialByte(const char* start, p += 8; } else { // We know the next 8 bytes have a special byte: find it -#ifdef IS_LITTLE_ENDIAN +#ifdef ABSL_IS_LITTLE_ENDIAN uint32_t v_32 = static_cast(v); // Low 32 bits of v #else uint32_t v_32 = UNALIGNED_LOAD32(p); diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/path.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/path.cc index 0d2d33d..8745710 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/path.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/path.cc @@ -203,6 +203,12 @@ bool Path::IsAbsolute() const { return util::IsAbsolute(c_str(), size()); } +bool Path::HasExtension(const Path& ext) const { + return pathname_.size() >= ext.size() && + pathname_.compare(pathname_.size() - ext.size(), ext.size(), + ext.native_value()) == 0; +} + Path Path::AppendUtf8(absl::string_view path) const { Path result{*this}; result.MutableAppendUtf8(path); diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/path.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/path.h index cecbc88..90d461e 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/path.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/path.h @@ -72,8 +72,7 @@ class Path { } #endif - Path() { - } + Path() = default; const string_type& native_value() const { return pathname_; @@ -83,6 +82,10 @@ class Path { return pathname_.c_str(); } + bool empty() const { + return pathname_.empty(); + } + size_t size() const { return pathname_.size(); } @@ -95,7 +98,7 @@ class Path { #if defined(__OBJC__) NSString* ToNSString() const { - return WrapNSString(native_value()); + return MakeNSString(native_value()); } #endif @@ -123,6 +126,14 @@ class Path { */ bool IsAbsolute() const; + /** + * Returns true if this pathname's last component has the given file + * extension. + * + * @param ext The file extension (including leading dot). + */ + bool HasExtension(const Path& ext) const; + /** * Returns a new Path with the given UTF-8 encoded path segment appended, * as if by calling `Append(Path::FromUtf8(path))`. diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/sanitizers.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/sanitizers.h new file mode 100644 index 0000000..3847d39 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/sanitizers.h @@ -0,0 +1,55 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_SANITIZERS_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_SANITIZERS_H_ + +// Clang feature detection compiler extension +#if defined(__has_feature) +#define HAS_FEATURE(FEATURE) __has_feature(FEATURE) +#else +#define HAS_FEATURE(FEATURE) 0 +#endif + +// Auto-detect the presence of sanitizers. Abseil does not do this yet, and +// instead relies on users to pass e.g. -DADDRESS_SANITIZER on the command-line. + +// Clang and GCC 4.8 +#if !defined(ADDRESS_SANITIZER) +#if HAS_FEATURE(address_sanitizer) || \ + (defined(__GNUC__) && defined(__SANITIZE_ADDRESS__)) +#define ADDRESS_SANITIZER 1 +#endif +#endif // !defined(ADDRESS_SANITIZER) + +// Clang-only +#if !defined(MEMORY_SANITIZER) +#if HAS_FEATURE(memory_sanitizer) +#define MEMORY_SANITIZER 1 +#endif +#endif // !defined(MEMORY_SANITIZER) + +// Clang and GCC 4.8+ +#if !defined(THREAD_SANITIZER) +#if HAS_FEATURE(thread_sanitizer) || \ + (defined(__GNUC__) && defined(__SANITIZE_THREAD__)) +#define THREAD_SANITIZER 1 +#endif +#endif // !defined(THREAD_SANITIZER) + +// There doesn't appear to be a __has_feature check for ubsan. + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_SANITIZERS_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status.cc index 06a643d..c184629 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status.cc @@ -17,6 +17,7 @@ #include "Firestore/core/src/firebase/firestore/util/status.h" #include +#include #include "Firestore/core/src/firebase/firestore/util/string_format.h" #include "absl/memory/memory.h" @@ -25,11 +26,9 @@ namespace firebase { namespace firestore { namespace util { -Status::Status(FirestoreErrorCode code, absl::string_view msg) { - HARD_ASSERT(code != FirestoreErrorCode::Ok); - state_ = absl::make_unique(); - state_->code = code; - state_->msg = static_cast(msg); +Status::Status(Error code, std::string msg) { + HARD_ASSERT(code != Error::Ok); + state_ = State::MakePtr(code, std::move(msg)); } void Status::Update(const Status& new_status) { @@ -39,24 +38,56 @@ void Status::Update(const Status& new_status) { } Status& Status::CausedBy(const Status& cause) { - if (cause.ok() || this == &cause) { + if (cause.ok() || this == &cause || cause.IsMovedFrom()) { return *this; } - if (ok()) { + if (ok() || IsMovedFrom()) { *this = cause; return *this; } + std::string new_message = error_message(); absl::StrAppend(&state_->msg, ": ", cause.error_message()); + + // If this Status has no accompanying PlatformError but the cause does, create + // a PlatformError for this Status ahead of time to preserve the causal chain + // that Status doesn't otherwise support. + if (state_->platform_error == nullptr && + cause.state_->platform_error != nullptr) { + state_->platform_error = + cause.state_->platform_error->WrapWith(code(), error_message()); + } + + return *this; +} + +Status& Status::WithPlatformError(std::unique_ptr error) { + HARD_ASSERT(!ok(), "Platform errors should not be applied to Status::OK()"); + if (IsMovedFrom()) { + std::string message = moved_from_message(); + state_ = State::MakePtr(Error::Internal, std::move(message)); + } + state_->platform_error = std::move(error); return *this; } +void Status::State::Deleter::operator()(const State* ptr) const { + if (ptr != State::MovedFromIndicator()) { + delete ptr; + } +} + +void Status::SetMovedFrom() { + // Set pointer value to `0x1` as the pointer is no longer useful. + state_ = State::StatePtr{State::MovedFromIndicator()}; +} + void Status::SlowCopyFrom(const State* src) { if (src == nullptr) { state_ = nullptr; } else { - state_ = absl::make_unique(*src); + state_ = State::MakePtr(*src); } } @@ -65,58 +96,63 @@ const std::string& Status::empty_string() { return *empty; } +const std::string& Status::moved_from_message() { + static std::string* message = new std::string("Status accessed after move."); + return *message; +} + std::string Status::ToString() const { if (state_ == nullptr) { return "OK"; } else { std::string result; switch (code()) { - case FirestoreErrorCode::Cancelled: + case Error::Cancelled: result = "Cancelled"; break; - case FirestoreErrorCode::Unknown: + case Error::Unknown: result = "Unknown"; break; - case FirestoreErrorCode::InvalidArgument: + case Error::InvalidArgument: result = "Invalid argument"; break; - case FirestoreErrorCode::DeadlineExceeded: + case Error::DeadlineExceeded: result = "Deadline exceeded"; break; - case FirestoreErrorCode::NotFound: + case Error::NotFound: result = "Not found"; break; - case FirestoreErrorCode::AlreadyExists: + case Error::AlreadyExists: result = "Already exists"; break; - case FirestoreErrorCode::PermissionDenied: + case Error::PermissionDenied: result = "Permission denied"; break; - case FirestoreErrorCode::Unauthenticated: + case Error::Unauthenticated: result = "Unauthenticated"; break; - case FirestoreErrorCode::ResourceExhausted: + case Error::ResourceExhausted: result = "Resource exhausted"; break; - case FirestoreErrorCode::FailedPrecondition: + case Error::FailedPrecondition: result = "Failed precondition"; break; - case FirestoreErrorCode::Aborted: + case Error::Aborted: result = "Aborted"; break; - case FirestoreErrorCode::OutOfRange: + case Error::OutOfRange: result = "Out of range"; break; - case FirestoreErrorCode::Unimplemented: + case Error::Unimplemented: result = "Unimplemented"; break; - case FirestoreErrorCode::Internal: + case Error::Internal: result = "Internal"; break; - case FirestoreErrorCode::Unavailable: + case Error::Unavailable: result = "Unavailable"; break; - case FirestoreErrorCode::DataLoss: + case Error::DataLoss: result = "Data loss"; break; default: @@ -124,7 +160,7 @@ std::string Status::ToString() const { break; } result += ": "; - result += state_->msg; + result += IsMovedFrom() ? moved_from_message() : state_->msg; return result; } } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status.h index d49089e..c21135e 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status.h @@ -25,9 +25,11 @@ #include #include #include +#include #include "Firestore/core/include/firebase/firestore/firestore_errors.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/status_fwd.h" #include "absl/base/attributes.h" #include "absl/strings/string_view.h" @@ -35,21 +37,26 @@ namespace firebase { namespace firestore { namespace util { +class PlatformError; + /// Denotes success or failure of a call. class ABSL_MUST_USE_RESULT Status { public: /// Create a success status. - Status() { - } + Status() = default; /// \brief Create a status with the specified error code and msg as a /// human-readable string containing more detailed information. - Status(FirestoreErrorCode code, absl::string_view msg); + Status(Error code, std::string msg); /// Copy the specified status. Status(const Status& s); void operator=(const Status& s); + /// Move the specified status. + Status(Status&& s) noexcept; + void operator=(Status&& s) noexcept; + static Status OK() { return Status(); } @@ -63,19 +70,22 @@ class ABSL_MUST_USE_RESULT Status { #if defined(__OBJC__) static Status FromNSError(NSError* error); + + NSError* ToNSError() const; #endif // defined(__OBJC__) /// Returns true iff the status indicates success. bool ok() const { - return (state_ == nullptr); + return state_ == nullptr; } - FirestoreErrorCode code() const { - return ok() ? FirestoreErrorCode::Ok : state_->code; + Error code() const { + return ok() ? Error::Ok : (IsMovedFrom() ? Error::Internal : state_->code); } const std::string& error_message() const { - return ok() ? empty_string() : state_->msg; + return ok() ? empty_string() + : (IsMovedFrom() ? moved_from_message() : state_->msg); } bool operator==(const Status& x) const; @@ -97,6 +107,8 @@ class ABSL_MUST_USE_RESULT Status { /// \return *this Status& CausedBy(const Status& cause); + Status& WithPlatformError(std::unique_ptr error); + /// \brief Return a string representation of this status suitable for /// printing. Returns the string `"OK"` for success. std::string ToString() const; @@ -109,19 +121,86 @@ class ABSL_MUST_USE_RESULT Status { private: static const std::string& empty_string(); + static const std::string& moved_from_message(); + struct State { - FirestoreErrorCode code; + State() = default; + State(const State& other); + State(Error code, std::string&& msg); + + struct Deleter { + void operator()(const State* ptr) const; + }; + // A `unique_ptr` with a custom deleter. If the pointer's value has been set + // to a special value (0x01) to indicate it is moved, invoking the custom + // deleter will be a no-op. + using StatePtr = std::unique_ptr; + + static State* MovedFromIndicator() { + return reinterpret_cast(0x01); + } + + template + static StatePtr MakePtr(Args&&... args) { + return StatePtr(new State(std::forward(args)...)); + } + + Error code; std::string msg; + + // An additional platform-specific error representation that was used to + // generate this Status. The PlatformError does not meaningfully contribute + // to the identity of this Status: it exists to allow tunneling e.g. + // NSError* to Status and back to NSError* losslessly. + std::unique_ptr platform_error; }; - // OK status has a `NULL` state_. Otherwise, `state_` points to - // a `State` structure containing the error code and message(s) - std::unique_ptr state_; + + // Asserts if `state_` is a valid pointer, should be used at all places where + // it is used as a pointer, instead of using `state_`. + bool IsMovedFrom() const { + return state_.get() == State::MovedFromIndicator(); + } + + // OK status has a `nullptr` `state_`. If this instance is moved, state_ has + // the value of `State::MovedFromIndicator()`. Otherwise `state_` points to + // a `State` structure containing the error code and message(s). + State::StatePtr state_; + + // Tags this instance as `moved-from`. + void SetMovedFrom(); void SlowCopyFrom(const State* src); }; +class PlatformError { + public: + virtual ~PlatformError() { + } + + virtual std::unique_ptr Copy() = 0; + + /** + * Creates a new PlatformError with the given code and message, whose cause is + * this PlatformError. + */ + virtual std::unique_ptr WrapWith(Error code, + std::string message) = 0; +}; + inline Status::Status(const Status& s) - : state_((s.state_ == nullptr) ? nullptr : new State(*s.state_)) { + : state_{s.state_ == nullptr ? State::StatePtr{} + : State::MakePtr(*s.state_)} { +} + +inline Status::State::State(const State& s) + : code(s.code), + msg(s.msg), + platform_error((s.platform_error == nullptr) ? nullptr + : s.platform_error->Copy()) { +} + +inline Status::State::State(Error code, std::string&& msg) + : code(code), msg(std::move(msg)) { } inline void Status::operator=(const Status& s) { @@ -132,6 +211,18 @@ inline void Status::operator=(const Status& s) { } } +inline Status::Status(Status&& s) noexcept : state_(std::move(s.state_)) { + s.SetMovedFrom(); +} + +inline void Status::operator=(Status&& s) noexcept { + // Moving into self is a no-op. + if (this != &s) { + state_ = std::move(s.state_); + s.SetMovedFrom(); + } +} + inline bool Status::operator==(const Status& x) const { return (this->state_ == x.state_) || (ToString() == x.ToString()); } @@ -140,7 +231,7 @@ inline bool Status::operator!=(const Status& x) const { return !(*this == x); } -typedef std::function StatusCallback; +typedef std::function StatusCallback; extern std::string StatusCheckOpHelperOutOfLine(const Status& v, const char* msg); diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_apple.mm b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_apple.mm index f0bf7a6..87f21cf 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_apple.mm +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_apple.mm @@ -18,30 +18,105 @@ #if defined(__APPLE__) +#include "Firestore/core/src/firebase/firestore/util/error_apple.h" #include "Firestore/core/src/firebase/firestore/util/string_format.h" +#include "absl/memory/memory.h" namespace firebase { namespace firestore { namespace util { +class UnderlyingNSError : public PlatformError { + public: + explicit UnderlyingNSError(NSError* error) : error_(error) { + } + + static std::unique_ptr Create(NSError* error) { + return absl::make_unique(error); + } + + static NSError* Recover( + const std::unique_ptr& platform_error) { + if (platform_error == nullptr) { + return nil; + } + + return static_cast(platform_error.get())->error(); + } + + std::unique_ptr Copy() override { + return absl::make_unique(error_); + } + + std::unique_ptr WrapWith(Error code, + std::string message) override { + NSError* chain = MakeNSError(code, message, error_); + return Create(chain); + } + + NSError* error() const { + return error_; + } + + private: + NSError* error_; +}; + +namespace { + +/** + * Converts a Firestore-generated NSError to the equivalent status. + */ +Status FromFirestoreNSError(NSError* error) { + auto error_code = static_cast(error.code); + HARD_ASSERT( + error_code >= Error::Cancelled && error_code <= Error::Unauthenticated, + "Unknown error code"); + + auto original = UnderlyingNSError::Create(error); + + return Status(static_cast(error_code), + MakeString(error.localizedDescription)) + .WithPlatformError(std::move(original)); +} + +} // namespace + Status Status::FromNSError(NSError* error) { if (!error) { return Status::OK(); } - NSError* original = error; + if ([error.domain isEqual:FIRFirestoreErrorDomain]) { + return FromFirestoreNSError(error); + } + + auto original = UnderlyingNSError::Create(error); while (error) { if ([error.domain isEqualToString:NSPOSIXErrorDomain]) { return FromErrno(static_cast(error.code), - MakeString(original.localizedDescription)); + MakeString(original->error().localizedDescription)) + .WithPlatformError(std::move(original)); } error = error.userInfo[NSUnderlyingErrorKey]; } - return Status{FirestoreErrorCode::Unknown, - StringFormat("Unknown error: %s", original)}; + return Status{Error::Unknown, + StringFormat("Unknown error: %s", original->error())} + .WithPlatformError(std::move(original)); +} + +NSError* Status::ToNSError() const { + if (ok()) return nil; + // Early exit because `state_` is moved. + if (IsMovedFrom()) return MakeNSError(code(), error_message()); + + NSError* error = UnderlyingNSError::Recover(state_->platform_error); + if (error) return error; + + return MakeNSError(code(), error_message()); } } // namespace util diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_fwd.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_fwd.h new file mode 100644 index 0000000..65ee204 --- /dev/null +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_fwd.h @@ -0,0 +1,42 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUS_FWD_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUS_FWD_H_ + +#include + +namespace firebase { +namespace firestore { +namespace util { + +// Forward declarations for Status classes. + +class Status; + +using StatusCallback = std::function; + +template +class StatusOr; + +template +using StatusOrCallback = std::function)>; + +} // namespace util +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUS_FWD_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_posix.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_posix.cc index 79c651b..90bf79b 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_posix.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_posix.cc @@ -26,10 +26,10 @@ namespace firestore { namespace util { /// Returns the Canonical error code for the given errno value. -static FirestoreErrorCode CodeForErrno(int errno_code) { +static Error CodeForErrno(int errno_code) { switch (errno_code) { case 0: - return FirestoreErrorCode::Ok; + return Error::Ok; // Internal canonical mappings call these failed preconditions, but for // our purposes these must indicate an internal error in file handling. @@ -37,7 +37,7 @@ static FirestoreErrorCode CodeForErrno(int errno_code) { #if defined(EBADFD) case EBADFD: // File descriptor in bad state #endif - return FirestoreErrorCode::Internal; + return Error::Internal; case EINVAL: // Invalid argument case ENAMETOOLONG: // Filename too long @@ -52,11 +52,11 @@ static FirestoreErrorCode CodeForErrno(int errno_code) { case ENOTTY: // Inappropriate I/O control operation case EPROTOTYPE: // Protocol wrong type for socket case ESPIPE: // Invalid seek - return FirestoreErrorCode::InvalidArgument; + return Error::InvalidArgument; case ETIMEDOUT: // Connection timed out case ETIME: // Timer expired - return FirestoreErrorCode::DeadlineExceeded; + return Error::DeadlineExceeded; case ENODEV: // No such device case ENOENT: // No such file or directory @@ -65,7 +65,7 @@ static FirestoreErrorCode CodeForErrno(int errno_code) { #endif case ENXIO: // No such device or address case ESRCH: // No such process - return FirestoreErrorCode::NotFound; + return Error::NotFound; case EEXIST: // File exists case EADDRNOTAVAIL: // Address not available @@ -73,7 +73,7 @@ static FirestoreErrorCode CodeForErrno(int errno_code) { #if defined(ENOTUNIQ) case ENOTUNIQ: // Name not unique on network #endif - return FirestoreErrorCode::AlreadyExists; + return Error::AlreadyExists; case EPERM: // Operation not permitted case EACCES: // Permission denied @@ -81,7 +81,7 @@ static FirestoreErrorCode CodeForErrno(int errno_code) { case ENOKEY: // Required key not available #endif case EROFS: // Read only file system - return FirestoreErrorCode::PermissionDenied; + return Error::PermissionDenied; case ENOTEMPTY: // Directory not empty case EISDIR: // Is a directory @@ -105,7 +105,7 @@ static FirestoreErrorCode CodeForErrno(int errno_code) { #if defined(EUNATCH) case EUNATCH: // Protocol driver not attached #endif - return FirestoreErrorCode::FailedPrecondition; + return Error::FailedPrecondition; case ENOSPC: // No space left on device #if defined(EDQUOT) @@ -121,7 +121,7 @@ static FirestoreErrorCode CodeForErrno(int errno_code) { #if defined(EUSERS) case EUSERS: // Too many users #endif - return FirestoreErrorCode::ResourceExhausted; + return Error::ResourceExhausted; #if defined(ECHRNG) case ECHRNG: // Channel number out of range @@ -129,7 +129,7 @@ static FirestoreErrorCode CodeForErrno(int errno_code) { case EFBIG: // File too large case EOVERFLOW: // Value too large to be stored in data type case ERANGE: // Result too large - return FirestoreErrorCode::OutOfRange; + return Error::OutOfRange; #if defined(ENOPKG) case ENOPKG: // Package not installed @@ -145,7 +145,7 @@ static FirestoreErrorCode CodeForErrno(int errno_code) { case ESOCKTNOSUPPORT: // Socket type not supported #endif case EXDEV: // Improper link - return FirestoreErrorCode::Unimplemented; + return Error::Unimplemented; case EAGAIN: // Resource temporarily unavailable #if defined(ECOMM) @@ -167,24 +167,28 @@ static FirestoreErrorCode CodeForErrno(int errno_code) { #if defined(ENONET) case ENONET: // Machine is not on the network #endif - return FirestoreErrorCode::Unavailable; + return Error::Unavailable; case EDEADLK: // Resource deadlock avoided #if defined(ESTALE) case ESTALE: // Stale file handle #endif - return FirestoreErrorCode::Aborted; + return Error::Aborted; case ECANCELED: // Operation cancelled - return FirestoreErrorCode::Cancelled; + return Error::Cancelled; default: - return FirestoreErrorCode::Unknown; + return Error::Unknown; } } Status Status::FromErrno(int errno_code, absl::string_view msg) { - FirestoreErrorCode canonical_code = CodeForErrno(errno_code); + if (errno_code == 0) { + return Status::OK(); + } + + Error canonical_code = CodeForErrno(errno_code); return Status{canonical_code, util::StringFormat("%s (errno %s: %s)", msg, errno_code, StrError(errno_code))}; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_win.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_win.cc index a268da2..3b95436 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_win.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/status_win.cc @@ -29,39 +29,39 @@ namespace util { * Returns the Canonical error code for the given Windows API error code as * obtained from GetLastError(). */ -static FirestoreErrorCode CodeForLastError(DWORD error) { +static Error CodeForLastError(DWORD error) { switch (error) { case ERROR_SUCCESS: - return FirestoreErrorCode::Ok; + return Error::Ok; - // return FirestoreErrorCode::Internal; + // return Error::Internal; case ERROR_INVALID_FUNCTION: case ERROR_INVALID_HANDLE: case ERROR_INVALID_NAME: - return FirestoreErrorCode::InvalidArgument; + return Error::InvalidArgument; - // return FirestoreErrorCode::DeadlineExceeded; + // return Error::DeadlineExceeded; case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_INVALID_DRIVE: case ERROR_BAD_NETPATH: case ERROR_DEV_NOT_EXIST: - return FirestoreErrorCode::NotFound; + return Error::NotFound; case ERROR_FILE_EXISTS: case ERROR_ALREADY_EXISTS: - return FirestoreErrorCode::AlreadyExists; + return Error::AlreadyExists; case ERROR_ACCESS_DENIED: case ERROR_INVALID_ACCESS: case ERROR_SHARING_VIOLATION: case ERROR_WRITE_PROTECT: case ERROR_LOCK_VIOLATION: - return FirestoreErrorCode::PermissionDenied; + return Error::PermissionDenied; - // return FirestoreErrorCode::FailedPrecondition; + // return Error::FailedPrecondition; case ERROR_TOO_MANY_OPEN_FILES: case ERROR_NOT_ENOUGH_MEMORY: @@ -69,22 +69,22 @@ static FirestoreErrorCode CodeForLastError(DWORD error) { case ERROR_NO_MORE_FILES: case ERROR_DISK_FULL: case ERROR_HANDLE_DISK_FULL: - return FirestoreErrorCode::ResourceExhausted; + return Error::ResourceExhausted; - // return FirestoreErrorCode::OutOfRange; + // return Error::OutOfRange; case ERROR_CALL_NOT_IMPLEMENTED: - return FirestoreErrorCode::Unimplemented; + return Error::Unimplemented; case ERROR_NOT_READY: - return FirestoreErrorCode::Unavailable; + return Error::Unavailable; - // return FirestoreErrorCode::Aborted; + // return Error::Aborted; - // return FirestoreErrorCode::Cancelled; + // return Error::Cancelled; default: - return FirestoreErrorCode::Unknown; + return Error::Unknown; } } @@ -93,7 +93,7 @@ Status Status::FromLastError(DWORD error, absl::string_view msg) { return Status::OK(); } - FirestoreErrorCode canonical_code = CodeForLastError(error); + Error canonical_code = CodeForLastError(error); std::string error_text = LastErrorMessage(error); return Status{canonical_code, util::StringFormat("%s (error %s: %s)", msg, error, error_text)}; diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor.cc b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor.cc index bbd5781..56ac590 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor.cc +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor.cc @@ -27,7 +27,7 @@ void Helper::HandleInvalidStatusCtorArg(Status* status) { "An OK status is not a valid constructor argument to StatusOr"; HARD_FAIL("%s", kMessage); // Fall back to Internal for non-debug builds - *status = Status(FirestoreErrorCode::Internal, kMessage); + *status = Status(Error::Internal, kMessage); } void Helper::Crash(const Status& status) { diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor.h index 9985956..587fc45 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor.h @@ -59,7 +59,7 @@ // // StatusOr FooFactory::MakeNewFoo(int arg) { // if (arg <= 0) { -// return Status(FirestoreErrorCode::InvalidArgument, +// return Status(Error::InvalidArgument, // "Arg must be positive"); // } else { // return new Foo(arg); @@ -150,7 +150,7 @@ class ABSL_MUST_USE_RESULT StatusOr // // REQUIRES: !status.ok(). This requirement is DCHECKed. // In optimized builds, passing Status::OK() here will have the effect - // of passing FirestoreErrorCode::Internal as a fallback. + // of passing Error::Internal as a fallback. StatusOr(const Status& status); // NOLINT: allow non-explicit 1-param ctor StatusOr& operator=(const Status& status); @@ -214,7 +214,7 @@ class ABSL_MUST_USE_RESULT StatusOr // Implementation details for StatusOr template -StatusOr::StatusOr() : Base(Status(FirestoreErrorCode::Unknown, "")) { +StatusOr::StatusOr() : Base(Status(Error::Unknown, "")) { } template diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor_callback.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor_callback.h deleted file mode 100644 index ff39b5d..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor_callback.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2019 Google - * - * 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. - */ - -#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_CALLBACK_H_ -#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_CALLBACK_H_ - -#include - -#include "Firestore/core/src/firebase/firestore/util/statusor.h" - -namespace firebase { -namespace firestore { -namespace util { - -template -using StatusOrCallback = std::function)>; - -} // namespace util -} // namespace firestore -} // namespace firebase - -#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STATUSOR_CALLBACK_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor_internals.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor_internals.h index d6c8de1..e662307 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor_internals.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/statusor_internals.h @@ -118,7 +118,7 @@ class StatusOrData { return *this; } - StatusOrData& operator=(StatusOrData&& other) { + StatusOrData& operator=(StatusOrData&& other) noexcept { if (this == &other) return *this; if (other.ok()) Assign(std::move(other.data_)); diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/string_apple.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/string_apple.h index 436d2ab..71f86d9 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/string_apple.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/string_apple.h @@ -24,10 +24,13 @@ #import #endif +#include #include #include "absl/strings/string_view.h" +CF_ASSUME_NONNULL_BEGIN + namespace firebase { namespace firestore { namespace util { @@ -45,28 +48,21 @@ inline CFStringRef MakeCFString(absl::string_view contents) { #if defined(__OBJC__) -// Translates a C string to the equivalent NSString without making a copy. -inline NSString* WrapNSStringNoCopy(const char* c_str) { - return [[NSString alloc] - initWithBytesNoCopy:const_cast(static_cast(c_str)) - length:strlen(c_str) - encoding:NSUTF8StringEncoding - freeWhenDone:NO]; -} - -// Translates a string_view to the equivalent NSString without making a copy. -inline NSString* WrapNSStringNoCopy(const absl::string_view str) { - return WrapNSStringNoCopy(str.data()); -} - // Translates a string_view string to the equivalent NSString by making a copy. -inline NSString* WrapNSString(const absl::string_view str) { +inline NSString* MakeNSString(absl::string_view str) { return [[NSString alloc] initWithBytes:const_cast(static_cast(str.data())) length:str.length() encoding:NSUTF8StringEncoding]; } +// Translates a nullable pointer to string to the equivalent NSString by making +// a copy. +inline NSString* _Nullable MakeNSString( + const std::shared_ptr& str) { + return str ? MakeNSString(*str) : nil; +} + // Creates an absl::string_view wrapper for the contents of the given // NSString. inline absl::string_view MakeStringView(NSString* str) { @@ -80,11 +76,21 @@ inline std::string MakeString(NSString* str) { return MakeString(cf_str); } +// Creates a nullable shared_ptr pointing to a string for the contents of the +// given NSString, or nullptr if it's nil. +inline std::shared_ptr MakeStringPtr( + NSString* _Nullable str) { + if (!str) return nullptr; + return std::make_shared(MakeString(str)); +} + #endif // defined(__OBJC__) } // namespace util } // namespace firestore } // namespace firebase +CF_ASSUME_NONNULL_END + #endif // defined(__APPLE__) #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_APPLE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/string_format.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/string_format.h index e76aeae..8858e1c 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/string_format.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/string_format.h @@ -21,6 +21,7 @@ #include #include +#include "Firestore/core/src/firebase/firestore/objc/objc_type_traits.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/src/firebase/firestore/util/type_traits.h" #include "absl/base/attributes.h" @@ -57,7 +58,7 @@ struct FormatChoice<5> {}; * * If the value is of type `const char*`, the text will be the value * interpreted as a C string. To show the address of a single char or to * show the `const char*` as an address, cast to `void*`. - * * If the value is any other pointer type, the text will be the hexidecimal + * * If the value is any other pointer type, the text will be the hexadecimal * formatting of the value as an unsigned integer. * * Otherwise the value is interpreted as anything absl::AlphaNum accepts. */ @@ -88,7 +89,7 @@ class FormatArg : public absl::AlphaNum { */ template < typename T, - typename = typename std::enable_if{}>::type> + typename = typename std::enable_if{}>::type> FormatArg(T object, internal::FormatChoice<1>) : AlphaNum{MakeStringView([object description])} { } @@ -121,7 +122,7 @@ class FormatArg : public absl::AlphaNum { /** * Creates a FormatArg from an arbitrary pointer, represented as a - * hexidecimal integer literal. + * hexadecimal integer literal. */ template FormatArg(T* pointer_value, internal::FormatChoice<4>) diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/to_string.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/to_string.h index 32f767f..5e1f5ee 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/to_string.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/to_string.h @@ -17,16 +17,13 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_TO_STRING_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_TO_STRING_H_ -#if __OBJC__ -#import -#endif // __OBJC__ - #include #include #include #include #include +#include "Firestore/core/src/firebase/firestore/objc/objc_type_traits.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/src/firebase/firestore/util/string_format.h" #include "Firestore/core/src/firebase/firestore/util/type_traits.h" @@ -124,7 +121,7 @@ struct ToStringChoice<6> {}; // Objective-C class template ::value>> + typename = absl::enable_if_t::value>> std::string ToStringImpl(T value, ToStringChoice<0>) { return MakeString([value description]); } diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/type_traits.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/type_traits.h index fbec417..d7ae2a1 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/type_traits.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/type_traits.h @@ -17,10 +17,6 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_TYPE_TRAITS_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_TYPE_TRAITS_H_ -#if __OBJC__ -#import // for id -#endif - #include #include @@ -30,28 +26,6 @@ namespace firebase { namespace firestore { namespace util { -#if __OBJC__ - -/** - * A type trait that identifies whether or not the given pointer points to an - * Objective-C object. - * - * is_objective_c_pointer::value == true - * is_objective_c_pointer*>::value == true - * - * // id is a dynamically typed pointer to an Objective-C object. - * is_objective_c_pointer::value == true - * - * // pointers to C++ classes are not Objective-C pointers. - * is_objective_c_pointer::value == false - * is_objective_c_pointer::value == false - * is_objective_c_pointer>::value == false - */ -template -using is_objective_c_pointer = std::is_convertible; - -#endif // __OBJC__ - // is_iterable template > diff --git a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/warnings.h b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/warnings.h index 6ce6017..7d82de3 100644 --- a/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/warnings.h +++ b/Example/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/util/warnings.h @@ -42,48 +42,50 @@ #define SUPPRESS_BEGIN_(name) _Pragma("GCC diagnostic push") _Pragma(name) +#define SUPPRESS_END() _Pragma("GCC diagnostic pop") + #elif defined(_MSC_VER) #define SUPPRESS_BEGIN_UNIMPLEMENTED_() __pragma(warning(push)) #define SUPPRESS_BEGIN_(name) \ __pragma(warning(push)) __pragma(warning(disable : name)) +#define SUPPRESS_END() __pragma(warning(pop)) + +#else +#define SUPPRESS_BEGIN_UNIMPLEMENTED_() +#define SUPPRESS_END() #endif // 'Public' macros. +// Ignore -Wcomma warnings in Clang +#if defined(__clang__) +#define SUPPRESS_COMMA_WARNINGS_BEGIN() \ + SUPPRESS_BEGIN_("GCC diagnostic ignored \"-Wcomma\"") +#else +#define SUPPRESS_COMMA_WARNINGS_BEGIN() SUPPRESS_BEGIN_UNIMPLEMENTED_() +#endif + +// Ignore -Wdocumentation warnings in Clang #if defined(__clang__) #define SUPPRESS_DOCUMENTATION_WARNINGS_BEGIN() \ SUPPRESS_BEGIN_("GCC diagnostic ignored \"-Wdocumentation\"") - -#define SUPPRESS_DEPRECATED_DECLARATIONS_BEGIN() \ - SUPPRESS_BEGIN_("GCC diagnostic ignored \"-Wdeprecated-declarations\"") - -#define SUPPRESS_END() _Pragma("GCC diagnostic pop") - -#elif defined(__GNUC__) +#else #define SUPPRESS_DOCUMENTATION_WARNINGS_BEGIN() SUPPRESS_BEGIN_UNIMPLEMENTED_() +#endif +// Ignore the use of deprecated declarations. +#if defined(__clang__) || defined(__GNUC__) #define SUPPRESS_DEPRECATED_DECLARATIONS_BEGIN() \ SUPPRESS_BEGIN_("GCC diagnostic ignored \"-Wdeprecated-declarations\"") - -#define SUPPRESS_END() _Pragma("GCC diagnostic pop") - #elif defined(_MSC_VER) // MSVC compiler warnings can be found here: (Look at the navbar on the left // and select the appropriate range): // https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warnings-by-compiler-version?view=vs-2017 -#define SUPPRESS_DOCUMENTATION_WARNINGS_BEGIN() SUPPRESS_BEGIN_UNIMPLEMENTED_() - #define SUPPRESS_DEPRECATED_DECLARATIONS_BEGIN() SUPPRESS_BEGIN_(4995) - -#define SUPPRESS_END() __pragma(warning(pop)) - #else -#define SUPPRESS_DOCUMENTATION_WARNINGS_BEGIN() -#define SUPPRESS_DEPRECATED_DECLARATIONS_BEGIN() -#define SUPPRESS_END() - +#define SUPPRESS_DEPRECATED_DECLARATIONS_BEGIN() SUPPRESS_BEGIN_UNIMPLEMENTED_() #endif #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_WARNINGS_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTArraySortedDictionary.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTArraySortedDictionary.h deleted file mode 100644 index 0fd7b44..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTArraySortedDictionary.h +++ /dev/null @@ -1,35 +0,0 @@ -#import - -#import "Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h" - -NS_ASSUME_NONNULL_BEGIN - -/** - * FSTArraySortedDictionary is an array backed implementation of FSTImmutableSortedDictionary. - * - * You should not use this class directly. You should use FSTImmutableSortedDictionary. - * - * FSTArraySortedDictionary uses arrays and linear lookups to achieve good memory efficiency while - * maintaining good performance for small collections. It also uses fewer allocations than a - * comparable red black tree. To avoid degrading performance with increasing collection size it - * will automatically convert to a FSTTreeSortedDictionary after an insert call above a certain - * threshold. - */ -@interface FSTArraySortedDictionary : - FSTImmutableSortedDictionary - -+ (FSTArraySortedDictionary *) - dictionaryWithDictionary:(NSDictionary *)dictionary - comparator:(NSComparator)comparator; - -- (id)init __attribute__((unavailable("Use initWithComparator:keys:values: instead."))); - -- (instancetype)initWithComparator:(NSComparator)comparator; - -- (instancetype)initWithComparator:(NSComparator)comparator - keys:(NSArray *)keys - values:(NSArray *)values NS_DESIGNATED_INITIALIZER; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTArraySortedDictionary.m b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTArraySortedDictionary.m deleted file mode 100644 index 985b514..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTArraySortedDictionary.m +++ /dev/null @@ -1,228 +0,0 @@ -#import "Firestore/third_party/Immutable/FSTArraySortedDictionary.h" - -#import "Firestore/third_party/Immutable/FSTArraySortedDictionaryEnumerator.h" -#import "Firestore/third_party/Immutable/FSTTreeSortedDictionary.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTArraySortedDictionary () -@property(nonatomic, copy, readwrite) NSComparator comparator; -@property(nonatomic, strong) NSArray *keys; -@property(nonatomic, strong) NSArray *values; -@end - -@implementation FSTArraySortedDictionary - -+ (FSTArraySortedDictionary *)dictionaryWithDictionary:(NSDictionary *)dictionary - comparator:(NSComparator)comparator { - NSMutableArray *keys = [NSMutableArray arrayWithCapacity:dictionary.count]; - [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { - [keys addObject:key]; - }]; - [keys sortUsingComparator:comparator]; - - [keys enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - if (idx > 0) { - if (comparator(keys[idx - 1], obj) != NSOrderedAscending) { - [NSException raise:NSInvalidArgumentException - format: - @"Can't create FSTImmutableSortedDictionary with keys " - @"with same ordering!"]; - } - } - }]; - - NSMutableArray *values = [NSMutableArray arrayWithCapacity:keys.count]; - NSInteger pos = 0; - for (id key in keys) { - values[pos++] = dictionary[key]; - } - NSAssert(values.count == keys.count, @"We added as many keys as values"); - return [[FSTArraySortedDictionary alloc] initWithComparator:comparator keys:keys values:values]; -} - -- (id)initWithComparator:(NSComparator)comparator { - return [self initWithComparator:comparator keys:[NSArray array] values:[NSArray array]]; -} - -// Designated initializer. -- (id)initWithComparator:(NSComparator)comparator keys:(NSArray *)keys values:(NSArray *)values { - self = [super init]; - if (self != nil) { - NSAssert(keys.count == values.count, @"keys and values must have the same count"); - _comparator = comparator; - _keys = keys; - _values = values; - } - return self; -} - -/** Returns the index of the first position where array[position] >= key. */ -- (int)findInsertPositionForKey:(id)key { - int newPos = 0; - while (newPos < self.keys.count && self.comparator(self.keys[newPos], key) < NSOrderedSame) { - newPos++; - } - return newPos; -} - -- (NSInteger)findKey:(id)key { - if (key == nil) { - return NSNotFound; - } - for (NSInteger pos = 0; pos < self.keys.count; pos++) { - NSComparisonResult result = self.comparator(key, self.keys[pos]); - if (result == NSOrderedSame) { - return pos; - } else if (result == NSOrderedAscending) { - return NSNotFound; - } - } - return NSNotFound; -} - -- (FSTImmutableSortedDictionary *)dictionaryBySettingObject:(id)value forKey:(id)key { - NSInteger pos = [self findKey:key]; - - if (pos == NSNotFound) { - /* - * If we're above the threshold we want to convert it to a tree backed implementation to not - * have degrading performance - */ - if (self.count >= kSortedDictionaryArrayToRBTreeSizeThreshold) { - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:self.count]; - for (NSInteger i = 0; i < self.keys.count; i++) { - dict[self.keys[i]] = self.values[i]; - } - dict[key] = value; - return [FSTTreeSortedDictionary dictionaryWithDictionary:dict comparator:self.comparator]; - } else { - NSMutableArray *newKeys = [NSMutableArray arrayWithArray:self.keys]; - NSMutableArray *newValues = [NSMutableArray arrayWithArray:self.values]; - NSInteger newPos = [self findInsertPositionForKey:key]; - [newKeys insertObject:key atIndex:newPos]; - [newValues insertObject:value atIndex:newPos]; - return [[FSTArraySortedDictionary alloc] initWithComparator:self.comparator - keys:newKeys - values:newValues]; - } - } else { - NSMutableArray *newKeys = [NSMutableArray arrayWithArray:self.keys]; - NSMutableArray *newValues = [NSMutableArray arrayWithArray:self.values]; - newKeys[pos] = key; - newValues[pos] = value; - return [[FSTArraySortedDictionary alloc] initWithComparator:self.comparator - keys:newKeys - values:newValues]; - } -} - -- (FSTImmutableSortedDictionary *)dictionaryByRemovingObjectForKey:(id)key { - NSInteger pos = [self findKey:key]; - if (pos == NSNotFound) { - return self; - } else { - NSMutableArray *newKeys = [NSMutableArray arrayWithArray:self.keys]; - NSMutableArray *newValues = [NSMutableArray arrayWithArray:self.values]; - [newKeys removeObjectAtIndex:pos]; - [newValues removeObjectAtIndex:pos]; - return [[FSTArraySortedDictionary alloc] initWithComparator:self.comparator - keys:newKeys - values:newValues]; - } -} - -- (nullable id)objectForKey:(id)key { - NSInteger pos = [self findKey:key]; - if (pos == NSNotFound) { - return nil; - } else { - return self.values[pos]; - } -} - -- (NSUInteger)indexOfKey:(id)key { - return [self findKey:key]; -} - -- (BOOL)isEmpty { - return self.keys.count == 0; -} - -- (NSUInteger)count { - return self.keys.count; -} - -- (id)minKey { - return [self.keys firstObject]; -} - -- (id)maxKey { - return [self.keys lastObject]; -} - -- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id, id, BOOL *))block { - [self enumerateKeysAndObjectsReverse:NO usingBlock:block]; -} - -- (void)enumerateKeysAndObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, id, BOOL *))block { - if (reverse) { - BOOL stop = NO; - for (NSInteger i = self.keys.count - 1; i >= 0; i--) { - block(self.keys[i], self.values[i], &stop); - if (stop) return; - } - } else { - BOOL stop = NO; - for (NSInteger i = 0; i < self.keys.count; i++) { - block(self.keys[i], self.values[i], &stop); - if (stop) return; - } - } -} - -- (BOOL)containsKey:(id)key { - return [self findKey:key] != NSNotFound; -} - -- (NSEnumerator *)keyEnumerator { - return [self.keys objectEnumerator]; -} - -- (NSEnumerator *)keyEnumeratorFrom:(id)startKey { - return [self keyEnumeratorFrom:startKey to:nil]; -} - -- (NSEnumerator *)keyEnumeratorFrom:(id)startKey to:(nullable id)endKey { - int start = [self findInsertPositionForKey:startKey]; - int end = (int)self.count; - if (endKey) { - end = [self findInsertPositionForKey:endKey]; - } - return [[FSTArraySortedDictionaryEnumerator alloc] initWithKeys:self.keys - startPos:start - endPos:end - isReverse:NO]; -} - -- (NSEnumerator *)reverseKeyEnumerator { - return [self.keys reverseObjectEnumerator]; -} - -- (NSEnumerator *)reverseKeyEnumeratorFrom:(id)startKey { - int startPos = [self findInsertPositionForKey:startKey]; - // if there's no exact match, findKeyOrInsertPosition will return the index *after* the closest - // match, but since this is a reverse iterator, we want to start just *before* the closest match. - if (startPos >= self.keys.count || - self.comparator(self.keys[startPos], startKey) != NSOrderedSame) { - startPos -= 1; - } - return [[FSTArraySortedDictionaryEnumerator alloc] initWithKeys:self.keys - startPos:startPos - endPos:-1 - isReverse:YES]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTArraySortedDictionaryEnumerator.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTArraySortedDictionaryEnumerator.h deleted file mode 100644 index 36c4f32..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTArraySortedDictionaryEnumerator.h +++ /dev/null @@ -1,26 +0,0 @@ -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTArraySortedDictionaryEnumerator : NSEnumerator - -- (id)init __attribute__((unavailable("Use initWithKeys:startPos:endPos:isReverse: instead."))); - -/** - * An enumerator for use with a dictionary. - * - * @param keys The keys to enumerator within. - * @param start The index of the initial key to return. - * @param end If end is after (or equal to) start (or before, if reverse), then the enumerator will - * stop and not return the value once it reaches end. - */ -- (instancetype)initWithKeys:(NSArray *)keys - startPos:(int)start - endPos:(int)end - isReverse:(BOOL)reverse NS_DESIGNATED_INITIALIZER; - -- (_Nullable ValueType)nextObject; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTArraySortedDictionaryEnumerator.m b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTArraySortedDictionaryEnumerator.m deleted file mode 100644 index 9039f96..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTArraySortedDictionaryEnumerator.m +++ /dev/null @@ -1,54 +0,0 @@ -#import "Firestore/third_party/Immutable/FSTArraySortedDictionaryEnumerator.h" - -NS_ASSUME_NONNULL_BEGIN - -// clang-format off -// For some reason, clang-format messes this line up... -@interface FSTArraySortedDictionaryEnumerator () -@property(nonatomic, assign) int pos; -@property(nonatomic, assign) int start; -@property(nonatomic, assign) int end; -@property(nonatomic, assign) BOOL reverse; -@property(nonatomic, strong) NSArray *keys; -@end -// clang-format on - -@implementation FSTArraySortedDictionaryEnumerator - -- (id)initWithKeys:(NSArray *)keys startPos:(int)start endPos:(int)end isReverse:(BOOL)reverse { - self = [super init]; - if (self != nil) { - _keys = keys; - _start = start; - _end = end; - _pos = start; - _reverse = reverse; - } - return self; -} - -- (nullable id)nextObject { - if (self.pos < 0 || self.pos >= self.keys.count) { - return nil; - } - if (self.reverse) { - if (self.pos <= self.end) { - return nil; - } - } else { - if (self.pos >= self.end) { - return nil; - } - } - int pos = self.pos; - if (self.reverse) { - self.pos--; - } else { - self.pos++; - } - return self.keys[pos]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h deleted file mode 100644 index cbb4da3..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Implementation of an immutable SortedMap using a Left-leaning Red-Black Tree, adapted from the - * implementation in Mugs (http://mads379.github.com/mugs/) by Mads Hartmann Jensen - * (mads379@gmail.com). - * - * Original paper on Left-leaning Red-Black Trees: - * http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf - * - * Invariant 1: No red node has a red child - * Invariant 2: Every leaf path has the same number of black nodes - * Invariant 3: Only the left child can be red (left leaning) - */ - -#import - -NS_ASSUME_NONNULL_BEGIN - -/** - * The size threshold where we use a tree backed sorted map instead of an array backed sorted map. - * This is a more or less arbitrary chosen value, that was chosen to be large enough to fit most of - * object kind of Firebase data, but small enough to not notice degradation in performance for - * inserting and lookups. Feel free to empirically determine this constant, but don't expect much - * gain in real world performance. - */ -extern const int kSortedDictionaryArrayToRBTreeSizeThreshold; - -/** - * FSTImmutableSortedDictionary is a dictionary. It is immutable, but has methods to create new - * dictionaries that are mutations of it, in an efficient way. - */ -@interface FSTImmutableSortedDictionary : NSObject - -+ (FSTImmutableSortedDictionary *)dictionaryWithComparator:(NSComparator)comparator; -+ (FSTImmutableSortedDictionary *)dictionaryWithDictionary: - (NSDictionary *)dictionary - comparator:(NSComparator)comparator; - -/** - * Creates a new dictionary identical to this one, but with a key-value pair added or updated. - * - * @param aValue The value to associate with the key. - * @param aKey The key to insert/update. - * @return A new dictionary with the added/updated value. - */ -- (FSTImmutableSortedDictionary *)dictionaryBySettingObject:(ValueType)aValue - forKey:(KeyType)aKey; - -/** - * Creates a new dictionary identical to this one, but with a key removed from it. - * - * @param aKey The key to remove. - * @return A new dictionary without that value. - */ -- (FSTImmutableSortedDictionary *)dictionaryByRemovingObjectForKey: - (KeyType)aKey; - -/** - * Looks up a value in the dictionary. - * - * @param key The key to look up. - * @return The value for the key, if present. - */ -- (nullable ValueType)objectForKey:(KeyType)key; - -/** - * Looks up a value in the dictionary. - * - * @param key The key to look up. - * @return The value for the key, if present. - */ -- (ValueType)objectForKeyedSubscript:(KeyType)key; - -/** - * Returns the index of the key or NSNotFound if the key is not found. - * - * @param key The key to return the index for. - * @return The index of the key, or NSNotFound if key not found. - */ -- (NSUInteger)indexOfKey:(KeyType)key; - -/** Returns true if the dictionary contains no elements. */ -- (BOOL)isEmpty; - -/** Returns the number of items in this dictionary. */ -- (NSUInteger)count; - -/** Returns the smallest key in this dictionary. */ -- (KeyType)minKey; - -/** Returns the largest key in this dictionary. */ -- (KeyType)maxKey; - -/** Calls the given block with each of the items in this dictionary, in order. */ -- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(KeyType key, ValueType value, BOOL *stop))block; - -/** Calls the given block with each of the items in this dictionary, in reverse order. */ -- (void)enumerateKeysAndObjectsReverse:(BOOL)reverse - usingBlock:(void (^)(KeyType key, ValueType value, BOOL *stop))block; - -/** Returns true if the dictionary contains the given key. */ -- (BOOL)containsKey:(KeyType)key; - -- (NSEnumerator *)keyEnumerator; -- (NSEnumerator *)keyEnumeratorFrom:(KeyType)startKey; -/** Enumerator for the range [startKey, endKey). */ -- (NSEnumerator *)keyEnumeratorFrom:(KeyType)startKey to:(nullable KeyType)endKey; -- (NSEnumerator *)reverseKeyEnumerator; -- (NSEnumerator *)reverseKeyEnumeratorFrom:(KeyType)startKey; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTImmutableSortedDictionary.m b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTImmutableSortedDictionary.m deleted file mode 100644 index 87c21a5..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTImmutableSortedDictionary.m +++ /dev/null @@ -1,139 +0,0 @@ -#import "Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h" - -#import "Firestore/third_party/Immutable/FSTArraySortedDictionary.h" -#import "Firestore/Source/Util/FSTClasses.h" -#import "Firestore/third_party/Immutable/FSTTreeSortedDictionary.h" - -NS_ASSUME_NONNULL_BEGIN - -const int kSortedDictionaryArrayToRBTreeSizeThreshold = 25; - -@implementation FSTImmutableSortedDictionary - -+ (FSTImmutableSortedDictionary *)dictionaryWithComparator:(NSComparator)comparator { - return [[FSTArraySortedDictionary alloc] initWithComparator:comparator]; -} - -+ (FSTImmutableSortedDictionary *)dictionaryWithDictionary:(NSDictionary *)dictionary - comparator:(NSComparator)comparator { - if (dictionary.count <= kSortedDictionaryArrayToRBTreeSizeThreshold) { - return [FSTArraySortedDictionary dictionaryWithDictionary:dictionary comparator:comparator]; - } else { - return [FSTTreeSortedDictionary dictionaryWithDictionary:dictionary comparator:comparator]; - } -} - -- (FSTImmutableSortedDictionary *)dictionaryBySettingObject:(id)aValue forKey:(id)aKey { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (FSTImmutableSortedDictionary *)dictionaryByRemovingObjectForKey:(id)aKey { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (BOOL)isEqual:(id)object { - if (![object isKindOfClass:[FSTImmutableSortedDictionary class]]) { - return NO; - } - - // TODO(klimt): We could make this more efficient if we put the comparison inside the - // implementations and short-circuit if they share the same tree node, for instance. - FSTImmutableSortedDictionary *other = (FSTImmutableSortedDictionary *)object; - if (self.count != other.count) { - return NO; - } - __block BOOL isEqual = YES; - [self enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { - id otherValue = [other objectForKey:key]; - isEqual = isEqual && (value == otherValue || [value isEqual:otherValue]); - *stop = !isEqual; - }]; - return isEqual; -} - -- (NSUInteger)hash { - __block NSUInteger hash = 0; - [self enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { - hash = (hash * 31 + [key hash]) * 17 + [value hash]; - }]; - return hash; -} - -- (NSString *)description { - NSMutableString *str = [[NSMutableString alloc] init]; - __block BOOL first = YES; - [str appendString:@"{ "]; - [self enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { - if (!first) { - [str appendString:@", "]; - } - first = NO; - [str appendString:[NSString stringWithFormat:@"%@: %@", key, value]]; - }]; - [str appendString:@" }"]; - return str; -} - -- (nullable id)objectForKey:(id)key { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (id)objectForKeyedSubscript:(id)key { - return [self objectForKey:key]; -} - -- (NSUInteger)indexOfKey:(id)key { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (BOOL)isEmpty { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (NSUInteger)count { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (id)minKey { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (id)maxKey { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id, id, BOOL *))block { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (void)enumerateKeysAndObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, id, BOOL *))block { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (BOOL)containsKey:(id)key { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (NSEnumerator *)keyEnumerator { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (NSEnumerator *)keyEnumeratorFrom:(id)startKey { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (NSEnumerator *)keyEnumeratorFrom:(id)startKey to:(nullable id)endKey { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (NSEnumerator *)reverseKeyEnumerator { - @throw FSTAbstractMethodException(); // NOLINT -} - -- (NSEnumerator *)reverseKeyEnumeratorFrom:(id)startKey { - @throw FSTAbstractMethodException(); // NOLINT -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTImmutableSortedSet.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTImmutableSortedSet.h deleted file mode 100644 index b432f98..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTImmutableSortedSet.h +++ /dev/null @@ -1,45 +0,0 @@ -#import - -NS_ASSUME_NONNULL_BEGIN - -/** - * FSTImmutableSortedSet is a set. It is immutable, but has methods to create new sets that are - * mutations of it, in an efficient way. - */ -@interface FSTImmutableSortedSet : NSObject - -+ (FSTImmutableSortedSet *)setWithComparator:(NSComparator)comparator; - -+ (FSTImmutableSortedSet *)setWithKeysFromDictionary:(NSDictionary *)array - comparator:(NSComparator)comparator; - -- (BOOL)containsObject:(KeyType)object; - -- (FSTImmutableSortedSet *)setByAddingObject:(KeyType)object; -- (FSTImmutableSortedSet *)setByRemovingObject:(KeyType)object; - -- (KeyType)firstObject; -- (KeyType)lastObject; -- (NSUInteger)count; -- (BOOL)isEmpty; - -/** - * Returns the index of the object or NSNotFound if the object is not found. - * - * @param object The object to return the index for. - * @return The index of the object, or NSNotFound if not found. - */ -- (NSUInteger)indexOfObject:(KeyType)object; - -- (void)enumerateObjectsUsingBlock:(void (^)(KeyType obj, BOOL *stop))block; -- (void)enumerateObjectsFrom:(KeyType)start - to:(_Nullable KeyType)end - usingBlock:(void (^)(KeyType obj, BOOL *stop))block; -- (void)enumerateObjectsReverse:(BOOL)reverse usingBlock:(void (^)(KeyType obj, BOOL *stop))block; - -- (NSEnumerator *)objectEnumerator; -- (NSEnumerator *)objectEnumeratorFrom:(KeyType)startKey; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTImmutableSortedSet.m b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTImmutableSortedSet.m deleted file mode 100644 index 1b63c2c..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTImmutableSortedSet.m +++ /dev/null @@ -1,140 +0,0 @@ -#import "Firestore/third_party/Immutable/FSTImmutableSortedSet.h" - -#import "Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTImmutableSortedSet () -@property(nonatomic, strong) FSTImmutableSortedDictionary *dictionary; -@end - -@implementation FSTImmutableSortedSet - -+ (FSTImmutableSortedSet *)setWithComparator:(NSComparator)comparator { - return [FSTImmutableSortedSet setWithKeysFromDictionary:@{} comparator:comparator]; -} - -+ (FSTImmutableSortedSet *)setWithKeysFromDictionary:(NSDictionary *)dictionary - comparator:(NSComparator)comparator { - FSTImmutableSortedDictionary *setDict = - [FSTImmutableSortedDictionary dictionaryWithDictionary:dictionary comparator:comparator]; - return [[FSTImmutableSortedSet alloc] initWithDictionary:setDict]; -} - -// Designated initializer. -- (id)initWithDictionary:(FSTImmutableSortedDictionary *)dictionary { - self = [super init]; - if (self != nil) { - _dictionary = dictionary; - } - return self; -} - -- (BOOL)isEqual:(id)object { - if (![object isKindOfClass:[FSTImmutableSortedSet class]]) { - return NO; - } - - FSTImmutableSortedSet *other = (FSTImmutableSortedSet *)object; - - return [self.dictionary isEqual:other.dictionary]; -} - -- (NSUInteger)hash { - return [self.dictionary hash]; -} - -- (BOOL)containsObject:(id)object { - return [self.dictionary containsKey:object]; -} - -- (FSTImmutableSortedSet *)setByAddingObject:(id)object { - FSTImmutableSortedDictionary *newDictionary = - [self.dictionary dictionaryBySettingObject:[NSNull null] forKey:object]; - if (newDictionary != self.dictionary) { - return [[FSTImmutableSortedSet alloc] initWithDictionary:newDictionary]; - } else { - return self; - } -} - -- (FSTImmutableSortedSet *)setByRemovingObject:(id)object { - FSTImmutableSortedDictionary *newDictionary = - [self.dictionary dictionaryByRemovingObjectForKey:object]; - if (newDictionary != self.dictionary) { - return [[FSTImmutableSortedSet alloc] initWithDictionary:newDictionary]; - } else { - return self; - } -} - -- (id)firstObject { - return [self.dictionary minKey]; -} - -- (id)lastObject { - return [self.dictionary maxKey]; -} - -- (NSUInteger)indexOfObject:(id)object { - return [self.dictionary indexOfKey:object]; -} - -- (NSUInteger)count { - return [self.dictionary count]; -} - -- (BOOL)isEmpty { - return [self.dictionary isEmpty]; -} - -- (void)enumerateObjectsUsingBlock:(void (^)(id, BOOL *))block { - [self enumerateObjectsReverse:NO usingBlock:block]; -} - -- (void)enumerateObjectsFrom:(id)start to:(_Nullable id)end usingBlock:(void (^)(id, BOOL *))block { - NSEnumerator *enumerator = [self.dictionary keyEnumeratorFrom:start to:end]; - id item = [enumerator nextObject]; - while (item) { - BOOL stop = NO; - block(item, &stop); - if (stop) { - return; - } - item = [enumerator nextObject]; - } -} - -- (void)enumerateObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, BOOL *))block { - [self.dictionary enumerateKeysAndObjectsReverse:reverse - usingBlock:^(id key, id value, BOOL *stop) { - block(key, stop); - }]; -} - -- (NSEnumerator *)objectEnumerator { - return [self.dictionary keyEnumerator]; -} - -- (NSEnumerator *)objectEnumeratorFrom:(id)startKey { - return [self.dictionary keyEnumeratorFrom:startKey]; -} - -- (NSString *)description { - NSMutableString *str = [[NSMutableString alloc] init]; - __block BOOL first = YES; - [str appendString:@"FSTImmutableSortedSet ( "]; - [self enumerateObjectsUsingBlock:^(id obj, BOOL *stop) { - if (!first) { - [str appendString:@", "]; - } - first = NO; - [str appendString:[NSString stringWithFormat:@"%@", obj]]; - }]; - [str appendString:@" )"]; - return str; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBEmptyNode.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBEmptyNode.h deleted file mode 100644 index 13c3bf8..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBEmptyNode.h +++ /dev/null @@ -1,11 +0,0 @@ -#import - -#import "Firestore/third_party/Immutable/FSTLLRBNode.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTLLRBEmptyNode : NSObject -+ (instancetype)emptyNode; -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBEmptyNode.m b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBEmptyNode.m deleted file mode 100644 index 45d2652..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBEmptyNode.m +++ /dev/null @@ -1,102 +0,0 @@ -#import "Firestore/third_party/Immutable/FSTLLRBEmptyNode.h" - -#import "Firestore/third_party/Immutable/FSTLLRBValueNode.h" - -NS_ASSUME_NONNULL_BEGIN - -@implementation FSTLLRBEmptyNode - -- (NSString *)description { - return @"[empty node]"; -} - -+ (instancetype)emptyNode { - static dispatch_once_t pred = 0; - __strong static id _sharedObject = nil; - dispatch_once(&pred, ^{ - _sharedObject = [[self alloc] init]; // or some other init method - }); - return _sharedObject; -} - -- (nullable id)key { - return nil; -} - -- (nullable id)value { - return nil; -} - -- (FSTLLRBColor)color { - return FSTLLRBColorUnspecified; -} - -- (nullable id)left { - return nil; -} - -- (nullable id)right { - return nil; -} - -- (instancetype)copyWith:(id _Nullable)aKey - withValue:(id _Nullable)aValue - withColor:(FSTLLRBColor)aColor - withLeft:(id _Nullable)aLeft - withRight:(id _Nullable)aRight { - // This class is a singleton anyway, so this is more efficient than calling the constructor again. - return self; -} - -- (id)insertKey:(id)aKey forValue:(id)aValue withComparator:(NSComparator)aComparator { - FSTLLRBValueNode *result = [[FSTLLRBValueNode alloc] initWithKey:aKey - withValue:aValue - withColor:FSTLLRBColorUnspecified - withLeft:nil - withRight:nil]; - return result; -} - -- (id)remove:(id)key withComparator:(NSComparator)aComparator { - return self; -} - -- (NSUInteger)count { - return 0; -} - -- (BOOL)isEmpty { - return YES; -} - -- (BOOL)inorderTraversal:(BOOL (^)(id key, id value))action { - return NO; -} - -- (BOOL)reverseTraversal:(BOOL (^)(id key, id value))action { - return NO; -} - -- (id)min { - return self; -} - -- (nullable id)minKey { - return nil; -} - -- (nullable id)maxKey { - return nil; -} - -- (BOOL)isRed { - return NO; -} - -- (int)check { - return 0; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBNode.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBNode.h deleted file mode 100644 index 082b875..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBNode.h +++ /dev/null @@ -1,68 +0,0 @@ -#import - -NS_ASSUME_NONNULL_BEGIN - -/** - * A FSTLLRBColor is the color of a tree node. It can be RED, BLACK, or unset. - */ -typedef NS_ENUM(NSInteger, FSTLLRBColor) { - FSTLLRBColorUnspecified = 0, - FSTLLRBColorRed = 1, - FSTLLRBColorBlack = 2, -}; - -/** - * FSTLLRBNode is the interface for a node in a FSTTreeSortedDictionary. - */ -@protocol FSTLLRBNode - -/** - * Creates a copy of the given node, changing any values that were specified. - * For any parameter that is left as nil, this instance's value will be used. - */ -- (instancetype)copyWith:(nullable id)aKey - withValue:(nullable id)aValue - withColor:(FSTLLRBColor)aColor - withLeft:(nullable id)aLeft - withRight:(nullable id)aRight; - -/** Returns a tree node with the given key-value pair set/updated. */ -- (id)insertKey:(id)aKey forValue:(id)aValue withComparator:(NSComparator)aComparator; - -/** Returns a tree node with the given key removed. */ -- (id)remove:(id)key withComparator:(NSComparator)aComparator; - -/** Returns the number of elements at this node or beneath it in the tree. */ -- (NSUInteger)count; - -/** Returns true if this is an FSTLLRBEmptyNode -- a leaf node in the tree. */ -- (BOOL)isEmpty; - -- (BOOL)inorderTraversal:(BOOL (^)(id key, id value))action; -- (BOOL)reverseTraversal:(BOOL (^)(id key, id value))action; - -/** Returns the left-most node under (or including) this node. */ -- (id)min; - -/** Returns the key of the left-most node under (or including) this node. */ -- (nullable id)minKey; - -/** Returns the key of the right-most node under (or including) this node. */ -- (nullable id)maxKey; - -/** Returns true if this node is red (as opposed to black). */ -- (BOOL)isRed; - -/** Checks that this node and below it hold the red-black invariants. Throws otherwise. */ -- (int)check; - -// Accessors for properties. -- (nullable id)key; -- (nullable id)value; -- (FSTLLRBColor)color; -- (nullable id)left; -- (nullable id)right; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBValueNode.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBValueNode.h deleted file mode 100644 index 9a62378..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBValueNode.h +++ /dev/null @@ -1,29 +0,0 @@ -#import - -#import "Firestore/third_party/Immutable/FSTLLRBNode.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTLLRBValueNode : NSObject - -- (id)init __attribute__(( - unavailable("Use initWithKey:withValue:withColor:withLeft:withRight: instead."))); - -- (instancetype)initWithKey:(nullable id)key - withValue:(nullable id)value - withColor:(FSTLLRBColor)color - withLeft:(nullable id)left - withRight:(nullable id)right NS_DESIGNATED_INITIALIZER; - -@property(nonatomic, assign, readonly) FSTLLRBColor color; -@property(nonatomic, strong, readonly, nullable) id key; -@property(nonatomic, strong, readonly, nullable) id value; -@property(nonatomic, strong, readonly, nullable) id right; - -// This property cannot be readonly, because it is set when building the tree. -// TODO(klimt): Find a way to build the tree without mutating this. -@property(nonatomic, strong, nullable) id left; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBValueNode.m b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBValueNode.m deleted file mode 100644 index e2590a1..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTLLRBValueNode.m +++ /dev/null @@ -1,307 +0,0 @@ -#import "Firestore/third_party/Immutable/FSTLLRBValueNode.h" - -#import "Firestore/third_party/Immutable/FSTLLRBEmptyNode.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTLLRBValueNode () -@property(nonatomic, assign) FSTLLRBColor color; -@property(nonatomic, assign) NSUInteger count; -@property(nonatomic, strong) id key; -@property(nonatomic, strong) id value; -@property(nonatomic, strong) id right; -@end - -@implementation FSTLLRBValueNode - -- (NSString *)colorDescription { - NSString *color = @"unspecified"; - if (self.color == FSTLLRBColorRed) { - color = @"red"; - } else if (self.color == FSTLLRBColorBlack) { - color = @"black"; - } - return color; -} - -- (NSString *)description { - NSString *color = self.colorDescription; - return [NSString stringWithFormat:@"[key=%@ val=%@ color=%@]", self.key, self.value, color]; -} - -// Designated initializer. -- (instancetype)initWithKey:(id _Nullable)aKey - withValue:(id _Nullable)aValue - withColor:(FSTLLRBColor)aColor - withLeft:(id _Nullable)aLeft - withRight:(id _Nullable)aRight { - self = [super init]; - if (self) { - _key = aKey; - _value = aValue; - _color = aColor != FSTLLRBColorUnspecified ? aColor : FSTLLRBColorRed; - _left = aLeft != nil ? aLeft : [FSTLLRBEmptyNode emptyNode]; - _right = aRight != nil ? aRight : [FSTLLRBEmptyNode emptyNode]; - _count = NSNotFound; - } - return self; -} - -- (instancetype)copyWith:(id _Nullable)aKey - withValue:(id _Nullable)aValue - withColor:(FSTLLRBColor)aColor - withLeft:(id _Nullable)aLeft - withRight:(id _Nullable)aRight { - return [[FSTLLRBValueNode alloc] - initWithKey:(aKey != nil) ? aKey : self.key - withValue:(aValue != nil) ? aValue : self.value - withColor:(aColor != FSTLLRBColorUnspecified) ? aColor : self.color - withLeft:(aLeft != nil) ? aLeft : self.left - withRight:(aRight != nil) ? aRight : self.right]; -} - -- (void)setLeft:(nullable id)left { - // Setting the left node should be only done by the builder, so doing it after someone has - // memoized count is an error. - NSAssert(_count == NSNotFound, @"Can't update left node after using count"); - _left = left; -} - -- (NSUInteger)count { - if (_count == NSNotFound) { - _count = _left.count + 1 + _right.count; - } - return _count; -} - -- (BOOL)isEmpty { - return NO; -} - -/** - * Early terminates if action returns YES. - * - * @return The first truthy value returned by action, or the last falsey value returned by action. - */ -- (BOOL)inorderTraversal:(BOOL (^)(id key, id value))action { - return [self.left inorderTraversal:action] || action(self.key, self.value) || - [self.right inorderTraversal:action]; -} - -- (BOOL)reverseTraversal:(BOOL (^)(id key, id value))action { - return [self.right reverseTraversal:action] || action(self.key, self.value) || - [self.left reverseTraversal:action]; -} - -- (id)min { - if ([self.left isEmpty]) { - return self; - } else { - return [self.left min]; - } -} - -- (nullable id)minKey { - return [[self min] key]; -} - -- (nullable id)maxKey { - if ([self.right isEmpty]) { - return self.key; - } else { - return [self.right maxKey]; - } -} - -- (id)insertKey:(id)aKey forValue:(id)aValue withComparator:(NSComparator)aComparator { - NSComparisonResult cmp = aComparator(aKey, self.key); - FSTLLRBValueNode *n = self; - - if (cmp == NSOrderedAscending) { - n = [n copyWith:nil - withValue:nil - withColor:FSTLLRBColorUnspecified - withLeft:[n.left insertKey:aKey forValue:aValue withComparator:aComparator] - withRight:nil]; - } else if (cmp == NSOrderedSame) { - n = [n copyWith:nil - withValue:aValue - withColor:FSTLLRBColorUnspecified - withLeft:nil - withRight:nil]; - } else { - n = [n copyWith:nil - withValue:nil - withColor:FSTLLRBColorUnspecified - withLeft:nil - withRight:[n.right insertKey:aKey forValue:aValue withComparator:aComparator]]; - } - - return [n fixUp]; -} - -- (id)removeMin { - if ([self.left isEmpty]) { - return [FSTLLRBEmptyNode emptyNode]; - } - - FSTLLRBValueNode *n = self; - if (![n.left isRed] && ![n.left.left isRed]) { - n = [n moveRedLeft]; - } - - n = [n copyWith:nil - withValue:nil - withColor:FSTLLRBColorUnspecified - withLeft:[(FSTLLRBValueNode *)n.left removeMin] - withRight:nil]; - return [n fixUp]; -} - -- (id)fixUp { - FSTLLRBValueNode *n = self; - if ([n.right isRed] && ![n.left isRed]) n = [n rotateLeft]; - if ([n.left isRed] && [n.left.left isRed]) n = [n rotateRight]; - if ([n.left isRed] && [n.right isRed]) n = [n colorFlip]; - return n; -} - -- (FSTLLRBValueNode *)moveRedLeft { - FSTLLRBValueNode *n = [self colorFlip]; - if ([n.right.left isRed]) { - n = [n copyWith:nil - withValue:nil - withColor:FSTLLRBColorUnspecified - withLeft:nil - withRight:[(FSTLLRBValueNode *)n.right rotateRight]]; - n = [n rotateLeft]; - n = [n colorFlip]; - } - return n; -} - -- (FSTLLRBValueNode *)moveRedRight { - FSTLLRBValueNode *n = [self colorFlip]; - if ([n.left.left isRed]) { - n = [n rotateRight]; - n = [n colorFlip]; - } - return n; -} - -- (id)rotateLeft { - id nl = [self copyWith:nil - withValue:nil - withColor:FSTLLRBColorRed - withLeft:nil - withRight:self.right.left]; - return [self.right copyWith:nil withValue:nil withColor:self.color withLeft:nl withRight:nil]; -} - -- (id)rotateRight { - id nr = [self copyWith:nil - withValue:nil - withColor:FSTLLRBColorRed - withLeft:self.left.right - withRight:nil]; - return [self.left copyWith:nil withValue:nil withColor:self.color withLeft:nil withRight:nr]; -} - -- (id)colorFlip { - FSTLLRBColor color = self.color == FSTLLRBColorBlack ? FSTLLRBColorRed : FSTLLRBColorBlack; - FSTLLRBColor leftColor = - self.left.color == FSTLLRBColorBlack ? FSTLLRBColorRed : FSTLLRBColorBlack; - FSTLLRBColor rightColor = - self.right.color == FSTLLRBColorBlack ? FSTLLRBColorRed : FSTLLRBColorBlack; - - id nleft = - [self.left copyWith:nil withValue:nil withColor:leftColor withLeft:nil withRight:nil]; - id nright = - [self.right copyWith:nil withValue:nil withColor:rightColor withLeft:nil withRight:nil]; - - return [self copyWith:nil withValue:nil withColor:color withLeft:nleft withRight:nright]; -} - -- (id)remove:(id)aKey withComparator:(NSComparator)comparator { - id smallest; - FSTLLRBValueNode *n = self; - - if (comparator(aKey, n.key) == NSOrderedAscending) { - if (![n.left isEmpty] && ![n.left isRed] && ![n.left.left isRed]) { - n = [n moveRedLeft]; - } - n = [n copyWith:nil - withValue:nil - withColor:FSTLLRBColorUnspecified - withLeft:[n.left remove:aKey withComparator:comparator] - withRight:nil]; - } else { - if ([n.left isRed]) { - n = [n rotateRight]; - } - - if (![n.right isEmpty] && ![n.right isRed] && ![n.right.left isRed]) { - n = [n moveRedRight]; - } - - if (comparator(aKey, n.key) == NSOrderedSame) { - if ([n.right isEmpty]) { - return [FSTLLRBEmptyNode emptyNode]; - } else { - smallest = [n.right min]; - n = [n copyWith:smallest.key - withValue:smallest.value - withColor:FSTLLRBColorUnspecified - withLeft:nil - withRight:[(FSTLLRBValueNode *)n.right removeMin]]; - } - } - n = [n copyWith:nil - withValue:nil - withColor:FSTLLRBColorUnspecified - withLeft:nil - withRight:[n.right remove:aKey withComparator:comparator]]; - } - return [n fixUp]; -} - -- (BOOL)isRed { - return self.color == FSTLLRBColorRed; -} - -- (BOOL)checkMaxDepth { - int blackDepth = [self check]; - if (pow(2.0, blackDepth) <= ([self count] + 1)) { - return YES; - } else { - return NO; - } -} - -- (int)check { - int blackDepth = 0; - - if ([self isRed] && [self.left isRed]) { - @throw - [[NSException alloc] initWithName:@"check" reason:@"Red node has a red child" userInfo:nil]; - } - - if ([self.right isRed]) { - @throw [[NSException alloc] initWithName:@"check" reason:@"Right child is red" userInfo:nil]; - } - - blackDepth = [self.left check]; - if (blackDepth != [self.right check]) { - NSString *err = - [NSString stringWithFormat:@"(%@ -> %@)blackDepth: %d ; self.right check: %d", self.value, - self.colorDescription, blackDepth, [self.right check]]; - @throw [[NSException alloc] initWithName:@"check" reason:err userInfo:nil]; - } else { - int ret = blackDepth + ([self isRed] ? 0 : 1); - return ret; - } -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTTreeSortedDictionary.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTTreeSortedDictionary.h deleted file mode 100644 index ca1a290..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTTreeSortedDictionary.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Implementation of an immutable SortedMap using a Left-leaning - * Red-Black Tree, adapted from the implementation in Mugs - * (http://mads379.github.com/mugs/) by Mads Hartmann Jensen - * (mads379@gmail.com). - * - * Original paper on Left-leaning Red-Black Trees: - * http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf - * - * Invariant 1: No red node has a red child - * Invariant 2: Every leaf path has the same number of black nodes - * Invariant 3: Only the left child can be red (left leaning) - */ - -#import - -#import "Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h" -#import "Firestore/third_party/Immutable/FSTLLRBNode.h" - -NS_ASSUME_NONNULL_BEGIN - -/** - * FSTTreeSortedDictionary is a tree-based implementation of FSTImmutableSortedDictionary. - * You should not use this class directly. You should use FSTImmutableSortedDictionary. - */ -@interface FSTTreeSortedDictionary : - FSTImmutableSortedDictionary - -@property(nonatomic, copy, readonly) NSComparator comparator; -@property(nonatomic, strong, readonly) id root; - -- (id)init __attribute__((unavailable("Use initWithComparator:withRoot: instead."))); - -- (instancetype)initWithComparator:(NSComparator)aComparator; - -- (instancetype)initWithComparator:(NSComparator)aComparator - withRoot:(id)aRoot NS_DESIGNATED_INITIALIZER; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTTreeSortedDictionary.m b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTTreeSortedDictionary.m deleted file mode 100644 index f113296..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTTreeSortedDictionary.m +++ /dev/null @@ -1,352 +0,0 @@ -#import "Firestore/third_party/Immutable/FSTTreeSortedDictionary.h" - -#import "Firestore/third_party/Immutable/FSTLLRBEmptyNode.h" -#import "Firestore/third_party/Immutable/FSTLLRBValueNode.h" -#import "Firestore/third_party/Immutable/FSTTreeSortedDictionaryEnumerator.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTTreeSortedDictionary () - -- (FSTTreeSortedDictionary *)dictionaryBySettingObject:(id)aValue forKey:(id)aKey; - -@property(nonatomic, strong) id root; -@property(nonatomic, copy, readwrite) NSComparator comparator; -@end - -@implementation FSTTreeSortedDictionary - -+ (FSTTreeSortedDictionary *)dictionaryWithDictionary:(NSDictionary *)dictionary - comparator:(NSComparator)comparator { - __block FSTTreeSortedDictionary *dict = - [[FSTTreeSortedDictionary alloc] initWithComparator:comparator]; - [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { - dict = [dict dictionaryBySettingObject:obj forKey:key]; - }]; - return dict; -} - -- (id)initWithComparator:(NSComparator)aComparator { - return [self initWithComparator:aComparator withRoot:[FSTLLRBEmptyNode emptyNode]]; -} - -// Designated initializer. -- (id)initWithComparator:(NSComparator)aComparator withRoot:(id)aRoot { - self = [super init]; - if (self) { - self.root = aRoot; - self.comparator = aComparator; - } - return self; -} - -/** - * Returns a copy of the map, with the specified key/value added or replaced. - */ -- (FSTTreeSortedDictionary *)dictionaryBySettingObject:(id)aValue forKey:(id)aKey { - return [[FSTTreeSortedDictionary alloc] - initWithComparator:self.comparator - withRoot:[[self.root insertKey:aKey forValue:aValue withComparator:self.comparator] - copyWith:nil - withValue:nil - withColor:FSTLLRBColorBlack - withLeft:nil - withRight:nil]]; -} - -- (FSTTreeSortedDictionary *)dictionaryByRemovingObjectForKey:(id)aKey { - // Remove is somewhat expensive even if the key doesn't exist (the tree does rebalancing and - // stuff). So avoid it. - if (![self containsKey:aKey]) { - return self; - } else { - return [[FSTTreeSortedDictionary alloc] - initWithComparator:self.comparator - withRoot:[[self.root remove:aKey withComparator:self.comparator] - copyWith:nil - withValue:nil - withColor:FSTLLRBColorBlack - withLeft:nil - withRight:nil]]; - } -} - -- (nullable id)objectForKey:(id)key { - NSComparisonResult cmp; - id node = self.root; - while (![node isEmpty]) { - cmp = self.comparator(key, node.key); - if (cmp == NSOrderedSame) { - return node.value; - } else if (cmp == NSOrderedAscending) { - node = node.left; - } else { - node = node.right; - } - } - return nil; -} - -- (NSUInteger)indexOfKey:(id)key { - NSUInteger prunedNodes = 0; - id node = self.root; - while (![node isEmpty]) { - NSComparisonResult cmp = self.comparator(key, node.key); - if (cmp == NSOrderedSame) { - return prunedNodes + node.left.count; - } else if (cmp == NSOrderedAscending) { - node = node.left; - } else if (cmp == NSOrderedDescending) { - prunedNodes += node.left.count + 1; - node = node.right; - } - } - return NSNotFound; -} - -- (BOOL)isEmpty { - return [self.root isEmpty]; -} - -- (NSUInteger)count { - return [self.root count]; -} - -- (id)minKey { - return [self.root minKey]; -} - -- (id)maxKey { - return [self.root maxKey]; -} - -- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id, id, BOOL *))block { - [self enumerateKeysAndObjectsReverse:NO usingBlock:block]; -} - -- (void)enumerateKeysAndObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, id, BOOL *))block { - if (reverse) { - __block BOOL stop = NO; - [self.root reverseTraversal:^BOOL(id key, id value) { - block(key, value, &stop); - return stop; - }]; - } else { - __block BOOL stop = NO; - [self.root inorderTraversal:^BOOL(id key, id value) { - block(key, value, &stop); - return stop; - }]; - } -} - -- (BOOL)containsKey:(id)key { - return ([self objectForKey:key] != nil); -} - -- (NSEnumerator *)keyEnumerator { - return [[FSTTreeSortedDictionaryEnumerator alloc] initWithImmutableSortedDictionary:self - startKey:nil - endKey:nil - isReverse:NO]; -} - -- (NSEnumerator *)keyEnumeratorFrom:(id)startKey { - return [[FSTTreeSortedDictionaryEnumerator alloc] initWithImmutableSortedDictionary:self - startKey:startKey - endKey:nil - isReverse:NO]; -} - -- (NSEnumerator *)keyEnumeratorFrom:(id)startKey to:(nullable id)endKey { - return [[FSTTreeSortedDictionaryEnumerator alloc] initWithImmutableSortedDictionary:self - startKey:startKey - endKey:endKey - isReverse:NO]; -} - -- (NSEnumerator *)reverseKeyEnumerator { - return [[FSTTreeSortedDictionaryEnumerator alloc] initWithImmutableSortedDictionary:self - startKey:nil - endKey:nil - isReverse:YES]; -} - -- (NSEnumerator *)reverseKeyEnumeratorFrom:(id)startKey { - return [[FSTTreeSortedDictionaryEnumerator alloc] initWithImmutableSortedDictionary:self - startKey:startKey - endKey:nil - isReverse:YES]; -} - -#pragma mark - -#pragma mark Tree Builder - -// Code to efficiently build a red black tree. - -typedef struct { - unsigned int bits; - unsigned short count; - unsigned short current; -} Base12List; - -unsigned int LogBase2(unsigned int num) { - return (unsigned int)(log(num) / log(2)); -} - -/** - * Works like an iterator, so it moves to the next bit. Do not call more than list->count times. - * @return whether or not the next bit is a 1 in base {1,2}. - */ -BOOL Base12ListNext(Base12List *list) { - BOOL result = !(list->bits & (0x1 << list->current)); - list->current--; - return result; -} - -static inline unsigned BitMask(int x) { - return (x >= sizeof(unsigned) * CHAR_BIT) ? (unsigned)-1 : (1U << x) - 1; -} - -/** - * We represent the base{1,2} number as the combination of a binary number and a number of bits that - * we care about. We iterate backwards, from most significant bit to least, to build up the llrb - * nodes. 0 base 2 => 1 base {1,2}, 1 base 2 => 2 base {1,2} - */ -Base12List *NewBase12List(unsigned int length) { - size_t sz = sizeof(Base12List); - Base12List *list = calloc(1, sz); - // Calculate the number of bits that we care about - list->count = (unsigned short)LogBase2(length + 1); - unsigned int mask = BitMask(list->count); - list->bits = (length + 1) & mask; - list->current = list->count - 1; - return list; -} - -void FreeBase12List(Base12List *list) { - free(list); -} - -+ (nullable id)buildBalancedTree:(NSArray *)keys - dictionary:(NSDictionary *)dictionary - subArrayStartIndex:(NSUInteger)startIndex - length:(NSUInteger)length { - length = MIN(keys.count - startIndex, length); // Bound length by the actual length of the array - if (length == 0) { - return nil; - } else if (length == 1) { - id key = keys[startIndex]; - return [[FSTLLRBValueNode alloc] initWithKey:key - withValue:dictionary[key] - withColor:FSTLLRBColorBlack - withLeft:nil - withRight:nil]; - } else { - NSUInteger middle = length / 2; - id left = [FSTTreeSortedDictionary buildBalancedTree:keys - dictionary:dictionary - subArrayStartIndex:startIndex - length:middle]; - id right = [FSTTreeSortedDictionary buildBalancedTree:keys - dictionary:dictionary - subArrayStartIndex:(startIndex + middle + 1) - length:middle]; - id key = keys[startIndex + middle]; - return [[FSTLLRBValueNode alloc] initWithKey:key - withValue:dictionary[key] - withColor:FSTLLRBColorBlack - withLeft:left - withRight:right]; - } -} - -+ (nullable id)rootFrom12List:(Base12List *)base12List - keyList:(NSArray *)keyList - dictionary:(NSDictionary *)dictionary { - __block FSTLLRBValueNode *root = nil; - __block FSTLLRBValueNode *node = nil; - __block NSUInteger index = keyList.count; - - void (^buildPennant)(FSTLLRBColor, NSUInteger) = ^(FSTLLRBColor color, NSUInteger chunkSize) { - NSUInteger startIndex = index - chunkSize + 1; - index -= chunkSize; - id key = keyList[index]; - FSTLLRBValueNode *childTree = [self buildBalancedTree:keyList - dictionary:dictionary - subArrayStartIndex:startIndex - length:(chunkSize - 1)]; - FSTLLRBValueNode *pennant = [[FSTLLRBValueNode alloc] initWithKey:key - withValue:dictionary[key] - withColor:color - withLeft:nil - withRight:childTree]; - if (node) { - // This is the only place this property is set. - node.left = pennant; - node = pennant; - } else { - root = pennant; - node = pennant; - } - }; - - for (int i = 0; i < base12List->count; ++i) { - BOOL isOne = Base12ListNext(base12List); - NSUInteger chunkSize = (NSUInteger)pow(2.0, base12List->count - (i + 1)); - if (isOne) { - buildPennant(FSTLLRBColorBlack, chunkSize); - } else { - buildPennant(FSTLLRBColorBlack, chunkSize); - buildPennant(FSTLLRBColorRed, chunkSize); - } - } - return root; -} - -/** - * Uses the algorithm linked here: - * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.46.1458 - */ -+ (FSTImmutableSortedDictionary *)fromDictionary:(NSDictionary *)dictionary - withComparator:(NSComparator)comparator { - // Steps: - // 0. Sort the array - // 1. Calculate the 1-2 number - // 2. Build From 1-2 number - // 0. for each digit in 1-2 number - // 0. calculate chunk size - // 1. build 1 or 2 pennants of that size - // 2. attach pennants and update node pointer - // 1. return root - NSMutableArray *sortedKeyList = [NSMutableArray arrayWithCapacity:dictionary.count]; - [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { - [sortedKeyList addObject:key]; - }]; - [sortedKeyList sortUsingComparator:comparator]; - - [sortedKeyList enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - if (idx > 0) { - if (comparator(sortedKeyList[idx - 1], obj) != NSOrderedAscending) { - [NSException raise:NSInvalidArgumentException - format: - @"Can't create FSTImmutableSortedDictionary " - @"with keys with same ordering!"]; - } - } - }]; - - Base12List *list = NewBase12List((unsigned int)sortedKeyList.count); - id root = [self rootFrom12List:list keyList:sortedKeyList dictionary:dictionary]; - FreeBase12List(list); - - if (root != nil) { - return [[FSTTreeSortedDictionary alloc] initWithComparator:comparator withRoot:root]; - } else { - return [[FSTTreeSortedDictionary alloc] initWithComparator:comparator]; - } -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTTreeSortedDictionaryEnumerator.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTTreeSortedDictionaryEnumerator.h deleted file mode 100644 index d31d4c2..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTTreeSortedDictionaryEnumerator.h +++ /dev/null @@ -1,21 +0,0 @@ -#import - -#import "Firestore/third_party/Immutable/FSTTreeSortedDictionary.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTTreeSortedDictionaryEnumerator : NSEnumerator - -- (id)init __attribute__(( - unavailable("Use initWithImmutableSortedDictionary:startKey:isReverse: instead."))); - -- (instancetype)initWithImmutableSortedDictionary: - (FSTTreeSortedDictionary *)aDict - startKey:(KeyType _Nullable)startKey - endKey:(KeyType _Nullable)endKey - isReverse:(BOOL)reverse NS_DESIGNATED_INITIALIZER; -- (nullable ValueType)nextObject; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTTreeSortedDictionaryEnumerator.m b/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTTreeSortedDictionaryEnumerator.m deleted file mode 100644 index b413792..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/Immutable/FSTTreeSortedDictionaryEnumerator.m +++ /dev/null @@ -1,114 +0,0 @@ -#import "Firestore/third_party/Immutable/FSTTreeSortedDictionaryEnumerator.h" - -NS_ASSUME_NONNULL_BEGIN - -// clang-format off -// For some reason, clang-format messes this line up... -@interface FSTTreeSortedDictionaryEnumerator () -/** The dictionary being enumerated. */ -@property(nonatomic, strong) FSTTreeSortedDictionary *immutableSortedDictionary; -/** The stack of tree nodes above the current node that will need to be revisited later. */ -@property(nonatomic, strong) NSMutableArray> *stack; -/** The direction of the traversal. YES=Descending. NO=Ascending. */ -@property(nonatomic, assign) BOOL isReverse; -/** If set, the enumerator should stop at this key and not return it. */ -@property(nonatomic, strong, nullable) id endKey; -@end -// clang-format on - -@implementation FSTTreeSortedDictionaryEnumerator - -- (instancetype)initWithImmutableSortedDictionary:(FSTTreeSortedDictionary *)aDict - startKey:(id _Nullable)startKey - endKey:(id _Nullable)endKey - isReverse:(BOOL)reverse { - self = [super init]; - if (self) { - _immutableSortedDictionary = aDict; - _stack = [[NSMutableArray alloc] init]; - _isReverse = reverse; - _endKey = endKey; - - NSComparator comparator = aDict.comparator; - id node = aDict.root; - - NSComparisonResult comparedToStart; - NSComparisonResult comparedToEnd; - while (![node isEmpty]) { - comparedToStart = NSOrderedDescending; - if (startKey) { - comparedToStart = comparator(node.key, startKey); - if (reverse) { - comparedToStart *= -1; - } - } - comparedToEnd = NSOrderedAscending; - if (endKey) { - comparedToEnd = comparator(node.key, endKey); - if (reverse) { - comparedToEnd *= -1; - } - } - - if (comparedToStart == NSOrderedAscending) { - // This node is less than our start key. Ignore it. - if (reverse) { - node = node.left; - } else { - node = node.right; - } - } else if (comparedToStart == NSOrderedSame) { - // This node is exactly equal to our start key. If it's less than the end key, push it on - // the stack, but stop iterating. - if (comparedToEnd == NSOrderedAscending) { - [_stack addObject:node]; - } - break; - } else { - // This node is greater than our start key. If it's less than our end key, add it to the - // stack and move on to the next one. - if (comparedToEnd == NSOrderedAscending) { - [_stack addObject:node]; - } - if (reverse) { - node = node.right; - } else { - node = node.left; - } - } - } - } - return self; -} - -- (nullable id)nextObject { - if ([self.stack count] == 0) { - return nil; - } - - id node = [self.stack lastObject]; - [self.stack removeLastObject]; - id result = node.key; - NSComparator comparator = self.immutableSortedDictionary.comparator; - - node = self.isReverse ? node.left : node.right; - while (![node isEmpty]) { - NSComparisonResult comparedToEnd = NSOrderedAscending; - if (self.endKey) { - comparedToEnd = comparator(node.key, self.endKey); - if (self.isReverse) { - comparedToEnd *= -1; - } - } - if (comparedToEnd == NSOrderedAscending) { - [self.stack addObject:node]; - } - node = self.isReverse ? node.right : node.left; - } - - return result; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/BUILD.bazel b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/BUILD.bazel deleted file mode 100644 index edd0274..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/BUILD.bazel +++ /dev/null @@ -1,51 +0,0 @@ -# -# Copyright 2017 The Abseil Authors. -# -# 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. -# - -package(default_visibility = ["//visibility:public"]) - -licenses(["notice"]) # Apache 2.0 - -load(":compiler_config_setting.bzl", "create_llvm_config") - -create_llvm_config( - name = "llvm_compiler", - visibility = [":__subpackages__"], -) - -# following configs are based on mapping defined in: https://git.io/v5Ijz -config_setting( - name = "ios", - values = { - "cpu": "darwin", - }, - visibility = [":__subpackages__"], -) - -config_setting( - name = "windows", - values = { - "cpu": "x64_windows", - }, - visibility = [":__subpackages__"], -) - -config_setting( - name = "ppc", - values = { - "cpu": "ppc", - }, - visibility = [":__subpackages__"], -) diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/CMakeLists.txt b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/CMakeLists.txt deleted file mode 100644 index 1d09b19..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright 2017 The Abseil Authors. -# -# 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. -# - - - -add_subdirectory(base) -add_subdirectory(algorithm) -add_subdirectory(container) -add_subdirectory(debugging) -add_subdirectory(hash) -add_subdirectory(memory) -add_subdirectory(meta) -add_subdirectory(numeric) -add_subdirectory(strings) -add_subdirectory(synchronization) -add_subdirectory(time) -add_subdirectory(types) -add_subdirectory(utility) diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/BUILD.bazel b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/BUILD.bazel deleted file mode 100644 index d04dc71..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/BUILD.bazel +++ /dev/null @@ -1,81 +0,0 @@ -# -# Copyright 2017 The Abseil Authors. -# -# 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. -# - -load( - "//absl:copts.bzl", - "ABSL_DEFAULT_COPTS", - "ABSL_TEST_COPTS", -) - -package(default_visibility = ["//visibility:public"]) - -licenses(["notice"]) # Apache 2.0 - -cc_library( - name = "algorithm", - hdrs = ["algorithm.h"], - copts = ABSL_DEFAULT_COPTS, -) - -cc_test( - name = "algorithm_test", - size = "small", - srcs = ["algorithm_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":algorithm", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "algorithm_benchmark", - srcs = ["equal_benchmark.cc"], - copts = ABSL_TEST_COPTS, - tags = ["benchmark"], - deps = [ - ":algorithm", - "//absl/base:core_headers", - "@com_github_google_benchmark//:benchmark_main", - ], -) - -cc_library( - name = "container", - hdrs = [ - "container.h", - ], - copts = ABSL_DEFAULT_COPTS, - deps = [ - ":algorithm", - "//absl/base:core_headers", - "//absl/meta:type_traits", - ], -) - -cc_test( - name = "container_test", - srcs = ["container_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":container", - "//absl/base", - "//absl/base:core_headers", - "//absl/memory", - "//absl/types:span", - "@com_google_googletest//:gtest_main", - ], -) diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/CMakeLists.txt b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/CMakeLists.txt deleted file mode 100644 index fdf45c5..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/CMakeLists.txt +++ /dev/null @@ -1,63 +0,0 @@ -# -# Copyright 2017 The Abseil Authors. -# -# 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. -# - -list(APPEND ALGORITHM_PUBLIC_HEADERS - "algorithm.h" - "container.h" -) - - -# -## TESTS -# - -# test algorithm_test -list(APPEND ALGORITHM_TEST_SRC - "algorithm_test.cc" - ${ALGORITHM_PUBLIC_HEADERS} - ${ALGORITHM_INTERNAL_HEADERS} -) - -absl_header_library( - TARGET - absl_algorithm - EXPORT_NAME - algorithm -) - -absl_test( - TARGET - algorithm_test - SOURCES - ${ALGORITHM_TEST_SRC} - PUBLIC_LIBRARIES - absl::algorithm -) - - - - -# test container_test -set(CONTAINER_TEST_SRC "container_test.cc") - -absl_test( - TARGET - container_test - SOURCES - ${CONTAINER_TEST_SRC} - PUBLIC_LIBRARIES - absl::algorithm -) diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/algorithm_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/algorithm_test.cc deleted file mode 100644 index e4322bc..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/algorithm_test.cc +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/algorithm/algorithm.h" - -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace { - -TEST(EqualTest, DefaultComparisonRandomAccess) { - std::vector v1{1, 2, 3}; - std::vector v2 = v1; - std::vector v3 = {1, 2}; - std::vector v4 = {1, 2, 4}; - - EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end())); - EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end())); - EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end())); -} - -TEST(EqualTest, DefaultComparison) { - std::list lst1{1, 2, 3}; - std::list lst2 = lst1; - std::list lst3{1, 2}; - std::list lst4{1, 2, 4}; - - EXPECT_TRUE(absl::equal(lst1.begin(), lst1.end(), lst2.begin(), lst2.end())); - EXPECT_FALSE(absl::equal(lst1.begin(), lst1.end(), lst3.begin(), lst3.end())); - EXPECT_FALSE(absl::equal(lst1.begin(), lst1.end(), lst4.begin(), lst4.end())); -} - -TEST(EqualTest, EmptyRange) { - std::vector v1{1, 2, 3}; - std::vector empty1; - std::vector empty2; - - EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), empty1.begin(), empty1.end())); - EXPECT_FALSE(absl::equal(empty1.begin(), empty1.end(), v1.begin(), v1.end())); - EXPECT_TRUE( - absl::equal(empty1.begin(), empty1.end(), empty2.begin(), empty2.end())); -} - -TEST(EqualTest, MixedIterTypes) { - std::vector v1{1, 2, 3}; - std::list lst1{v1.begin(), v1.end()}; - std::list lst2{1, 2, 4}; - std::list lst3{1, 2}; - - EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), lst1.begin(), lst1.end())); - EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), lst2.begin(), lst2.end())); - EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), lst3.begin(), lst3.end())); -} - -TEST(EqualTest, MixedValueTypes) { - std::vector v1{1, 2, 3}; - std::vector v2{1, 2, 3}; - std::vector v3{1, 2}; - std::vector v4{1, 2, 4}; - - EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end())); - EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end())); - EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end())); -} - -TEST(EqualTest, WeirdIterators) { - std::vector v1{true, false}; - std::vector v2 = v1; - std::vector v3{true}; - std::vector v4{true, true, true}; - - EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end())); - EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end())); - EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end())); -} - -TEST(EqualTest, CustomComparison) { - int n[] = {1, 2, 3, 4}; - std::vector v1{&n[0], &n[1], &n[2]}; - std::vector v2 = v1; - std::vector v3{&n[0], &n[1], &n[3]}; - std::vector v4{&n[0], &n[1]}; - - auto eq = [](int* a, int* b) { return *a == *b; }; - - EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end(), eq)); - EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end(), eq)); - EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end(), eq)); -} - -TEST(EqualTest, MoveOnlyPredicate) { - std::vector v1{1, 2, 3}; - std::vector v2{4, 5, 6}; - - // move-only equality predicate - struct Eq { - Eq() = default; - Eq(Eq &&) = default; - Eq(const Eq &) = delete; - Eq &operator=(const Eq &) = delete; - bool operator()(const int a, const int b) const { return a == b; } - }; - - EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v1.begin(), v1.end(), Eq())); - EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end(), Eq())); -} - -struct CountingTrivialPred { - int* count; - bool operator()(int, int) const { - ++*count; - return true; - } -}; - -TEST(EqualTest, RandomAccessComplexity) { - std::vector v1{1, 1, 3}; - std::vector v2 = v1; - std::vector v3{1, 2}; - - do { - int count = 0; - absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end(), - CountingTrivialPred{&count}); - EXPECT_LE(count, 3); - } while (std::next_permutation(v2.begin(), v2.end())); - - int count = 0; - absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end(), - CountingTrivialPred{&count}); - EXPECT_EQ(count, 0); -} - -class LinearSearchTest : public testing::Test { - protected: - LinearSearchTest() : container_{1, 2, 3} {} - - static bool Is3(int n) { return n == 3; } - static bool Is4(int n) { return n == 4; } - - std::vector container_; -}; - -TEST_F(LinearSearchTest, linear_search) { - EXPECT_TRUE(absl::linear_search(container_.begin(), container_.end(), 3)); - EXPECT_FALSE(absl::linear_search(container_.begin(), container_.end(), 4)); -} - -TEST_F(LinearSearchTest, linear_searchConst) { - const std::vector *const const_container = &container_; - EXPECT_TRUE( - absl::linear_search(const_container->begin(), const_container->end(), 3)); - EXPECT_FALSE( - absl::linear_search(const_container->begin(), const_container->end(), 4)); -} - -TEST(RotateTest, Rotate) { - std::vector v{0, 1, 2, 3, 4}; - EXPECT_EQ(*absl::rotate(v.begin(), v.begin() + 2, v.end()), 0); - EXPECT_THAT(v, testing::ElementsAreArray({2, 3, 4, 0, 1})); - - std::list l{0, 1, 2, 3, 4}; - EXPECT_EQ(*absl::rotate(l.begin(), std::next(l.begin(), 3), l.end()), 0); - EXPECT_THAT(l, testing::ElementsAreArray({3, 4, 0, 1, 2})); -} - -} // namespace diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/container_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/container_test.cc deleted file mode 100644 index 1502b17..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/container_test.cc +++ /dev/null @@ -1,1012 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/algorithm/container.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/base/casts.h" -#include "absl/base/macros.h" -#include "absl/memory/memory.h" -#include "absl/types/span.h" - -namespace { - -using ::testing::Each; -using ::testing::ElementsAre; -using ::testing::Gt; -using ::testing::IsNull; -using ::testing::Lt; -using ::testing::Pointee; -using ::testing::Truly; -using ::testing::UnorderedElementsAre; - -// Most of these tests just check that the code compiles, not that it -// does the right thing. That's fine since the functions just forward -// to the STL implementation. -class NonMutatingTest : public testing::Test { - protected: - std::unordered_set container_ = {1, 2, 3}; - std::list sequence_ = {1, 2, 3}; - std::vector vector_ = {1, 2, 3}; - int array_[3] = {1, 2, 3}; -}; - -struct AccumulateCalls { - void operator()(int value) { - calls.push_back(value); - } - std::vector calls; -}; - -bool Predicate(int value) { return value < 3; } -bool BinPredicate(int v1, int v2) { return v1 < v2; } -bool Equals(int v1, int v2) { return v1 == v2; } -bool IsOdd(int x) { return x % 2 != 0; } - - -TEST_F(NonMutatingTest, Distance) { - EXPECT_EQ(container_.size(), absl::c_distance(container_)); - EXPECT_EQ(sequence_.size(), absl::c_distance(sequence_)); - EXPECT_EQ(vector_.size(), absl::c_distance(vector_)); - EXPECT_EQ(ABSL_ARRAYSIZE(array_), absl::c_distance(array_)); - - // Works with a temporary argument. - EXPECT_EQ(vector_.size(), absl::c_distance(std::vector(vector_))); -} - -TEST_F(NonMutatingTest, Distance_OverloadedBeginEnd) { - // Works with classes which have custom ADL-selected overloads of std::begin - // and std::end. - std::initializer_list a = {1, 2, 3}; - std::valarray b = {1, 2, 3}; - EXPECT_EQ(3, absl::c_distance(a)); - EXPECT_EQ(3, absl::c_distance(b)); - - // It is assumed that other c_* functions use the same mechanism for - // ADL-selecting begin/end overloads. -} - -TEST_F(NonMutatingTest, ForEach) { - AccumulateCalls c = absl::c_for_each(container_, AccumulateCalls()); - // Don't rely on the unordered_set's order. - std::sort(c.calls.begin(), c.calls.end()); - EXPECT_EQ(vector_, c.calls); - - // Works with temporary container, too. - AccumulateCalls c2 = - absl::c_for_each(std::unordered_set(container_), AccumulateCalls()); - std::sort(c2.calls.begin(), c2.calls.end()); - EXPECT_EQ(vector_, c2.calls); -} - -TEST_F(NonMutatingTest, FindReturnsCorrectType) { - auto it = absl::c_find(container_, 3); - EXPECT_EQ(3, *it); - absl::c_find(absl::implicit_cast&>(sequence_), 3); -} - -TEST_F(NonMutatingTest, FindIf) { absl::c_find_if(container_, Predicate); } - -TEST_F(NonMutatingTest, FindIfNot) { - absl::c_find_if_not(container_, Predicate); -} - -TEST_F(NonMutatingTest, FindEnd) { - absl::c_find_end(sequence_, vector_); - absl::c_find_end(vector_, sequence_); -} - -TEST_F(NonMutatingTest, FindEndWithPredicate) { - absl::c_find_end(sequence_, vector_, BinPredicate); - absl::c_find_end(vector_, sequence_, BinPredicate); -} - -TEST_F(NonMutatingTest, FindFirstOf) { - absl::c_find_first_of(container_, sequence_); - absl::c_find_first_of(sequence_, container_); -} - -TEST_F(NonMutatingTest, FindFirstOfWithPredicate) { - absl::c_find_first_of(container_, sequence_, BinPredicate); - absl::c_find_first_of(sequence_, container_, BinPredicate); -} - -TEST_F(NonMutatingTest, AdjacentFind) { absl::c_adjacent_find(sequence_); } - -TEST_F(NonMutatingTest, AdjacentFindWithPredicate) { - absl::c_adjacent_find(sequence_, BinPredicate); -} - -TEST_F(NonMutatingTest, Count) { EXPECT_EQ(1, absl::c_count(container_, 3)); } - -TEST_F(NonMutatingTest, CountIf) { - EXPECT_EQ(2, absl::c_count_if(container_, Predicate)); - const std::unordered_set& const_container = container_; - EXPECT_EQ(2, absl::c_count_if(const_container, Predicate)); -} - -TEST_F(NonMutatingTest, Mismatch) { - absl::c_mismatch(container_, sequence_); - absl::c_mismatch(sequence_, container_); -} - -TEST_F(NonMutatingTest, MismatchWithPredicate) { - absl::c_mismatch(container_, sequence_, BinPredicate); - absl::c_mismatch(sequence_, container_, BinPredicate); -} - -TEST_F(NonMutatingTest, Equal) { - EXPECT_TRUE(absl::c_equal(vector_, sequence_)); - EXPECT_TRUE(absl::c_equal(sequence_, vector_)); - - // Test that behavior appropriately differs from that of equal(). - std::vector vector_plus = {1, 2, 3}; - vector_plus.push_back(4); - EXPECT_FALSE(absl::c_equal(vector_plus, sequence_)); - EXPECT_FALSE(absl::c_equal(sequence_, vector_plus)); -} - -TEST_F(NonMutatingTest, EqualWithPredicate) { - EXPECT_TRUE(absl::c_equal(vector_, sequence_, Equals)); - EXPECT_TRUE(absl::c_equal(sequence_, vector_, Equals)); - - // Test that behavior appropriately differs from that of equal(). - std::vector vector_plus = {1, 2, 3}; - vector_plus.push_back(4); - EXPECT_FALSE(absl::c_equal(vector_plus, sequence_, Equals)); - EXPECT_FALSE(absl::c_equal(sequence_, vector_plus, Equals)); -} - -TEST_F(NonMutatingTest, IsPermutation) { - auto vector_permut_ = vector_; - std::next_permutation(vector_permut_.begin(), vector_permut_.end()); - EXPECT_TRUE(absl::c_is_permutation(vector_permut_, sequence_)); - EXPECT_TRUE(absl::c_is_permutation(sequence_, vector_permut_)); - - // Test that behavior appropriately differs from that of is_permutation(). - std::vector vector_plus = {1, 2, 3}; - vector_plus.push_back(4); - EXPECT_FALSE(absl::c_is_permutation(vector_plus, sequence_)); - EXPECT_FALSE(absl::c_is_permutation(sequence_, vector_plus)); -} - -TEST_F(NonMutatingTest, IsPermutationWithPredicate) { - auto vector_permut_ = vector_; - std::next_permutation(vector_permut_.begin(), vector_permut_.end()); - EXPECT_TRUE(absl::c_is_permutation(vector_permut_, sequence_, Equals)); - EXPECT_TRUE(absl::c_is_permutation(sequence_, vector_permut_, Equals)); - - // Test that behavior appropriately differs from that of is_permutation(). - std::vector vector_plus = {1, 2, 3}; - vector_plus.push_back(4); - EXPECT_FALSE(absl::c_is_permutation(vector_plus, sequence_, Equals)); - EXPECT_FALSE(absl::c_is_permutation(sequence_, vector_plus, Equals)); -} - -TEST_F(NonMutatingTest, Search) { - absl::c_search(sequence_, vector_); - absl::c_search(vector_, sequence_); - absl::c_search(array_, sequence_); -} - -TEST_F(NonMutatingTest, SearchWithPredicate) { - absl::c_search(sequence_, vector_, BinPredicate); - absl::c_search(vector_, sequence_, BinPredicate); -} - -TEST_F(NonMutatingTest, SearchN) { absl::c_search_n(sequence_, 3, 1); } - -TEST_F(NonMutatingTest, SearchNWithPredicate) { - absl::c_search_n(sequence_, 3, 1, BinPredicate); -} - -TEST_F(NonMutatingTest, LowerBound) { - std::list::iterator i = absl::c_lower_bound(sequence_, 3); - ASSERT_TRUE(i != sequence_.end()); - EXPECT_EQ(2, std::distance(sequence_.begin(), i)); - EXPECT_EQ(3, *i); -} - -TEST_F(NonMutatingTest, LowerBoundWithPredicate) { - std::vector v(vector_); - std::sort(v.begin(), v.end(), std::greater()); - std::vector::iterator i = absl::c_lower_bound(v, 3, std::greater()); - EXPECT_TRUE(i == v.begin()); - EXPECT_EQ(3, *i); -} - -TEST_F(NonMutatingTest, UpperBound) { - std::list::iterator i = absl::c_upper_bound(sequence_, 1); - ASSERT_TRUE(i != sequence_.end()); - EXPECT_EQ(1, std::distance(sequence_.begin(), i)); - EXPECT_EQ(2, *i); -} - -TEST_F(NonMutatingTest, UpperBoundWithPredicate) { - std::vector v(vector_); - std::sort(v.begin(), v.end(), std::greater()); - std::vector::iterator i = absl::c_upper_bound(v, 1, std::greater()); - EXPECT_EQ(3, i - v.begin()); - EXPECT_TRUE(i == v.end()); -} - -TEST_F(NonMutatingTest, EqualRange) { - std::pair::iterator, std::list::iterator> p = - absl::c_equal_range(sequence_, 2); - EXPECT_EQ(1, std::distance(sequence_.begin(), p.first)); - EXPECT_EQ(2, std::distance(sequence_.begin(), p.second)); -} - -TEST_F(NonMutatingTest, EqualRangeArray) { - auto p = absl::c_equal_range(array_, 2); - EXPECT_EQ(1, std::distance(std::begin(array_), p.first)); - EXPECT_EQ(2, std::distance(std::begin(array_), p.second)); -} - -TEST_F(NonMutatingTest, EqualRangeWithPredicate) { - std::vector v(vector_); - std::sort(v.begin(), v.end(), std::greater()); - std::pair::iterator, std::vector::iterator> p = - absl::c_equal_range(v, 2, std::greater()); - EXPECT_EQ(1, std::distance(v.begin(), p.first)); - EXPECT_EQ(2, std::distance(v.begin(), p.second)); -} - -TEST_F(NonMutatingTest, BinarySearch) { - EXPECT_TRUE(absl::c_binary_search(vector_, 2)); - EXPECT_TRUE(absl::c_binary_search(std::vector(vector_), 2)); -} - -TEST_F(NonMutatingTest, BinarySearchWithPredicate) { - std::vector v(vector_); - std::sort(v.begin(), v.end(), std::greater()); - EXPECT_TRUE(absl::c_binary_search(v, 2, std::greater())); - EXPECT_TRUE( - absl::c_binary_search(std::vector(v), 2, std::greater())); -} - -TEST_F(NonMutatingTest, MinElement) { - std::list::iterator i = absl::c_min_element(sequence_); - ASSERT_TRUE(i != sequence_.end()); - EXPECT_EQ(*i, 1); -} - -TEST_F(NonMutatingTest, MinElementWithPredicate) { - std::list::iterator i = - absl::c_min_element(sequence_, std::greater()); - ASSERT_TRUE(i != sequence_.end()); - EXPECT_EQ(*i, 3); -} - -TEST_F(NonMutatingTest, MaxElement) { - std::list::iterator i = absl::c_max_element(sequence_); - ASSERT_TRUE(i != sequence_.end()); - EXPECT_EQ(*i, 3); -} - -TEST_F(NonMutatingTest, MaxElementWithPredicate) { - std::list::iterator i = - absl::c_max_element(sequence_, std::greater()); - ASSERT_TRUE(i != sequence_.end()); - EXPECT_EQ(*i, 1); -} - -TEST_F(NonMutatingTest, LexicographicalCompare) { - EXPECT_FALSE(absl::c_lexicographical_compare(sequence_, sequence_)); - - std::vector v; - v.push_back(1); - v.push_back(2); - v.push_back(4); - - EXPECT_TRUE(absl::c_lexicographical_compare(sequence_, v)); - EXPECT_TRUE(absl::c_lexicographical_compare(std::list(sequence_), v)); -} - -TEST_F(NonMutatingTest, LexicographicalCopmareWithPredicate) { - EXPECT_FALSE(absl::c_lexicographical_compare(sequence_, sequence_, - std::greater())); - - std::vector v; - v.push_back(1); - v.push_back(2); - v.push_back(4); - - EXPECT_TRUE( - absl::c_lexicographical_compare(v, sequence_, std::greater())); - EXPECT_TRUE(absl::c_lexicographical_compare( - std::vector(v), std::list(sequence_), std::greater())); -} - -TEST_F(NonMutatingTest, Includes) { - std::set s(vector_.begin(), vector_.end()); - s.insert(4); - EXPECT_TRUE(absl::c_includes(s, vector_)); -} - -TEST_F(NonMutatingTest, IncludesWithPredicate) { - std::vector v = {3, 2, 1}; - std::set> s(v.begin(), v.end()); - s.insert(4); - EXPECT_TRUE(absl::c_includes(s, v, std::greater())); -} - -class NumericMutatingTest : public testing::Test { - protected: - std::list list_ = {1, 2, 3}; - std::vector output_; -}; - -TEST_F(NumericMutatingTest, Iota) { - absl::c_iota(list_, 5); - std::list expected{5, 6, 7}; - EXPECT_EQ(list_, expected); -} - -TEST_F(NonMutatingTest, Accumulate) { - EXPECT_EQ(absl::c_accumulate(sequence_, 4), 1 + 2 + 3 + 4); -} - -TEST_F(NonMutatingTest, AccumulateWithBinaryOp) { - EXPECT_EQ(absl::c_accumulate(sequence_, 4, std::multiplies()), - 1 * 2 * 3 * 4); -} - -TEST_F(NonMutatingTest, AccumulateLvalueInit) { - int lvalue = 4; - EXPECT_EQ(absl::c_accumulate(sequence_, lvalue), 1 + 2 + 3 + 4); -} - -TEST_F(NonMutatingTest, AccumulateWithBinaryOpLvalueInit) { - int lvalue = 4; - EXPECT_EQ(absl::c_accumulate(sequence_, lvalue, std::multiplies()), - 1 * 2 * 3 * 4); -} - -TEST_F(NonMutatingTest, InnerProduct) { - EXPECT_EQ(absl::c_inner_product(sequence_, vector_, 1000), - 1000 + 1 * 1 + 2 * 2 + 3 * 3); -} - -TEST_F(NonMutatingTest, InnerProductWithBinaryOps) { - EXPECT_EQ(absl::c_inner_product(sequence_, vector_, 10, - std::multiplies(), std::plus()), - 10 * (1 + 1) * (2 + 2) * (3 + 3)); -} - -TEST_F(NonMutatingTest, InnerProductLvalueInit) { - int lvalue = 1000; - EXPECT_EQ(absl::c_inner_product(sequence_, vector_, lvalue), - 1000 + 1 * 1 + 2 * 2 + 3 * 3); -} - -TEST_F(NonMutatingTest, InnerProductWithBinaryOpsLvalueInit) { - int lvalue = 10; - EXPECT_EQ(absl::c_inner_product(sequence_, vector_, lvalue, - std::multiplies(), std::plus()), - 10 * (1 + 1) * (2 + 2) * (3 + 3)); -} - -TEST_F(NumericMutatingTest, AdjacentDifference) { - auto last = absl::c_adjacent_difference(list_, std::back_inserter(output_)); - *last = 1000; - std::vector expected{1, 2 - 1, 3 - 2, 1000}; - EXPECT_EQ(output_, expected); -} - -TEST_F(NumericMutatingTest, AdjacentDifferenceWithBinaryOp) { - auto last = absl::c_adjacent_difference(list_, std::back_inserter(output_), - std::multiplies()); - *last = 1000; - std::vector expected{1, 2 * 1, 3 * 2, 1000}; - EXPECT_EQ(output_, expected); -} - -TEST_F(NumericMutatingTest, PartialSum) { - auto last = absl::c_partial_sum(list_, std::back_inserter(output_)); - *last = 1000; - std::vector expected{1, 1 + 2, 1 + 2 + 3, 1000}; - EXPECT_EQ(output_, expected); -} - -TEST_F(NumericMutatingTest, PartialSumWithBinaryOp) { - auto last = absl::c_partial_sum(list_, std::back_inserter(output_), - std::multiplies()); - *last = 1000; - std::vector expected{1, 1 * 2, 1 * 2 * 3, 1000}; - EXPECT_EQ(output_, expected); -} - -TEST_F(NonMutatingTest, LinearSearch) { - EXPECT_TRUE(absl::c_linear_search(container_, 3)); - EXPECT_FALSE(absl::c_linear_search(container_, 4)); -} - -TEST_F(NonMutatingTest, AllOf) { - const std::vector& v = vector_; - EXPECT_FALSE(absl::c_all_of(v, [](int x) { return x > 1; })); - EXPECT_TRUE(absl::c_all_of(v, [](int x) { return x > 0; })); -} - -TEST_F(NonMutatingTest, AnyOf) { - const std::vector& v = vector_; - EXPECT_TRUE(absl::c_any_of(v, [](int x) { return x > 2; })); - EXPECT_FALSE(absl::c_any_of(v, [](int x) { return x > 5; })); -} - -TEST_F(NonMutatingTest, NoneOf) { - const std::vector& v = vector_; - EXPECT_FALSE(absl::c_none_of(v, [](int x) { return x > 2; })); - EXPECT_TRUE(absl::c_none_of(v, [](int x) { return x > 5; })); -} - -TEST_F(NonMutatingTest, MinMaxElementLess) { - std::pair::const_iterator, std::vector::const_iterator> - p = absl::c_minmax_element(vector_, std::less()); - EXPECT_TRUE(p.first == vector_.begin()); - EXPECT_TRUE(p.second == vector_.begin() + 2); -} - -TEST_F(NonMutatingTest, MinMaxElementGreater) { - std::pair::const_iterator, std::vector::const_iterator> - p = absl::c_minmax_element(vector_, std::greater()); - EXPECT_TRUE(p.first == vector_.begin() + 2); - EXPECT_TRUE(p.second == vector_.begin()); -} - -TEST_F(NonMutatingTest, MinMaxElementNoPredicate) { - std::pair::const_iterator, std::vector::const_iterator> - p = absl::c_minmax_element(vector_); - EXPECT_TRUE(p.first == vector_.begin()); - EXPECT_TRUE(p.second == vector_.begin() + 2); -} - -class SortingTest : public testing::Test { - protected: - std::list sorted_ = {1, 2, 3, 4}; - std::list unsorted_ = {2, 4, 1, 3}; - std::list reversed_ = {4, 3, 2, 1}; -}; - -TEST_F(SortingTest, IsSorted) { - EXPECT_TRUE(absl::c_is_sorted(sorted_)); - EXPECT_FALSE(absl::c_is_sorted(unsorted_)); - EXPECT_FALSE(absl::c_is_sorted(reversed_)); -} - -TEST_F(SortingTest, IsSortedWithPredicate) { - EXPECT_FALSE(absl::c_is_sorted(sorted_, std::greater())); - EXPECT_FALSE(absl::c_is_sorted(unsorted_, std::greater())); - EXPECT_TRUE(absl::c_is_sorted(reversed_, std::greater())); -} - -TEST_F(SortingTest, IsSortedUntil) { - EXPECT_EQ(1, *absl::c_is_sorted_until(unsorted_)); - EXPECT_EQ(4, *absl::c_is_sorted_until(unsorted_, std::greater())); -} - -TEST_F(SortingTest, NthElement) { - std::vector unsorted = {2, 4, 1, 3}; - absl::c_nth_element(unsorted, unsorted.begin() + 2); - EXPECT_THAT(unsorted, - ElementsAre(Lt(3), Lt(3), 3, Gt(3))); - absl::c_nth_element(unsorted, unsorted.begin() + 2, std::greater()); - EXPECT_THAT(unsorted, - ElementsAre(Gt(2), Gt(2), 2, Lt(2))); -} - -TEST(MutatingTest, IsPartitioned) { - EXPECT_TRUE( - absl::c_is_partitioned(std::vector{1, 3, 5, 2, 4, 6}, IsOdd)); - EXPECT_FALSE( - absl::c_is_partitioned(std::vector{1, 2, 3, 4, 5, 6}, IsOdd)); - EXPECT_FALSE( - absl::c_is_partitioned(std::vector{2, 4, 6, 1, 3, 5}, IsOdd)); -} - -TEST(MutatingTest, Partition) { - std::vector actual = {1, 2, 3, 4, 5}; - absl::c_partition(actual, IsOdd); - EXPECT_THAT(actual, Truly([](const std::vector& c) { - return absl::c_is_partitioned(c, IsOdd); - })); -} - -TEST(MutatingTest, StablePartition) { - std::vector actual = {1, 2, 3, 4, 5}; - absl::c_stable_partition(actual, IsOdd); - EXPECT_THAT(actual, ElementsAre(1, 3, 5, 2, 4)); -} - -TEST(MutatingTest, PartitionCopy) { - const std::vector initial = {1, 2, 3, 4, 5}; - std::vector odds, evens; - auto ends = absl::c_partition_copy(initial, back_inserter(odds), - back_inserter(evens), IsOdd); - *ends.first = 7; - *ends.second = 6; - EXPECT_THAT(odds, ElementsAre(1, 3, 5, 7)); - EXPECT_THAT(evens, ElementsAre(2, 4, 6)); -} - -TEST(MutatingTest, PartitionPoint) { - const std::vector initial = {1, 3, 5, 2, 4}; - auto middle = absl::c_partition_point(initial, IsOdd); - EXPECT_EQ(2, *middle); -} - -TEST(MutatingTest, CopyMiddle) { - const std::vector initial = {4, -1, -2, -3, 5}; - const std::list input = {1, 2, 3}; - const std::vector expected = {4, 1, 2, 3, 5}; - - std::list test_list(initial.begin(), initial.end()); - absl::c_copy(input, ++test_list.begin()); - EXPECT_EQ(std::list(expected.begin(), expected.end()), test_list); - - std::vector test_vector = initial; - absl::c_copy(input, test_vector.begin() + 1); - EXPECT_EQ(expected, test_vector); -} - -TEST(MutatingTest, CopyFrontInserter) { - const std::list initial = {4, 5}; - const std::list input = {1, 2, 3}; - const std::list expected = {3, 2, 1, 4, 5}; - - std::list test_list = initial; - absl::c_copy(input, std::front_inserter(test_list)); - EXPECT_EQ(expected, test_list); -} - -TEST(MutatingTest, CopyBackInserter) { - const std::vector initial = {4, 5}; - const std::list input = {1, 2, 3}; - const std::vector expected = {4, 5, 1, 2, 3}; - - std::list test_list(initial.begin(), initial.end()); - absl::c_copy(input, std::back_inserter(test_list)); - EXPECT_EQ(std::list(expected.begin(), expected.end()), test_list); - - std::vector test_vector = initial; - absl::c_copy(input, std::back_inserter(test_vector)); - EXPECT_EQ(expected, test_vector); -} - -TEST(MutatingTest, CopyN) { - const std::vector initial = {1, 2, 3, 4, 5}; - const std::vector expected = {1, 2}; - std::vector actual; - absl::c_copy_n(initial, 2, back_inserter(actual)); - EXPECT_EQ(expected, actual); -} - -TEST(MutatingTest, CopyIf) { - const std::list input = {1, 2, 3}; - std::vector output; - absl::c_copy_if(input, std::back_inserter(output), - [](int i) { return i != 2; }); - EXPECT_THAT(output, ElementsAre(1, 3)); -} - -TEST(MutatingTest, CopyBackward) { - std::vector actual = {1, 2, 3, 4, 5}; - std::vector expected = {1, 2, 1, 2, 3}; - absl::c_copy_backward(absl::MakeSpan(actual.data(), 3), actual.end()); - EXPECT_EQ(expected, actual); -} - -TEST(MutatingTest, Move) { - std::vector> src; - src.emplace_back(absl::make_unique(1)); - src.emplace_back(absl::make_unique(2)); - src.emplace_back(absl::make_unique(3)); - src.emplace_back(absl::make_unique(4)); - src.emplace_back(absl::make_unique(5)); - - std::vector> dest = {}; - absl::c_move(src, std::back_inserter(dest)); - EXPECT_THAT(src, Each(IsNull())); - EXPECT_THAT(dest, ElementsAre(Pointee(1), Pointee(2), Pointee(3), Pointee(4), - Pointee(5))); -} - -TEST(MutatingTest, MoveWithRvalue) { - auto MakeRValueSrc = [] { - std::vector> src; - src.emplace_back(absl::make_unique(1)); - src.emplace_back(absl::make_unique(2)); - src.emplace_back(absl::make_unique(3)); - return src; - }; - - std::vector> dest = MakeRValueSrc(); - absl::c_move(MakeRValueSrc(), std::back_inserter(dest)); - EXPECT_THAT(dest, ElementsAre(Pointee(1), Pointee(2), Pointee(3), Pointee(1), - Pointee(2), Pointee(3))); -} - -TEST(MutatingTest, SwapRanges) { - std::vector odds = {2, 4, 6}; - std::vector evens = {1, 3, 5}; - absl::c_swap_ranges(odds, evens); - EXPECT_THAT(odds, ElementsAre(1, 3, 5)); - EXPECT_THAT(evens, ElementsAre(2, 4, 6)); -} - -TEST_F(NonMutatingTest, Transform) { - std::vector x{0, 2, 4}, y, z; - auto end = absl::c_transform(x, back_inserter(y), std::negate()); - EXPECT_EQ(std::vector({0, -2, -4}), y); - *end = 7; - EXPECT_EQ(std::vector({0, -2, -4, 7}), y); - - y = {1, 3, 0}; - end = absl::c_transform(x, y, back_inserter(z), std::plus()); - EXPECT_EQ(std::vector({1, 5, 4}), z); - *end = 7; - EXPECT_EQ(std::vector({1, 5, 4, 7}), z); -} - -TEST(MutatingTest, Replace) { - const std::vector initial = {1, 2, 3, 1, 4, 5}; - const std::vector expected = {4, 2, 3, 4, 4, 5}; - - std::vector test_vector = initial; - absl::c_replace(test_vector, 1, 4); - EXPECT_EQ(expected, test_vector); - - std::list test_list(initial.begin(), initial.end()); - absl::c_replace(test_list, 1, 4); - EXPECT_EQ(std::list(expected.begin(), expected.end()), test_list); -} - -TEST(MutatingTest, ReplaceIf) { - std::vector actual = {1, 2, 3, 4, 5}; - const std::vector expected = {0, 2, 0, 4, 0}; - - absl::c_replace_if(actual, IsOdd, 0); - EXPECT_EQ(expected, actual); -} - -TEST(MutatingTest, ReplaceCopy) { - const std::vector initial = {1, 2, 3, 1, 4, 5}; - const std::vector expected = {4, 2, 3, 4, 4, 5}; - - std::vector actual; - absl::c_replace_copy(initial, back_inserter(actual), 1, 4); - EXPECT_EQ(expected, actual); -} - -TEST(MutatingTest, Sort) { - std::vector test_vector = {2, 3, 1, 4}; - absl::c_sort(test_vector); - EXPECT_THAT(test_vector, ElementsAre(1, 2, 3, 4)); -} - -TEST(MutatingTest, SortWithPredicate) { - std::vector test_vector = {2, 3, 1, 4}; - absl::c_sort(test_vector, std::greater()); - EXPECT_THAT(test_vector, ElementsAre(4, 3, 2, 1)); -} - -// For absl::c_stable_sort tests. Needs an operator< that does not cover all -// fields so that the test can check the sort preserves order of equal elements. -struct Element { - int key; - int value; - friend bool operator<(const Element& e1, const Element& e2) { - return e1.key < e2.key; - } - // Make gmock print useful diagnostics. - friend std::ostream& operator<<(std::ostream& o, const Element& e) { - return o << "{" << e.key << ", " << e.value << "}"; - } -}; - -MATCHER_P2(IsElement, key, value, "") { - return arg.key == key && arg.value == value; -} - -TEST(MutatingTest, StableSort) { - std::vector test_vector = {{1, 1}, {2, 1}, {2, 0}, {1, 0}, {2, 2}}; - absl::c_stable_sort(test_vector); - EXPECT_THAT( - test_vector, - ElementsAre(IsElement(1, 1), IsElement(1, 0), IsElement(2, 1), - IsElement(2, 0), IsElement(2, 2))); -} - -TEST(MutatingTest, StableSortWithPredicate) { - std::vector test_vector = {{1, 1}, {2, 1}, {2, 0}, {1, 0}, {2, 2}}; - absl::c_stable_sort(test_vector, [](const Element& e1, const Element& e2) { - return e2 < e1; - }); - EXPECT_THAT( - test_vector, - ElementsAre(IsElement(2, 1), IsElement(2, 0), IsElement(2, 2), - IsElement(1, 1), IsElement(1, 0))); -} - -TEST(MutatingTest, ReplaceCopyIf) { - const std::vector initial = {1, 2, 3, 4, 5}; - const std::vector expected = {0, 2, 0, 4, 0}; - - std::vector actual; - absl::c_replace_copy_if(initial, back_inserter(actual), IsOdd, 0); - EXPECT_EQ(expected, actual); -} - -TEST(MutatingTest, Fill) { - std::vector actual(5); - absl::c_fill(actual, 1); - EXPECT_THAT(actual, ElementsAre(1, 1, 1, 1, 1)); -} - -TEST(MutatingTest, FillN) { - std::vector actual(5, 0); - absl::c_fill_n(actual, 2, 1); - EXPECT_THAT(actual, ElementsAre(1, 1, 0, 0, 0)); -} - -TEST(MutatingTest, Generate) { - std::vector actual(5); - int x = 0; - absl::c_generate(actual, [&x]() { return ++x; }); - EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5)); -} - -TEST(MutatingTest, GenerateN) { - std::vector actual(5, 0); - int x = 0; - absl::c_generate_n(actual, 3, [&x]() { return ++x; }); - EXPECT_THAT(actual, ElementsAre(1, 2, 3, 0, 0)); -} - -TEST(MutatingTest, RemoveCopy) { - std::vector actual; - absl::c_remove_copy(std::vector{1, 2, 3}, back_inserter(actual), 2); - EXPECT_THAT(actual, ElementsAre(1, 3)); -} - -TEST(MutatingTest, RemoveCopyIf) { - std::vector actual; - absl::c_remove_copy_if(std::vector{1, 2, 3}, back_inserter(actual), - IsOdd); - EXPECT_THAT(actual, ElementsAre(2)); -} - -TEST(MutatingTest, UniqueCopy) { - std::vector actual; - absl::c_unique_copy(std::vector{1, 2, 2, 2, 3, 3, 2}, - back_inserter(actual)); - EXPECT_THAT(actual, ElementsAre(1, 2, 3, 2)); -} - -TEST(MutatingTest, UniqueCopyWithPredicate) { - std::vector actual; - absl::c_unique_copy(std::vector{1, 2, 3, -1, -2, -3, 1}, - back_inserter(actual), - [](int x, int y) { return (x < 0) == (y < 0); }); - EXPECT_THAT(actual, ElementsAre(1, -1, 1)); -} - -TEST(MutatingTest, Reverse) { - std::vector test_vector = {1, 2, 3, 4}; - absl::c_reverse(test_vector); - EXPECT_THAT(test_vector, ElementsAre(4, 3, 2, 1)); - - std::list test_list = {1, 2, 3, 4}; - absl::c_reverse(test_list); - EXPECT_THAT(test_list, ElementsAre(4, 3, 2, 1)); -} - -TEST(MutatingTest, ReverseCopy) { - std::vector actual; - absl::c_reverse_copy(std::vector{1, 2, 3, 4}, back_inserter(actual)); - EXPECT_THAT(actual, ElementsAre(4, 3, 2, 1)); -} - -TEST(MutatingTest, Rotate) { - std::vector actual = {1, 2, 3, 4}; - auto it = absl::c_rotate(actual, actual.begin() + 2); - EXPECT_THAT(actual, testing::ElementsAreArray({3, 4, 1, 2})); - EXPECT_EQ(*it, 1); -} - -TEST(MutatingTest, RotateCopy) { - std::vector initial = {1, 2, 3, 4}; - std::vector actual; - auto end = - absl::c_rotate_copy(initial, initial.begin() + 2, back_inserter(actual)); - *end = 5; - EXPECT_THAT(actual, ElementsAre(3, 4, 1, 2, 5)); -} - -TEST(MutatingTest, Shuffle) { - std::vector actual = {1, 2, 3, 4, 5}; - absl::c_shuffle(actual, std::random_device()); - EXPECT_THAT(actual, UnorderedElementsAre(1, 2, 3, 4, 5)); -} - -TEST(MutatingTest, PartialSort) { - std::vector sequence{5, 3, 42, 0}; - absl::c_partial_sort(sequence, sequence.begin() + 2); - EXPECT_THAT(absl::MakeSpan(sequence.data(), 2), ElementsAre(0, 3)); - absl::c_partial_sort(sequence, sequence.begin() + 2, std::greater()); - EXPECT_THAT(absl::MakeSpan(sequence.data(), 2), ElementsAre(42, 5)); -} - -TEST(MutatingTest, PartialSortCopy) { - const std::vector initial = {5, 3, 42, 0}; - std::vector actual(2); - absl::c_partial_sort_copy(initial, actual); - EXPECT_THAT(actual, ElementsAre(0, 3)); - absl::c_partial_sort_copy(initial, actual, std::greater()); - EXPECT_THAT(actual, ElementsAre(42, 5)); -} - -TEST(MutatingTest, Merge) { - std::vector actual; - absl::c_merge(std::vector{1, 3, 5}, std::vector{2, 4}, - back_inserter(actual)); - EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5)); -} - -TEST(MutatingTest, MergeWithComparator) { - std::vector actual; - absl::c_merge(std::vector{5, 3, 1}, std::vector{4, 2}, - back_inserter(actual), std::greater()); - EXPECT_THAT(actual, ElementsAre(5, 4, 3, 2, 1)); -} - -TEST(MutatingTest, InplaceMerge) { - std::vector actual = {1, 3, 5, 2, 4}; - absl::c_inplace_merge(actual, actual.begin() + 3); - EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5)); -} - -TEST(MutatingTest, InplaceMergeWithComparator) { - std::vector actual = {5, 3, 1, 4, 2}; - absl::c_inplace_merge(actual, actual.begin() + 3, std::greater()); - EXPECT_THAT(actual, ElementsAre(5, 4, 3, 2, 1)); -} - -class SetOperationsTest : public testing::Test { - protected: - std::vector a_ = {1, 2, 3}; - std::vector b_ = {1, 3, 5}; - - std::vector a_reversed_ = {3, 2, 1}; - std::vector b_reversed_ = {5, 3, 1}; -}; - -TEST_F(SetOperationsTest, SetUnion) { - std::vector actual; - absl::c_set_union(a_, b_, back_inserter(actual)); - EXPECT_THAT(actual, ElementsAre(1, 2, 3, 5)); -} - -TEST_F(SetOperationsTest, SetUnionWithComparator) { - std::vector actual; - absl::c_set_union(a_reversed_, b_reversed_, back_inserter(actual), - std::greater()); - EXPECT_THAT(actual, ElementsAre(5, 3, 2, 1)); -} - -TEST_F(SetOperationsTest, SetIntersection) { - std::vector actual; - absl::c_set_intersection(a_, b_, back_inserter(actual)); - EXPECT_THAT(actual, ElementsAre(1, 3)); -} - -TEST_F(SetOperationsTest, SetIntersectionWithComparator) { - std::vector actual; - absl::c_set_intersection(a_reversed_, b_reversed_, back_inserter(actual), - std::greater()); - EXPECT_THAT(actual, ElementsAre(3, 1)); -} - -TEST_F(SetOperationsTest, SetDifference) { - std::vector actual; - absl::c_set_difference(a_, b_, back_inserter(actual)); - EXPECT_THAT(actual, ElementsAre(2)); -} - -TEST_F(SetOperationsTest, SetDifferenceWithComparator) { - std::vector actual; - absl::c_set_difference(a_reversed_, b_reversed_, back_inserter(actual), - std::greater()); - EXPECT_THAT(actual, ElementsAre(2)); -} - -TEST_F(SetOperationsTest, SetSymmetricDifference) { - std::vector actual; - absl::c_set_symmetric_difference(a_, b_, back_inserter(actual)); - EXPECT_THAT(actual, ElementsAre(2, 5)); -} - -TEST_F(SetOperationsTest, SetSymmetricDifferenceWithComparator) { - std::vector actual; - absl::c_set_symmetric_difference(a_reversed_, b_reversed_, - back_inserter(actual), std::greater()); - EXPECT_THAT(actual, ElementsAre(5, 2)); -} - -TEST(HeapOperationsTest, WithoutComparator) { - std::vector heap = {1, 2, 3}; - EXPECT_FALSE(absl::c_is_heap(heap)); - absl::c_make_heap(heap); - EXPECT_TRUE(absl::c_is_heap(heap)); - heap.push_back(4); - EXPECT_EQ(3, absl::c_is_heap_until(heap) - heap.begin()); - absl::c_push_heap(heap); - EXPECT_EQ(4, heap[0]); - absl::c_pop_heap(heap); - EXPECT_EQ(4, heap[3]); - absl::c_make_heap(heap); - absl::c_sort_heap(heap); - EXPECT_THAT(heap, ElementsAre(1, 2, 3, 4)); - EXPECT_FALSE(absl::c_is_heap(heap)); -} - -TEST(HeapOperationsTest, WithComparator) { - using greater = std::greater; - std::vector heap = {3, 2, 1}; - EXPECT_FALSE(absl::c_is_heap(heap, greater())); - absl::c_make_heap(heap, greater()); - EXPECT_TRUE(absl::c_is_heap(heap, greater())); - heap.push_back(0); - EXPECT_EQ(3, absl::c_is_heap_until(heap, greater()) - heap.begin()); - absl::c_push_heap(heap, greater()); - EXPECT_EQ(0, heap[0]); - absl::c_pop_heap(heap, greater()); - EXPECT_EQ(0, heap[3]); - absl::c_make_heap(heap, greater()); - absl::c_sort_heap(heap, greater()); - EXPECT_THAT(heap, ElementsAre(3, 2, 1, 0)); - EXPECT_FALSE(absl::c_is_heap(heap, greater())); -} - -TEST(MutatingTest, PermutationOperations) { - std::vector initial = {1, 2, 3, 4}; - std::vector permuted = initial; - - absl::c_next_permutation(permuted); - EXPECT_TRUE(absl::c_is_permutation(initial, permuted)); - EXPECT_TRUE(absl::c_is_permutation(initial, permuted, std::equal_to())); - - std::vector permuted2 = initial; - absl::c_prev_permutation(permuted2, std::greater()); - EXPECT_EQ(permuted, permuted2); - - absl::c_prev_permutation(permuted); - EXPECT_EQ(initial, permuted); -} - -} // namespace diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/equal_benchmark.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/equal_benchmark.cc deleted file mode 100644 index 19c0780..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/algorithm/equal_benchmark.cc +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include -#include - -#include "benchmark/benchmark.h" -#include "absl/algorithm/algorithm.h" - -namespace { - -// The range of sequence sizes to benchmark. -constexpr int kMinBenchmarkSize = 1024; -constexpr int kMaxBenchmarkSize = 8 * 1024 * 1024; - -// A user-defined type for use in equality benchmarks. Note that we expect -// std::memcmp to win for this type: libstdc++'s std::equal only defers to -// memcmp for integral types. This is because it is not straightforward to -// guarantee that std::memcmp would produce a result "as-if" compared by -// operator== for other types (example gotchas: NaN floats, structs with -// padding). -struct EightBits { - explicit EightBits(int /* unused */) : data(0) {} - bool operator==(const EightBits& rhs) const { return data == rhs.data; } - uint8_t data; -}; - -template -void BM_absl_equal_benchmark(benchmark::State& state) { - std::vector xs(state.range(0), T(0)); - std::vector ys = xs; - while (state.KeepRunning()) { - const bool same = absl::equal(xs.begin(), xs.end(), ys.begin(), ys.end()); - benchmark::DoNotOptimize(same); - } -} - -template -void BM_std_equal_benchmark(benchmark::State& state) { - std::vector xs(state.range(0), T(0)); - std::vector ys = xs; - while (state.KeepRunning()) { - const bool same = std::equal(xs.begin(), xs.end(), ys.begin()); - benchmark::DoNotOptimize(same); - } -} - -template -void BM_memcmp_benchmark(benchmark::State& state) { - std::vector xs(state.range(0), T(0)); - std::vector ys = xs; - while (state.KeepRunning()) { - const bool same = - std::memcmp(xs.data(), ys.data(), xs.size() * sizeof(T)) == 0; - benchmark::DoNotOptimize(same); - } -} - -// The expectation is that the compiler should be able to elide the equality -// comparison altogether for sufficiently simple types. -template -void BM_absl_equal_self_benchmark(benchmark::State& state) { - std::vector xs(state.range(0), T(0)); - while (state.KeepRunning()) { - const bool same = absl::equal(xs.begin(), xs.end(), xs.begin(), xs.end()); - benchmark::DoNotOptimize(same); - } -} - -BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint8_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint8_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint8_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint8_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); - -BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint16_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint16_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint16_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint16_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); - -BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint32_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint32_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint32_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint32_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); - -BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint64_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint64_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint64_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint64_t) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); - -BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, EightBits) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_std_equal_benchmark, EightBits) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_memcmp_benchmark, EightBits) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); -BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, EightBits) - ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); - -} // namespace diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/BUILD.bazel b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/BUILD.bazel deleted file mode 100644 index 44de05e..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/BUILD.bazel +++ /dev/null @@ -1,457 +0,0 @@ -# -# Copyright 2017 The Abseil Authors. -# -# 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. -# - -load( - "//absl:copts.bzl", - "ABSL_DEFAULT_COPTS", - "ABSL_TEST_COPTS", - "ABSL_EXCEPTIONS_FLAG", - "ABSL_EXCEPTIONS_FLAG_LINKOPTS", -) - -package(default_visibility = ["//visibility:public"]) - -licenses(["notice"]) # Apache 2.0 - -cc_library( - name = "spinlock_wait", - srcs = [ - "internal/spinlock_akaros.inc", - "internal/spinlock_linux.inc", - "internal/spinlock_posix.inc", - "internal/spinlock_wait.cc", - "internal/spinlock_win32.inc", - ], - hdrs = [ - "internal/scheduling_mode.h", - "internal/spinlock_wait.h", - ], - copts = ABSL_DEFAULT_COPTS, - visibility = [ - "//absl/base:__pkg__", - ], - deps = [":core_headers"], -) - -cc_library( - name = "config", - hdrs = [ - "config.h", - "policy_checks.h", - ], - copts = ABSL_DEFAULT_COPTS, -) - -cc_library( - name = "dynamic_annotations", - srcs = ["dynamic_annotations.cc"], - hdrs = ["dynamic_annotations.h"], - copts = ABSL_DEFAULT_COPTS, - defines = ["__CLANG_SUPPORT_DYN_ANNOTATION__"], -) - -cc_library( - name = "core_headers", - hdrs = [ - "attributes.h", - "macros.h", - "optimization.h", - "port.h", - "thread_annotations.h", - ], - copts = ABSL_DEFAULT_COPTS, - deps = [ - ":config", - ], -) - -cc_library( - name = "malloc_internal", - srcs = [ - "internal/low_level_alloc.cc", - ], - hdrs = [ - "internal/direct_mmap.h", - "internal/low_level_alloc.h", - ], - copts = ABSL_DEFAULT_COPTS, - visibility = [ - "//absl:__subpackages__", - ], - deps = [ - ":base", - ":config", - ":core_headers", - ":dynamic_annotations", - ":spinlock_wait", - ], -) - -cc_library( - name = "base_internal", - hdrs = [ - "internal/hide_ptr.h", - "internal/identity.h", - "internal/inline_variable.h", - "internal/invoke.h", - ], - copts = ABSL_DEFAULT_COPTS, - visibility = [ - "//absl:__subpackages__", - ], -) - -cc_library( - name = "base", - srcs = [ - "internal/cycleclock.cc", - "internal/raw_logging.cc", - "internal/spinlock.cc", - "internal/sysinfo.cc", - "internal/thread_identity.cc", - "internal/unscaledcycleclock.cc", - ], - hdrs = [ - "call_once.h", - "casts.h", - "internal/atomic_hook.h", - "internal/cycleclock.h", - "internal/low_level_scheduling.h", - "internal/per_thread_tls.h", - "internal/raw_logging.h", - "internal/spinlock.h", - "internal/sysinfo.h", - "internal/thread_identity.h", - "internal/tsan_mutex_interface.h", - "internal/unscaledcycleclock.h", - "log_severity.h", - ], - copts = ABSL_DEFAULT_COPTS, - deps = [ - ":base_internal", - ":config", - ":core_headers", - ":dynamic_annotations", - ":spinlock_wait", - ], -) - -cc_test( - name = "atomic_hook_test", - size = "small", - srcs = ["internal/atomic_hook_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":base", - ":core_headers", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "bit_cast_test", - size = "small", - srcs = [ - "bit_cast_test.cc", - ], - copts = ABSL_TEST_COPTS, - deps = [ - ":base", - ":core_headers", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "throw_delegate", - srcs = ["internal/throw_delegate.cc"], - hdrs = ["internal/throw_delegate.h"], - copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, - visibility = [ - "//absl:__subpackages__", - ], - deps = [ - ":base", - ":config", - ], -) - -cc_test( - name = "throw_delegate_test", - srcs = ["throw_delegate_test.cc"], - copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, - deps = [ - ":throw_delegate", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "exception_testing", - testonly = 1, - hdrs = ["internal/exception_testing.h"], - copts = ABSL_TEST_COPTS, - visibility = [ - "//absl:__subpackages__", - ], - deps = [ - ":config", - "@com_google_googletest//:gtest", - ], -) - -cc_library( - name = "pretty_function", - hdrs = ["internal/pretty_function.h"], - visibility = ["//absl:__subpackages__"], -) - -cc_library( - name = "exception_safety_testing", - testonly = 1, - srcs = ["internal/exception_safety_testing.cc"], - hdrs = ["internal/exception_safety_testing.h"], - copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, - deps = [ - ":base", - ":config", - ":pretty_function", - "//absl/memory", - "//absl/meta:type_traits", - "//absl/strings", - "//absl/utility", - "@com_google_googletest//:gtest", - ], -) - -cc_test( - name = "exception_safety_testing_test", - srcs = ["exception_safety_testing_test.cc"], - copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, - deps = [ - ":exception_safety_testing", - "//absl/memory", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "inline_variable_test", - size = "small", - srcs = [ - "inline_variable_test.cc", - "inline_variable_test_a.cc", - "inline_variable_test_b.cc", - "internal/inline_variable_testing.h", - ], - copts = ABSL_TEST_COPTS, - deps = [ - ":base_internal", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "invoke_test", - size = "small", - srcs = ["invoke_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":base_internal", - "//absl/memory", - "//absl/strings", - "@com_google_googletest//:gtest_main", - ], -) - -# Common test library made available for use in non-absl code that overrides -# AbslInternalSpinLockDelay and AbslInternalSpinLockWake. -cc_library( - name = "spinlock_test_common", - testonly = 1, - srcs = ["spinlock_test_common.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":base", - ":core_headers", - ":spinlock_wait", - "//absl/synchronization", - "@com_google_googletest//:gtest", - ], - alwayslink = 1, -) - -cc_test( - name = "spinlock_test", - size = "medium", - srcs = ["spinlock_test_common.cc"], - copts = ABSL_TEST_COPTS, - tags = ["no_test_wasm"], - deps = [ - ":base", - ":core_headers", - ":spinlock_wait", - "//absl/synchronization", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "endian", - hdrs = [ - "internal/endian.h", - "internal/unaligned_access.h", - ], - copts = ABSL_DEFAULT_COPTS, - deps = [ - ":config", - ":core_headers", - ], -) - -cc_test( - name = "endian_test", - srcs = ["internal/endian_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":base", - ":config", - ":endian", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "config_test", - srcs = ["config_test.cc"], - copts = ABSL_TEST_COPTS, - tags = [ - "no_test_wasm", - ], - deps = [ - ":config", - "//absl/synchronization:thread_pool", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "call_once_test", - srcs = ["call_once_test.cc"], - copts = ABSL_TEST_COPTS, - tags = [ - "no_test_wasm", - ], - deps = [ - ":base", - ":core_headers", - "//absl/synchronization", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "raw_logging_test", - srcs = ["raw_logging_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":base", - "//absl/strings", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "sysinfo_test", - size = "small", - srcs = ["internal/sysinfo_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":base", - "//absl/synchronization", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "low_level_alloc_test", - size = "small", - srcs = ["internal/low_level_alloc_test.cc"], - copts = ABSL_TEST_COPTS, - linkopts = select({ - "//absl:windows": [], - "//conditions:default": ["-pthread"], - }), - tags = ["no_test_ios_x86_64"], - deps = [":malloc_internal"], -) - -cc_test( - name = "thread_identity_test", - size = "small", - srcs = ["internal/thread_identity_test.cc"], - copts = ABSL_TEST_COPTS, - linkopts = select({ - "//absl:windows": [], - "//conditions:default": ["-pthread"], - }), - tags = [ - "no_test_wasm", - ], - deps = [ - ":base", - ":core_headers", - "//absl/synchronization", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "thread_identity_benchmark", - srcs = ["internal/thread_identity_benchmark.cc"], - copts = ABSL_TEST_COPTS, - tags = ["benchmark"], - visibility = ["//visibility:private"], - deps = [ - ":base", - "//absl/synchronization", - "@com_github_google_benchmark//:benchmark_main", - ], -) - -cc_library( - name = "bits", - hdrs = ["internal/bits.h"], - visibility = [ - "//absl:__subpackages__", - ], - deps = [":core_headers"], -) - -cc_test( - name = "bits_test", - size = "small", - srcs = ["internal/bits_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":bits", - "@com_google_googletest//:gtest_main", - ], -) diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/CMakeLists.txt b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/CMakeLists.txt deleted file mode 100644 index d506bc4..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/CMakeLists.txt +++ /dev/null @@ -1,396 +0,0 @@ -# -# Copyright 2017 The Abseil Authors. -# -# 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. -# - -list(APPEND BASE_PUBLIC_HEADERS - "attributes.h" - "call_once.h" - "casts.h" - "config.h" - "dynamic_annotations.h" - "log_severity.h" - "macros.h" - "optimization.h" - "policy_checks.h" - "port.h" - "thread_annotations.h" -) - - -list(APPEND BASE_INTERNAL_HEADERS - "internal/atomic_hook.h" - "internal/bits.h" - "internal/cycleclock.h" - "internal/direct_mmap.h" - "internal/endian.h" - "internal/exception_testing.h" - "internal/exception_safety_testing.h" - "internal/hide_ptr.h" - "internal/identity.h" - "internal/invoke.h" - "internal/inline_variable.h" - "internal/low_level_alloc.h" - "internal/low_level_scheduling.h" - "internal/per_thread_tls.h" - "internal/pretty_function.h" - "internal/raw_logging.h" - "internal/scheduling_mode.h" - "internal/spinlock.h" - "internal/spinlock_wait.h" - "internal/sysinfo.h" - "internal/thread_identity.h" - "internal/throw_delegate.h" - "internal/tsan_mutex_interface.h" - "internal/unaligned_access.h" - "internal/unscaledcycleclock.h" -) - - -# absl_base main library -list(APPEND BASE_SRC - "internal/cycleclock.cc" - "internal/raw_logging.cc" - "internal/spinlock.cc" - "internal/sysinfo.cc" - "internal/thread_identity.cc" - "internal/unscaledcycleclock.cc" - "internal/low_level_alloc.cc" - ${BASE_PUBLIC_HEADERS} - ${BASE_INTERNAL_HEADERS} -) - -absl_library( - TARGET - absl_base - SOURCES - ${BASE_SRC} - PUBLIC_LIBRARIES - absl_dynamic_annotations - absl_internal_spinlock_wait - EXPORT_NAME - base -) - -absl_cc_library( - NAME - throw_delegate - SRCS - "internal/throw_delegate.cc" - HDRS - "internal/throw_delegate.h" - COPTS - ${ABSL_EXCEPTIONS_FLAG} - DEPS - absl::base -) - - -# exception-safety testing library -absl_cc_library( - NAME - exception_safety_testing - HDRS - "internal/exception_safety_testing.h" - SRCS - "internal/exception_safety_testing.cc" - COPTS - ${ABSL_EXCEPTIONS_FLAG} - DEPS - absl::base - absl::memory - absl::meta - absl::strings - absl::optional - gtest - TESTONLY -) - - -# dynamic_annotations library -set(DYNAMIC_ANNOTATIONS_SRC "dynamic_annotations.cc") - -absl_library( - TARGET - absl_dynamic_annotations - SOURCES - ${DYNAMIC_ANNOTATIONS_SRC} -) - -absl_cc_library( - NAME - config - HDRS - "config.h" - "policy_checks.h" - PUBLIC -) - -absl_cc_library( - NAME - core_headers - HDRS - "attributes.h" - "macros.h" - "optimization.h" - "port.h" - "thread_annotations.h" - DEPS - absl::config - PUBLIC -) - -absl_cc_library( - NAME - spinlock_wait - SRCS - "internal/spinlock_wait.cc" - HDRS - "internal/scheduling_mode.h" - "internal/spinlock_wait.h" -) - -absl_cc_library( - NAME - malloc_internal - SRCS - "internal/low_level_alloc.cc" - HDRS - "internal/direct_mmap.h" - "internal/low_level_alloc.h" - DEPS - absl_dynamic_annotations -) - - - -# -## TESTS -# - -# call once test -set(ATOMIC_HOOK_TEST_SRC "internal/atomic_hook_test.cc") -set(ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES absl::base) - -absl_test( - TARGET - atomic_hook_test - SOURCES - ${ATOMIC_HOOK_TEST_SRC} - PUBLIC_LIBRARIES - ${ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES} -) - - -# call once test -set(CALL_ONCE_TEST_SRC "call_once_test.cc") -set(CALL_ONCE_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET - call_once_test - SOURCES - ${CALL_ONCE_TEST_SRC} - PUBLIC_LIBRARIES - ${CALL_ONCE_TEST_PUBLIC_LIBRARIES} -) - - -# test bit_cast_test -set(BIT_CAST_TEST_SRC "bit_cast_test.cc") - -absl_test( - TARGET - bit_cast_test - SOURCES - ${BIT_CAST_TEST_SRC} -) - - -# test absl_throw_delegate_test -set(THROW_DELEGATE_TEST_SRC "throw_delegate_test.cc") -set(THROW_DELEGATE_TEST_PUBLIC_LIBRARIES absl::base absl_internal_throw_delegate) - -absl_test( - TARGET - throw_delegate_test - SOURCES - ${THROW_DELEGATE_TEST_SRC} - PUBLIC_LIBRARIES - ${THROW_DELEGATE_TEST_PUBLIC_LIBRARIES} -) - - -# test invoke_test -set(INVOKE_TEST_SRC "invoke_test.cc") -set(INVOKE_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - invoke_test - SOURCES - ${INVOKE_TEST_SRC} - PUBLIC_LIBRARIES - ${INVOKE_TEST_PUBLIC_LIBRARIES} -) - - -# test inline_variable_test -list(APPEND INLINE_VARIABLE_TEST_SRC - "internal/inline_variable_testing.h" - "inline_variable_test.cc" - "inline_variable_test_a.cc" - "inline_variable_test_b.cc" -) - -set(INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES absl::base) - -absl_test( - TARGET - inline_variable_test - SOURCES - ${INLINE_VARIABLE_TEST_SRC} - PUBLIC_LIBRARIES - ${INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES} -) - - -# test spinlock_test_common -set(SPINLOCK_TEST_COMMON_SRC "spinlock_test_common.cc") -set(SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET - spinlock_test_common - SOURCES - ${SPINLOCK_TEST_COMMON_SRC} - PUBLIC_LIBRARIES - ${SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES} -) - - -# test spinlock_test -set(SPINLOCK_TEST_SRC "spinlock_test_common.cc") -set(SPINLOCK_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET - spinlock_test - SOURCES - ${SPINLOCK_TEST_SRC} - PUBLIC_LIBRARIES - ${SPINLOCK_TEST_PUBLIC_LIBRARIES} -) - - -# test endian_test -set(ENDIAN_TEST_SRC "internal/endian_test.cc") - -absl_test( - TARGET - endian_test - SOURCES - ${ENDIAN_TEST_SRC} -) - - -# test config_test -set(CONFIG_TEST_SRC "config_test.cc") -set(CONFIG_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) -absl_test( - TARGET - config_test - SOURCES - ${CONFIG_TEST_SRC} - PUBLIC_LIBRARIES - ${CONFIG_TEST_PUBLIC_LIBRARIES} -) - - -# test raw_logging_test -set(RAW_LOGGING_TEST_SRC "raw_logging_test.cc") -set(RAW_LOGGING_TEST_PUBLIC_LIBRARIES absl::base absl::strings) - -absl_test( - TARGET - raw_logging_test - SOURCES - ${RAW_LOGGING_TEST_SRC} - PUBLIC_LIBRARIES - ${RAW_LOGGING_TEST_PUBLIC_LIBRARIES} -) - - -# test sysinfo_test -set(SYSINFO_TEST_SRC "internal/sysinfo_test.cc") -set(SYSINFO_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET - sysinfo_test - SOURCES - ${SYSINFO_TEST_SRC} - PUBLIC_LIBRARIES - ${SYSINFO_TEST_PUBLIC_LIBRARIES} -) - - -# test low_level_alloc_test -set(LOW_LEVEL_ALLOC_TEST_SRC "internal/low_level_alloc_test.cc") -set(LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES absl::base) - -absl_test( - TARGET - low_level_alloc_test - SOURCES - ${LOW_LEVEL_ALLOC_TEST_SRC} - PUBLIC_LIBRARIES - ${LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES} -) - - -# test thread_identity_test -set(THREAD_IDENTITY_TEST_SRC "internal/thread_identity_test.cc") -set(THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET - thread_identity_test - SOURCES - ${THREAD_IDENTITY_TEST_SRC} - PUBLIC_LIBRARIES - ${THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES} -) - -#test exceptions_safety_testing_test -set(EXCEPTION_SAFETY_TESTING_TEST_SRC "exception_safety_testing_test.cc") -set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES - absl::base - absl_internal_exception_safety_testing - absl::memory - absl::meta - absl::strings - absl::utility -) - -absl_test( - TARGET - absl_exception_safety_testing_test - SOURCES - ${EXCEPTION_SAFETY_TESTING_TEST_SRC} - PUBLIC_LIBRARIES - ${EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS - ${ABSL_EXCEPTIONS_FLAG} -) diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/bit_cast_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/bit_cast_test.cc deleted file mode 100644 index 8cd878d..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/bit_cast_test.cc +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -// Unit test for bit_cast template. - -#include -#include - -#include "gtest/gtest.h" -#include "absl/base/casts.h" -#include "absl/base/macros.h" - -namespace absl { -namespace { - -template -struct marshall { char buf[N]; }; - -template -void TestMarshall(const T values[], int num_values) { - for (int i = 0; i < num_values; ++i) { - T t0 = values[i]; - marshall m0 = absl::bit_cast >(t0); - T t1 = absl::bit_cast(m0); - marshall m1 = absl::bit_cast >(t1); - ASSERT_EQ(0, memcmp(&t0, &t1, sizeof(T))); - ASSERT_EQ(0, memcmp(&m0, &m1, sizeof(T))); - } -} - -// Convert back and forth to an integral type. The C++ standard does -// not guarantee this will work, but we test that this works on all the -// platforms we support. -// -// Likewise, we below make assumptions about sizeof(float) and -// sizeof(double) which the standard does not guarantee, but which hold on the -// platforms we support. - -template -void TestIntegral(const T values[], int num_values) { - for (int i = 0; i < num_values; ++i) { - T t0 = values[i]; - I i0 = absl::bit_cast(t0); - T t1 = absl::bit_cast(i0); - I i1 = absl::bit_cast(t1); - ASSERT_EQ(0, memcmp(&t0, &t1, sizeof(T))); - ASSERT_EQ(i0, i1); - } -} - -TEST(BitCast, Bool) { - static const bool bool_list[] = { false, true }; - TestMarshall(bool_list, ABSL_ARRAYSIZE(bool_list)); -} - -TEST(BitCast, Int32) { - static const int32_t int_list[] = - { 0, 1, 100, 2147483647, -1, -100, -2147483647, -2147483647-1 }; - TestMarshall(int_list, ABSL_ARRAYSIZE(int_list)); -} - -TEST(BitCast, Int64) { - static const int64_t int64_list[] = - { 0, 1, 1LL << 40, -1, -(1LL<<40) }; - TestMarshall(int64_list, ABSL_ARRAYSIZE(int64_list)); -} - -TEST(BitCast, Uint64) { - static const uint64_t uint64_list[] = - { 0, 1, 1LLU << 40, 1LLU << 63 }; - TestMarshall(uint64_list, ABSL_ARRAYSIZE(uint64_list)); -} - -TEST(BitCast, Float) { - static const float float_list[] = - { 0.0f, 1.0f, -1.0f, 10.0f, -10.0f, - 1e10f, 1e20f, 1e-10f, 1e-20f, - 2.71828f, 3.14159f }; - TestMarshall(float_list, ABSL_ARRAYSIZE(float_list)); - TestIntegral(float_list, ABSL_ARRAYSIZE(float_list)); - TestIntegral(float_list, ABSL_ARRAYSIZE(float_list)); -} - -TEST(BitCast, Double) { - static const double double_list[] = - { 0.0, 1.0, -1.0, 10.0, -10.0, - 1e10, 1e100, 1e-10, 1e-100, - 2.718281828459045, - 3.141592653589793238462643383279502884197169399375105820974944 }; - TestMarshall(double_list, ABSL_ARRAYSIZE(double_list)); - TestIntegral(double_list, ABSL_ARRAYSIZE(double_list)); - TestIntegral(double_list, ABSL_ARRAYSIZE(double_list)); -} - -} // namespace -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/call_once_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/call_once_test.cc deleted file mode 100644 index cd58ee1..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/call_once_test.cc +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/base/call_once.h" - -#include -#include - -#include "gtest/gtest.h" -#include "absl/base/thread_annotations.h" -#include "absl/synchronization/mutex.h" - -namespace absl { -namespace { - -absl::once_flag once; -Mutex counters_mu; - -int running_thread_count GUARDED_BY(counters_mu) = 0; -int call_once_invoke_count GUARDED_BY(counters_mu) = 0; -int call_once_finished_count GUARDED_BY(counters_mu) = 0; -int call_once_return_count GUARDED_BY(counters_mu) = 0; -bool done_blocking GUARDED_BY(counters_mu) = false; - -// Function to be called from absl::call_once. Waits for a notification. -void WaitAndIncrement() { - counters_mu.Lock(); - ++call_once_invoke_count; - counters_mu.Unlock(); - - counters_mu.LockWhen(Condition(&done_blocking)); - ++call_once_finished_count; - counters_mu.Unlock(); -} - -void ThreadBody() { - counters_mu.Lock(); - ++running_thread_count; - counters_mu.Unlock(); - - absl::call_once(once, WaitAndIncrement); - - counters_mu.Lock(); - ++call_once_return_count; - counters_mu.Unlock(); -} - -// Returns true if all threads are set up for the test. -bool ThreadsAreSetup(void*) EXCLUSIVE_LOCKS_REQUIRED(counters_mu) { - // All ten threads must be running, and WaitAndIncrement should be blocked. - return running_thread_count == 10 && call_once_invoke_count == 1; -} - -TEST(CallOnceTest, ExecutionCount) { - std::vector threads; - - // Start 10 threads all calling call_once on the same once_flag. - for (int i = 0; i < 10; ++i) { - threads.emplace_back(ThreadBody); - } - - - // Wait until all ten threads have started, and WaitAndIncrement has been - // invoked. - counters_mu.LockWhen(Condition(ThreadsAreSetup, nullptr)); - - // WaitAndIncrement should have been invoked by exactly one call_once() - // instance. That thread should be blocking on a notification, and all other - // call_once instances should be blocking as well. - EXPECT_EQ(call_once_invoke_count, 1); - EXPECT_EQ(call_once_finished_count, 0); - EXPECT_EQ(call_once_return_count, 0); - - // Allow WaitAndIncrement to finish executing. Once it does, the other - // call_once waiters will be unblocked. - done_blocking = true; - counters_mu.Unlock(); - - for (std::thread& thread : threads) { - thread.join(); - } - - counters_mu.Lock(); - EXPECT_EQ(call_once_invoke_count, 1); - EXPECT_EQ(call_once_finished_count, 1); - EXPECT_EQ(call_once_return_count, 10); - counters_mu.Unlock(); -} - -} // namespace -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/config_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/config_test.cc deleted file mode 100644 index c839712..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/config_test.cc +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/base/config.h" - -#include - -#include "gtest/gtest.h" -#include "absl/synchronization/internal/thread_pool.h" - -namespace { - -TEST(ConfigTest, Endianness) { - union { - uint32_t value; - uint8_t data[sizeof(uint32_t)]; - } number; - number.data[0] = 0x00; - number.data[1] = 0x01; - number.data[2] = 0x02; - number.data[3] = 0x03; -#if defined(ABSL_IS_LITTLE_ENDIAN) && defined(ABSL_IS_BIG_ENDIAN) -#error Both ABSL_IS_LITTLE_ENDIAN and ABSL_IS_BIG_ENDIAN are defined -#elif defined(ABSL_IS_LITTLE_ENDIAN) - EXPECT_EQ(UINT32_C(0x03020100), number.value); -#elif defined(ABSL_IS_BIG_ENDIAN) - EXPECT_EQ(UINT32_C(0x00010203), number.value); -#else -#error Unknown endianness -#endif -} - -#if defined(ABSL_HAVE_THREAD_LOCAL) -TEST(ConfigTest, ThreadLocal) { - static thread_local int mine_mine_mine = 16; - EXPECT_EQ(16, mine_mine_mine); - { - absl::synchronization_internal::ThreadPool pool(1); - pool.Schedule([&] { - EXPECT_EQ(16, mine_mine_mine); - mine_mine_mine = 32; - EXPECT_EQ(32, mine_mine_mine); - }); - } - EXPECT_EQ(16, mine_mine_mine); -} -#endif - -} // namespace diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/dynamic_annotations.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/dynamic_annotations.h deleted file mode 100644 index 7e328d9..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/dynamic_annotations.h +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Copyright 2017 The Abseil Authors. - * - * 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. - */ -/* This file defines dynamic annotations for use with dynamic analysis - tool such as valgrind, PIN, etc. - - Dynamic annotation is a source code annotation that affects - the generated code (that is, the annotation is not a comment). - Each such annotation is attached to a particular - instruction and/or to a particular object (address) in the program. - - The annotations that should be used by users are macros in all upper-case - (e.g., ANNOTATE_THREAD_NAME). - - Actual implementation of these macros may differ depending on the - dynamic analysis tool being used. - - This file supports the following configurations: - - Dynamic Annotations enabled (with static thread-safety warnings disabled). - In this case, macros expand to functions implemented by Thread Sanitizer, - when building with TSan. When not provided an external implementation, - dynamic_annotations.cc provides no-op implementations. - - - Static Clang thread-safety warnings enabled. - When building with a Clang compiler that supports thread-safety warnings, - a subset of annotations can be statically-checked at compile-time. We - expand these macros to static-inline functions that can be analyzed for - thread-safety, but afterwards elided when building the final binary. - - - All annotations are disabled. - If neither Dynamic Annotations nor Clang thread-safety warnings are - enabled, then all annotation-macros expand to empty. */ - -#ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ -#define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ - -#ifndef DYNAMIC_ANNOTATIONS_ENABLED -# define DYNAMIC_ANNOTATIONS_ENABLED 0 -#endif - -#if DYNAMIC_ANNOTATIONS_ENABLED != 0 - - /* ------------------------------------------------------------- - Annotations that suppress errors. It is usually better to express the - program's synchronization using the other annotations, but these can - be used when all else fails. */ - - /* Report that we may have a benign race at "pointer", with size - "sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the - point where "pointer" has been allocated, preferably close to the point - where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC. */ - #define ANNOTATE_BENIGN_RACE(pointer, description) \ - AnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \ - sizeof(*(pointer)), description) - - /* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to - the memory range [address, address+size). */ - #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ - AnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description) - - /* Enable (enable!=0) or disable (enable==0) race detection for all threads. - This annotation could be useful if you want to skip expensive race analysis - during some period of program execution, e.g. during initialization. */ - #define ANNOTATE_ENABLE_RACE_DETECTION(enable) \ - AnnotateEnableRaceDetection(__FILE__, __LINE__, enable) - - /* ------------------------------------------------------------- - Annotations useful for debugging. */ - - /* Report the current thread name to a race detector. */ - #define ANNOTATE_THREAD_NAME(name) \ - AnnotateThreadName(__FILE__, __LINE__, name) - - /* ------------------------------------------------------------- - Annotations useful when implementing locks. They are not - normally needed by modules that merely use locks. - The "lock" argument is a pointer to the lock object. */ - - /* Report that a lock has been created at address "lock". */ - #define ANNOTATE_RWLOCK_CREATE(lock) \ - AnnotateRWLockCreate(__FILE__, __LINE__, lock) - - /* Report that a linker initialized lock has been created at address "lock". - */ -#ifdef THREAD_SANITIZER - #define ANNOTATE_RWLOCK_CREATE_STATIC(lock) \ - AnnotateRWLockCreateStatic(__FILE__, __LINE__, lock) -#else - #define ANNOTATE_RWLOCK_CREATE_STATIC(lock) ANNOTATE_RWLOCK_CREATE(lock) -#endif - - /* Report that the lock at address "lock" is about to be destroyed. */ - #define ANNOTATE_RWLOCK_DESTROY(lock) \ - AnnotateRWLockDestroy(__FILE__, __LINE__, lock) - - /* Report that the lock at address "lock" has been acquired. - is_w=1 for writer lock, is_w=0 for reader lock. */ - #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ - AnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w) - - /* Report that the lock at address "lock" is about to be released. */ - #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ - AnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w) - -#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ - - #define ANNOTATE_RWLOCK_CREATE(lock) /* empty */ - #define ANNOTATE_RWLOCK_CREATE_STATIC(lock) /* empty */ - #define ANNOTATE_RWLOCK_DESTROY(lock) /* empty */ - #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */ - #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */ - #define ANNOTATE_BENIGN_RACE(address, description) /* empty */ - #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */ - #define ANNOTATE_THREAD_NAME(name) /* empty */ - #define ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */ - -#endif /* DYNAMIC_ANNOTATIONS_ENABLED */ - -/* These annotations are also made available to LLVM's Memory Sanitizer */ -#if DYNAMIC_ANNOTATIONS_ENABLED == 1 || defined(MEMORY_SANITIZER) - #define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ - AnnotateMemoryIsInitialized(__FILE__, __LINE__, address, size) - - #define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \ - AnnotateMemoryIsUninitialized(__FILE__, __LINE__, address, size) -#else - #define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */ - #define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */ -#endif /* DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */ -/* TODO(delesley) -- Replace __CLANG_SUPPORT_DYN_ANNOTATION__ with the - appropriate feature ID. */ -#if defined(__clang__) && (!defined(SWIG)) \ - && defined(__CLANG_SUPPORT_DYN_ANNOTATION__) - - #if DYNAMIC_ANNOTATIONS_ENABLED == 0 - #define ANNOTALYSIS_ENABLED - #endif - - /* When running in opt-mode, GCC will issue a warning, if these attributes are - compiled. Only include them when compiling using Clang. */ - #define ATTRIBUTE_IGNORE_READS_BEGIN \ - __attribute((exclusive_lock_function("*"))) - #define ATTRIBUTE_IGNORE_READS_END \ - __attribute((unlock_function("*"))) -#else - #define ATTRIBUTE_IGNORE_READS_BEGIN /* empty */ - #define ATTRIBUTE_IGNORE_READS_END /* empty */ -#endif /* defined(__clang__) && ... */ - -#if (DYNAMIC_ANNOTATIONS_ENABLED != 0) || defined(ANNOTALYSIS_ENABLED) - #define ANNOTATIONS_ENABLED -#endif - -#if (DYNAMIC_ANNOTATIONS_ENABLED != 0) - - /* Request the analysis tool to ignore all reads in the current thread - until ANNOTATE_IGNORE_READS_END is called. - Useful to ignore intentional racey reads, while still checking - other reads and all writes. - See also ANNOTATE_UNPROTECTED_READ. */ - #define ANNOTATE_IGNORE_READS_BEGIN() \ - AnnotateIgnoreReadsBegin(__FILE__, __LINE__) - - /* Stop ignoring reads. */ - #define ANNOTATE_IGNORE_READS_END() \ - AnnotateIgnoreReadsEnd(__FILE__, __LINE__) - - /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. */ - #define ANNOTATE_IGNORE_WRITES_BEGIN() \ - AnnotateIgnoreWritesBegin(__FILE__, __LINE__) - - /* Stop ignoring writes. */ - #define ANNOTATE_IGNORE_WRITES_END() \ - AnnotateIgnoreWritesEnd(__FILE__, __LINE__) - -/* Clang provides limited support for static thread-safety analysis - through a feature called Annotalysis. We configure macro-definitions - according to whether Annotalysis support is available. */ -#elif defined(ANNOTALYSIS_ENABLED) - - #define ANNOTATE_IGNORE_READS_BEGIN() \ - StaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__) - - #define ANNOTATE_IGNORE_READS_END() \ - StaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__) - - #define ANNOTATE_IGNORE_WRITES_BEGIN() \ - StaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__) - - #define ANNOTATE_IGNORE_WRITES_END() \ - StaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__) - -#else - #define ANNOTATE_IGNORE_READS_BEGIN() /* empty */ - #define ANNOTATE_IGNORE_READS_END() /* empty */ - #define ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */ - #define ANNOTATE_IGNORE_WRITES_END() /* empty */ -#endif - -/* Implement the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more - primitive annotations defined above. */ -#if defined(ANNOTATIONS_ENABLED) - - /* Start ignoring all memory accesses (both reads and writes). */ - #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ - do { \ - ANNOTATE_IGNORE_READS_BEGIN(); \ - ANNOTATE_IGNORE_WRITES_BEGIN(); \ - }while (0) - - /* Stop ignoring both reads and writes. */ - #define ANNOTATE_IGNORE_READS_AND_WRITES_END() \ - do { \ - ANNOTATE_IGNORE_WRITES_END(); \ - ANNOTATE_IGNORE_READS_END(); \ - }while (0) - -#else - #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */ - #define ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */ -#endif - -/* Use the macros above rather than using these functions directly. */ -#include -#ifdef __cplusplus -extern "C" { -#endif -void AnnotateRWLockCreate(const char *file, int line, - const volatile void *lock); -void AnnotateRWLockCreateStatic(const char *file, int line, - const volatile void *lock); -void AnnotateRWLockDestroy(const char *file, int line, - const volatile void *lock); -void AnnotateRWLockAcquired(const char *file, int line, - const volatile void *lock, long is_w); /* NOLINT */ -void AnnotateRWLockReleased(const char *file, int line, - const volatile void *lock, long is_w); /* NOLINT */ -void AnnotateBenignRace(const char *file, int line, - const volatile void *address, - const char *description); -void AnnotateBenignRaceSized(const char *file, int line, - const volatile void *address, - size_t size, - const char *description); -void AnnotateThreadName(const char *file, int line, - const char *name); -void AnnotateEnableRaceDetection(const char *file, int line, int enable); -void AnnotateMemoryIsInitialized(const char *file, int line, - const volatile void *mem, size_t size); -void AnnotateMemoryIsUninitialized(const char *file, int line, - const volatile void *mem, size_t size); - -/* Annotations expand to these functions, when Dynamic Annotations are enabled. - These functions are either implemented as no-op calls, if no Sanitizer is - attached, or provided with externally-linked implementations by a library - like ThreadSanitizer. */ -void AnnotateIgnoreReadsBegin(const char *file, int line) - ATTRIBUTE_IGNORE_READS_BEGIN; -void AnnotateIgnoreReadsEnd(const char *file, int line) - ATTRIBUTE_IGNORE_READS_END; -void AnnotateIgnoreWritesBegin(const char *file, int line); -void AnnotateIgnoreWritesEnd(const char *file, int line); - -#if defined(ANNOTALYSIS_ENABLED) -/* When Annotalysis is enabled without Dynamic Annotations, the use of - static-inline functions allows the annotations to be read at compile-time, - while still letting the compiler elide the functions from the final build. - - TODO(delesley) -- The exclusive lock here ignores writes as well, but - allows IGNORE_READS_AND_WRITES to work properly. */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -static inline void StaticAnnotateIgnoreReadsBegin(const char *file, int line) - ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; } -static inline void StaticAnnotateIgnoreReadsEnd(const char *file, int line) - ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; } -static inline void StaticAnnotateIgnoreWritesBegin( - const char *file, int line) { (void)file; (void)line; } -static inline void StaticAnnotateIgnoreWritesEnd( - const char *file, int line) { (void)file; (void)line; } -#pragma GCC diagnostic pop -#endif - -/* Return non-zero value if running under valgrind. - - If "valgrind.h" is included into dynamic_annotations.cc, - the regular valgrind mechanism will be used. - See http://valgrind.org/docs/manual/manual-core-adv.html about - RUNNING_ON_VALGRIND and other valgrind "client requests". - The file "valgrind.h" may be obtained by doing - svn co svn://svn.valgrind.org/valgrind/trunk/include - - If for some reason you can't use "valgrind.h" or want to fake valgrind, - there are two ways to make this function return non-zero: - - Use environment variable: export RUNNING_ON_VALGRIND=1 - - Make your tool intercept the function RunningOnValgrind() and - change its return value. - */ -int RunningOnValgrind(void); - -/* ValgrindSlowdown returns: - * 1.0, if (RunningOnValgrind() == 0) - * 50.0, if (RunningOnValgrind() != 0 && getenv("VALGRIND_SLOWDOWN") == NULL) - * atof(getenv("VALGRIND_SLOWDOWN")) otherwise - This function can be used to scale timeout values: - EXAMPLE: - for (;;) { - DoExpensiveBackgroundTask(); - SleepForSeconds(5 * ValgrindSlowdown()); - } - */ -double ValgrindSlowdown(void); - -#ifdef __cplusplus -} -#endif - -/* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. - - Instead of doing - ANNOTATE_IGNORE_READS_BEGIN(); - ... = x; - ANNOTATE_IGNORE_READS_END(); - one can use - ... = ANNOTATE_UNPROTECTED_READ(x); */ -#if defined(__cplusplus) && defined(ANNOTATIONS_ENABLED) -template -inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) { /* NOLINT */ - ANNOTATE_IGNORE_READS_BEGIN(); - T res = x; - ANNOTATE_IGNORE_READS_END(); - return res; - } -#else - #define ANNOTATE_UNPROTECTED_READ(x) (x) -#endif - -#if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus) - /* Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable. */ - #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ - namespace { \ - class static_var ## _annotator { \ - public: \ - static_var ## _annotator() { \ - ANNOTATE_BENIGN_RACE_SIZED(&static_var, \ - sizeof(static_var), \ - # static_var ": " description); \ - } \ - }; \ - static static_var ## _annotator the ## static_var ## _annotator;\ - } // namespace -#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ - #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */ -#endif /* DYNAMIC_ANNOTATIONS_ENABLED */ - -#ifdef ADDRESS_SANITIZER -/* Describe the current state of a contiguous container such as e.g. - * std::vector or std::string. For more details see - * sanitizer/common_interface_defs.h, which is provided by the compiler. */ -#include -#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \ - __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid) -#define ADDRESS_SANITIZER_REDZONE(name) \ - struct { char x[8] __attribute__ ((aligned (8))); } name -#else -#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) -#define ADDRESS_SANITIZER_REDZONE(name) -#endif // ADDRESS_SANITIZER - -/* Undefine the macros intended only in this file. */ -#undef ANNOTALYSIS_ENABLED -#undef ANNOTATIONS_ENABLED -#undef ATTRIBUTE_IGNORE_READS_BEGIN -#undef ATTRIBUTE_IGNORE_READS_END - -#endif /* ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ */ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc deleted file mode 100644 index 7518264..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc +++ /dev/null @@ -1,954 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/base/internal/exception_safety_testing.h" - -#include -#include -#include -#include -#include -#include - -#include "gtest/gtest-spi.h" -#include "gtest/gtest.h" -#include "absl/memory/memory.h" - -namespace testing { - -namespace { - -using ::testing::exceptions_internal::SetCountdown; -using ::testing::exceptions_internal::TestException; -using ::testing::exceptions_internal::UnsetCountdown; - -// EXPECT_NO_THROW can't inspect the thrown inspection in general. -template -void ExpectNoThrow(const F& f) { - try { - f(); - } catch (const TestException& e) { - ADD_FAILURE() << "Unexpected exception thrown from " << e.what(); - } -} - -TEST(ThrowingValueTest, Throws) { - SetCountdown(); - EXPECT_THROW(ThrowingValue<> bomb, TestException); - - // It's not guaranteed that every operator only throws *once*. The default - // ctor only throws once, though, so use it to make sure we only throw when - // the countdown hits 0 - SetCountdown(2); - ExpectNoThrow([]() { ThrowingValue<> bomb; }); - ExpectNoThrow([]() { ThrowingValue<> bomb; }); - EXPECT_THROW(ThrowingValue<> bomb, TestException); - - UnsetCountdown(); -} - -// Tests that an operation throws when the countdown is at 0, doesn't throw when -// the countdown doesn't hit 0, and doesn't modify the state of the -// ThrowingValue if it throws -template -void TestOp(const F& f) { - ExpectNoThrow(f); - - SetCountdown(); - EXPECT_THROW(f(), TestException); - UnsetCountdown(); -} - -TEST(ThrowingValueTest, ThrowingCtors) { - ThrowingValue<> bomb; - - TestOp([]() { ThrowingValue<> bomb(1); }); - TestOp([&]() { ThrowingValue<> bomb1 = bomb; }); - TestOp([&]() { ThrowingValue<> bomb1 = std::move(bomb); }); -} - -TEST(ThrowingValueTest, ThrowingAssignment) { - ThrowingValue<> bomb, bomb1; - - TestOp([&]() { bomb = bomb1; }); - TestOp([&]() { bomb = std::move(bomb1); }); - - // Test that when assignment throws, the assignment should fail (lhs != rhs) - // and strong guarantee fails (lhs != lhs_copy). - { - ThrowingValue<> lhs(39), rhs(42); - ThrowingValue<> lhs_copy(lhs); - SetCountdown(); - EXPECT_THROW(lhs = rhs, TestException); - UnsetCountdown(); - EXPECT_NE(lhs, rhs); - EXPECT_NE(lhs_copy, lhs); - } - { - ThrowingValue<> lhs(39), rhs(42); - ThrowingValue<> lhs_copy(lhs), rhs_copy(rhs); - SetCountdown(); - EXPECT_THROW(lhs = std::move(rhs), TestException); - UnsetCountdown(); - EXPECT_NE(lhs, rhs_copy); - EXPECT_NE(lhs_copy, lhs); - } -} - -TEST(ThrowingValueTest, ThrowingComparisons) { - ThrowingValue<> bomb1, bomb2; - TestOp([&]() { return bomb1 == bomb2; }); - TestOp([&]() { return bomb1 != bomb2; }); - TestOp([&]() { return bomb1 < bomb2; }); - TestOp([&]() { return bomb1 <= bomb2; }); - TestOp([&]() { return bomb1 > bomb2; }); - TestOp([&]() { return bomb1 >= bomb2; }); -} - -TEST(ThrowingValueTest, ThrowingArithmeticOps) { - ThrowingValue<> bomb1(1), bomb2(2); - - TestOp([&bomb1]() { +bomb1; }); - TestOp([&bomb1]() { -bomb1; }); - TestOp([&bomb1]() { ++bomb1; }); - TestOp([&bomb1]() { bomb1++; }); - TestOp([&bomb1]() { --bomb1; }); - TestOp([&bomb1]() { bomb1--; }); - - TestOp([&]() { bomb1 + bomb2; }); - TestOp([&]() { bomb1 - bomb2; }); - TestOp([&]() { bomb1* bomb2; }); - TestOp([&]() { bomb1 / bomb2; }); - TestOp([&]() { bomb1 << 1; }); - TestOp([&]() { bomb1 >> 1; }); -} - -TEST(ThrowingValueTest, ThrowingLogicalOps) { - ThrowingValue<> bomb1, bomb2; - - TestOp([&bomb1]() { !bomb1; }); - TestOp([&]() { bomb1&& bomb2; }); - TestOp([&]() { bomb1 || bomb2; }); -} - -TEST(ThrowingValueTest, ThrowingBitwiseOps) { - ThrowingValue<> bomb1, bomb2; - - TestOp([&bomb1]() { ~bomb1; }); - TestOp([&]() { bomb1& bomb2; }); - TestOp([&]() { bomb1 | bomb2; }); - TestOp([&]() { bomb1 ^ bomb2; }); -} - -TEST(ThrowingValueTest, ThrowingCompoundAssignmentOps) { - ThrowingValue<> bomb1(1), bomb2(2); - - TestOp([&]() { bomb1 += bomb2; }); - TestOp([&]() { bomb1 -= bomb2; }); - TestOp([&]() { bomb1 *= bomb2; }); - TestOp([&]() { bomb1 /= bomb2; }); - TestOp([&]() { bomb1 %= bomb2; }); - TestOp([&]() { bomb1 &= bomb2; }); - TestOp([&]() { bomb1 |= bomb2; }); - TestOp([&]() { bomb1 ^= bomb2; }); - TestOp([&]() { bomb1 *= bomb2; }); -} - -TEST(ThrowingValueTest, ThrowingStreamOps) { - ThrowingValue<> bomb; - - TestOp([&]() { - std::istringstream stream; - stream >> bomb; - }); - TestOp([&]() { - std::stringstream stream; - stream << bomb; - }); -} - -// Tests the operator<< of ThrowingValue by forcing ConstructorTracker to emit -// a nonfatal failure that contains the string representation of the Thrower -TEST(ThrowingValueTest, StreamOpsOutput) { - using ::testing::TypeSpec; - exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); - - // Test default spec list (kEverythingThrows) - EXPECT_NONFATAL_FAILURE( - { - using Thrower = ThrowingValue; - auto thrower = Thrower(123); - thrower.~Thrower(); - }, - "ThrowingValue<>(123)"); - - // Test with one item in spec list (kNoThrowCopy) - EXPECT_NONFATAL_FAILURE( - { - using Thrower = ThrowingValue; - auto thrower = Thrower(234); - thrower.~Thrower(); - }, - "ThrowingValue(234)"); - - // Test with multiple items in spec list (kNoThrowMove, kNoThrowNew) - EXPECT_NONFATAL_FAILURE( - { - using Thrower = - ThrowingValue; - auto thrower = Thrower(345); - thrower.~Thrower(); - }, - "ThrowingValue(345)"); - - // Test with all items in spec list (kNoThrowCopy, kNoThrowMove, kNoThrowNew) - EXPECT_NONFATAL_FAILURE( - { - using Thrower = ThrowingValue(-1)>; - auto thrower = Thrower(456); - thrower.~Thrower(); - }, - "ThrowingValue(456)"); -} - -template -void TestAllocatingOp(const F& f) { - ExpectNoThrow(f); - - SetCountdown(); - EXPECT_THROW(f(), exceptions_internal::TestBadAllocException); - UnsetCountdown(); -} - -TEST(ThrowingValueTest, ThrowingAllocatingOps) { - // make_unique calls unqualified operator new, so these exercise the - // ThrowingValue overloads. - TestAllocatingOp([]() { return absl::make_unique>(1); }); - TestAllocatingOp([]() { return absl::make_unique[]>(2); }); -} - -TEST(ThrowingValueTest, NonThrowingMoveCtor) { - ThrowingValue nothrow_ctor; - - SetCountdown(); - ExpectNoThrow([¬hrow_ctor]() { - ThrowingValue nothrow1 = std::move(nothrow_ctor); - }); - UnsetCountdown(); -} - -TEST(ThrowingValueTest, NonThrowingMoveAssign) { - ThrowingValue nothrow_assign1, nothrow_assign2; - - SetCountdown(); - ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() { - nothrow_assign1 = std::move(nothrow_assign2); - }); - UnsetCountdown(); -} - -TEST(ThrowingValueTest, ThrowingCopyCtor) { - ThrowingValue<> tv; - - TestOp([&]() { ThrowingValue<> tv_copy(tv); }); -} - -TEST(ThrowingValueTest, ThrowingCopyAssign) { - ThrowingValue<> tv1, tv2; - - TestOp([&]() { tv1 = tv2; }); -} - -TEST(ThrowingValueTest, NonThrowingCopyCtor) { - ThrowingValue nothrow_ctor; - - SetCountdown(); - ExpectNoThrow([¬hrow_ctor]() { - ThrowingValue nothrow1(nothrow_ctor); - }); - UnsetCountdown(); -} - -TEST(ThrowingValueTest, NonThrowingCopyAssign) { - ThrowingValue nothrow_assign1, nothrow_assign2; - - SetCountdown(); - ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() { - nothrow_assign1 = nothrow_assign2; - }); - UnsetCountdown(); -} - -TEST(ThrowingValueTest, ThrowingSwap) { - ThrowingValue<> bomb1, bomb2; - TestOp([&]() { std::swap(bomb1, bomb2); }); -} - -TEST(ThrowingValueTest, NonThrowingSwap) { - ThrowingValue bomb1, bomb2; - ExpectNoThrow([&]() { std::swap(bomb1, bomb2); }); -} - -TEST(ThrowingValueTest, NonThrowingAllocation) { - ThrowingValue* allocated; - ThrowingValue* array; - - ExpectNoThrow([&allocated]() { - allocated = new ThrowingValue(1); - delete allocated; - }); - ExpectNoThrow([&array]() { - array = new ThrowingValue[2]; - delete[] array; - }); -} - -TEST(ThrowingValueTest, NonThrowingDelete) { - auto* allocated = new ThrowingValue<>(1); - auto* array = new ThrowingValue<>[2]; - - SetCountdown(); - ExpectNoThrow([allocated]() { delete allocated; }); - SetCountdown(); - ExpectNoThrow([array]() { delete[] array; }); - - UnsetCountdown(); -} - -using Storage = - absl::aligned_storage_t), alignof(ThrowingValue<>)>; - -TEST(ThrowingValueTest, NonThrowingPlacementDelete) { - constexpr int kArrayLen = 2; - // We intentionally create extra space to store the tag allocated by placement - // new[]. - constexpr int kStorageLen = 4; - - Storage buf; - Storage array_buf[kStorageLen]; - auto* placed = new (&buf) ThrowingValue<>(1); - auto placed_array = new (&array_buf) ThrowingValue<>[kArrayLen]; - - SetCountdown(); - ExpectNoThrow([placed, &buf]() { - placed->~ThrowingValue<>(); - ThrowingValue<>::operator delete(placed, &buf); - }); - - SetCountdown(); - ExpectNoThrow([&, placed_array]() { - for (int i = 0; i < kArrayLen; ++i) placed_array[i].~ThrowingValue<>(); - ThrowingValue<>::operator delete[](placed_array, &array_buf); - }); - - UnsetCountdown(); -} - -TEST(ThrowingValueTest, NonThrowingDestructor) { - auto* allocated = new ThrowingValue<>(); - - SetCountdown(); - ExpectNoThrow([allocated]() { delete allocated; }); - UnsetCountdown(); -} - -TEST(ThrowingBoolTest, ThrowingBool) { - ThrowingBool t = true; - - // Test that it's contextually convertible to bool - if (t) { // NOLINT(whitespace/empty_if_body) - } - EXPECT_TRUE(t); - - TestOp([&]() { (void)!t; }); -} - -TEST(ThrowingAllocatorTest, MemoryManagement) { - // Just exercise the memory management capabilities under LSan to make sure we - // don't leak. - ThrowingAllocator int_alloc; - int* ip = int_alloc.allocate(1); - int_alloc.deallocate(ip, 1); - int* i_array = int_alloc.allocate(2); - int_alloc.deallocate(i_array, 2); - - ThrowingAllocator> tv_alloc; - ThrowingValue<>* ptr = tv_alloc.allocate(1); - tv_alloc.deallocate(ptr, 1); - ThrowingValue<>* tv_array = tv_alloc.allocate(2); - tv_alloc.deallocate(tv_array, 2); -} - -TEST(ThrowingAllocatorTest, CallsGlobalNew) { - ThrowingAllocator, AllocSpec::kNoThrowAllocate> nothrow_alloc; - ThrowingValue<>* ptr; - - SetCountdown(); - // This will only throw if ThrowingValue::new is called. - ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); }); - nothrow_alloc.deallocate(ptr, 1); - - UnsetCountdown(); -} - -TEST(ThrowingAllocatorTest, ThrowingConstructors) { - ThrowingAllocator int_alloc; - int* ip = nullptr; - - SetCountdown(); - EXPECT_THROW(ip = int_alloc.allocate(1), TestException); - ExpectNoThrow([&]() { ip = int_alloc.allocate(1); }); - - *ip = 1; - SetCountdown(); - EXPECT_THROW(int_alloc.construct(ip, 2), TestException); - EXPECT_EQ(*ip, 1); - int_alloc.deallocate(ip, 1); - - UnsetCountdown(); -} - -TEST(ThrowingAllocatorTest, NonThrowingConstruction) { - { - ThrowingAllocator int_alloc; - int* ip = nullptr; - - SetCountdown(); - ExpectNoThrow([&]() { ip = int_alloc.allocate(1); }); - - SetCountdown(); - ExpectNoThrow([&]() { int_alloc.construct(ip, 2); }); - - EXPECT_EQ(*ip, 2); - int_alloc.deallocate(ip, 1); - - UnsetCountdown(); - } - - { - ThrowingAllocator int_alloc; - int* ip = nullptr; - ExpectNoThrow([&]() { ip = int_alloc.allocate(1); }); - ExpectNoThrow([&]() { int_alloc.construct(ip, 2); }); - EXPECT_EQ(*ip, 2); - int_alloc.deallocate(ip, 1); - } - - { - ThrowingAllocator, AllocSpec::kNoThrowAllocate> - nothrow_alloc; - ThrowingValue<>* ptr; - - SetCountdown(); - ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); }); - - SetCountdown(); - ExpectNoThrow( - [&]() { nothrow_alloc.construct(ptr, 2, testing::nothrow_ctor); }); - - EXPECT_EQ(ptr->Get(), 2); - nothrow_alloc.destroy(ptr); - nothrow_alloc.deallocate(ptr, 1); - - UnsetCountdown(); - } - - { - ThrowingAllocator a; - - SetCountdown(); - ExpectNoThrow([&]() { ThrowingAllocator a1 = a; }); - - SetCountdown(); - ExpectNoThrow([&]() { ThrowingAllocator a1 = std::move(a); }); - - UnsetCountdown(); - } -} - -TEST(ThrowingAllocatorTest, ThrowingAllocatorConstruction) { - ThrowingAllocator a; - TestOp([]() { ThrowingAllocator a; }); - TestOp([&]() { a.select_on_container_copy_construction(); }); -} - -TEST(ThrowingAllocatorTest, State) { - ThrowingAllocator a1, a2; - EXPECT_NE(a1, a2); - - auto a3 = a1; - EXPECT_EQ(a3, a1); - int* ip = a1.allocate(1); - EXPECT_EQ(a3, a1); - a3.deallocate(ip, 1); - EXPECT_EQ(a3, a1); -} - -TEST(ThrowingAllocatorTest, InVector) { - std::vector, ThrowingAllocator>> v; - for (int i = 0; i < 20; ++i) v.push_back({}); - for (int i = 0; i < 20; ++i) v.pop_back(); -} - -TEST(ThrowingAllocatorTest, InList) { - std::list, ThrowingAllocator>> l; - for (int i = 0; i < 20; ++i) l.push_back({}); - for (int i = 0; i < 20; ++i) l.pop_back(); - for (int i = 0; i < 20; ++i) l.push_front({}); - for (int i = 0; i < 20; ++i) l.pop_front(); -} - -template -struct NullaryTestValidator : public std::false_type {}; - -template -struct NullaryTestValidator< - TesterInstance, - absl::void_t().Test())>> - : public std::true_type {}; - -template -bool HasNullaryTest(const TesterInstance&) { - return NullaryTestValidator::value; -} - -void DummyOp(void*) {} - -template -struct UnaryTestValidator : public std::false_type {}; - -template -struct UnaryTestValidator< - TesterInstance, - absl::void_t().Test(DummyOp))>> - : public std::true_type {}; - -template -bool HasUnaryTest(const TesterInstance&) { - return UnaryTestValidator::value; -} - -TEST(ExceptionSafetyTesterTest, IncompleteTypesAreNotTestable) { - using T = exceptions_internal::UninitializedT; - auto op = [](T* t) {}; - auto inv = [](T*) { return testing::AssertionSuccess(); }; - auto fac = []() { return absl::make_unique(); }; - - // Test that providing operation and inveriants still does not allow for the - // the invocation of .Test() and .Test(op) because it lacks a factory - auto without_fac = - testing::MakeExceptionSafetyTester().WithOperation(op).WithContracts( - inv, testing::strong_guarantee); - EXPECT_FALSE(HasNullaryTest(without_fac)); - EXPECT_FALSE(HasUnaryTest(without_fac)); - - // Test that providing contracts and factory allows the invocation of - // .Test(op) but does not allow for .Test() because it lacks an operation - auto without_op = testing::MakeExceptionSafetyTester() - .WithContracts(inv, testing::strong_guarantee) - .WithFactory(fac); - EXPECT_FALSE(HasNullaryTest(without_op)); - EXPECT_TRUE(HasUnaryTest(without_op)); - - // Test that providing operation and factory still does not allow for the - // the invocation of .Test() and .Test(op) because it lacks contracts - auto without_inv = - testing::MakeExceptionSafetyTester().WithOperation(op).WithFactory(fac); - EXPECT_FALSE(HasNullaryTest(without_inv)); - EXPECT_FALSE(HasUnaryTest(without_inv)); -} - -struct ExampleStruct {}; - -std::unique_ptr ExampleFunctionFactory() { - return absl::make_unique(); -} - -void ExampleFunctionOperation(ExampleStruct*) {} - -testing::AssertionResult ExampleFunctionContract(ExampleStruct*) { - return testing::AssertionSuccess(); -} - -struct { - std::unique_ptr operator()() const { - return ExampleFunctionFactory(); - } -} example_struct_factory; - -struct { - void operator()(ExampleStruct*) const {} -} example_struct_operation; - -struct { - testing::AssertionResult operator()(ExampleStruct* example_struct) const { - return ExampleFunctionContract(example_struct); - } -} example_struct_contract; - -auto example_lambda_factory = []() { return ExampleFunctionFactory(); }; - -auto example_lambda_operation = [](ExampleStruct*) {}; - -auto example_lambda_contract = [](ExampleStruct* example_struct) { - return ExampleFunctionContract(example_struct); -}; - -// Testing that function references, pointers, structs with operator() and -// lambdas can all be used with ExceptionSafetyTester -TEST(ExceptionSafetyTesterTest, MixedFunctionTypes) { - // function reference - EXPECT_TRUE(testing::MakeExceptionSafetyTester() - .WithFactory(ExampleFunctionFactory) - .WithOperation(ExampleFunctionOperation) - .WithContracts(ExampleFunctionContract) - .Test()); - - // function pointer - EXPECT_TRUE(testing::MakeExceptionSafetyTester() - .WithFactory(&ExampleFunctionFactory) - .WithOperation(&ExampleFunctionOperation) - .WithContracts(&ExampleFunctionContract) - .Test()); - - // struct - EXPECT_TRUE(testing::MakeExceptionSafetyTester() - .WithFactory(example_struct_factory) - .WithOperation(example_struct_operation) - .WithContracts(example_struct_contract) - .Test()); - - // lambda - EXPECT_TRUE(testing::MakeExceptionSafetyTester() - .WithFactory(example_lambda_factory) - .WithOperation(example_lambda_operation) - .WithContracts(example_lambda_contract) - .Test()); -} - -struct NonNegative { - bool operator==(const NonNegative& other) const { return i == other.i; } - int i; -}; - -testing::AssertionResult CheckNonNegativeInvariants(NonNegative* g) { - if (g->i >= 0) { - return testing::AssertionSuccess(); - } - return testing::AssertionFailure() - << "i should be non-negative but is " << g->i; -} - -struct { - template - void operator()(T* t) const { - (*t)(); - } -} invoker; - -auto tester = - testing::MakeExceptionSafetyTester().WithOperation(invoker).WithContracts( - CheckNonNegativeInvariants); -auto strong_tester = tester.WithContracts(testing::strong_guarantee); - -struct FailsBasicGuarantee : public NonNegative { - void operator()() { - --i; - ThrowingValue<> bomb; - ++i; - } -}; - -TEST(ExceptionCheckTest, BasicGuaranteeFailure) { - EXPECT_FALSE(tester.WithInitialValue(FailsBasicGuarantee{}).Test()); -} - -struct FollowsBasicGuarantee : public NonNegative { - void operator()() { - ++i; - ThrowingValue<> bomb; - } -}; - -TEST(ExceptionCheckTest, BasicGuarantee) { - EXPECT_TRUE(tester.WithInitialValue(FollowsBasicGuarantee{}).Test()); -} - -TEST(ExceptionCheckTest, StrongGuaranteeFailure) { - EXPECT_FALSE(strong_tester.WithInitialValue(FailsBasicGuarantee{}).Test()); - EXPECT_FALSE(strong_tester.WithInitialValue(FollowsBasicGuarantee{}).Test()); -} - -struct BasicGuaranteeWithExtraContracts : public NonNegative { - // After operator(), i is incremented. If operator() throws, i is set to 9999 - void operator()() { - int old_i = i; - i = kExceptionSentinel; - ThrowingValue<> bomb; - i = ++old_i; - } - - static constexpr int kExceptionSentinel = 9999; -}; -constexpr int BasicGuaranteeWithExtraContracts::kExceptionSentinel; - -TEST(ExceptionCheckTest, BasicGuaranteeWithExtraContracts) { - auto tester_with_val = - tester.WithInitialValue(BasicGuaranteeWithExtraContracts{}); - EXPECT_TRUE(tester_with_val.Test()); - EXPECT_TRUE( - tester_with_val - .WithContracts([](BasicGuaranteeWithExtraContracts* o) { - if (o->i == BasicGuaranteeWithExtraContracts::kExceptionSentinel) { - return testing::AssertionSuccess(); - } - return testing::AssertionFailure() - << "i should be " - << BasicGuaranteeWithExtraContracts::kExceptionSentinel - << ", but is " << o->i; - }) - .Test()); -} - -struct FollowsStrongGuarantee : public NonNegative { - void operator()() { ThrowingValue<> bomb; } -}; - -TEST(ExceptionCheckTest, StrongGuarantee) { - EXPECT_TRUE(tester.WithInitialValue(FollowsStrongGuarantee{}).Test()); - EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{}).Test()); -} - -struct HasReset : public NonNegative { - void operator()() { - i = -1; - ThrowingValue<> bomb; - i = 1; - } - - void reset() { i = 0; } -}; - -testing::AssertionResult CheckHasResetContracts(HasReset* h) { - h->reset(); - return testing::AssertionResult(h->i == 0); -} - -TEST(ExceptionCheckTest, ModifyingChecker) { - auto set_to_1000 = [](FollowsBasicGuarantee* g) { - g->i = 1000; - return testing::AssertionSuccess(); - }; - auto is_1000 = [](FollowsBasicGuarantee* g) { - return testing::AssertionResult(g->i == 1000); - }; - auto increment = [](FollowsStrongGuarantee* g) { - ++g->i; - return testing::AssertionSuccess(); - }; - - EXPECT_FALSE(tester.WithInitialValue(FollowsBasicGuarantee{}) - .WithContracts(set_to_1000, is_1000) - .Test()); - EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{}) - .WithContracts(increment) - .Test()); - EXPECT_TRUE(testing::MakeExceptionSafetyTester() - .WithInitialValue(HasReset{}) - .WithContracts(CheckHasResetContracts) - .Test(invoker)); -} - -TEST(ExceptionSafetyTesterTest, ResetsCountdown) { - auto test = - testing::MakeExceptionSafetyTester() - .WithInitialValue(ThrowingValue<>()) - .WithContracts([](ThrowingValue<>*) { return AssertionSuccess(); }) - .WithOperation([](ThrowingValue<>*) {}); - ASSERT_TRUE(test.Test()); - // If the countdown isn't reset because there were no exceptions thrown, then - // this will fail with a termination from an unhandled exception - EXPECT_TRUE(test.Test()); -} - -struct NonCopyable : public NonNegative { - NonCopyable(const NonCopyable&) = delete; - NonCopyable() : NonNegative{0} {} - - void operator()() { ThrowingValue<> bomb; } -}; - -TEST(ExceptionCheckTest, NonCopyable) { - auto factory = []() { return absl::make_unique(); }; - EXPECT_TRUE(tester.WithFactory(factory).Test()); - EXPECT_TRUE(strong_tester.WithFactory(factory).Test()); -} - -struct NonEqualityComparable : public NonNegative { - void operator()() { ThrowingValue<> bomb; } - - void ModifyOnThrow() { - ++i; - ThrowingValue<> bomb; - static_cast(bomb); - --i; - } -}; - -TEST(ExceptionCheckTest, NonEqualityComparable) { - auto nec_is_strong = [](NonEqualityComparable* nec) { - return testing::AssertionResult(nec->i == NonEqualityComparable().i); - }; - auto strong_nec_tester = tester.WithInitialValue(NonEqualityComparable{}) - .WithContracts(nec_is_strong); - - EXPECT_TRUE(strong_nec_tester.Test()); - EXPECT_FALSE(strong_nec_tester.Test( - [](NonEqualityComparable* n) { n->ModifyOnThrow(); })); -} - -template -struct ExhaustivenessTester { - void operator()() { - successes |= 1; - T b1; - static_cast(b1); - successes |= (1 << 1); - T b2; - static_cast(b2); - successes |= (1 << 2); - T b3; - static_cast(b3); - successes |= (1 << 3); - } - - bool operator==(const ExhaustivenessTester>&) const { - return true; - } - - static unsigned char successes; -}; - -struct { - template - testing::AssertionResult operator()(ExhaustivenessTester*) const { - return testing::AssertionSuccess(); - } -} CheckExhaustivenessTesterContracts; - -template -unsigned char ExhaustivenessTester::successes = 0; - -TEST(ExceptionCheckTest, Exhaustiveness) { - auto exhaust_tester = testing::MakeExceptionSafetyTester() - .WithContracts(CheckExhaustivenessTesterContracts) - .WithOperation(invoker); - - EXPECT_TRUE( - exhaust_tester.WithInitialValue(ExhaustivenessTester{}).Test()); - EXPECT_EQ(ExhaustivenessTester::successes, 0xF); - - EXPECT_TRUE( - exhaust_tester.WithInitialValue(ExhaustivenessTester>{}) - .WithContracts(testing::strong_guarantee) - .Test()); - EXPECT_EQ(ExhaustivenessTester>::successes, 0xF); -} - -struct LeaksIfCtorThrows : private exceptions_internal::TrackedObject { - LeaksIfCtorThrows() : TrackedObject(ABSL_PRETTY_FUNCTION) { - ++counter; - ThrowingValue<> v; - static_cast(v); - --counter; - } - LeaksIfCtorThrows(const LeaksIfCtorThrows&) noexcept - : TrackedObject(ABSL_PRETTY_FUNCTION) {} - static int counter; -}; -int LeaksIfCtorThrows::counter = 0; - -TEST(ExceptionCheckTest, TestLeakyCtor) { - testing::TestThrowingCtor(); - EXPECT_EQ(LeaksIfCtorThrows::counter, 1); - LeaksIfCtorThrows::counter = 0; -} - -struct Tracked : private exceptions_internal::TrackedObject { - Tracked() : TrackedObject(ABSL_PRETTY_FUNCTION) {} -}; - -TEST(ConstructorTrackerTest, CreatedBefore) { - Tracked a, b, c; - exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); -} - -TEST(ConstructorTrackerTest, CreatedAfter) { - exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); - Tracked a, b, c; -} - -TEST(ConstructorTrackerTest, NotDestroyedAfter) { - absl::aligned_storage_t storage; - EXPECT_NONFATAL_FAILURE( - { - exceptions_internal::ConstructorTracker ct( - exceptions_internal::countdown); - new (&storage) Tracked; - }, - "not destroyed"); -} - -TEST(ConstructorTrackerTest, DestroyedTwice) { - exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); - EXPECT_NONFATAL_FAILURE( - { - Tracked t; - t.~Tracked(); - }, - "re-destroyed"); -} - -TEST(ConstructorTrackerTest, ConstructedTwice) { - exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); - absl::aligned_storage_t storage; - EXPECT_NONFATAL_FAILURE( - { - new (&storage) Tracked; - new (&storage) Tracked; - reinterpret_cast(&storage)->~Tracked(); - }, - "re-constructed"); -} - -TEST(ThrowingValueTraitsTest, RelationalOperators) { - ThrowingValue<> a, b; - EXPECT_TRUE((std::is_convertible::value)); - EXPECT_TRUE((std::is_convertible::value)); - EXPECT_TRUE((std::is_convertible::value)); - EXPECT_TRUE((std::is_convertible::value)); - EXPECT_TRUE((std::is_convertible b), bool>::value)); - EXPECT_TRUE((std::is_convertible= b), bool>::value)); -} - -TEST(ThrowingAllocatorTraitsTest, Assignablility) { - EXPECT_TRUE(absl::is_move_assignable>::value); - EXPECT_TRUE(absl::is_copy_assignable>::value); - EXPECT_TRUE(std::is_nothrow_move_assignable>::value); - EXPECT_TRUE(std::is_nothrow_copy_assignable>::value); -} - -} // namespace - -} // namespace testing diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/inline_variable_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/inline_variable_test.cc deleted file mode 100644 index 5499189..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/inline_variable_test.cc +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include - -#include "absl/base/internal/inline_variable.h" -#include "absl/base/internal/inline_variable_testing.h" - -#include "gtest/gtest.h" - -namespace absl { -namespace inline_variable_testing_internal { -namespace { - -TEST(InlineVariableTest, Constexpr) { - static_assert(inline_variable_foo.value == 5, ""); - static_assert(other_inline_variable_foo.value == 5, ""); - static_assert(inline_variable_int == 5, ""); - static_assert(other_inline_variable_int == 5, ""); -} - -TEST(InlineVariableTest, DefaultConstructedIdentityEquality) { - EXPECT_EQ(get_foo_a().value, 5); - EXPECT_EQ(get_foo_b().value, 5); - EXPECT_EQ(&get_foo_a(), &get_foo_b()); -} - -TEST(InlineVariableTest, DefaultConstructedIdentityInequality) { - EXPECT_NE(&inline_variable_foo, &other_inline_variable_foo); -} - -TEST(InlineVariableTest, InitializedIdentityEquality) { - EXPECT_EQ(get_int_a(), 5); - EXPECT_EQ(get_int_b(), 5); - EXPECT_EQ(&get_int_a(), &get_int_b()); -} - -TEST(InlineVariableTest, InitializedIdentityInequality) { - EXPECT_NE(&inline_variable_int, &other_inline_variable_int); -} - -TEST(InlineVariableTest, FunPtrType) { - static_assert( - std::is_same::type>::value, - ""); -} - -} // namespace -} // namespace inline_variable_testing_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/inline_variable_test_a.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/inline_variable_test_a.cc deleted file mode 100644 index a3bf3b6..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/inline_variable_test_a.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/base/internal/inline_variable_testing.h" - -namespace absl { -namespace inline_variable_testing_internal { - -const Foo& get_foo_a() { return inline_variable_foo; } - -const int& get_int_a() { return inline_variable_int; } - -} // namespace inline_variable_testing_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/inline_variable_test_b.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/inline_variable_test_b.cc deleted file mode 100644 index b4b9393..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/inline_variable_test_b.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/base/internal/inline_variable_testing.h" - -namespace absl { -namespace inline_variable_testing_internal { - -const Foo& get_foo_b() { return inline_variable_foo; } - -const int& get_int_b() { return inline_variable_int; } - -} // namespace inline_variable_testing_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/atomic_hook_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/atomic_hook_test.cc deleted file mode 100644 index cf74075..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/atomic_hook_test.cc +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include "absl/base/internal/atomic_hook.h" - -#include "gtest/gtest.h" -#include "absl/base/attributes.h" - -namespace { - -int value = 0; -void TestHook(int x) { value = x; } - -TEST(AtomicHookTest, NoDefaultFunction) { - ABSL_CONST_INIT static absl::base_internal::AtomicHook hook; - value = 0; - - // Test the default DummyFunction. - EXPECT_TRUE(hook.Load() == nullptr); - EXPECT_EQ(value, 0); - hook(1); - EXPECT_EQ(value, 0); - - // Test a stored hook. - hook.Store(TestHook); - EXPECT_TRUE(hook.Load() == TestHook); - EXPECT_EQ(value, 0); - hook(1); - EXPECT_EQ(value, 1); - - // Calling Store() with the same hook should not crash. - hook.Store(TestHook); - EXPECT_TRUE(hook.Load() == TestHook); - EXPECT_EQ(value, 1); - hook(2); - EXPECT_EQ(value, 2); -} - -TEST(AtomicHookTest, WithDefaultFunction) { - // Set the default value to TestHook at compile-time. - ABSL_CONST_INIT static absl::base_internal::AtomicHook hook( - TestHook); - value = 0; - - // Test the default value is TestHook. - EXPECT_TRUE(hook.Load() == TestHook); - EXPECT_EQ(value, 0); - hook(1); - EXPECT_EQ(value, 1); - - // Calling Store() with the same hook should not crash. - hook.Store(TestHook); - EXPECT_TRUE(hook.Load() == TestHook); - EXPECT_EQ(value, 1); - hook(2); - EXPECT_EQ(value, 2); -} - -} // namespace diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/bits_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/bits_test.cc deleted file mode 100644 index e5d991d..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/bits_test.cc +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include "absl/base/internal/bits.h" - -#include "gtest/gtest.h" - -namespace { - -int CLZ64(uint64_t n) { - int fast = absl::base_internal::CountLeadingZeros64(n); - int slow = absl::base_internal::CountLeadingZeros64Slow(n); - EXPECT_EQ(fast, slow) << n; - return fast; -} - -TEST(BitsTest, CountLeadingZeros64) { - EXPECT_EQ(64, CLZ64(uint64_t{})); - EXPECT_EQ(0, CLZ64(~uint64_t{})); - - for (int index = 0; index < 64; index++) { - uint64_t x = static_cast(1) << index; - const auto cnt = 63 - index; - ASSERT_EQ(cnt, CLZ64(x)) << index; - ASSERT_EQ(cnt, CLZ64(x + x - 1)) << index; - } -} - -int CLZ32(uint32_t n) { - int fast = absl::base_internal::CountLeadingZeros32(n); - int slow = absl::base_internal::CountLeadingZeros32Slow(n); - EXPECT_EQ(fast, slow) << n; - return fast; -} - -TEST(BitsTest, CountLeadingZeros32) { - EXPECT_EQ(32, CLZ32(uint32_t{})); - EXPECT_EQ(0, CLZ32(~uint32_t{})); - - for (int index = 0; index < 32; index++) { - uint32_t x = static_cast(1) << index; - const auto cnt = 31 - index; - ASSERT_EQ(cnt, CLZ32(x)) << index; - ASSERT_EQ(cnt, CLZ32(x + x - 1)) << index; - ASSERT_EQ(CLZ64(x), CLZ32(x) + 32); - } -} - -int CTZ64(uint64_t n) { - int fast = absl::base_internal::CountTrailingZerosNonZero64(n); - int slow = absl::base_internal::CountTrailingZerosNonZero64Slow(n); - EXPECT_EQ(fast, slow) << n; - return fast; -} - -TEST(BitsTest, CountTrailingZerosNonZero64) { - EXPECT_EQ(0, CTZ64(~uint64_t{})); - - for (int index = 0; index < 64; index++) { - uint64_t x = static_cast(1) << index; - const auto cnt = index; - ASSERT_EQ(cnt, CTZ64(x)) << index; - ASSERT_EQ(cnt, CTZ64(~(x - 1))) << index; - } -} - -int CTZ32(uint32_t n) { - int fast = absl::base_internal::CountTrailingZerosNonZero32(n); - int slow = absl::base_internal::CountTrailingZerosNonZero32Slow(n); - EXPECT_EQ(fast, slow) << n; - return fast; -} - -TEST(BitsTest, CountTrailingZerosNonZero32) { - EXPECT_EQ(0, CTZ32(~uint32_t{})); - - for (int index = 0; index < 32; index++) { - uint32_t x = static_cast(1) << index; - const auto cnt = index; - ASSERT_EQ(cnt, CTZ32(x)) << index; - ASSERT_EQ(cnt, CTZ32(~(x - 1))) << index; - } -} - - -} // namespace diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/cycleclock.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/cycleclock.cc deleted file mode 100644 index a742df0..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/cycleclock.cc +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -// The implementation of CycleClock::Frequency. -// -// NOTE: only i386 and x86_64 have been well tested. -// PPC, sparc, alpha, and ia64 are based on -// http://peter.kuscsik.com/wordpress/?p=14 -// with modifications by m3b. See also -// https://setisvn.ssl.berkeley.edu/svn/lib/fftw-3.0.1/kernel/cycle.h - -#include "absl/base/internal/cycleclock.h" - -#include // NOLINT(build/c++11) - -#include "absl/base/internal/unscaledcycleclock.h" - -namespace absl { -namespace base_internal { - -#if ABSL_USE_UNSCALED_CYCLECLOCK - -namespace { - -#ifdef NDEBUG -#ifdef ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY -// Not debug mode and the UnscaledCycleClock frequency is the CPU -// frequency. Scale the CycleClock to prevent overflow if someone -// tries to represent the time as cycles since the Unix epoch. -static constexpr int32_t kShift = 1; -#else -// Not debug mode and the UnscaledCycleClock isn't operating at the -// raw CPU frequency. There is no need to do any scaling, so don't -// needlessly sacrifice precision. -static constexpr int32_t kShift = 0; -#endif -#else -// In debug mode use a different shift to discourage depending on a -// particular shift value. -static constexpr int32_t kShift = 2; -#endif - -static constexpr double kFrequencyScale = 1.0 / (1 << kShift); - -} // namespace - -int64_t CycleClock::Now() { - return base_internal::UnscaledCycleClock::Now() >> kShift; -} - -double CycleClock::Frequency() { - return kFrequencyScale * base_internal::UnscaledCycleClock::Frequency(); -} - -#else - -int64_t CycleClock::Now() { - return std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); -} - -double CycleClock::Frequency() { - return 1e9; -} - -#endif - -} // namespace base_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/endian_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/endian_test.cc deleted file mode 100644 index e276915..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/endian_test.cc +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/base/internal/endian.h" - -#include -#include -#include -#include -#include - -#include "gtest/gtest.h" -#include "absl/base/config.h" - -namespace absl { -namespace { - -const uint64_t kInitialNumber{0x0123456789abcdef}; -const uint64_t k64Value{kInitialNumber}; -const uint32_t k32Value{0x01234567}; -const uint16_t k16Value{0x0123}; -const int kNumValuesToTest = 1000000; -const int kRandomSeed = 12345; - -#if defined(ABSL_IS_BIG_ENDIAN) -const uint64_t kInitialInNetworkOrder{kInitialNumber}; -const uint64_t k64ValueLE{0xefcdab8967452301}; -const uint32_t k32ValueLE{0x67452301}; -const uint16_t k16ValueLE{0x2301}; - -const uint64_t k64ValueBE{kInitialNumber}; -const uint32_t k32ValueBE{k32Value}; -const uint16_t k16ValueBE{k16Value}; -#elif defined(ABSL_IS_LITTLE_ENDIAN) -const uint64_t kInitialInNetworkOrder{0xefcdab8967452301}; -const uint64_t k64ValueLE{kInitialNumber}; -const uint32_t k32ValueLE{k32Value}; -const uint16_t k16ValueLE{k16Value}; - -const uint64_t k64ValueBE{0xefcdab8967452301}; -const uint32_t k32ValueBE{0x67452301}; -const uint16_t k16ValueBE{0x2301}; -#endif - -template -std::vector GenerateAllValuesForType() { - std::vector result; - T next = std::numeric_limits::min(); - while (true) { - result.push_back(next); - if (next == std::numeric_limits::max()) { - return result; - } - ++next; - } -} - -template -std::vector GenerateRandomIntegers(size_t numValuesToTest) { - std::vector result; - std::mt19937_64 rng(kRandomSeed); - for (size_t i = 0; i < numValuesToTest; ++i) { - result.push_back(rng()); - } - return result; -} - -void ManualByteSwap(char* bytes, int length) { - if (length == 1) - return; - - EXPECT_EQ(0, length % 2); - for (int i = 0; i < length / 2; ++i) { - int j = (length - 1) - i; - using std::swap; - swap(bytes[i], bytes[j]); - } -} - -template -inline T UnalignedLoad(const char* p) { - static_assert( - sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, - "Unexpected type size"); - - switch (sizeof(T)) { - case 1: return *reinterpret_cast(p); - case 2: - return ABSL_INTERNAL_UNALIGNED_LOAD16(p); - case 4: - return ABSL_INTERNAL_UNALIGNED_LOAD32(p); - case 8: - return ABSL_INTERNAL_UNALIGNED_LOAD64(p); - default: - // Suppresses invalid "not all control paths return a value" on MSVC - return {}; - } -} - -template -static void GBSwapHelper(const std::vector& host_values_to_test, - const ByteSwapper& byte_swapper) { - // Test byte_swapper against a manual byte swap. - for (typename std::vector::const_iterator it = host_values_to_test.begin(); - it != host_values_to_test.end(); ++it) { - T host_value = *it; - - char actual_value[sizeof(host_value)]; - memcpy(actual_value, &host_value, sizeof(host_value)); - byte_swapper(actual_value); - - char expected_value[sizeof(host_value)]; - memcpy(expected_value, &host_value, sizeof(host_value)); - ManualByteSwap(expected_value, sizeof(host_value)); - - ASSERT_EQ(0, memcmp(actual_value, expected_value, sizeof(host_value))) - << "Swap output for 0x" << std::hex << host_value << " does not match. " - << "Expected: 0x" << UnalignedLoad(expected_value) << "; " - << "actual: 0x" << UnalignedLoad(actual_value); - } -} - -void Swap16(char* bytes) { - ABSL_INTERNAL_UNALIGNED_STORE16( - bytes, gbswap_16(ABSL_INTERNAL_UNALIGNED_LOAD16(bytes))); -} - -void Swap32(char* bytes) { - ABSL_INTERNAL_UNALIGNED_STORE32( - bytes, gbswap_32(ABSL_INTERNAL_UNALIGNED_LOAD32(bytes))); -} - -void Swap64(char* bytes) { - ABSL_INTERNAL_UNALIGNED_STORE64( - bytes, gbswap_64(ABSL_INTERNAL_UNALIGNED_LOAD64(bytes))); -} - -TEST(EndianessTest, Uint16) { - GBSwapHelper(GenerateAllValuesForType(), &Swap16); -} - -TEST(EndianessTest, Uint32) { - GBSwapHelper(GenerateRandomIntegers(kNumValuesToTest), &Swap32); -} - -TEST(EndianessTest, Uint64) { - GBSwapHelper(GenerateRandomIntegers(kNumValuesToTest), &Swap64); -} - -TEST(EndianessTest, ghtonll_gntohll) { - // Test that absl::ghtonl compiles correctly - uint32_t test = 0x01234567; - EXPECT_EQ(absl::gntohl(absl::ghtonl(test)), test); - - uint64_t comp = absl::ghtonll(kInitialNumber); - EXPECT_EQ(comp, kInitialInNetworkOrder); - comp = absl::gntohll(kInitialInNetworkOrder); - EXPECT_EQ(comp, kInitialNumber); - - // Test that htonll and ntohll are each others' inverse functions on a - // somewhat assorted batch of numbers. 37 is chosen to not be anything - // particularly nice base 2. - uint64_t value = 1; - for (int i = 0; i < 100; ++i) { - comp = absl::ghtonll(absl::gntohll(value)); - EXPECT_EQ(value, comp); - comp = absl::gntohll(absl::ghtonll(value)); - EXPECT_EQ(value, comp); - value *= 37; - } -} - -TEST(EndianessTest, little_endian) { - // Check little_endian uint16_t. - uint64_t comp = little_endian::FromHost16(k16Value); - EXPECT_EQ(comp, k16ValueLE); - comp = little_endian::ToHost16(k16ValueLE); - EXPECT_EQ(comp, k16Value); - - // Check little_endian uint32_t. - comp = little_endian::FromHost32(k32Value); - EXPECT_EQ(comp, k32ValueLE); - comp = little_endian::ToHost32(k32ValueLE); - EXPECT_EQ(comp, k32Value); - - // Check little_endian uint64_t. - comp = little_endian::FromHost64(k64Value); - EXPECT_EQ(comp, k64ValueLE); - comp = little_endian::ToHost64(k64ValueLE); - EXPECT_EQ(comp, k64Value); - - // Check little-endian Load and store functions. - uint16_t u16Buf; - uint32_t u32Buf; - uint64_t u64Buf; - - little_endian::Store16(&u16Buf, k16Value); - EXPECT_EQ(u16Buf, k16ValueLE); - comp = little_endian::Load16(&u16Buf); - EXPECT_EQ(comp, k16Value); - - little_endian::Store32(&u32Buf, k32Value); - EXPECT_EQ(u32Buf, k32ValueLE); - comp = little_endian::Load32(&u32Buf); - EXPECT_EQ(comp, k32Value); - - little_endian::Store64(&u64Buf, k64Value); - EXPECT_EQ(u64Buf, k64ValueLE); - comp = little_endian::Load64(&u64Buf); - EXPECT_EQ(comp, k64Value); -} - -TEST(EndianessTest, big_endian) { - // Check big-endian Load and store functions. - uint16_t u16Buf; - uint32_t u32Buf; - uint64_t u64Buf; - - unsigned char buffer[10]; - big_endian::Store16(&u16Buf, k16Value); - EXPECT_EQ(u16Buf, k16ValueBE); - uint64_t comp = big_endian::Load16(&u16Buf); - EXPECT_EQ(comp, k16Value); - - big_endian::Store32(&u32Buf, k32Value); - EXPECT_EQ(u32Buf, k32ValueBE); - comp = big_endian::Load32(&u32Buf); - EXPECT_EQ(comp, k32Value); - - big_endian::Store64(&u64Buf, k64Value); - EXPECT_EQ(u64Buf, k64ValueBE); - comp = big_endian::Load64(&u64Buf); - EXPECT_EQ(comp, k64Value); - - big_endian::Store16(buffer + 1, k16Value); - EXPECT_EQ(u16Buf, k16ValueBE); - comp = big_endian::Load16(buffer + 1); - EXPECT_EQ(comp, k16Value); - - big_endian::Store32(buffer + 1, k32Value); - EXPECT_EQ(u32Buf, k32ValueBE); - comp = big_endian::Load32(buffer + 1); - EXPECT_EQ(comp, k32Value); - - big_endian::Store64(buffer + 1, k64Value); - EXPECT_EQ(u64Buf, k64ValueBE); - comp = big_endian::Load64(buffer + 1); - EXPECT_EQ(comp, k64Value); -} - -} // namespace -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.cc deleted file mode 100644 index 8207b7d..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.cc +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/base/internal/exception_safety_testing.h" - -#include "gtest/gtest.h" -#include "absl/meta/type_traits.h" - -namespace testing { - -exceptions_internal::NoThrowTag nothrow_ctor; - -exceptions_internal::StrongGuaranteeTagType strong_guarantee; - -exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester() { - return {}; -} - -namespace exceptions_internal { - -int countdown = -1; - -ConstructorTracker* ConstructorTracker::current_tracker_instance_ = nullptr; - -void MaybeThrow(absl::string_view msg, bool throw_bad_alloc) { - if (countdown-- == 0) { - if (throw_bad_alloc) throw TestBadAllocException(msg); - throw TestException(msg); - } -} - -testing::AssertionResult FailureMessage(const TestException& e, - int countdown) noexcept { - return testing::AssertionFailure() << "Exception thrown from " << e.what(); -} - -std::string GetSpecString(TypeSpec spec) { - std::string out; - absl::string_view sep; - const auto append = [&](absl::string_view s) { - absl::StrAppend(&out, sep, s); - sep = " | "; - }; - if (static_cast(TypeSpec::kNoThrowCopy & spec)) { - append("kNoThrowCopy"); - } - if (static_cast(TypeSpec::kNoThrowMove & spec)) { - append("kNoThrowMove"); - } - if (static_cast(TypeSpec::kNoThrowNew & spec)) { - append("kNoThrowNew"); - } - return out; -} - -std::string GetSpecString(AllocSpec spec) { - return static_cast(AllocSpec::kNoThrowAllocate & spec) - ? "kNoThrowAllocate" - : ""; -} - -} // namespace exceptions_internal - -} // namespace testing diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h deleted file mode 100644 index d4d41a8..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h +++ /dev/null @@ -1,1094 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -// Utilities for testing exception-safety - -#ifndef ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_ -#define ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gtest/gtest.h" -#include "absl/base/config.h" -#include "absl/base/internal/pretty_function.h" -#include "absl/memory/memory.h" -#include "absl/meta/type_traits.h" -#include "absl/strings/string_view.h" -#include "absl/strings/substitute.h" -#include "absl/utility/utility.h" - -namespace testing { - -enum class TypeSpec; -enum class AllocSpec; - -constexpr TypeSpec operator|(TypeSpec a, TypeSpec b) { - using T = absl::underlying_type_t; - return static_cast(static_cast(a) | static_cast(b)); -} - -constexpr TypeSpec operator&(TypeSpec a, TypeSpec b) { - using T = absl::underlying_type_t; - return static_cast(static_cast(a) & static_cast(b)); -} - -constexpr AllocSpec operator|(AllocSpec a, AllocSpec b) { - using T = absl::underlying_type_t; - return static_cast(static_cast(a) | static_cast(b)); -} - -constexpr AllocSpec operator&(AllocSpec a, AllocSpec b) { - using T = absl::underlying_type_t; - return static_cast(static_cast(a) & static_cast(b)); -} - -namespace exceptions_internal { - -std::string GetSpecString(TypeSpec); -std::string GetSpecString(AllocSpec); - -struct NoThrowTag {}; -struct StrongGuaranteeTagType {}; - -// A simple exception class. We throw this so that test code can catch -// exceptions specifically thrown by ThrowingValue. -class TestException { - public: - explicit TestException(absl::string_view msg) : msg_(msg) {} - virtual ~TestException() {} - virtual const char* what() const noexcept { return msg_.c_str(); } - - private: - std::string msg_; -}; - -// TestBadAllocException exists because allocation functions must throw an -// exception which can be caught by a handler of std::bad_alloc. We use a child -// class of std::bad_alloc so we can customise the error message, and also -// derive from TestException so we don't accidentally end up catching an actual -// bad_alloc exception in TestExceptionSafety. -class TestBadAllocException : public std::bad_alloc, public TestException { - public: - explicit TestBadAllocException(absl::string_view msg) : TestException(msg) {} - using TestException::what; -}; - -extern int countdown; - -// Allows the countdown variable to be set manually (defaulting to the initial -// value of 0) -inline void SetCountdown(int i = 0) { countdown = i; } -// Sets the countdown to the terminal value -1 -inline void UnsetCountdown() { SetCountdown(-1); } - -void MaybeThrow(absl::string_view msg, bool throw_bad_alloc = false); - -testing::AssertionResult FailureMessage(const TestException& e, - int countdown) noexcept; - -struct TrackedAddress { - bool is_alive; - std::string description; -}; - -// Inspects the constructions and destructions of anything inheriting from -// TrackedObject. This allows us to safely "leak" TrackedObjects, as -// ConstructorTracker will destroy everything left over in its destructor. -class ConstructorTracker { - public: - explicit ConstructorTracker(int count) : countdown_(count) { - assert(current_tracker_instance_ == nullptr); - current_tracker_instance_ = this; - } - - ~ConstructorTracker() { - assert(current_tracker_instance_ == this); - current_tracker_instance_ = nullptr; - - for (auto& it : address_map_) { - void* address = it.first; - TrackedAddress& tracked_address = it.second; - if (tracked_address.is_alive) { - ADD_FAILURE() << ErrorMessage(address, tracked_address.description, - countdown_, "Object was not destroyed."); - } - } - } - - static void ObjectConstructed(void* address, std::string description) { - if (!CurrentlyTracking()) return; - - TrackedAddress& tracked_address = - current_tracker_instance_->address_map_[address]; - if (tracked_address.is_alive) { - ADD_FAILURE() << ErrorMessage( - address, tracked_address.description, - current_tracker_instance_->countdown_, - "Object was re-constructed. Current object was constructed by " + - description); - } - tracked_address = {true, std::move(description)}; - } - - static void ObjectDestructed(void* address) { - if (!CurrentlyTracking()) return; - - auto it = current_tracker_instance_->address_map_.find(address); - // Not tracked. Ignore. - if (it == current_tracker_instance_->address_map_.end()) return; - - TrackedAddress& tracked_address = it->second; - if (!tracked_address.is_alive) { - ADD_FAILURE() << ErrorMessage(address, tracked_address.description, - current_tracker_instance_->countdown_, - "Object was re-destroyed."); - } - tracked_address.is_alive = false; - } - - private: - static bool CurrentlyTracking() { - return current_tracker_instance_ != nullptr; - } - - static std::string ErrorMessage(void* address, const std::string& address_description, - int countdown, const std::string& error_description) { - return absl::Substitute( - "With coundtown at $0:\n" - " $1\n" - " Object originally constructed by $2\n" - " Object address: $3\n", - countdown, error_description, address_description, address); - } - - std::unordered_map address_map_; - int countdown_; - - static ConstructorTracker* current_tracker_instance_; -}; - -class TrackedObject { - public: - TrackedObject(const TrackedObject&) = delete; - TrackedObject(TrackedObject&&) = delete; - - protected: - explicit TrackedObject(std::string description) { - ConstructorTracker::ObjectConstructed(this, std::move(description)); - } - - ~TrackedObject() noexcept { ConstructorTracker::ObjectDestructed(this); } -}; -} // namespace exceptions_internal - -extern exceptions_internal::NoThrowTag nothrow_ctor; - -extern exceptions_internal::StrongGuaranteeTagType strong_guarantee; - -// A test class which is convertible to bool. The conversion can be -// instrumented to throw at a controlled time. -class ThrowingBool { - public: - ThrowingBool(bool b) noexcept : b_(b) {} // NOLINT(runtime/explicit) - operator bool() const { // NOLINT - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return b_; - } - - private: - bool b_; -}; - -/* - * Configuration enum for the ThrowingValue type that defines behavior for the - * lifetime of the instance. Use testing::nothrow_ctor to prevent the integer - * constructor from throwing. - * - * kEverythingThrows: Every operation can throw an exception - * kNoThrowCopy: Copy construction and copy assignment will not throw - * kNoThrowMove: Move construction and move assignment will not throw - * kNoThrowNew: Overloaded operators new and new[] will not throw - */ -enum class TypeSpec { - kEverythingThrows = 0, - kNoThrowCopy = 1, - kNoThrowMove = 1 << 1, - kNoThrowNew = 1 << 2, -}; - -/* - * A testing class instrumented to throw an exception at a controlled time. - * - * ThrowingValue implements a slightly relaxed version of the Regular concept -- - * that is it's a value type with the expected semantics. It also implements - * arithmetic operations. It doesn't implement member and pointer operators - * like operator-> or operator[]. - * - * ThrowingValue can be instrumented to have certain operations be noexcept by - * using compile-time bitfield template arguments. That is, to make an - * ThrowingValue which has noexcept move construction/assignment and noexcept - * copy construction/assignment, use the following: - * ThrowingValue my_thrwr{val}; - */ -template -class ThrowingValue : private exceptions_internal::TrackedObject { - static constexpr bool IsSpecified(TypeSpec spec) { - return static_cast(Spec & spec); - } - - static constexpr int kDefaultValue = 0; - static constexpr int kBadValue = 938550620; - - public: - ThrowingValue() : TrackedObject(GetInstanceString(kDefaultValue)) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - dummy_ = kDefaultValue; - } - - ThrowingValue(const ThrowingValue& other) noexcept( - IsSpecified(TypeSpec::kNoThrowCopy)) - : TrackedObject(GetInstanceString(other.dummy_)) { - if (!IsSpecified(TypeSpec::kNoThrowCopy)) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - } - dummy_ = other.dummy_; - } - - ThrowingValue(ThrowingValue&& other) noexcept( - IsSpecified(TypeSpec::kNoThrowMove)) - : TrackedObject(GetInstanceString(other.dummy_)) { - if (!IsSpecified(TypeSpec::kNoThrowMove)) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - } - dummy_ = other.dummy_; - } - - explicit ThrowingValue(int i) : TrackedObject(GetInstanceString(i)) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - dummy_ = i; - } - - ThrowingValue(int i, exceptions_internal::NoThrowTag) noexcept - : TrackedObject(GetInstanceString(i)), dummy_(i) {} - - // absl expects nothrow destructors - ~ThrowingValue() noexcept = default; - - ThrowingValue& operator=(const ThrowingValue& other) noexcept( - IsSpecified(TypeSpec::kNoThrowCopy)) { - dummy_ = kBadValue; - if (!IsSpecified(TypeSpec::kNoThrowCopy)) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - } - dummy_ = other.dummy_; - return *this; - } - - ThrowingValue& operator=(ThrowingValue&& other) noexcept( - IsSpecified(TypeSpec::kNoThrowMove)) { - dummy_ = kBadValue; - if (!IsSpecified(TypeSpec::kNoThrowMove)) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - } - dummy_ = other.dummy_; - return *this; - } - - // Arithmetic Operators - ThrowingValue operator+(const ThrowingValue& other) const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ + other.dummy_, nothrow_ctor); - } - - ThrowingValue operator+() const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_, nothrow_ctor); - } - - ThrowingValue operator-(const ThrowingValue& other) const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ - other.dummy_, nothrow_ctor); - } - - ThrowingValue operator-() const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(-dummy_, nothrow_ctor); - } - - ThrowingValue& operator++() { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - ++dummy_; - return *this; - } - - ThrowingValue operator++(int) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - auto out = ThrowingValue(dummy_, nothrow_ctor); - ++dummy_; - return out; - } - - ThrowingValue& operator--() { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - --dummy_; - return *this; - } - - ThrowingValue operator--(int) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - auto out = ThrowingValue(dummy_, nothrow_ctor); - --dummy_; - return out; - } - - ThrowingValue operator*(const ThrowingValue& other) const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ * other.dummy_, nothrow_ctor); - } - - ThrowingValue operator/(const ThrowingValue& other) const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ / other.dummy_, nothrow_ctor); - } - - ThrowingValue operator%(const ThrowingValue& other) const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ % other.dummy_, nothrow_ctor); - } - - ThrowingValue operator<<(int shift) const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ << shift, nothrow_ctor); - } - - ThrowingValue operator>>(int shift) const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ >> shift, nothrow_ctor); - } - - // Comparison Operators - // NOTE: We use `ThrowingBool` instead of `bool` because most STL - // types/containers requires T to be convertible to bool. - friend ThrowingBool operator==(const ThrowingValue& a, - const ThrowingValue& b) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return a.dummy_ == b.dummy_; - } - friend ThrowingBool operator!=(const ThrowingValue& a, - const ThrowingValue& b) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return a.dummy_ != b.dummy_; - } - friend ThrowingBool operator<(const ThrowingValue& a, - const ThrowingValue& b) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return a.dummy_ < b.dummy_; - } - friend ThrowingBool operator<=(const ThrowingValue& a, - const ThrowingValue& b) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return a.dummy_ <= b.dummy_; - } - friend ThrowingBool operator>(const ThrowingValue& a, - const ThrowingValue& b) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return a.dummy_ > b.dummy_; - } - friend ThrowingBool operator>=(const ThrowingValue& a, - const ThrowingValue& b) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return a.dummy_ >= b.dummy_; - } - - // Logical Operators - ThrowingBool operator!() const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return !dummy_; - } - - ThrowingBool operator&&(const ThrowingValue& other) const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return dummy_ && other.dummy_; - } - - ThrowingBool operator||(const ThrowingValue& other) const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return dummy_ || other.dummy_; - } - - // Bitwise Logical Operators - ThrowingValue operator~() const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(~dummy_, nothrow_ctor); - } - - ThrowingValue operator&(const ThrowingValue& other) const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ & other.dummy_, nothrow_ctor); - } - - ThrowingValue operator|(const ThrowingValue& other) const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ | other.dummy_, nothrow_ctor); - } - - ThrowingValue operator^(const ThrowingValue& other) const { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return ThrowingValue(dummy_ ^ other.dummy_, nothrow_ctor); - } - - // Compound Assignment operators - ThrowingValue& operator+=(const ThrowingValue& other) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - dummy_ += other.dummy_; - return *this; - } - - ThrowingValue& operator-=(const ThrowingValue& other) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - dummy_ -= other.dummy_; - return *this; - } - - ThrowingValue& operator*=(const ThrowingValue& other) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - dummy_ *= other.dummy_; - return *this; - } - - ThrowingValue& operator/=(const ThrowingValue& other) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - dummy_ /= other.dummy_; - return *this; - } - - ThrowingValue& operator%=(const ThrowingValue& other) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - dummy_ %= other.dummy_; - return *this; - } - - ThrowingValue& operator&=(const ThrowingValue& other) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - dummy_ &= other.dummy_; - return *this; - } - - ThrowingValue& operator|=(const ThrowingValue& other) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - dummy_ |= other.dummy_; - return *this; - } - - ThrowingValue& operator^=(const ThrowingValue& other) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - dummy_ ^= other.dummy_; - return *this; - } - - ThrowingValue& operator<<=(int shift) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - dummy_ <<= shift; - return *this; - } - - ThrowingValue& operator>>=(int shift) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - dummy_ >>= shift; - return *this; - } - - // Pointer operators - void operator&() const = delete; // NOLINT(runtime/operator) - - // Stream operators - friend std::ostream& operator<<(std::ostream& os, const ThrowingValue& tv) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return os << GetInstanceString(tv.dummy_); - } - - friend std::istream& operator>>(std::istream& is, const ThrowingValue&) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - return is; - } - - // Memory management operators - // Args.. allows us to overload regular and placement new in one shot - template - static void* operator new(size_t s, Args&&... args) noexcept( - IsSpecified(TypeSpec::kNoThrowNew)) { - if (!IsSpecified(TypeSpec::kNoThrowNew)) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true); - } - return ::operator new(s, std::forward(args)...); - } - - template - static void* operator new[](size_t s, Args&&... args) noexcept( - IsSpecified(TypeSpec::kNoThrowNew)) { - if (!IsSpecified(TypeSpec::kNoThrowNew)) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true); - } - return ::operator new[](s, std::forward(args)...); - } - - // Abseil doesn't support throwing overloaded operator delete. These are - // provided so a throwing operator-new can clean up after itself. - // - // We provide both regular and templated operator delete because if only the - // templated version is provided as we did with operator new, the compiler has - // no way of knowing which overload of operator delete to call. See - // http://en.cppreference.com/w/cpp/memory/new/operator_delete and - // http://en.cppreference.com/w/cpp/language/delete for the gory details. - void operator delete(void* p) noexcept { ::operator delete(p); } - - template - void operator delete(void* p, Args&&... args) noexcept { - ::operator delete(p, std::forward(args)...); - } - - void operator delete[](void* p) noexcept { return ::operator delete[](p); } - - template - void operator delete[](void* p, Args&&... args) noexcept { - return ::operator delete[](p, std::forward(args)...); - } - - // Non-standard access to the actual contained value. No need for this to - // throw. - int& Get() noexcept { return dummy_; } - const int& Get() const noexcept { return dummy_; } - - private: - static std::string GetInstanceString(int dummy) { - return absl::StrCat("ThrowingValue<", - exceptions_internal::GetSpecString(Spec), ">(", dummy, - ")"); - } - - int dummy_; -}; -// While not having to do with exceptions, explicitly delete comma operator, to -// make sure we don't use it on user-supplied types. -template -void operator,(const ThrowingValue&, T&&) = delete; -template -void operator,(T&&, const ThrowingValue&) = delete; - -/* - * Configuration enum for the ThrowingAllocator type that defines behavior for - * the lifetime of the instance. - * - * kEverythingThrows: Calls to the member functions may throw - * kNoThrowAllocate: Calls to the member functions will not throw - */ -enum class AllocSpec { - kEverythingThrows = 0, - kNoThrowAllocate = 1, -}; - -/* - * An allocator type which is instrumented to throw at a controlled time, or not - * to throw, using AllocSpec. The supported settings are the default of every - * function which is allowed to throw in a conforming allocator possibly - * throwing, or nothing throws, in line with the ABSL_ALLOCATOR_THROWS - * configuration macro. - */ -template -class ThrowingAllocator : private exceptions_internal::TrackedObject { - static constexpr bool IsSpecified(AllocSpec spec) { - return static_cast(Spec & spec); - } - - public: - using pointer = T*; - using const_pointer = const T*; - using reference = T&; - using const_reference = const T&; - using void_pointer = void*; - using const_void_pointer = const void*; - using value_type = T; - using size_type = size_t; - using difference_type = ptrdiff_t; - - using is_nothrow = - std::integral_constant; - using propagate_on_container_copy_assignment = std::true_type; - using propagate_on_container_move_assignment = std::true_type; - using propagate_on_container_swap = std::true_type; - using is_always_equal = std::false_type; - - ThrowingAllocator() : TrackedObject(GetInstanceString(next_id_)) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - dummy_ = std::make_shared(next_id_++); - } - - template - ThrowingAllocator(const ThrowingAllocator& other) noexcept // NOLINT - : TrackedObject(GetInstanceString(*other.State())), - dummy_(other.State()) {} - - // According to C++11 standard [17.6.3.5], Table 28, the move/copy ctors of - // allocator shall not exit via an exception, thus they are marked noexcept. - ThrowingAllocator(const ThrowingAllocator& other) noexcept - : TrackedObject(GetInstanceString(*other.State())), - dummy_(other.State()) {} - - template - ThrowingAllocator(ThrowingAllocator&& other) noexcept // NOLINT - : TrackedObject(GetInstanceString(*other.State())), - dummy_(std::move(other.State())) {} - - ThrowingAllocator(ThrowingAllocator&& other) noexcept - : TrackedObject(GetInstanceString(*other.State())), - dummy_(std::move(other.State())) {} - - ~ThrowingAllocator() noexcept = default; - - ThrowingAllocator& operator=(const ThrowingAllocator& other) noexcept { - dummy_ = other.State(); - return *this; - } - - template - ThrowingAllocator& operator=( - const ThrowingAllocator& other) noexcept { - dummy_ = other.State(); - return *this; - } - - template - ThrowingAllocator& operator=(ThrowingAllocator&& other) noexcept { - dummy_ = std::move(other.State()); - return *this; - } - - template - struct rebind { - using other = ThrowingAllocator; - }; - - pointer allocate(size_type n) noexcept( - IsSpecified(AllocSpec::kNoThrowAllocate)) { - ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); - return static_cast(::operator new(n * sizeof(T))); - } - - pointer allocate(size_type n, const_void_pointer) noexcept( - IsSpecified(AllocSpec::kNoThrowAllocate)) { - return allocate(n); - } - - void deallocate(pointer ptr, size_type) noexcept { - ReadState(); - ::operator delete(static_cast(ptr)); - } - - template - void construct(U* ptr, Args&&... args) noexcept( - IsSpecified(AllocSpec::kNoThrowAllocate)) { - ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); - ::new (static_cast(ptr)) U(std::forward(args)...); - } - - template - void destroy(U* p) noexcept { - ReadState(); - p->~U(); - } - - size_type max_size() const noexcept { - return (std::numeric_limits::max)() / sizeof(value_type); - } - - ThrowingAllocator select_on_container_copy_construction() noexcept( - IsSpecified(AllocSpec::kNoThrowAllocate)) { - auto& out = *this; - ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); - return out; - } - - template - bool operator==(const ThrowingAllocator& other) const noexcept { - return dummy_ == other.dummy_; - } - - template - bool operator!=(const ThrowingAllocator& other) const noexcept { - return dummy_ != other.dummy_; - } - - template - friend class ThrowingAllocator; - - private: - static std::string GetInstanceString(int dummy) { - return absl::StrCat("ThrowingAllocator<", - exceptions_internal::GetSpecString(Spec), ">(", dummy, - ")"); - } - - const std::shared_ptr& State() const { return dummy_; } - std::shared_ptr& State() { return dummy_; } - - void ReadState() { - // we know that this will never be true, but the compiler doesn't, so this - // should safely force a read of the value. - if (*dummy_ < 0) std::abort(); - } - - void ReadStateAndMaybeThrow(absl::string_view msg) const { - if (!IsSpecified(AllocSpec::kNoThrowAllocate)) { - exceptions_internal::MaybeThrow( - absl::Substitute("Allocator id $0 threw from $1", *dummy_, msg)); - } - } - - static int next_id_; - std::shared_ptr dummy_; -}; - -template -int ThrowingAllocator::next_id_ = 0; - -// Tests for resource leaks by attempting to construct a T using args repeatedly -// until successful, using the countdown method. Side effects can then be -// tested for resource leaks. -template -void TestThrowingCtor(Args&&... args) { - struct Cleanup { - ~Cleanup() { exceptions_internal::UnsetCountdown(); } - } c; - for (int count = 0;; ++count) { - exceptions_internal::ConstructorTracker ct(count); - exceptions_internal::SetCountdown(count); - try { - T temp(std::forward(args)...); - static_cast(temp); - break; - } catch (const exceptions_internal::TestException&) { - } - } -} - -// Tests the nothrow guarantee of the provided nullary operation. If the an -// exception is thrown, the result will be AssertionFailure(). Otherwise, it -// will be AssertionSuccess(). -template -testing::AssertionResult TestNothrowOp(const Operation& operation) { - struct Cleanup { - Cleanup() { exceptions_internal::SetCountdown(); } - ~Cleanup() { exceptions_internal::UnsetCountdown(); } - } c; - try { - operation(); - return testing::AssertionSuccess(); - } catch (const exceptions_internal::TestException&) { - return testing::AssertionFailure() - << "TestException thrown during call to operation() when nothrow " - "guarantee was expected."; - } catch (...) { - return testing::AssertionFailure() - << "Unknown exception thrown during call to operation() when " - "nothrow guarantee was expected."; - } -} - -namespace exceptions_internal { - -// Dummy struct for ExceptionSafetyTestBuilder<> partial state. -struct UninitializedT {}; - -template -class DefaultFactory { - public: - explicit DefaultFactory(const T& t) : t_(t) {} - std::unique_ptr operator()() const { return absl::make_unique(t_); } - - private: - T t_; -}; - -template -using EnableIfTestable = typename absl::enable_if_t< - LazyContractsCount != 0 && - !std::is_same::value && - !std::is_same::value>; - -template -class ExceptionSafetyTestBuilder; - -} // namespace exceptions_internal - -/* - * Constructs an empty ExceptionSafetyTestBuilder. All - * ExceptionSafetyTestBuilder objects are immutable and all With[thing] mutation - * methods return new instances of ExceptionSafetyTestBuilder. - * - * In order to test a T for exception safety, a factory for that T, a testable - * operation, and at least one contract callback returning an assertion - * result must be applied using the respective methods. - */ -exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester(); - -namespace exceptions_internal { -template -struct IsUniquePtr : std::false_type {}; - -template -struct IsUniquePtr> : std::true_type {}; - -template -struct FactoryPtrTypeHelper { - using type = decltype(std::declval()()); - - static_assert(IsUniquePtr::value, "Factories must return a unique_ptr"); -}; - -template -using FactoryPtrType = typename FactoryPtrTypeHelper::type; - -template -using FactoryElementType = typename FactoryPtrType::element_type; - -template -class ExceptionSafetyTest { - using Factory = std::function()>; - using Operation = std::function; - using Contract = std::function; - - public: - template - explicit ExceptionSafetyTest(const Factory& f, const Operation& op, - const Contracts&... contracts) - : factory_(f), operation_(op), contracts_{WrapContract(contracts)...} {} - - AssertionResult Test() const { - for (int count = 0;; ++count) { - exceptions_internal::ConstructorTracker ct(count); - - for (const auto& contract : contracts_) { - auto t_ptr = factory_(); - try { - SetCountdown(count); - operation_(t_ptr.get()); - // Unset for the case that the operation throws no exceptions, which - // would leave the countdown set and break the *next* exception safety - // test after this one. - UnsetCountdown(); - return AssertionSuccess(); - } catch (const exceptions_internal::TestException& e) { - if (!contract(t_ptr.get())) { - return AssertionFailure() << e.what() << " failed contract check"; - } - } - } - } - } - - private: - template - Contract WrapContract(const ContractFn& contract) { - return [contract](T* t_ptr) { return AssertionResult(contract(t_ptr)); }; - } - - Contract WrapContract(StrongGuaranteeTagType) { - return [this](T* t_ptr) { return AssertionResult(*factory_() == *t_ptr); }; - } - - Factory factory_; - Operation operation_; - std::vector contracts_; -}; - -/* - * Builds a tester object that tests if performing a operation on a T follows - * exception safety guarantees. Verification is done via contract assertion - * callbacks applied to T instances post-throw. - * - * Template parameters for ExceptionSafetyTestBuilder: - * - * - Factory: The factory object (passed in via tester.WithFactory(...) or - * tester.WithInitialValue(...)) must be invocable with the signature - * `std::unique_ptr operator()() const` where T is the type being tested. - * It is used for reliably creating identical T instances to test on. - * - * - Operation: The operation object (passsed in via tester.WithOperation(...) - * or tester.Test(...)) must be invocable with the signature - * `void operator()(T*) const` where T is the type being tested. It is used - * for performing steps on a T instance that may throw and that need to be - * checked for exception safety. Each call to the operation will receive a - * fresh T instance so it's free to modify and destroy the T instances as it - * pleases. - * - * - Contracts...: The contract assertion callback objects (passed in via - * tester.WithContracts(...)) must be invocable with the signature - * `testing::AssertionResult operator()(T*) const` where T is the type being - * tested. Contract assertion callbacks are provided T instances post-throw. - * They must return testing::AssertionSuccess when the type contracts of the - * provided T instance hold. If the type contracts of the T instance do not - * hold, they must return testing::AssertionFailure. Execution order of - * Contracts... is unspecified. They will each individually get a fresh T - * instance so they are free to modify and destroy the T instances as they - * please. - */ -template -class ExceptionSafetyTestBuilder { - public: - /* - * Returns a new ExceptionSafetyTestBuilder with an included T factory based - * on the provided T instance. The existing factory will not be included in - * the newly created tester instance. The created factory returns a new T - * instance by copy-constructing the provided const T& t. - * - * Preconditions for tester.WithInitialValue(const T& t): - * - * - The const T& t object must be copy-constructible where T is the type - * being tested. For non-copy-constructible objects, use the method - * tester.WithFactory(...). - */ - template - ExceptionSafetyTestBuilder, Operation, Contracts...> - WithInitialValue(const T& t) const { - return WithFactory(DefaultFactory(t)); - } - - /* - * Returns a new ExceptionSafetyTestBuilder with the provided T factory - * included. The existing factory will not be included in the newly-created - * tester instance. This method is intended for use with types lacking a copy - * constructor. Types that can be copy-constructed should instead use the - * method tester.WithInitialValue(...). - */ - template - ExceptionSafetyTestBuilder, Operation, Contracts...> - WithFactory(const NewFactory& new_factory) const { - return {new_factory, operation_, contracts_}; - } - - /* - * Returns a new ExceptionSafetyTestBuilder with the provided testable - * operation included. The existing operation will not be included in the - * newly created tester. - */ - template - ExceptionSafetyTestBuilder, Contracts...> - WithOperation(const NewOperation& new_operation) const { - return {factory_, new_operation, contracts_}; - } - - /* - * Returns a new ExceptionSafetyTestBuilder with the provided MoreContracts... - * combined with the Contracts... that were already included in the instance - * on which the method was called. Contracts... cannot be removed or replaced - * once added to an ExceptionSafetyTestBuilder instance. A fresh object must - * be created in order to get an empty Contracts... list. - * - * In addition to passing in custom contract assertion callbacks, this method - * accepts `testing::strong_guarantee` as an argument which checks T instances - * post-throw against freshly created T instances via operator== to verify - * that any state changes made during the execution of the operation were - * properly rolled back. - */ - template - ExceptionSafetyTestBuilder...> - WithContracts(const MoreContracts&... more_contracts) const { - return { - factory_, operation_, - std::tuple_cat(contracts_, std::tuple...>( - more_contracts...))}; - } - - /* - * Returns a testing::AssertionResult that is the reduced result of the - * exception safety algorithm. The algorithm short circuits and returns - * AssertionFailure after the first contract callback returns an - * AssertionFailure. Otherwise, if all contract callbacks return an - * AssertionSuccess, the reduced result is AssertionSuccess. - * - * The passed-in testable operation will not be saved in a new tester instance - * nor will it modify/replace the existing tester instance. This is useful - * when each operation being tested is unique and does not need to be reused. - * - * Preconditions for tester.Test(const NewOperation& new_operation): - * - * - May only be called after at least one contract assertion callback and a - * factory or initial value have been provided. - */ - template < - typename NewOperation, - typename = EnableIfTestable> - testing::AssertionResult Test(const NewOperation& new_operation) const { - return TestImpl(new_operation, absl::index_sequence_for()); - } - - /* - * Returns a testing::AssertionResult that is the reduced result of the - * exception safety algorithm. The algorithm short circuits and returns - * AssertionFailure after the first contract callback returns an - * AssertionFailure. Otherwise, if all contract callbacks return an - * AssertionSuccess, the reduced result is AssertionSuccess. - * - * Preconditions for tester.Test(): - * - * - May only be called after at least one contract assertion callback, a - * factory or initial value and a testable operation have been provided. - */ - template < - typename LazyOperation = Operation, - typename = EnableIfTestable> - testing::AssertionResult Test() const { - return Test(operation_); - } - - private: - template - friend class ExceptionSafetyTestBuilder; - - friend ExceptionSafetyTestBuilder<> testing::MakeExceptionSafetyTester(); - - ExceptionSafetyTestBuilder() {} - - ExceptionSafetyTestBuilder(const Factory& f, const Operation& o, - const std::tuple& i) - : factory_(f), operation_(o), contracts_(i) {} - - template - testing::AssertionResult TestImpl(SelectedOperation selected_operation, - absl::index_sequence) const { - return ExceptionSafetyTest>( - factory_, selected_operation, std::get(contracts_)...) - .Test(); - } - - Factory factory_; - Operation operation_; - std::tuple contracts_; -}; - -} // namespace exceptions_internal - -} // namespace testing - -#endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/exception_testing.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/exception_testing.h deleted file mode 100644 index 0cf7918..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/exception_testing.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -// Testing utilities for ABSL types which throw exceptions. - -#ifndef ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_ -#define ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_ - -#include "gtest/gtest.h" -#include "absl/base/config.h" - -// ABSL_BASE_INTERNAL_EXPECT_FAIL tests either for a specified thrown exception -// if exceptions are enabled, or for death with a specified text in the error -// message -#ifdef ABSL_HAVE_EXCEPTIONS - -#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \ - EXPECT_THROW(expr, exception_t) - -#elif defined(__ANDROID__) -// Android asserts do not log anywhere that gtest can currently inspect. -// So we expect exit, but cannot match the message. -#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \ - EXPECT_DEATH(expr, ".*") -#else -#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \ - EXPECT_DEATH_IF_SUPPORTED(expr, text) - -#endif - -#endif // ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/inline_variable_testing.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/inline_variable_testing.h deleted file mode 100644 index a0dd2bb..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/inline_variable_testing.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#ifndef ABSL_BASE_INLINE_VARIABLE_TESTING_H_ -#define ABSL_BASE_INLINE_VARIABLE_TESTING_H_ - -#include "absl/base/internal/inline_variable.h" - -namespace absl { -namespace inline_variable_testing_internal { - -struct Foo { - int value = 5; -}; - -ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, inline_variable_foo, {}); -ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, other_inline_variable_foo, {}); - -ABSL_INTERNAL_INLINE_CONSTEXPR(int, inline_variable_int, 5); -ABSL_INTERNAL_INLINE_CONSTEXPR(int, other_inline_variable_int, 5); - -ABSL_INTERNAL_INLINE_CONSTEXPR(void(*)(), inline_variable_fun_ptr, nullptr); - -const Foo& get_foo_a(); -const Foo& get_foo_b(); - -const int& get_int_a(); -const int& get_int_b(); - -} // namespace inline_variable_testing_internal -} // namespace absl - -#endif // ABSL_BASE_INLINE_VARIABLE_TESTING_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc deleted file mode 100644 index cf2b363..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/base/internal/low_level_alloc.h" - -#include -#include -#include -#include // NOLINT(build/c++11) -#include -#include - -namespace absl { -namespace base_internal { -namespace { - -// This test doesn't use gtest since it needs to test that everything -// works before main(). -#define TEST_ASSERT(x) \ - if (!(x)) { \ - printf("TEST_ASSERT(%s) FAILED ON LINE %d\n", #x, __LINE__); \ - abort(); \ - } - -// a block of memory obtained from the allocator -struct BlockDesc { - char *ptr; // pointer to memory - int len; // number of bytes - int fill; // filled with data starting with this -}; - -// Check that the pattern placed in the block d -// by RandomizeBlockDesc is still there. -static void CheckBlockDesc(const BlockDesc &d) { - for (int i = 0; i != d.len; i++) { - TEST_ASSERT((d.ptr[i] & 0xff) == ((d.fill + i) & 0xff)); - } -} - -// Fill the block "*d" with a pattern -// starting with a random byte. -static void RandomizeBlockDesc(BlockDesc *d) { - d->fill = rand() & 0xff; - for (int i = 0; i != d->len; i++) { - d->ptr[i] = (d->fill + i) & 0xff; - } -} - -// Use to indicate to the malloc hooks that -// this calls is from LowLevelAlloc. -static bool using_low_level_alloc = false; - -// n times, toss a coin, and based on the outcome -// either allocate a new block or deallocate an old block. -// New blocks are placed in a std::unordered_map with a random key -// and initialized with RandomizeBlockDesc(). -// If keys conflict, the older block is freed. -// Old blocks are always checked with CheckBlockDesc() -// before being freed. At the end of the run, -// all remaining allocated blocks are freed. -// If use_new_arena is true, use a fresh arena, and then delete it. -// If call_malloc_hook is true and user_arena is true, -// allocations and deallocations are reported via the MallocHook -// interface. -static void Test(bool use_new_arena, bool call_malloc_hook, int n) { - typedef std::unordered_map AllocMap; - AllocMap allocated; - AllocMap::iterator it; - BlockDesc block_desc; - int rnd; - LowLevelAlloc::Arena *arena = 0; - if (use_new_arena) { - int32_t flags = call_malloc_hook ? LowLevelAlloc::kCallMallocHook : 0; - arena = LowLevelAlloc::NewArena(flags); - } - for (int i = 0; i != n; i++) { - if (i != 0 && i % 10000 == 0) { - printf("."); - fflush(stdout); - } - - switch (rand() & 1) { // toss a coin - case 0: // coin came up heads: add a block - using_low_level_alloc = true; - block_desc.len = rand() & 0x3fff; - block_desc.ptr = - reinterpret_cast( - arena == 0 - ? LowLevelAlloc::Alloc(block_desc.len) - : LowLevelAlloc::AllocWithArena(block_desc.len, arena)); - using_low_level_alloc = false; - RandomizeBlockDesc(&block_desc); - rnd = rand(); - it = allocated.find(rnd); - if (it != allocated.end()) { - CheckBlockDesc(it->second); - using_low_level_alloc = true; - LowLevelAlloc::Free(it->second.ptr); - using_low_level_alloc = false; - it->second = block_desc; - } else { - allocated[rnd] = block_desc; - } - break; - case 1: // coin came up tails: remove a block - it = allocated.begin(); - if (it != allocated.end()) { - CheckBlockDesc(it->second); - using_low_level_alloc = true; - LowLevelAlloc::Free(it->second.ptr); - using_low_level_alloc = false; - allocated.erase(it); - } - break; - } - } - // remove all remaining blocks - while ((it = allocated.begin()) != allocated.end()) { - CheckBlockDesc(it->second); - using_low_level_alloc = true; - LowLevelAlloc::Free(it->second.ptr); - using_low_level_alloc = false; - allocated.erase(it); - } - if (use_new_arena) { - TEST_ASSERT(LowLevelAlloc::DeleteArena(arena)); - } -} -// LowLevelAlloc is designed to be safe to call before main(). -static struct BeforeMain { - BeforeMain() { - Test(false, false, 50000); - Test(true, false, 50000); - Test(true, true, 50000); - } -} before_main; - -} // namespace -} // namespace base_internal -} // namespace absl - -int main(int argc, char *argv[]) { - // The actual test runs in the global constructor of `before_main`. - printf("PASS\n"); - return 0; -} diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/sysinfo_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/sysinfo_test.cc deleted file mode 100644 index e0d9aab..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/sysinfo_test.cc +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/base/internal/sysinfo.h" - -#ifndef _WIN32 -#include -#include -#endif - -#include // NOLINT(build/c++11) -#include -#include - -#include "gtest/gtest.h" -#include "absl/synchronization/barrier.h" -#include "absl/synchronization/mutex.h" - -namespace absl { -namespace base_internal { -namespace { - -TEST(SysinfoTest, NumCPUs) { - EXPECT_NE(NumCPUs(), 0) - << "NumCPUs() should not have the default value of 0"; -} - -TEST(SysinfoTest, NominalCPUFrequency) { -#if !(defined(__aarch64__) && defined(__linux__)) - EXPECT_GE(NominalCPUFrequency(), 1000.0) - << "NominalCPUFrequency() did not return a reasonable value"; -#else - // TODO(absl-team): Aarch64 cannot read the CPU frequency from sysfs, so we - // get back 1.0. Fix once the value is available. - EXPECT_EQ(NominalCPUFrequency(), 1.0) - << "CPU frequency detection was fixed! Please update unittest."; -#endif -} - -TEST(SysinfoTest, GetTID) { - EXPECT_EQ(GetTID(), GetTID()); // Basic compile and equality test. -#ifdef __native_client__ - // Native Client has a race condition bug that leads to memory - // exaustion when repeatedly creating and joining threads. - // https://bugs.chromium.org/p/nativeclient/issues/detail?id=1027 - return; -#endif - // Test that TIDs are unique to each thread. - // Uses a few loops to exercise implementations that reallocate IDs. - for (int i = 0; i < 32; ++i) { - constexpr int kNumThreads = 64; - Barrier all_threads_done(kNumThreads); - std::vector threads; - - Mutex mutex; - std::unordered_set tids; - - for (int j = 0; j < kNumThreads; ++j) { - threads.push_back(std::thread([&]() { - pid_t id = GetTID(); - { - MutexLock lock(&mutex); - ASSERT_TRUE(tids.find(id) == tids.end()); - tids.insert(id); - } - // We can't simply join the threads here. The threads need to - // be alive otherwise the TID might have been reallocated to - // another live thread. - all_threads_done.Block(); - })); - } - for (auto& thread : threads) { - thread.join(); - } - } -} - -#ifdef __linux__ -TEST(SysinfoTest, LinuxGetTID) { - // On Linux, for the main thread, GetTID()==getpid() is guaranteed by the API. - EXPECT_EQ(GetTID(), getpid()); -} -#endif - -} // namespace -} // namespace base_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc deleted file mode 100644 index 242522b..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "benchmark/benchmark.h" -#include "absl/base/internal/thread_identity.h" -#include "absl/synchronization/internal/create_thread_identity.h" -#include "absl/synchronization/internal/per_thread_sem.h" - -namespace { - -void BM_SafeCurrentThreadIdentity(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize( - absl::synchronization_internal::GetOrCreateCurrentThreadIdentity()); - } -} -BENCHMARK(BM_SafeCurrentThreadIdentity); - -void BM_UnsafeCurrentThreadIdentity(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize( - absl::base_internal::CurrentThreadIdentityIfPresent()); - } -} -BENCHMARK(BM_UnsafeCurrentThreadIdentity); - -} // namespace diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/thread_identity_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/thread_identity_test.cc deleted file mode 100644 index ecb8af6..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/thread_identity_test.cc +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/base/internal/thread_identity.h" - -#include // NOLINT(build/c++11) -#include - -#include "gtest/gtest.h" -#include "absl/base/attributes.h" -#include "absl/base/internal/spinlock.h" -#include "absl/base/macros.h" -#include "absl/synchronization/internal/per_thread_sem.h" -#include "absl/synchronization/mutex.h" - -namespace absl { -namespace base_internal { -namespace { - -// protects num_identities_reused -static absl::base_internal::SpinLock map_lock( - absl::base_internal::kLinkerInitialized); -static int num_identities_reused; - -static const void* const kCheckNoIdentity = reinterpret_cast(1); - -static void TestThreadIdentityCurrent(const void* assert_no_identity) { - ThreadIdentity* identity; - - // We have to test this conditionally, because if the test framework relies - // on Abseil, then some previous action may have already allocated an - // identity. - if (assert_no_identity == kCheckNoIdentity) { - identity = CurrentThreadIdentityIfPresent(); - EXPECT_TRUE(identity == nullptr); - } - - identity = synchronization_internal::GetOrCreateCurrentThreadIdentity(); - EXPECT_TRUE(identity != nullptr); - ThreadIdentity* identity_no_init; - identity_no_init = CurrentThreadIdentityIfPresent(); - EXPECT_TRUE(identity == identity_no_init); - - // Check that per_thread_synch is correctly aligned. - EXPECT_EQ(0, reinterpret_cast(&identity->per_thread_synch) % - PerThreadSynch::kAlignment); - EXPECT_EQ(identity, identity->per_thread_synch.thread_identity()); - - absl::base_internal::SpinLockHolder l(&map_lock); - num_identities_reused++; -} - -TEST(ThreadIdentityTest, BasicIdentityWorks) { - // This tests for the main() thread. - TestThreadIdentityCurrent(nullptr); -} - -TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) { - // Now try the same basic test with multiple threads being created and - // destroyed. This makes sure that: - // - New threads are created without a ThreadIdentity. - // - We re-allocate ThreadIdentity objects from the free-list. - // - If a thread implementation chooses to recycle threads, that - // correct re-initialization occurs. - static const int kNumLoops = 3; - static const int kNumThreads = 400; - for (int iter = 0; iter < kNumLoops; iter++) { - std::vector threads; - for (int i = 0; i < kNumThreads; ++i) { - threads.push_back( - std::thread(TestThreadIdentityCurrent, kCheckNoIdentity)); - } - for (auto& thread : threads) { - thread.join(); - } - } - - // We should have recycled ThreadIdentity objects above; while (external) - // library threads allocating their own identities may preclude some - // reuse, we should have sufficient repetitions to exclude this. - EXPECT_LT(kNumThreads, num_identities_reused); -} - -TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) { - // This test repeatly creates and joins a series of threads, each of - // which acquires and releases shared Mutex locks. This verifies - // Mutex operations work correctly under a reused - // ThreadIdentity. Note that the most likely failure mode of this - // test is a crash or deadlock. - static const int kNumLoops = 10; - static const int kNumThreads = 12; - static const int kNumMutexes = 3; - static const int kNumLockLoops = 5; - - Mutex mutexes[kNumMutexes]; - for (int iter = 0; iter < kNumLoops; ++iter) { - std::vector threads; - for (int thread = 0; thread < kNumThreads; ++thread) { - threads.push_back(std::thread([&]() { - for (int l = 0; l < kNumLockLoops; ++l) { - for (int m = 0; m < kNumMutexes; ++m) { - MutexLock lock(&mutexes[m]); - } - } - })); - } - for (auto& thread : threads) { - thread.join(); - } - } -} - -} // namespace -} // namespace base_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/unaligned_access.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/unaligned_access.h deleted file mode 100644 index f9df3b7..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/internal/unaligned_access.h +++ /dev/null @@ -1,317 +0,0 @@ -// -// Copyright 2017 The Abseil Authors. -// -// 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. -// - -#ifndef ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_ -#define ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_ - -#include -#include - -#include "absl/base/attributes.h" - -// unaligned APIs - -// Portable handling of unaligned loads, stores, and copies. -// On some platforms, like ARM, the copy functions can be more efficient -// then a load and a store. -// -// It is possible to implement all of these these using constant-length memcpy -// calls, which is portable and will usually be inlined into simple loads and -// stores if the architecture supports it. However, such inlining usually -// happens in a pass that's quite late in compilation, which means the resulting -// loads and stores cannot participate in many other optimizations, leading to -// overall worse code. - -// The unaligned API is C++ only. The declarations use C++ features -// (namespaces, inline) which are absent or incompatible in C. -#if defined(__cplusplus) - -#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\ - defined(MEMORY_SANITIZER) -// Consider we have an unaligned load/store of 4 bytes from address 0x...05. -// AddressSanitizer will treat it as a 3-byte access to the range 05:07 and -// will miss a bug if 08 is the first unaddressable byte. -// ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will -// miss a race between this access and some other accesses to 08. -// MemorySanitizer will correctly propagate the shadow on unaligned stores -// and correctly report bugs on unaligned loads, but it may not properly -// update and report the origin of the uninitialized memory. -// For all three tools, replacing an unaligned access with a tool-specific -// callback solves the problem. - -// Make sure uint16_t/uint32_t/uint64_t are defined. -#include - -extern "C" { -uint16_t __sanitizer_unaligned_load16(const void *p); -uint32_t __sanitizer_unaligned_load32(const void *p); -uint64_t __sanitizer_unaligned_load64(const void *p); -void __sanitizer_unaligned_store16(void *p, uint16_t v); -void __sanitizer_unaligned_store32(void *p, uint32_t v); -void __sanitizer_unaligned_store64(void *p, uint64_t v); -} // extern "C" - -namespace absl { -namespace base_internal { - -inline uint16_t UnalignedLoad16(const void *p) { - return __sanitizer_unaligned_load16(p); -} - -inline uint32_t UnalignedLoad32(const void *p) { - return __sanitizer_unaligned_load32(p); -} - -inline uint64_t UnalignedLoad64(const void *p) { - return __sanitizer_unaligned_load64(p); -} - -inline void UnalignedStore16(void *p, uint16_t v) { - __sanitizer_unaligned_store16(p, v); -} - -inline void UnalignedStore32(void *p, uint32_t v) { - __sanitizer_unaligned_store32(p, v); -} - -inline void UnalignedStore64(void *p, uint64_t v) { - __sanitizer_unaligned_store64(p, v); -} - -} // namespace base_internal -} // namespace absl - -#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ - (absl::base_internal::UnalignedLoad16(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ - (absl::base_internal::UnalignedLoad32(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ - (absl::base_internal::UnalignedLoad64(_p)) - -#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ - (absl::base_internal::UnalignedStore16(_p, _val)) -#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ - (absl::base_internal::UnalignedStore32(_p, _val)) -#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ - (absl::base_internal::UnalignedStore64(_p, _val)) - -#elif defined(UNDEFINED_BEHAVIOR_SANITIZER) - -namespace absl { -namespace base_internal { - -inline uint16_t UnalignedLoad16(const void *p) { - uint16_t t; - memcpy(&t, p, sizeof t); - return t; -} - -inline uint32_t UnalignedLoad32(const void *p) { - uint32_t t; - memcpy(&t, p, sizeof t); - return t; -} - -inline uint64_t UnalignedLoad64(const void *p) { - uint64_t t; - memcpy(&t, p, sizeof t); - return t; -} - -inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); } - -inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); } - -inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } - -} // namespace base_internal -} // namespace absl - -#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ - (absl::base_internal::UnalignedLoad16(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ - (absl::base_internal::UnalignedLoad32(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ - (absl::base_internal::UnalignedLoad64(_p)) - -#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ - (absl::base_internal::UnalignedStore16(_p, _val)) -#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ - (absl::base_internal::UnalignedStore32(_p, _val)) -#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ - (absl::base_internal::UnalignedStore64(_p, _val)) - -#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \ - defined(_M_IX86) || defined(__ppc__) || defined(__PPC__) || \ - defined(__ppc64__) || defined(__PPC64__) - -// x86 and x86-64 can perform unaligned loads/stores directly; -// modern PowerPC hardware can also do unaligned integer loads and stores; -// but note: the FPU still sends unaligned loads and stores to a trap handler! - -#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ - (*reinterpret_cast(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ - (*reinterpret_cast(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ - (*reinterpret_cast(_p)) - -#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ - (*reinterpret_cast(_p) = (_val)) -#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ - (*reinterpret_cast(_p) = (_val)) -#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ - (*reinterpret_cast(_p) = (_val)) - -#elif defined(__arm__) && \ - !defined(__ARM_ARCH_5__) && \ - !defined(__ARM_ARCH_5T__) && \ - !defined(__ARM_ARCH_5TE__) && \ - !defined(__ARM_ARCH_5TEJ__) && \ - !defined(__ARM_ARCH_6__) && \ - !defined(__ARM_ARCH_6J__) && \ - !defined(__ARM_ARCH_6K__) && \ - !defined(__ARM_ARCH_6Z__) && \ - !defined(__ARM_ARCH_6ZK__) && \ - !defined(__ARM_ARCH_6T2__) - - -// ARMv7 and newer support native unaligned accesses, but only of 16-bit -// and 32-bit values (not 64-bit); older versions either raise a fatal signal, -// do an unaligned read and rotate the words around a bit, or do the reads very -// slowly (trip through kernel mode). There's no simple #define that says just -// "ARMv7 or higher", so we have to filter away all ARMv5 and ARMv6 -// sub-architectures. Newer gcc (>= 4.6) set an __ARM_FEATURE_ALIGNED #define, -// so in time, maybe we can move on to that. -// -// This is a mess, but there's not much we can do about it. -// -// To further complicate matters, only LDR instructions (single reads) are -// allowed to be unaligned, not LDRD (two reads) or LDM (many reads). Unless we -// explicitly tell the compiler that these accesses can be unaligned, it can and -// will combine accesses. On armcc, the way to signal this is done by accessing -// through the type (uint32_t __packed *), but GCC has no such attribute -// (it ignores __attribute__((packed)) on individual variables). However, -// we can tell it that a _struct_ is unaligned, which has the same effect, -// so we do that. - -namespace absl { -namespace base_internal { - -struct Unaligned16Struct { - uint16_t value; - uint8_t dummy; // To make the size non-power-of-two. -} ABSL_ATTRIBUTE_PACKED; - -struct Unaligned32Struct { - uint32_t value; - uint8_t dummy; // To make the size non-power-of-two. -} ABSL_ATTRIBUTE_PACKED; - -} // namespace base_internal -} // namespace absl - -#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ - ((reinterpret_cast(_p)) \ - ->value) -#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ - ((reinterpret_cast(_p)) \ - ->value) - -#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ - ((reinterpret_cast< ::absl::base_internal::Unaligned16Struct *>(_p)) \ - ->value = (_val)) -#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ - ((reinterpret_cast< ::absl::base_internal::Unaligned32Struct *>(_p)) \ - ->value = (_val)) - -namespace absl { -namespace base_internal { - -inline uint64_t UnalignedLoad64(const void *p) { - uint64_t t; - memcpy(&t, p, sizeof t); - return t; -} - -inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } - -} // namespace base_internal -} // namespace absl - -#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ - (absl::base_internal::UnalignedLoad64(_p)) -#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ - (absl::base_internal::UnalignedStore64(_p, _val)) - -#else - -// ABSL_INTERNAL_NEED_ALIGNED_LOADS is defined when the underlying platform -// doesn't support unaligned access. -#define ABSL_INTERNAL_NEED_ALIGNED_LOADS - -// These functions are provided for architectures that don't support -// unaligned loads and stores. - -namespace absl { -namespace base_internal { - -inline uint16_t UnalignedLoad16(const void *p) { - uint16_t t; - memcpy(&t, p, sizeof t); - return t; -} - -inline uint32_t UnalignedLoad32(const void *p) { - uint32_t t; - memcpy(&t, p, sizeof t); - return t; -} - -inline uint64_t UnalignedLoad64(const void *p) { - uint64_t t; - memcpy(&t, p, sizeof t); - return t; -} - -inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); } - -inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); } - -inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } - -} // namespace base_internal -} // namespace absl - -#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ - (absl::base_internal::UnalignedLoad16(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ - (absl::base_internal::UnalignedLoad32(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ - (absl::base_internal::UnalignedLoad64(_p)) - -#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ - (absl::base_internal::UnalignedStore16(_p, _val)) -#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ - (absl::base_internal::UnalignedStore32(_p, _val)) -#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ - (absl::base_internal::UnalignedStore64(_p, _val)) - -#endif - -#endif // defined(__cplusplus), end of unaligned API - -#endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/invoke_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/invoke_test.cc deleted file mode 100644 index 466bf11..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/invoke_test.cc +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/base/internal/invoke.h" - -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/memory/memory.h" -#include "absl/strings/str_cat.h" - -namespace absl { -namespace base_internal { -namespace { - -int Function(int a, int b) { return a - b; } - -int Sink(std::unique_ptr p) { - return *p; -} - -std::unique_ptr Factory(int n) { - return make_unique(n); -} - -void NoOp() {} - -struct ConstFunctor { - int operator()(int a, int b) const { return a - b; } -}; - -struct MutableFunctor { - int operator()(int a, int b) { return a - b; } -}; - -struct EphemeralFunctor { - int operator()(int a, int b) && { return a - b; } -}; - -struct OverloadedFunctor { - template - std::string operator()(const Args&... args) & { - return StrCat("&", args...); - } - template - std::string operator()(const Args&... args) const& { - return StrCat("const&", args...); - } - template - std::string operator()(const Args&... args) && { - return StrCat("&&", args...); - } -}; - -struct Class { - int Method(int a, int b) { return a - b; } - int ConstMethod(int a, int b) const { return a - b; } - - int member; -}; - -struct FlipFlop { - int ConstMethod() const { return member; } - FlipFlop operator*() const { return {-member}; } - - int member; -}; - -// CallMaybeWithArg(f) resolves either to Invoke(f) or Invoke(f, 42), depending -// on which one is valid. -template -decltype(Invoke(std::declval())) CallMaybeWithArg(const F& f) { - return Invoke(f); -} - -template -decltype(Invoke(std::declval(), 42)) CallMaybeWithArg(const F& f) { - return Invoke(f, 42); -} - -TEST(InvokeTest, Function) { - EXPECT_EQ(1, Invoke(Function, 3, 2)); - EXPECT_EQ(1, Invoke(&Function, 3, 2)); -} - -TEST(InvokeTest, NonCopyableArgument) { - EXPECT_EQ(42, Invoke(Sink, make_unique(42))); -} - -TEST(InvokeTest, NonCopyableResult) { - EXPECT_THAT(Invoke(Factory, 42), ::testing::Pointee(42)); -} - -TEST(InvokeTest, VoidResult) { - Invoke(NoOp); -} - -TEST(InvokeTest, ConstFunctor) { - EXPECT_EQ(1, Invoke(ConstFunctor(), 3, 2)); -} - -TEST(InvokeTest, MutableFunctor) { - MutableFunctor f; - EXPECT_EQ(1, Invoke(f, 3, 2)); - EXPECT_EQ(1, Invoke(MutableFunctor(), 3, 2)); -} - -TEST(InvokeTest, EphemeralFunctor) { - EphemeralFunctor f; - EXPECT_EQ(1, Invoke(std::move(f), 3, 2)); - EXPECT_EQ(1, Invoke(EphemeralFunctor(), 3, 2)); -} - -TEST(InvokeTest, OverloadedFunctor) { - OverloadedFunctor f; - const OverloadedFunctor& cf = f; - - EXPECT_EQ("&", Invoke(f)); - EXPECT_EQ("& 42", Invoke(f, " 42")); - - EXPECT_EQ("const&", Invoke(cf)); - EXPECT_EQ("const& 42", Invoke(cf, " 42")); - - EXPECT_EQ("&&", Invoke(std::move(f))); - EXPECT_EQ("&& 42", Invoke(std::move(f), " 42")); -} - -TEST(InvokeTest, ReferenceWrapper) { - ConstFunctor cf; - MutableFunctor mf; - EXPECT_EQ(1, Invoke(std::cref(cf), 3, 2)); - EXPECT_EQ(1, Invoke(std::ref(cf), 3, 2)); - EXPECT_EQ(1, Invoke(std::ref(mf), 3, 2)); -} - -TEST(InvokeTest, MemberFunction) { - std::unique_ptr p(new Class); - std::unique_ptr cp(new Class); - EXPECT_EQ(1, Invoke(&Class::Method, p, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::Method, p.get(), 3, 2)); - - EXPECT_EQ(1, Invoke(&Class::ConstMethod, p, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::ConstMethod, p.get(), 3, 2)); - EXPECT_EQ(1, Invoke(&Class::ConstMethod, *p, 3, 2)); - - EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp.get(), 3, 2)); - EXPECT_EQ(1, Invoke(&Class::ConstMethod, *cp, 3, 2)); - - EXPECT_EQ(1, Invoke(&Class::Method, make_unique(), 3, 2)); - EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique(), 3, 2)); - EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique(), 3, 2)); -} - -TEST(InvokeTest, DataMember) { - std::unique_ptr p(new Class{42}); - std::unique_ptr cp(new Class{42}); - EXPECT_EQ(42, Invoke(&Class::member, p)); - EXPECT_EQ(42, Invoke(&Class::member, *p)); - EXPECT_EQ(42, Invoke(&Class::member, p.get())); - - Invoke(&Class::member, p) = 42; - Invoke(&Class::member, p.get()) = 42; - - EXPECT_EQ(42, Invoke(&Class::member, cp)); - EXPECT_EQ(42, Invoke(&Class::member, *cp)); - EXPECT_EQ(42, Invoke(&Class::member, cp.get())); -} - -TEST(InvokeTest, FlipFlop) { - FlipFlop obj = {42}; - // This call could resolve to (obj.*&FlipFlop::ConstMethod)() or - // ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former. - EXPECT_EQ(42, Invoke(&FlipFlop::ConstMethod, obj)); - EXPECT_EQ(42, Invoke(&FlipFlop::member, obj)); -} - -TEST(InvokeTest, SfinaeFriendly) { - CallMaybeWithArg(NoOp); - EXPECT_THAT(CallMaybeWithArg(Factory), ::testing::Pointee(42)); -} - -} // namespace -} // namespace base_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/raw_logging_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/raw_logging_test.cc deleted file mode 100644 index b21cf65..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/raw_logging_test.cc +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -// This test serves primarily as a compilation test for base/raw_logging.h. -// Raw logging testing is covered by logging_unittest.cc, which is not as -// portable as this test. - -#include "absl/base/internal/raw_logging.h" - -#include - -#include "gtest/gtest.h" -#include "absl/strings/str_cat.h" - -namespace { - -TEST(RawLoggingCompilationTest, Log) { - ABSL_RAW_LOG(INFO, "RAW INFO: %d", 1); - ABSL_RAW_LOG(INFO, "RAW INFO: %d %d", 1, 2); - ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d", 1, 2, 3); - ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d %d", 1, 2, 3, 4); - ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d %d %d", 1, 2, 3, 4, 5); - ABSL_RAW_LOG(WARNING, "RAW WARNING: %d", 1); - ABSL_RAW_LOG(ERROR, "RAW ERROR: %d", 1); -} - -TEST(RawLoggingCompilationTest, PassingCheck) { - ABSL_RAW_CHECK(true, "RAW CHECK"); -} - -// Not all platforms support output from raw log, so we don't verify any -// particular output for RAW check failures (expecting the empty string -// accomplishes this). This test is primarily a compilation test, but we -// are verifying process death when EXPECT_DEATH works for a platform. -const char kExpectedDeathOutput[] = ""; - -TEST(RawLoggingDeathTest, FailingCheck) { - EXPECT_DEATH_IF_SUPPORTED(ABSL_RAW_CHECK(1 == 0, "explanation"), - kExpectedDeathOutput); -} - -TEST(RawLoggingDeathTest, LogFatal) { - EXPECT_DEATH_IF_SUPPORTED(ABSL_RAW_LOG(FATAL, "my dog has fleas"), - kExpectedDeathOutput); -} - -TEST(InternalLog, CompilationTest) { - ABSL_INTERNAL_LOG(INFO, "Internal Log"); - std::string log_msg = "Internal Log"; - ABSL_INTERNAL_LOG(INFO, log_msg); - - ABSL_INTERNAL_LOG(INFO, log_msg + " 2"); - - float d = 1.1f; - ABSL_INTERNAL_LOG(INFO, absl::StrCat("Internal log ", 3, " + ", d)); -} - -TEST(InternalLogDeathTest, FailingCheck) { - EXPECT_DEATH_IF_SUPPORTED(ABSL_INTERNAL_CHECK(1 == 0, "explanation"), - kExpectedDeathOutput); -} - -TEST(InternalLogDeathTest, LogFatal) { - EXPECT_DEATH_IF_SUPPORTED(ABSL_INTERNAL_LOG(FATAL, "my dog has fleas"), - kExpectedDeathOutput); -} - -} // namespace diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/spinlock_test_common.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/spinlock_test_common.cc deleted file mode 100644 index 1b50884..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/spinlock_test_common.cc +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -// A bunch of threads repeatedly hash an array of ints protected by a -// spinlock. If the spinlock is working properly, all elements of the -// array should be equal at the end of the test. - -#include -#include -#include -#include // NOLINT(build/c++11) -#include - -#include "gtest/gtest.h" -#include "absl/base/attributes.h" -#include "absl/base/internal/low_level_scheduling.h" -#include "absl/base/internal/scheduling_mode.h" -#include "absl/base/internal/spinlock.h" -#include "absl/base/internal/sysinfo.h" -#include "absl/base/macros.h" -#include "absl/synchronization/blocking_counter.h" -#include "absl/synchronization/notification.h" - -constexpr int32_t kNumThreads = 10; -constexpr int32_t kIters = 1000; - -namespace absl { -namespace base_internal { - -// This is defined outside of anonymous namespace so that it can be -// a friend of SpinLock to access protected methods for testing. -struct SpinLockTest { - static uint32_t EncodeWaitCycles(int64_t wait_start_time, - int64_t wait_end_time) { - return SpinLock::EncodeWaitCycles(wait_start_time, wait_end_time); - } - static uint64_t DecodeWaitCycles(uint32_t lock_value) { - return SpinLock::DecodeWaitCycles(lock_value); - } -}; - -namespace { - -static constexpr int kArrayLength = 10; -static uint32_t values[kArrayLength]; -static SpinLock static_spinlock(base_internal::kLinkerInitialized); -static SpinLock static_cooperative_spinlock( - base_internal::kLinkerInitialized, - base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL); -static SpinLock static_noncooperative_spinlock( - base_internal::kLinkerInitialized, base_internal::SCHEDULE_KERNEL_ONLY); - - -// Simple integer hash function based on the public domain lookup2 hash. -// http://burtleburtle.net/bob/c/lookup2.c -static uint32_t Hash32(uint32_t a, uint32_t c) { - uint32_t b = 0x9e3779b9UL; // The golden ratio; an arbitrary value. - a -= b; a -= c; a ^= (c >> 13); - b -= c; b -= a; b ^= (a << 8); - c -= a; c -= b; c ^= (b >> 13); - a -= b; a -= c; a ^= (c >> 12); - b -= c; b -= a; b ^= (a << 16); - c -= a; c -= b; c ^= (b >> 5); - a -= b; a -= c; a ^= (c >> 3); - b -= c; b -= a; b ^= (a << 10); - c -= a; c -= b; c ^= (b >> 15); - return c; -} - -static void TestFunction(int thread_salt, SpinLock* spinlock) { - for (int i = 0; i < kIters; i++) { - SpinLockHolder h(spinlock); - for (int j = 0; j < kArrayLength; j++) { - const int index = (j + thread_salt) % kArrayLength; - values[index] = Hash32(values[index], thread_salt); - std::this_thread::yield(); - } - } -} - -static void ThreadedTest(SpinLock* spinlock) { - std::vector threads; - for (int i = 0; i < kNumThreads; ++i) { - threads.push_back(std::thread(TestFunction, i, spinlock)); - } - for (auto& thread : threads) { - thread.join(); - } - - SpinLockHolder h(spinlock); - for (int i = 1; i < kArrayLength; i++) { - EXPECT_EQ(values[0], values[i]); - } -} - -TEST(SpinLock, StackNonCooperativeDisablesScheduling) { - SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY); - spinlock.Lock(); - EXPECT_FALSE(base_internal::SchedulingGuard::ReschedulingIsAllowed()); - spinlock.Unlock(); -} - -TEST(SpinLock, StaticNonCooperativeDisablesScheduling) { - static_noncooperative_spinlock.Lock(); - EXPECT_FALSE(base_internal::SchedulingGuard::ReschedulingIsAllowed()); - static_noncooperative_spinlock.Unlock(); -} - -TEST(SpinLock, WaitCyclesEncoding) { - // These are implementation details not exported by SpinLock. - const int kProfileTimestampShift = 7; - const int kLockwordReservedShift = 3; - const uint32_t kSpinLockSleeper = 8; - - // We should be able to encode up to (1^kMaxCycleBits - 1) without clamping - // but the lower kProfileTimestampShift will be dropped. - const int kMaxCyclesShift = - 32 - kLockwordReservedShift + kProfileTimestampShift; - const uint64_t kMaxCycles = (int64_t{1} << kMaxCyclesShift) - 1; - - // These bits should be zero after encoding. - const uint32_t kLockwordReservedMask = (1 << kLockwordReservedShift) - 1; - - // These bits are dropped when wait cycles are encoded. - const uint64_t kProfileTimestampMask = (1 << kProfileTimestampShift) - 1; - - // Test a bunch of random values - std::default_random_engine generator; - // Shift to avoid overflow below. - std::uniform_int_distribution time_distribution( - 0, std::numeric_limits::max() >> 4); - std::uniform_int_distribution cycle_distribution(0, kMaxCycles); - - for (int i = 0; i < 100; i++) { - int64_t start_time = time_distribution(generator); - int64_t cycles = cycle_distribution(generator); - int64_t end_time = start_time + cycles; - uint32_t lock_value = SpinLockTest::EncodeWaitCycles(start_time, end_time); - EXPECT_EQ(0, lock_value & kLockwordReservedMask); - uint64_t decoded = SpinLockTest::DecodeWaitCycles(lock_value); - EXPECT_EQ(0, decoded & kProfileTimestampMask); - EXPECT_EQ(cycles & ~kProfileTimestampMask, decoded); - } - - // Test corner cases - int64_t start_time = time_distribution(generator); - EXPECT_EQ(0, SpinLockTest::EncodeWaitCycles(start_time, start_time)); - EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(0)); - EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(kLockwordReservedMask)); - EXPECT_EQ(kMaxCycles & ~kProfileTimestampMask, - SpinLockTest::DecodeWaitCycles(~kLockwordReservedMask)); - - // Check that we cannot produce kSpinLockSleeper during encoding. - int64_t sleeper_cycles = - kSpinLockSleeper << (kProfileTimestampShift - kLockwordReservedShift); - uint32_t sleeper_value = - SpinLockTest::EncodeWaitCycles(start_time, start_time + sleeper_cycles); - EXPECT_NE(sleeper_value, kSpinLockSleeper); - - // Test clamping - uint32_t max_value = - SpinLockTest::EncodeWaitCycles(start_time, start_time + kMaxCycles); - uint64_t max_value_decoded = SpinLockTest::DecodeWaitCycles(max_value); - uint64_t expected_max_value_decoded = kMaxCycles & ~kProfileTimestampMask; - EXPECT_EQ(expected_max_value_decoded, max_value_decoded); - - const int64_t step = (1 << kProfileTimestampShift); - uint32_t after_max_value = - SpinLockTest::EncodeWaitCycles(start_time, start_time + kMaxCycles + step); - uint64_t after_max_value_decoded = - SpinLockTest::DecodeWaitCycles(after_max_value); - EXPECT_EQ(expected_max_value_decoded, after_max_value_decoded); - - uint32_t before_max_value = SpinLockTest::EncodeWaitCycles( - start_time, start_time + kMaxCycles - step); - uint64_t before_max_value_decoded = - SpinLockTest::DecodeWaitCycles(before_max_value); - EXPECT_GT(expected_max_value_decoded, before_max_value_decoded); -} -TEST(SpinLockWithThreads, StaticSpinLock) { - ThreadedTest(&static_spinlock); -} -TEST(SpinLockWithThreads, StackSpinLock) { - SpinLock spinlock; - ThreadedTest(&spinlock); -} - -TEST(SpinLockWithThreads, StackCooperativeSpinLock) { - SpinLock spinlock(base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL); - ThreadedTest(&spinlock); -} - -TEST(SpinLockWithThreads, StackNonCooperativeSpinLock) { - SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY); - ThreadedTest(&spinlock); -} - -TEST(SpinLockWithThreads, StaticCooperativeSpinLock) { - ThreadedTest(&static_cooperative_spinlock); -} - -TEST(SpinLockWithThreads, StaticNonCooperativeSpinLock) { - ThreadedTest(&static_noncooperative_spinlock); -} - -TEST(SpinLockWithThreads, DoesNotDeadlock) { - struct Helper { - static void NotifyThenLock(Notification* locked, SpinLock* spinlock, - BlockingCounter* b) { - locked->WaitForNotification(); // Wait for LockThenWait() to hold "s". - b->DecrementCount(); - SpinLockHolder l(spinlock); - } - - static void LockThenWait(Notification* locked, SpinLock* spinlock, - BlockingCounter* b) { - SpinLockHolder l(spinlock); - locked->Notify(); - b->Wait(); - } - - static void DeadlockTest(SpinLock* spinlock, int num_spinners) { - Notification locked; - BlockingCounter counter(num_spinners); - std::vector threads; - - threads.push_back( - std::thread(Helper::LockThenWait, &locked, spinlock, &counter)); - for (int i = 0; i < num_spinners; ++i) { - threads.push_back( - std::thread(Helper::NotifyThenLock, &locked, spinlock, &counter)); - } - - for (auto& thread : threads) { - thread.join(); - } - } - }; - - SpinLock stack_cooperative_spinlock( - base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL); - SpinLock stack_noncooperative_spinlock(base_internal::SCHEDULE_KERNEL_ONLY); - Helper::DeadlockTest(&stack_cooperative_spinlock, - base_internal::NumCPUs() * 2); - Helper::DeadlockTest(&stack_noncooperative_spinlock, - base_internal::NumCPUs() * 2); - Helper::DeadlockTest(&static_cooperative_spinlock, - base_internal::NumCPUs() * 2); - Helper::DeadlockTest(&static_noncooperative_spinlock, - base_internal::NumCPUs() * 2); -} - -} // namespace -} // namespace base_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/thread_annotations.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/thread_annotations.h deleted file mode 100644 index 2241ace..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/thread_annotations.h +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. -// -// ----------------------------------------------------------------------------- -// File: thread_annotations.h -// ----------------------------------------------------------------------------- -// -// This header file contains macro definitions for thread safety annotations -// that allow developers to document the locking policies of multi-threaded -// code. The annotations can also help program analysis tools to identify -// potential thread safety issues. -// -// -// These annotations are implemented using compiler attributes. Using the macros -// defined here instead of raw attributes allow for portability and future -// compatibility. -// -// When referring to mutexes in the arguments of the attributes, you should -// use variable names or more complex expressions (e.g. my_object->mutex_) -// that evaluate to a concrete mutex object whenever possible. If the mutex -// you want to refer to is not in scope, you may use a member pointer -// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object. - -#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_ -#define ABSL_BASE_THREAD_ANNOTATIONS_H_ -#if defined(__clang__) -#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) -#else -#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op -#endif - -// GUARDED_BY() -// -// Documents if a shared field or global variable needs to be protected by a -// mutex. GUARDED_BY() allows the user to specify a particular mutex that -// should be held when accessing the annotated variable. -// -// Although this annotation (and PT_GUARDED_BY, below) cannot be applied to -// local variables, a local variable and its associated mutex can often be -// combined into a small class or struct, thereby allowing the annotation. -// -// Example: -// -// class Foo { -// Mutex mu_; -// int p1_ GUARDED_BY(mu_); -// ... -// }; -#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) - -// PT_GUARDED_BY() -// -// Documents if the memory location pointed to by a pointer should be guarded -// by a mutex when dereferencing the pointer. -// -// Example: -// class Foo { -// Mutex mu_; -// int *p1_ PT_GUARDED_BY(mu_); -// ... -// }; -// -// Note that a pointer variable to a shared memory location could itself be a -// shared variable. -// -// Example: -// -// // `q_`, guarded by `mu1_`, points to a shared memory location that is -// // guarded by `mu2_`: -// int *q_ GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_); -#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) - -// ACQUIRED_AFTER() / ACQUIRED_BEFORE() -// -// Documents the acquisition order between locks that can be held -// simultaneously by a thread. For any two locks that need to be annotated -// to establish an acquisition order, only one of them needs the annotation. -// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER -// and ACQUIRED_BEFORE.) -// -// As with GUARDED_BY, this is only applicable to mutexes that are shared -// fields or global variables. -// -// Example: -// -// Mutex m1_; -// Mutex m2_ ACQUIRED_AFTER(m1_); -#define ACQUIRED_AFTER(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) - -#define ACQUIRED_BEFORE(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) - -// EXCLUSIVE_LOCKS_REQUIRED() / SHARED_LOCKS_REQUIRED() -// -// Documents a function that expects a mutex to be held prior to entry. -// The mutex is expected to be held both on entry to, and exit from, the -// function. -// -// An exclusive lock allows read-write access to the guarded data member(s), and -// only one thread can acquire a lock exclusively at any one time. A shared lock -// allows read-only access, and any number of threads can acquire a shared lock -// concurrently. -// -// Generally, non-const methods should be annotated with -// EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with -// SHARED_LOCKS_REQUIRED. -// -// Example: -// -// Mutex mu1, mu2; -// int a GUARDED_BY(mu1); -// int b GUARDED_BY(mu2); -// -// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... } -// void bar() const SHARED_LOCKS_REQUIRED(mu1, mu2) { ... } -#define EXCLUSIVE_LOCKS_REQUIRED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) - -#define SHARED_LOCKS_REQUIRED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__)) - -// LOCKS_EXCLUDED() -// -// Documents the locks acquired in the body of the function. These locks -// cannot be held when calling this function (as Abseil's `Mutex` locks are -// non-reentrant). -#define LOCKS_EXCLUDED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) - -// LOCK_RETURNED() -// -// Documents a function that returns a mutex without acquiring it. For example, -// a public getter method that returns a pointer to a private mutex should -// be annotated with LOCK_RETURNED. -#define LOCK_RETURNED(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) - -// LOCKABLE -// -// Documents if a class/type is a lockable type (such as the `Mutex` class). -#define LOCKABLE \ - THREAD_ANNOTATION_ATTRIBUTE__(lockable) - -// SCOPED_LOCKABLE -// -// Documents if a class does RAII locking (such as the `MutexLock` class). -// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is -// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no -// arguments; the analysis will assume that the destructor unlocks whatever the -// constructor locked. -#define SCOPED_LOCKABLE \ - THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) - -// EXCLUSIVE_LOCK_FUNCTION() -// -// Documents functions that acquire a lock in the body of a function, and do -// not release it. -#define EXCLUSIVE_LOCK_FUNCTION(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__)) - -// SHARED_LOCK_FUNCTION() -// -// Documents functions that acquire a shared (reader) lock in the body of a -// function, and do not release it. -#define SHARED_LOCK_FUNCTION(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__)) - -// UNLOCK_FUNCTION() -// -// Documents functions that expect a lock to be held on entry to the function, -// and release it in the body of the function. -#define UNLOCK_FUNCTION(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__)) - -// EXCLUSIVE_TRYLOCK_FUNCTION() / SHARED_TRYLOCK_FUNCTION() -// -// Documents functions that try to acquire a lock, and return success or failure -// (or a non-boolean value that can be interpreted as a boolean). -// The first argument should be `true` for functions that return `true` on -// success, or `false` for functions that return `false` on success. The second -// argument specifies the mutex that is locked on success. If unspecified, this -// mutex is assumed to be `this`. -#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__)) - -#define SHARED_TRYLOCK_FUNCTION(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__)) - -// ASSERT_EXCLUSIVE_LOCK() / ASSERT_SHARED_LOCK() -// -// Documents functions that dynamically check to see if a lock is held, and fail -// if it is not held. -#define ASSERT_EXCLUSIVE_LOCK(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__)) - -#define ASSERT_SHARED_LOCK(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__)) - -// NO_THREAD_SAFETY_ANALYSIS -// -// Turns off thread safety checking within the body of a particular function. -// This annotation is used to mark functions that are known to be correct, but -// the locking behavior is more complicated than the analyzer can handle. -#define NO_THREAD_SAFETY_ANALYSIS \ - THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) - -//------------------------------------------------------------------------------ -// Tool-Supplied Annotations -//------------------------------------------------------------------------------ - -// TS_UNCHECKED should be placed around lock expressions that are not valid -// C++ syntax, but which are present for documentation purposes. These -// annotations will be ignored by the analysis. -#define TS_UNCHECKED(x) "" - -// TS_FIXME is used to mark lock expressions that are not valid C++ syntax. -// It is used by automated tools to mark and disable invalid expressions. -// The annotation should either be fixed, or changed to TS_UNCHECKED. -#define TS_FIXME(x) "" - -// Like NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of -// a particular function. However, this attribute is used to mark functions -// that are incorrect and need to be fixed. It is used by automated tools to -// avoid breaking the build when the analysis is updated. -// Code owners are expected to eventually fix the routine. -#define NO_THREAD_SAFETY_ANALYSIS_FIXME NO_THREAD_SAFETY_ANALYSIS - -// Similar to NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a GUARDED_BY -// annotation that needs to be fixed, because it is producing thread safety -// warning. It disables the GUARDED_BY. -#define GUARDED_BY_FIXME(x) - -// Disables warnings for a single read operation. This can be used to avoid -// warnings when it is known that the read is not actually involved in a race, -// but the compiler cannot confirm that. -#define TS_UNCHECKED_READ(x) thread_safety_analysis::ts_unchecked_read(x) - - -namespace thread_safety_analysis { - -// Takes a reference to a guarded data member, and returns an unguarded -// reference. -template -inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS { - return v; -} - -template -inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS { - return v; -} - -} // namespace thread_safety_analysis - -#endif // ABSL_BASE_THREAD_ANNOTATIONS_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/throw_delegate_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/throw_delegate_test.cc deleted file mode 100644 index 0f15df0..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/base/throw_delegate_test.cc +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/base/internal/throw_delegate.h" - -#include -#include -#include - -#include "gtest/gtest.h" - -namespace { - -using absl::base_internal::ThrowStdLogicError; -using absl::base_internal::ThrowStdInvalidArgument; -using absl::base_internal::ThrowStdDomainError; -using absl::base_internal::ThrowStdLengthError; -using absl::base_internal::ThrowStdOutOfRange; -using absl::base_internal::ThrowStdRuntimeError; -using absl::base_internal::ThrowStdRangeError; -using absl::base_internal::ThrowStdOverflowError; -using absl::base_internal::ThrowStdUnderflowError; -using absl::base_internal::ThrowStdBadFunctionCall; -using absl::base_internal::ThrowStdBadAlloc; - -constexpr const char* what_arg = "The quick brown fox jumps over the lazy dog"; - -template -void ExpectThrowChar(void (*f)(const char*)) { - try { - f(what_arg); - FAIL() << "Didn't throw"; - } catch (const E& e) { - EXPECT_STREQ(e.what(), what_arg); - } -} - -template -void ExpectThrowString(void (*f)(const std::string&)) { - try { - f(what_arg); - FAIL() << "Didn't throw"; - } catch (const E& e) { - EXPECT_STREQ(e.what(), what_arg); - } -} - -template -void ExpectThrowNoWhat(void (*f)()) { - try { - f(); - FAIL() << "Didn't throw"; - } catch (const E& e) { - } -} - -TEST(ThrowHelper, Test) { - // Not using EXPECT_THROW because we want to check the .what() message too. - ExpectThrowChar(ThrowStdLogicError); - ExpectThrowChar(ThrowStdInvalidArgument); - ExpectThrowChar(ThrowStdDomainError); - ExpectThrowChar(ThrowStdLengthError); - ExpectThrowChar(ThrowStdOutOfRange); - ExpectThrowChar(ThrowStdRuntimeError); - ExpectThrowChar(ThrowStdRangeError); - ExpectThrowChar(ThrowStdOverflowError); - ExpectThrowChar(ThrowStdUnderflowError); - - ExpectThrowString(ThrowStdLogicError); - ExpectThrowString(ThrowStdInvalidArgument); - ExpectThrowString(ThrowStdDomainError); - ExpectThrowString(ThrowStdLengthError); - ExpectThrowString(ThrowStdOutOfRange); - ExpectThrowString(ThrowStdRuntimeError); - ExpectThrowString(ThrowStdRangeError); - ExpectThrowString(ThrowStdOverflowError); - ExpectThrowString(ThrowStdUnderflowError); - - ExpectThrowNoWhat(ThrowStdBadFunctionCall); - ExpectThrowNoWhat(ThrowStdBadAlloc); -} - -} // namespace diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/compiler_config_setting.bzl b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/compiler_config_setting.bzl deleted file mode 100644 index b77c4f5..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/compiler_config_setting.bzl +++ /dev/null @@ -1,39 +0,0 @@ -# -# Copyright 2018 The Abseil Authors. -# -# 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. -# - -"""Creates config_setting that allows selecting based on 'compiler' value.""" - -def create_llvm_config(name, visibility): - # The "do_not_use_tools_cpp_compiler_present" attribute exists to - # distinguish between older versions of Bazel that do not support - # "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do. - # In the future, the only way to select on the compiler will be through - # flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can - # be removed. - if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"): - native.config_setting( - name = name, - flag_values = { - "@bazel_tools//tools/cpp:compiler": "llvm", - }, - visibility = visibility, - ) - else: - native.config_setting( - name = name, - values = {"compiler": "llvm"}, - visibility = visibility, - ) diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/BUILD.bazel b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/BUILD.bazel deleted file mode 100644 index d75f891..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/BUILD.bazel +++ /dev/null @@ -1,646 +0,0 @@ -# -# Copyright 2017 The Abseil Authors. -# -# 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. -# - -load( - "//absl:copts.bzl", - "ABSL_DEFAULT_COPTS", - "ABSL_TEST_COPTS", - "ABSL_EXCEPTIONS_FLAG", - "ABSL_EXCEPTIONS_FLAG_LINKOPTS", -) - -package(default_visibility = ["//visibility:public"]) - -licenses(["notice"]) # Apache 2.0 - -cc_library( - name = "compressed_tuple", - hdrs = ["internal/compressed_tuple.h"], - copts = ABSL_DEFAULT_COPTS, - deps = [ - "//absl/utility", - ], -) - -cc_test( - name = "compressed_tuple_test", - srcs = ["internal/compressed_tuple_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":compressed_tuple", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "fixed_array", - hdrs = ["fixed_array.h"], - copts = ABSL_DEFAULT_COPTS, - deps = [ - ":compressed_tuple", - "//absl/algorithm", - "//absl/base:core_headers", - "//absl/base:dynamic_annotations", - "//absl/base:throw_delegate", - "//absl/memory", - ], -) - -cc_test( - name = "fixed_array_test", - srcs = ["fixed_array_test.cc"], - copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, - deps = [ - ":fixed_array", - "//absl/base:exception_testing", - "//absl/hash:hash_testing", - "//absl/memory", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "fixed_array_test_noexceptions", - srcs = ["fixed_array_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":fixed_array", - "//absl/base:exception_testing", - "//absl/hash:hash_testing", - "//absl/memory", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "fixed_array_exception_safety_test", - srcs = ["fixed_array_exception_safety_test.cc"], - copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, - deps = [ - ":fixed_array", - "//absl/base:exception_safety_testing", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "fixed_array_benchmark", - srcs = ["fixed_array_benchmark.cc"], - copts = ABSL_TEST_COPTS + ["$(STACK_FRAME_UNLIMITED)"], - tags = ["benchmark"], - deps = [ - ":fixed_array", - "@com_github_google_benchmark//:benchmark_main", - ], -) - -cc_library( - name = "inlined_vector", - hdrs = ["inlined_vector.h"], - copts = ABSL_DEFAULT_COPTS, - deps = [ - "//absl/algorithm", - "//absl/base:core_headers", - "//absl/base:throw_delegate", - "//absl/memory", - ], -) - -cc_test( - name = "inlined_vector_test", - srcs = ["inlined_vector_test.cc"], - copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, - deps = [ - ":inlined_vector", - ":test_instance_tracker", - "//absl/base", - "//absl/base:core_headers", - "//absl/base:exception_testing", - "//absl/hash:hash_testing", - "//absl/memory", - "//absl/strings", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "inlined_vector_test_noexceptions", - srcs = ["inlined_vector_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":inlined_vector", - ":test_instance_tracker", - "//absl/base", - "//absl/base:core_headers", - "//absl/base:exception_testing", - "//absl/hash:hash_testing", - "//absl/memory", - "//absl/strings", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "inlined_vector_benchmark", - srcs = ["inlined_vector_benchmark.cc"], - copts = ABSL_TEST_COPTS, - tags = ["benchmark"], - deps = [ - ":inlined_vector", - "//absl/base", - "//absl/strings", - "@com_github_google_benchmark//:benchmark_main", - ], -) - -cc_library( - name = "test_instance_tracker", - testonly = 1, - srcs = ["internal/test_instance_tracker.cc"], - hdrs = ["internal/test_instance_tracker.h"], - copts = ABSL_DEFAULT_COPTS, - visibility = [ - "//absl:__subpackages__", - ], -) - -cc_test( - name = "test_instance_tracker_test", - srcs = ["internal/test_instance_tracker_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":test_instance_tracker", - "@com_google_googletest//:gtest_main", - ], -) - -NOTEST_TAGS_NONMOBILE = [ - "no_test_darwin_x86_64", - "no_test_loonix", -] - -NOTEST_TAGS_MOBILE = [ - "no_test_android_arm", - "no_test_android_arm64", - "no_test_android_x86", - "no_test_ios_x86_64", -] - -NOTEST_TAGS = NOTEST_TAGS_MOBILE + NOTEST_TAGS_NONMOBILE - -cc_library( - name = "flat_hash_map", - hdrs = ["flat_hash_map.h"], - copts = ABSL_DEFAULT_COPTS, - deps = [ - ":container_memory", - ":hash_function_defaults", - ":raw_hash_map", - "//absl/memory", - ], -) - -cc_test( - name = "flat_hash_map_test", - srcs = ["flat_hash_map_test.cc"], - copts = ABSL_TEST_COPTS + ["-DUNORDERED_MAP_CXX17"], - tags = NOTEST_TAGS_NONMOBILE, - deps = [ - ":flat_hash_map", - ":hash_generator_testing", - ":unordered_map_constructor_test", - ":unordered_map_lookup_test", - ":unordered_map_modifiers_test", - "//absl/types:any", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "flat_hash_set", - hdrs = ["flat_hash_set.h"], - copts = ABSL_DEFAULT_COPTS, - deps = [ - ":container_memory", - ":hash_function_defaults", - ":raw_hash_set", - "//absl/base:core_headers", - "//absl/memory", - ], -) - -cc_test( - name = "flat_hash_set_test", - srcs = ["flat_hash_set_test.cc"], - copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"], - tags = NOTEST_TAGS_NONMOBILE, - deps = [ - ":flat_hash_set", - ":hash_generator_testing", - ":unordered_set_constructor_test", - ":unordered_set_lookup_test", - ":unordered_set_modifiers_test", - "//absl/memory", - "//absl/strings", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "node_hash_map", - hdrs = ["node_hash_map.h"], - copts = ABSL_DEFAULT_COPTS, - deps = [ - ":container_memory", - ":hash_function_defaults", - ":node_hash_policy", - ":raw_hash_map", - "//absl/memory", - ], -) - -cc_test( - name = "node_hash_map_test", - srcs = ["node_hash_map_test.cc"], - copts = ABSL_TEST_COPTS + ["-DUNORDERED_MAP_CXX17"], - tags = NOTEST_TAGS_NONMOBILE, - deps = [ - ":hash_generator_testing", - ":node_hash_map", - ":tracked", - ":unordered_map_constructor_test", - ":unordered_map_lookup_test", - ":unordered_map_modifiers_test", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "node_hash_set", - hdrs = ["node_hash_set.h"], - copts = ABSL_DEFAULT_COPTS, - deps = [ - ":hash_function_defaults", - ":node_hash_policy", - ":raw_hash_set", - "//absl/memory", - ], -) - -cc_test( - name = "node_hash_set_test", - srcs = ["node_hash_set_test.cc"], - copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"], - tags = NOTEST_TAGS_NONMOBILE, - deps = [ - ":hash_generator_testing", - ":node_hash_set", - ":unordered_set_constructor_test", - ":unordered_set_lookup_test", - ":unordered_set_modifiers_test", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "container_memory", - hdrs = ["internal/container_memory.h"], - copts = ABSL_DEFAULT_COPTS, - deps = [ - "//absl/memory", - "//absl/utility", - ], -) - -cc_test( - name = "container_memory_test", - srcs = ["internal/container_memory_test.cc"], - copts = ABSL_TEST_COPTS, - tags = NOTEST_TAGS_NONMOBILE, - deps = [ - ":container_memory", - "//absl/strings", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "hash_function_defaults", - hdrs = ["internal/hash_function_defaults.h"], - copts = ABSL_DEFAULT_COPTS, - deps = [ - "//absl/base:config", - "//absl/hash", - "//absl/strings", - ], -) - -cc_test( - name = "hash_function_defaults_test", - srcs = ["internal/hash_function_defaults_test.cc"], - copts = ABSL_TEST_COPTS, - tags = NOTEST_TAGS, - deps = [ - ":hash_function_defaults", - "//absl/hash", - "//absl/strings", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "hash_generator_testing", - testonly = 1, - srcs = ["internal/hash_generator_testing.cc"], - hdrs = ["internal/hash_generator_testing.h"], - copts = ABSL_TEST_COPTS, - deps = [ - ":hash_policy_testing", - "//absl/meta:type_traits", - "//absl/strings", - ], -) - -cc_library( - name = "hash_policy_testing", - testonly = 1, - hdrs = ["internal/hash_policy_testing.h"], - copts = ABSL_TEST_COPTS, - deps = [ - "//absl/hash", - "//absl/strings", - ], -) - -cc_test( - name = "hash_policy_testing_test", - srcs = ["internal/hash_policy_testing_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":hash_policy_testing", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "hash_policy_traits", - hdrs = ["internal/hash_policy_traits.h"], - copts = ABSL_DEFAULT_COPTS, - deps = ["//absl/meta:type_traits"], -) - -cc_test( - name = "hash_policy_traits_test", - srcs = ["internal/hash_policy_traits_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":hash_policy_traits", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "hashtable_debug", - hdrs = ["internal/hashtable_debug.h"], - copts = ABSL_DEFAULT_COPTS, - deps = [ - ":hashtable_debug_hooks", - ], -) - -cc_library( - name = "hashtable_debug_hooks", - hdrs = ["internal/hashtable_debug_hooks.h"], - copts = ABSL_DEFAULT_COPTS, -) - -cc_library( - name = "node_hash_policy", - hdrs = ["internal/node_hash_policy.h"], - copts = ABSL_DEFAULT_COPTS, -) - -cc_test( - name = "node_hash_policy_test", - srcs = ["internal/node_hash_policy_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":hash_policy_traits", - ":node_hash_policy", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "raw_hash_map", - hdrs = ["internal/raw_hash_map.h"], - copts = ABSL_DEFAULT_COPTS, - deps = [ - ":container_memory", - ":raw_hash_set", - ], -) - -cc_library( - name = "raw_hash_set", - srcs = ["internal/raw_hash_set.cc"], - hdrs = ["internal/raw_hash_set.h"], - copts = ABSL_DEFAULT_COPTS, - deps = [ - ":compressed_tuple", - ":container_memory", - ":hash_policy_traits", - ":hashtable_debug_hooks", - ":layout", - "//absl/base:bits", - "//absl/base:config", - "//absl/base:core_headers", - "//absl/base:endian", - "//absl/memory", - "//absl/meta:type_traits", - "//absl/types:optional", - "//absl/utility", - ], -) - -cc_test( - name = "raw_hash_set_test", - srcs = ["internal/raw_hash_set_test.cc"], - copts = ABSL_TEST_COPTS, - linkstatic = 1, - tags = NOTEST_TAGS, - deps = [ - ":container_memory", - ":hash_function_defaults", - ":hash_policy_testing", - ":hashtable_debug", - ":raw_hash_set", - "//absl/base", - "//absl/base:core_headers", - "//absl/strings", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "raw_hash_set_allocator_test", - size = "small", - srcs = ["internal/raw_hash_set_allocator_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":raw_hash_set", - ":tracked", - "//absl/base:core_headers", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "layout", - hdrs = ["internal/layout.h"], - copts = ABSL_DEFAULT_COPTS, - deps = [ - "//absl/base:core_headers", - "//absl/meta:type_traits", - "//absl/strings", - "//absl/types:span", - "//absl/utility", - ], -) - -cc_test( - name = "layout_test", - size = "small", - srcs = ["internal/layout_test.cc"], - copts = ABSL_TEST_COPTS, - tags = NOTEST_TAGS, - visibility = ["//visibility:private"], - deps = [ - ":layout", - "//absl/base", - "//absl/base:core_headers", - "//absl/types:span", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "tracked", - testonly = 1, - hdrs = ["internal/tracked.h"], - copts = ABSL_TEST_COPTS, -) - -cc_library( - name = "unordered_map_constructor_test", - testonly = 1, - hdrs = ["internal/unordered_map_constructor_test.h"], - copts = ABSL_TEST_COPTS, - deps = [ - ":hash_generator_testing", - ":hash_policy_testing", - "@com_google_googletest//:gtest", - ], -) - -cc_library( - name = "unordered_map_lookup_test", - testonly = 1, - hdrs = ["internal/unordered_map_lookup_test.h"], - copts = ABSL_TEST_COPTS, - deps = [ - ":hash_generator_testing", - ":hash_policy_testing", - "@com_google_googletest//:gtest", - ], -) - -cc_library( - name = "unordered_map_modifiers_test", - testonly = 1, - hdrs = ["internal/unordered_map_modifiers_test.h"], - copts = ABSL_TEST_COPTS, - deps = [ - ":hash_generator_testing", - ":hash_policy_testing", - "@com_google_googletest//:gtest", - ], -) - -cc_library( - name = "unordered_set_constructor_test", - testonly = 1, - hdrs = ["internal/unordered_set_constructor_test.h"], - copts = ABSL_TEST_COPTS, - deps = [ - ":hash_generator_testing", - ":hash_policy_testing", - "@com_google_googletest//:gtest", - ], -) - -cc_library( - name = "unordered_set_lookup_test", - testonly = 1, - hdrs = ["internal/unordered_set_lookup_test.h"], - copts = ABSL_TEST_COPTS, - deps = [ - ":hash_generator_testing", - ":hash_policy_testing", - "@com_google_googletest//:gtest", - ], -) - -cc_library( - name = "unordered_set_modifiers_test", - testonly = 1, - hdrs = ["internal/unordered_set_modifiers_test.h"], - copts = ABSL_TEST_COPTS, - deps = [ - ":hash_generator_testing", - ":hash_policy_testing", - "@com_google_googletest//:gtest", - ], -) - -cc_test( - name = "unordered_set_test", - srcs = ["internal/unordered_set_test.cc"], - copts = ABSL_TEST_COPTS, - tags = NOTEST_TAGS_NONMOBILE, - deps = [ - ":unordered_set_constructor_test", - ":unordered_set_lookup_test", - ":unordered_set_modifiers_test", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "unordered_map_test", - srcs = ["internal/unordered_map_test.cc"], - copts = ABSL_TEST_COPTS, - tags = NOTEST_TAGS_NONMOBILE, - deps = [ - ":unordered_map_constructor_test", - ":unordered_map_lookup_test", - ":unordered_map_modifiers_test", - "@com_google_googletest//:gtest_main", - ], -) diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/CMakeLists.txt b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/CMakeLists.txt deleted file mode 100644 index 72113e1..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/CMakeLists.txt +++ /dev/null @@ -1,177 +0,0 @@ -# -# Copyright 2017 The Abseil Authors. -# -# 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. -# - - -list(APPEND CONTAINER_PUBLIC_HEADERS - "fixed_array.h" - "flat_hash_map.h" - "flat_hash_set.h" - "inlined_vector.h" - "node_hash_map.h" - "node_hash_set.h" -) - - -list(APPEND CONTAINER_INTERNAL_HEADERS - "internal/compressed_tuple.h" - "internal/container_memory.h" - "internal/hash_function_defaults.h" - "internal/hash_generator_testing.h" - "internal/hash_policy_testing.h" - "internal/hash_policy_traits.h" - "internal/hashtable_debug.h" - "internal/layout.h" - "internal/node_hash_policy.h" - "internal/raw_hash_map.h" - "internal/raw_hash_set.h" - "internal/test_instance_tracker.h" - "internal/tracked.h" - "internal/unordered_map_constructor_test.h" - "internal/unordered_map_lookup_test.h" - "internal/unordered_map_modifiers_test.h" - "internal/unordered_set_constructor_test.h" - "internal/unordered_set_lookup_test.h" - "internal/unordered_set_modifiers_test.h" -) - - -absl_library( - TARGET - absl_container - SOURCES - "internal/raw_hash_set.cc" - EXPORT_NAME - container -) - -# -## TESTS -# - -list(APPEND TEST_INSTANCE_TRACKER_LIB_SRC - "internal/test_instance_tracker.cc" - ${CONTAINER_PUBLIC_HEADERS} - ${CONTAINER_INTERNAL_HEADERS} -) - - -absl_library( - TARGET - test_instance_tracker_lib - SOURCES - ${TEST_INSTANCE_TRACKER_LIB_SRC} - PUBLIC_LIBRARIES - absl::container -) - - - -# test fixed_array_test -set(FIXED_ARRAY_TEST_SRC "fixed_array_test.cc") -set(FIXED_ARRAY_TEST_PUBLIC_LIBRARIES absl::base absl_internal_throw_delegate test_instance_tracker_lib) - -absl_test( - TARGET - fixed_array_test - SOURCES - ${FIXED_ARRAY_TEST_SRC} - PUBLIC_LIBRARIES - ${FIXED_ARRAY_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS - ${ABSL_EXCEPTIONS_FLAG} -) - - - -absl_test( - TARGET - fixed_array_test_noexceptions - SOURCES - ${FIXED_ARRAY_TEST_SRC} - PUBLIC_LIBRARIES - ${FIXED_ARRAY_TEST_PUBLIC_LIBRARIES} -) - - -# test fixed_array_exception_safety_test -set(FIXED_ARRAY_EXCEPTION_SAFETY_TEST_SRC "fixed_array_exception_safety_test.cc") -set(FIXED_ARRAY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES - absl::container - absl_internal_exception_safety_testing -) - -absl_test( - TARGET - fixed_array_exception_safety_test - SOURCES - ${FIXED_ARRAY_EXCEPTION_SAFETY_TEST_SRC} - PUBLIC_LIBRARIES - ${FIXED_ARRAY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS - ${ABSL_EXCEPTIONS_FLAG} -) - - -# test inlined_vector_test -set(INLINED_VECTOR_TEST_SRC "inlined_vector_test.cc") -set(INLINED_VECTOR_TEST_PUBLIC_LIBRARIES absl::base absl_internal_throw_delegate test_instance_tracker_lib) - -absl_test( - TARGET - inlined_vector_test - SOURCES - ${INLINED_VECTOR_TEST_SRC} - PUBLIC_LIBRARIES - ${INLINED_VECTOR_TEST_PUBLIC_LIBRARIES} -) - -absl_test( - TARGET - inlined_vector_test_noexceptions - SOURCES - ${INLINED_VECTOR_TEST_SRC} - PUBLIC_LIBRARIES - ${INLINED_VECTOR_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS - ${ABSL_NOEXCEPTION_CXXFLAGS} -) - - -# test test_instance_tracker_test -set(TEST_INSTANCE_TRACKER_TEST_SRC "internal/test_instance_tracker_test.cc") -set(TEST_INSTANCE_TRACKER_TEST_PUBLIC_LIBRARIES absl::base absl_internal_throw_delegate test_instance_tracker_lib) - - -absl_test( - TARGET - test_instance_tracker_test - SOURCES - ${TEST_INSTANCE_TRACKER_TEST_SRC} - PUBLIC_LIBRARIES - ${TEST_INSTANCE_TRACKER_TEST_PUBLIC_LIBRARIES} -) - -absl_test( - TARGET - raw_hash_set_test - SOURCES - "internal/raw_hash_set_test.cc" - PUBLIC_LIBRARIES - absl::base - absl::hash - absl_internal_throw_delegate - test_instance_tracker_lib -) diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/fixed_array.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/fixed_array.h deleted file mode 100644 index 6da8441..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/fixed_array.h +++ /dev/null @@ -1,518 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. -// -// ----------------------------------------------------------------------------- -// File: fixed_array.h -// ----------------------------------------------------------------------------- -// -// A `FixedArray` represents a non-resizable array of `T` where the length of -// the array can be determined at run-time. It is a good replacement for -// non-standard and deprecated uses of `alloca()` and variable length arrays -// within the GCC extension. (See -// https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html). -// -// `FixedArray` allocates small arrays inline, keeping performance fast by -// avoiding heap operations. It also helps reduce the chances of -// accidentally overflowing your stack if large input is passed to -// your function. - -#ifndef ABSL_CONTAINER_FIXED_ARRAY_H_ -#define ABSL_CONTAINER_FIXED_ARRAY_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "absl/algorithm/algorithm.h" -#include "absl/base/dynamic_annotations.h" -#include "absl/base/internal/throw_delegate.h" -#include "absl/base/macros.h" -#include "absl/base/optimization.h" -#include "absl/base/port.h" -#include "absl/container/internal/compressed_tuple.h" -#include "absl/memory/memory.h" - -namespace absl { - -constexpr static auto kFixedArrayUseDefault = static_cast(-1); - -// ----------------------------------------------------------------------------- -// FixedArray -// ----------------------------------------------------------------------------- -// -// A `FixedArray` provides a run-time fixed-size array, allocating a small array -// inline for efficiency. -// -// Most users should not specify an `inline_elements` argument and let -// `FixedArray` automatically determine the number of elements -// to store inline based on `sizeof(T)`. If `inline_elements` is specified, the -// `FixedArray` implementation will use inline storage for arrays with a -// length <= `inline_elements`. -// -// Note that a `FixedArray` constructed with a `size_type` argument will -// default-initialize its values by leaving trivially constructible types -// uninitialized (e.g. int, int[4], double), and others default-constructed. -// This matches the behavior of c-style arrays and `std::array`, but not -// `std::vector`. -// -// Note that `FixedArray` does not provide a public allocator; if it requires a -// heap allocation, it will do so with global `::operator new[]()` and -// `::operator delete[]()`, even if T provides class-scope overrides for these -// operators. -template > -class FixedArray { - static_assert(!std::is_array::value || std::extent::value > 0, - "Arrays with unknown bounds cannot be used with FixedArray."); - - static constexpr size_t kInlineBytesDefault = 256; - - using AllocatorTraits = std::allocator_traits; - // std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17, - // but this seems to be mostly pedantic. - template - using EnableIfForwardIterator = absl::enable_if_t::iterator_category, - std::forward_iterator_tag>::value>; - static constexpr bool NoexceptCopyable() { - return std::is_nothrow_copy_constructible::value && - absl::allocator_is_nothrow::value; - } - static constexpr bool NoexceptMovable() { - return std::is_nothrow_move_constructible::value && - absl::allocator_is_nothrow::value; - } - static constexpr bool DefaultConstructorIsNonTrivial() { - return !absl::is_trivially_default_constructible::value; - } - - public: - using allocator_type = typename AllocatorTraits::allocator_type; - using value_type = typename allocator_type::value_type; - using pointer = typename allocator_type::pointer; - using const_pointer = typename allocator_type::const_pointer; - using reference = typename allocator_type::reference; - using const_reference = typename allocator_type::const_reference; - using size_type = typename allocator_type::size_type; - using difference_type = typename allocator_type::difference_type; - using iterator = pointer; - using const_iterator = const_pointer; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - - static constexpr size_type inline_elements = - (N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type) - : static_cast(N)); - - FixedArray( - const FixedArray& other, - const allocator_type& a = allocator_type()) noexcept(NoexceptCopyable()) - : FixedArray(other.begin(), other.end(), a) {} - - FixedArray( - FixedArray&& other, - const allocator_type& a = allocator_type()) noexcept(NoexceptMovable()) - : FixedArray(std::make_move_iterator(other.begin()), - std::make_move_iterator(other.end()), a) {} - - // Creates an array object that can store `n` elements. - // Note that trivially constructible elements will be uninitialized. - explicit FixedArray(size_type n, const allocator_type& a = allocator_type()) - : storage_(n, a) { - if (DefaultConstructorIsNonTrivial()) { - memory_internal::ConstructRange(storage_.alloc(), storage_.begin(), - storage_.end()); - } - } - - // Creates an array initialized with `n` copies of `val`. - FixedArray(size_type n, const value_type& val, - const allocator_type& a = allocator_type()) - : storage_(n, a) { - memory_internal::ConstructRange(storage_.alloc(), storage_.begin(), - storage_.end(), val); - } - - // Creates an array initialized with the size and contents of `init_list`. - FixedArray(std::initializer_list init_list, - const allocator_type& a = allocator_type()) - : FixedArray(init_list.begin(), init_list.end(), a) {} - - // Creates an array initialized with the elements from the input - // range. The array's size will always be `std::distance(first, last)`. - // REQUIRES: Iterator must be a forward_iterator or better. - template * = nullptr> - FixedArray(Iterator first, Iterator last, - const allocator_type& a = allocator_type()) - : storage_(std::distance(first, last), a) { - memory_internal::CopyRange(storage_.alloc(), storage_.begin(), first, last); - } - - ~FixedArray() noexcept { - for (auto* cur = storage_.begin(); cur != storage_.end(); ++cur) { - AllocatorTraits::destroy(storage_.alloc(), cur); - } - } - - // Assignments are deleted because they break the invariant that the size of a - // `FixedArray` never changes. - void operator=(FixedArray&&) = delete; - void operator=(const FixedArray&) = delete; - - // FixedArray::size() - // - // Returns the length of the fixed array. - size_type size() const { return storage_.size(); } - - // FixedArray::max_size() - // - // Returns the largest possible value of `std::distance(begin(), end())` for a - // `FixedArray`. This is equivalent to the most possible addressable bytes - // over the number of bytes taken by T. - constexpr size_type max_size() const { - return (std::numeric_limits::max)() / sizeof(value_type); - } - - // FixedArray::empty() - // - // Returns whether or not the fixed array is empty. - bool empty() const { return size() == 0; } - - // FixedArray::memsize() - // - // Returns the memory size of the fixed array in bytes. - size_t memsize() const { return size() * sizeof(value_type); } - - // FixedArray::data() - // - // Returns a const T* pointer to elements of the `FixedArray`. This pointer - // can be used to access (but not modify) the contained elements. - const_pointer data() const { return AsValueType(storage_.begin()); } - - // Overload of FixedArray::data() to return a T* pointer to elements of the - // fixed array. This pointer can be used to access and modify the contained - // elements. - pointer data() { return AsValueType(storage_.begin()); } - - // FixedArray::operator[] - // - // Returns a reference the ith element of the fixed array. - // REQUIRES: 0 <= i < size() - reference operator[](size_type i) { - assert(i < size()); - return data()[i]; - } - - // Overload of FixedArray::operator()[] to return a const reference to the - // ith element of the fixed array. - // REQUIRES: 0 <= i < size() - const_reference operator[](size_type i) const { - assert(i < size()); - return data()[i]; - } - - // FixedArray::at - // - // Bounds-checked access. Returns a reference to the ith element of the - // fiexed array, or throws std::out_of_range - reference at(size_type i) { - if (ABSL_PREDICT_FALSE(i >= size())) { - base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check"); - } - return data()[i]; - } - - // Overload of FixedArray::at() to return a const reference to the ith element - // of the fixed array. - const_reference at(size_type i) const { - if (ABSL_PREDICT_FALSE(i >= size())) { - base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check"); - } - return data()[i]; - } - - // FixedArray::front() - // - // Returns a reference to the first element of the fixed array. - reference front() { return *begin(); } - - // Overload of FixedArray::front() to return a reference to the first element - // of a fixed array of const values. - const_reference front() const { return *begin(); } - - // FixedArray::back() - // - // Returns a reference to the last element of the fixed array. - reference back() { return *(end() - 1); } - - // Overload of FixedArray::back() to return a reference to the last element - // of a fixed array of const values. - const_reference back() const { return *(end() - 1); } - - // FixedArray::begin() - // - // Returns an iterator to the beginning of the fixed array. - iterator begin() { return data(); } - - // Overload of FixedArray::begin() to return a const iterator to the - // beginning of the fixed array. - const_iterator begin() const { return data(); } - - // FixedArray::cbegin() - // - // Returns a const iterator to the beginning of the fixed array. - const_iterator cbegin() const { return begin(); } - - // FixedArray::end() - // - // Returns an iterator to the end of the fixed array. - iterator end() { return data() + size(); } - - // Overload of FixedArray::end() to return a const iterator to the end of the - // fixed array. - const_iterator end() const { return data() + size(); } - - // FixedArray::cend() - // - // Returns a const iterator to the end of the fixed array. - const_iterator cend() const { return end(); } - - // FixedArray::rbegin() - // - // Returns a reverse iterator from the end of the fixed array. - reverse_iterator rbegin() { return reverse_iterator(end()); } - - // Overload of FixedArray::rbegin() to return a const reverse iterator from - // the end of the fixed array. - const_reverse_iterator rbegin() const { - return const_reverse_iterator(end()); - } - - // FixedArray::crbegin() - // - // Returns a const reverse iterator from the end of the fixed array. - const_reverse_iterator crbegin() const { return rbegin(); } - - // FixedArray::rend() - // - // Returns a reverse iterator from the beginning of the fixed array. - reverse_iterator rend() { return reverse_iterator(begin()); } - - // Overload of FixedArray::rend() for returning a const reverse iterator - // from the beginning of the fixed array. - const_reverse_iterator rend() const { - return const_reverse_iterator(begin()); - } - - // FixedArray::crend() - // - // Returns a reverse iterator from the beginning of the fixed array. - const_reverse_iterator crend() const { return rend(); } - - // FixedArray::fill() - // - // Assigns the given `value` to all elements in the fixed array. - void fill(const value_type& val) { std::fill(begin(), end(), val); } - - // Relational operators. Equality operators are elementwise using - // `operator==`, while order operators order FixedArrays lexicographically. - friend bool operator==(const FixedArray& lhs, const FixedArray& rhs) { - return absl::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); - } - - friend bool operator!=(const FixedArray& lhs, const FixedArray& rhs) { - return !(lhs == rhs); - } - - friend bool operator<(const FixedArray& lhs, const FixedArray& rhs) { - return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), - rhs.end()); - } - - friend bool operator>(const FixedArray& lhs, const FixedArray& rhs) { - return rhs < lhs; - } - - friend bool operator<=(const FixedArray& lhs, const FixedArray& rhs) { - return !(rhs < lhs); - } - - friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs) { - return !(lhs < rhs); - } - - template - friend H AbslHashValue(H h, const FixedArray& v) { - return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()), - v.size()); - } - - private: - // StorageElement - // - // For FixedArrays with a C-style-array value_type, StorageElement is a POD - // wrapper struct called StorageElementWrapper that holds the value_type - // instance inside. This is needed for construction and destruction of the - // entire array regardless of how many dimensions it has. For all other cases, - // StorageElement is just an alias of value_type. - // - // Maintainer's Note: The simpler solution would be to simply wrap value_type - // in a struct whether it's an array or not. That causes some paranoid - // diagnostics to misfire, believing that 'data()' returns a pointer to a - // single element, rather than the packed array that it really is. - // e.g.: - // - // FixedArray buf(1); - // sprintf(buf.data(), "foo"); - // - // error: call to int __builtin___sprintf_chk(etc...) - // will always overflow destination buffer [-Werror] - // - template , - size_t InnerN = std::extent::value> - struct StorageElementWrapper { - InnerT array[InnerN]; - }; - - using StorageElement = - absl::conditional_t::value, - StorageElementWrapper, value_type>; - using StorageElementBuffer = - absl::aligned_storage_t; - - static pointer AsValueType(pointer ptr) { return ptr; } - static pointer AsValueType(StorageElementWrapper* ptr) { - return std::addressof(ptr->array); - } - - static_assert(sizeof(StorageElement) == sizeof(value_type), ""); - static_assert(alignof(StorageElement) == alignof(value_type), ""); - - struct NonEmptyInlinedStorage { - StorageElement* data() { - return reinterpret_cast(inlined_storage_.data()); - } - -#ifdef ADDRESS_SANITIZER - void* RedzoneBegin() { return &redzone_begin_; } - void* RedzoneEnd() { return &redzone_end_ + 1; } -#endif // ADDRESS_SANITIZER - - void AnnotateConstruct(size_type); - void AnnotateDestruct(size_type); - - ADDRESS_SANITIZER_REDZONE(redzone_begin_); - std::array inlined_storage_; - ADDRESS_SANITIZER_REDZONE(redzone_end_); - }; - - struct EmptyInlinedStorage { - StorageElement* data() { return nullptr; } - void AnnotateConstruct(size_type) {} - void AnnotateDestruct(size_type) {} - }; - - using InlinedStorage = - absl::conditional_t; - - // Storage - // - // An instance of Storage manages the inline and out-of-line memory for - // instances of FixedArray. This guarantees that even when construction of - // individual elements fails in the FixedArray constructor body, the - // destructor for Storage will still be called and out-of-line memory will be - // properly deallocated. - // - class Storage : public InlinedStorage { - public: - Storage(size_type n, const allocator_type& a) - : size_alloc_(n, a), data_(InitializeData()) {} - - ~Storage() noexcept { - if (UsingInlinedStorage(size())) { - InlinedStorage::AnnotateDestruct(size()); - } else { - AllocatorTraits::deallocate(alloc(), AsValueType(begin()), size()); - } - } - - size_type size() const { return size_alloc_.template get<0>(); } - StorageElement* begin() const { return data_; } - StorageElement* end() const { return begin() + size(); } - allocator_type& alloc() { - return size_alloc_.template get<1>(); - } - - private: - static bool UsingInlinedStorage(size_type n) { - return n <= inline_elements; - } - - StorageElement* InitializeData() { - if (UsingInlinedStorage(size())) { - InlinedStorage::AnnotateConstruct(size()); - return InlinedStorage::data(); - } else { - return reinterpret_cast( - AllocatorTraits::allocate(alloc(), size())); - } - } - - // `CompressedTuple` takes advantage of EBCO for stateless `allocator_type`s - container_internal::CompressedTuple size_alloc_; - StorageElement* data_; - }; - - Storage storage_; -}; - -template -constexpr size_t FixedArray::kInlineBytesDefault; - -template -constexpr typename FixedArray::size_type - FixedArray::inline_elements; - -template -void FixedArray::NonEmptyInlinedStorage::AnnotateConstruct( - typename FixedArray::size_type n) { -#ifdef ADDRESS_SANITIZER - if (!n) return; - ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(), data() + n); - ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(), RedzoneBegin()); -#endif // ADDRESS_SANITIZER - static_cast(n); // Mark used when not in asan mode -} - -template -void FixedArray::NonEmptyInlinedStorage::AnnotateDestruct( - typename FixedArray::size_type n) { -#ifdef ADDRESS_SANITIZER - if (!n) return; - ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n, RedzoneEnd()); - ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(), data()); -#endif // ADDRESS_SANITIZER - static_cast(n); // Mark used when not in asan mode -} -} // namespace absl -#endif // ABSL_CONTAINER_FIXED_ARRAY_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/fixed_array_benchmark.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/fixed_array_benchmark.cc deleted file mode 100644 index b4f0cf2..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/fixed_array_benchmark.cc +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/container/fixed_array.h" - -#include -#include - -#include "benchmark/benchmark.h" - -namespace { - -// For benchmarking -- simple class with constructor and destructor that -// set an int to a constant.. -class SimpleClass { - public: - SimpleClass() : i(3) { } - ~SimpleClass() { i = 0; } - private: - int i; -}; - -template -void BM_FixedArray(benchmark::State& state) { - const int size = state.range(0); - for (auto _ : state) { - absl::FixedArray fa(size); - benchmark::DoNotOptimize(fa.data()); - } -} -BENCHMARK_TEMPLATE(BM_FixedArray, char, absl::kFixedArrayUseDefault) - ->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, char, 0)->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, char, 1)->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, char, 16)->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, char, 256)->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, char, 65536)->Range(0, 1 << 16); - -BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, absl::kFixedArrayUseDefault) - ->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 0)->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 1)->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 16)->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 256)->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 65536)->Range(0, 1 << 16); - -BENCHMARK_TEMPLATE(BM_FixedArray, std::string, absl::kFixedArrayUseDefault) - ->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 0)->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 1)->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 16)->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 256)->Range(0, 1 << 16); -BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 65536)->Range(0, 1 << 16); - -} // namespace diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/fixed_array_exception_safety_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/fixed_array_exception_safety_test.cc deleted file mode 100644 index da63dbf..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/fixed_array_exception_safety_test.cc +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include - -#include "absl/container/fixed_array.h" - -#include "gtest/gtest.h" -#include "absl/base/internal/exception_safety_testing.h" - -namespace absl { - -namespace { - -constexpr size_t kInlined = 25; -constexpr size_t kSmallSize = kInlined / 2; -constexpr size_t kLargeSize = kInlined * 2; - -constexpr int kInitialValue = 5; -constexpr int kUpdatedValue = 10; - -using ::testing::TestThrowingCtor; - -using Thrower = testing::ThrowingValue; -using FixedArr = absl::FixedArray; - -using MoveThrower = testing::ThrowingValue; -using MoveFixedArr = absl::FixedArray; - -TEST(FixedArrayExceptionSafety, CopyConstructor) { - auto small = FixedArr(kSmallSize); - TestThrowingCtor(small); - - auto large = FixedArr(kLargeSize); - TestThrowingCtor(large); -} - -TEST(FixedArrayExceptionSafety, MoveConstructor) { - TestThrowingCtor(FixedArr(kSmallSize)); - TestThrowingCtor(FixedArr(kLargeSize)); - - // TypeSpec::kNoThrowMove - TestThrowingCtor(MoveFixedArr(kSmallSize)); - TestThrowingCtor(MoveFixedArr(kLargeSize)); -} - -TEST(FixedArrayExceptionSafety, SizeConstructor) { - TestThrowingCtor(kSmallSize); - TestThrowingCtor(kLargeSize); -} - -TEST(FixedArrayExceptionSafety, SizeValueConstructor) { - TestThrowingCtor(kSmallSize, Thrower()); - TestThrowingCtor(kLargeSize, Thrower()); -} - -TEST(FixedArrayExceptionSafety, IteratorConstructor) { - auto small = FixedArr(kSmallSize); - TestThrowingCtor(small.begin(), small.end()); - - auto large = FixedArr(kLargeSize); - TestThrowingCtor(large.begin(), large.end()); -} - -TEST(FixedArrayExceptionSafety, InitListConstructor) { - constexpr int small_inlined = 3; - using SmallFixedArr = absl::FixedArray; - - TestThrowingCtor(std::initializer_list{}); - // Test inlined allocation - TestThrowingCtor( - std::initializer_list{Thrower{}, Thrower{}}); - // Test out of line allocation - TestThrowingCtor(std::initializer_list{ - Thrower{}, Thrower{}, Thrower{}, Thrower{}, Thrower{}}); -} - -testing::AssertionResult ReadMemory(FixedArr* fixed_arr) { - // Marked volatile to prevent optimization. Used for running asan tests. - volatile int sum = 0; - for (const auto& thrower : *fixed_arr) { - sum += thrower.Get(); - } - return testing::AssertionSuccess() << "Values sum to [" << sum << "]"; -} - -TEST(FixedArrayExceptionSafety, Fill) { - auto test_fill = testing::MakeExceptionSafetyTester() - .WithContracts(ReadMemory) - .WithOperation([&](FixedArr* fixed_arr_ptr) { - auto thrower = - Thrower(kUpdatedValue, testing::nothrow_ctor); - fixed_arr_ptr->fill(thrower); - }); - - EXPECT_TRUE( - test_fill.WithInitialValue(FixedArr(kSmallSize, Thrower(kInitialValue))) - .Test()); - EXPECT_TRUE( - test_fill.WithInitialValue(FixedArr(kLargeSize, Thrower(kInitialValue))) - .Test()); -} - -} // namespace - -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/fixed_array_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/fixed_array_test.cc deleted file mode 100644 index 205ff41..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/fixed_array_test.cc +++ /dev/null @@ -1,872 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/container/fixed_array.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/base/internal/exception_testing.h" -#include "absl/hash/hash_testing.h" -#include "absl/memory/memory.h" - -using ::testing::ElementsAreArray; - -namespace { - -// Helper routine to determine if a absl::FixedArray used stack allocation. -template -static bool IsOnStack(const ArrayType& a) { - return a.size() <= ArrayType::inline_elements; -} - -class ConstructionTester { - public: - ConstructionTester() - : self_ptr_(this), - value_(0) { - constructions++; - } - ~ConstructionTester() { - assert(self_ptr_ == this); - self_ptr_ = nullptr; - destructions++; - } - - // These are incremented as elements are constructed and destructed so we can - // be sure all elements are properly cleaned up. - static int constructions; - static int destructions; - - void CheckConstructed() { - assert(self_ptr_ == this); - } - - void set(int value) { value_ = value; } - int get() { return value_; } - - private: - // self_ptr_ should always point to 'this' -- that's how we can be sure the - // constructor has been called. - ConstructionTester* self_ptr_; - int value_; -}; - -int ConstructionTester::constructions = 0; -int ConstructionTester::destructions = 0; - -// ThreeInts will initialize its three ints to the value stored in -// ThreeInts::counter. The constructor increments counter so that each object -// in an array of ThreeInts will have different values. -class ThreeInts { - public: - ThreeInts() { - x_ = counter; - y_ = counter; - z_ = counter; - ++counter; - } - - static int counter; - - int x_, y_, z_; -}; - -int ThreeInts::counter = 0; - -TEST(FixedArrayTest, CopyCtor) { - absl::FixedArray on_stack(5); - std::iota(on_stack.begin(), on_stack.end(), 0); - absl::FixedArray stack_copy = on_stack; - EXPECT_THAT(stack_copy, ElementsAreArray(on_stack)); - EXPECT_TRUE(IsOnStack(stack_copy)); - - absl::FixedArray allocated(15); - std::iota(allocated.begin(), allocated.end(), 0); - absl::FixedArray alloced_copy = allocated; - EXPECT_THAT(alloced_copy, ElementsAreArray(allocated)); - EXPECT_FALSE(IsOnStack(alloced_copy)); -} - -TEST(FixedArrayTest, MoveCtor) { - absl::FixedArray, 10> on_stack(5); - for (int i = 0; i < 5; ++i) { - on_stack[i] = absl::make_unique(i); - } - - absl::FixedArray, 10> stack_copy = std::move(on_stack); - for (int i = 0; i < 5; ++i) EXPECT_EQ(*(stack_copy[i]), i); - EXPECT_EQ(stack_copy.size(), on_stack.size()); - - absl::FixedArray, 10> allocated(15); - for (int i = 0; i < 15; ++i) { - allocated[i] = absl::make_unique(i); - } - - absl::FixedArray, 10> alloced_copy = - std::move(allocated); - for (int i = 0; i < 15; ++i) EXPECT_EQ(*(alloced_copy[i]), i); - EXPECT_EQ(allocated.size(), alloced_copy.size()); -} - -TEST(FixedArrayTest, SmallObjects) { - // Small object arrays - { - // Short arrays should be on the stack - absl::FixedArray array(4); - EXPECT_TRUE(IsOnStack(array)); - } - - { - // Large arrays should be on the heap - absl::FixedArray array(1048576); - EXPECT_FALSE(IsOnStack(array)); - } - - { - // Arrays of <= default size should be on the stack - absl::FixedArray array(100); - EXPECT_TRUE(IsOnStack(array)); - } - - { - // Arrays of > default size should be on the stack - absl::FixedArray array(101); - EXPECT_FALSE(IsOnStack(array)); - } - - { - // Arrays with different size elements should use approximately - // same amount of stack space - absl::FixedArray array1(0); - absl::FixedArray array2(0); - EXPECT_LE(sizeof(array1), sizeof(array2)+100); - EXPECT_LE(sizeof(array2), sizeof(array1)+100); - } - - { - // Ensure that vectors are properly constructed inside a fixed array. - absl::FixedArray > array(2); - EXPECT_EQ(0, array[0].size()); - EXPECT_EQ(0, array[1].size()); - } - - { - // Regardless of absl::FixedArray implementation, check that a type with a - // low alignment requirement and a non power-of-two size is initialized - // correctly. - ThreeInts::counter = 1; - absl::FixedArray array(2); - EXPECT_EQ(1, array[0].x_); - EXPECT_EQ(1, array[0].y_); - EXPECT_EQ(1, array[0].z_); - EXPECT_EQ(2, array[1].x_); - EXPECT_EQ(2, array[1].y_); - EXPECT_EQ(2, array[1].z_); - } -} - -TEST(FixedArrayTest, AtThrows) { - absl::FixedArray a = {1, 2, 3}; - EXPECT_EQ(a.at(2), 3); - ABSL_BASE_INTERNAL_EXPECT_FAIL(a.at(3), std::out_of_range, - "failed bounds check"); -} - -TEST(FixedArrayRelationalsTest, EqualArrays) { - for (int i = 0; i < 10; ++i) { - absl::FixedArray a1(i); - std::iota(a1.begin(), a1.end(), 0); - absl::FixedArray a2(a1.begin(), a1.end()); - - EXPECT_TRUE(a1 == a2); - EXPECT_FALSE(a1 != a2); - EXPECT_TRUE(a2 == a1); - EXPECT_FALSE(a2 != a1); - EXPECT_FALSE(a1 < a2); - EXPECT_FALSE(a1 > a2); - EXPECT_FALSE(a2 < a1); - EXPECT_FALSE(a2 > a1); - EXPECT_TRUE(a1 <= a2); - EXPECT_TRUE(a1 >= a2); - EXPECT_TRUE(a2 <= a1); - EXPECT_TRUE(a2 >= a1); - } -} - -TEST(FixedArrayRelationalsTest, UnequalArrays) { - for (int i = 1; i < 10; ++i) { - absl::FixedArray a1(i); - std::iota(a1.begin(), a1.end(), 0); - absl::FixedArray a2(a1.begin(), a1.end()); - --a2[i / 2]; - - EXPECT_FALSE(a1 == a2); - EXPECT_TRUE(a1 != a2); - EXPECT_FALSE(a2 == a1); - EXPECT_TRUE(a2 != a1); - EXPECT_FALSE(a1 < a2); - EXPECT_TRUE(a1 > a2); - EXPECT_TRUE(a2 < a1); - EXPECT_FALSE(a2 > a1); - EXPECT_FALSE(a1 <= a2); - EXPECT_TRUE(a1 >= a2); - EXPECT_TRUE(a2 <= a1); - EXPECT_FALSE(a2 >= a1); - } -} - -template -static void TestArray(int n) { - SCOPED_TRACE(n); - SCOPED_TRACE(stack_elements); - ConstructionTester::constructions = 0; - ConstructionTester::destructions = 0; - { - absl::FixedArray array(n); - - EXPECT_THAT(array.size(), n); - EXPECT_THAT(array.memsize(), sizeof(ConstructionTester) * n); - EXPECT_THAT(array.begin() + n, array.end()); - - // Check that all elements were constructed - for (int i = 0; i < n; i++) { - array[i].CheckConstructed(); - } - // Check that no other elements were constructed - EXPECT_THAT(ConstructionTester::constructions, n); - - // Test operator[] - for (int i = 0; i < n; i++) { - array[i].set(i); - } - for (int i = 0; i < n; i++) { - EXPECT_THAT(array[i].get(), i); - EXPECT_THAT(array.data()[i].get(), i); - } - - // Test data() - for (int i = 0; i < n; i++) { - array.data()[i].set(i + 1); - } - for (int i = 0; i < n; i++) { - EXPECT_THAT(array[i].get(), i+1); - EXPECT_THAT(array.data()[i].get(), i+1); - } - } // Close scope containing 'array'. - - // Check that all constructed elements were destructed. - EXPECT_EQ(ConstructionTester::constructions, - ConstructionTester::destructions); -} - -template -static void TestArrayOfArrays(int n) { - SCOPED_TRACE(n); - SCOPED_TRACE(inline_elements); - SCOPED_TRACE(elements_per_inner_array); - ConstructionTester::constructions = 0; - ConstructionTester::destructions = 0; - { - using InnerArray = ConstructionTester[elements_per_inner_array]; - // Heap-allocate the FixedArray to avoid blowing the stack frame. - auto array_ptr = - absl::make_unique>(n); - auto& array = *array_ptr; - - ASSERT_EQ(array.size(), n); - ASSERT_EQ(array.memsize(), - sizeof(ConstructionTester) * elements_per_inner_array * n); - ASSERT_EQ(array.begin() + n, array.end()); - - // Check that all elements were constructed - for (int i = 0; i < n; i++) { - for (int j = 0; j < elements_per_inner_array; j++) { - (array[i])[j].CheckConstructed(); - } - } - // Check that no other elements were constructed - ASSERT_EQ(ConstructionTester::constructions, n * elements_per_inner_array); - - // Test operator[] - for (int i = 0; i < n; i++) { - for (int j = 0; j < elements_per_inner_array; j++) { - (array[i])[j].set(i * elements_per_inner_array + j); - } - } - for (int i = 0; i < n; i++) { - for (int j = 0; j < elements_per_inner_array; j++) { - ASSERT_EQ((array[i])[j].get(), i * elements_per_inner_array + j); - ASSERT_EQ((array.data()[i])[j].get(), i * elements_per_inner_array + j); - } - } - - // Test data() - for (int i = 0; i < n; i++) { - for (int j = 0; j < elements_per_inner_array; j++) { - (array.data()[i])[j].set((i + 1) * elements_per_inner_array + j); - } - } - for (int i = 0; i < n; i++) { - for (int j = 0; j < elements_per_inner_array; j++) { - ASSERT_EQ((array[i])[j].get(), - (i + 1) * elements_per_inner_array + j); - ASSERT_EQ((array.data()[i])[j].get(), - (i + 1) * elements_per_inner_array + j); - } - } - } // Close scope containing 'array'. - - // Check that all constructed elements were destructed. - EXPECT_EQ(ConstructionTester::constructions, - ConstructionTester::destructions); -} - -TEST(IteratorConstructorTest, NonInline) { - int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 }; - absl::FixedArray const fixed( - kInput, kInput + ABSL_ARRAYSIZE(kInput)); - ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size()); - for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) { - ASSERT_EQ(kInput[i], fixed[i]); - } -} - -TEST(IteratorConstructorTest, Inline) { - int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 }; - absl::FixedArray const fixed( - kInput, kInput + ABSL_ARRAYSIZE(kInput)); - ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size()); - for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) { - ASSERT_EQ(kInput[i], fixed[i]); - } -} - -TEST(IteratorConstructorTest, NonPod) { - char const* kInput[] = - { "red", "orange", "yellow", "green", "blue", "indigo", "violet" }; - absl::FixedArray const fixed(kInput, kInput + ABSL_ARRAYSIZE(kInput)); - ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size()); - for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) { - ASSERT_EQ(kInput[i], fixed[i]); - } -} - -TEST(IteratorConstructorTest, FromEmptyVector) { - std::vector const empty; - absl::FixedArray const fixed(empty.begin(), empty.end()); - EXPECT_EQ(0, fixed.size()); - EXPECT_EQ(empty.size(), fixed.size()); -} - -TEST(IteratorConstructorTest, FromNonEmptyVector) { - int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 }; - std::vector const items(kInput, kInput + ABSL_ARRAYSIZE(kInput)); - absl::FixedArray const fixed(items.begin(), items.end()); - ASSERT_EQ(items.size(), fixed.size()); - for (size_t i = 0; i < items.size(); ++i) { - ASSERT_EQ(items[i], fixed[i]); - } -} - -TEST(IteratorConstructorTest, FromBidirectionalIteratorRange) { - int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 }; - std::list const items(kInput, kInput + ABSL_ARRAYSIZE(kInput)); - absl::FixedArray const fixed(items.begin(), items.end()); - EXPECT_THAT(fixed, testing::ElementsAreArray(kInput)); -} - -TEST(InitListConstructorTest, InitListConstruction) { - absl::FixedArray fixed = {1, 2, 3}; - EXPECT_THAT(fixed, testing::ElementsAreArray({1, 2, 3})); -} - -TEST(FillConstructorTest, NonEmptyArrays) { - absl::FixedArray stack_array(4, 1); - EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1})); - - absl::FixedArray heap_array(4, 1); - EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1})); -} - -TEST(FillConstructorTest, EmptyArray) { - absl::FixedArray empty_fill(0, 1); - absl::FixedArray empty_size(0); - EXPECT_EQ(empty_fill, empty_size); -} - -TEST(FillConstructorTest, NotTriviallyCopyable) { - std::string str = "abcd"; - absl::FixedArray strings = {str, str, str, str}; - - absl::FixedArray array(4, str); - EXPECT_EQ(array, strings); -} - -TEST(FillConstructorTest, Disambiguation) { - absl::FixedArray a(1, 2); - EXPECT_THAT(a, testing::ElementsAre(2)); -} - -TEST(FixedArrayTest, ManySizedArrays) { - std::vector sizes; - for (int i = 1; i < 100; i++) sizes.push_back(i); - for (int i = 100; i <= 1000; i += 100) sizes.push_back(i); - for (int n : sizes) { - TestArray<0>(n); - TestArray<1>(n); - TestArray<64>(n); - TestArray<1000>(n); - } -} - -TEST(FixedArrayTest, ManySizedArraysOfArraysOf1) { - for (int n = 1; n < 1000; n++) { - ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 0>(n))); - ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1>(n))); - ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 64>(n))); - ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1000>(n))); - } -} - -TEST(FixedArrayTest, ManySizedArraysOfArraysOf2) { - for (int n = 1; n < 1000; n++) { - TestArrayOfArrays<2, 0>(n); - TestArrayOfArrays<2, 1>(n); - TestArrayOfArrays<2, 64>(n); - TestArrayOfArrays<2, 1000>(n); - } -} - -// If value_type is put inside of a struct container, -// we might evoke this error in a hardened build unless data() is carefully -// written, so check on that. -// error: call to int __builtin___sprintf_chk(etc...) -// will always overflow destination buffer [-Werror] -TEST(FixedArrayTest, AvoidParanoidDiagnostics) { - absl::FixedArray buf(32); - sprintf(buf.data(), "foo"); // NOLINT(runtime/printf) -} - -TEST(FixedArrayTest, TooBigInlinedSpace) { - struct TooBig { - char c[1 << 20]; - }; // too big for even one on the stack - - // Simulate the data members of absl::FixedArray, a pointer and a size_t. - struct Data { - TooBig* p; - size_t size; - }; - - // Make sure TooBig objects are not inlined for 0 or default size. - static_assert(sizeof(absl::FixedArray) == sizeof(Data), - "0-sized absl::FixedArray should have same size as Data."); - static_assert(alignof(absl::FixedArray) == alignof(Data), - "0-sized absl::FixedArray should have same alignment as Data."); - static_assert(sizeof(absl::FixedArray) == sizeof(Data), - "default-sized absl::FixedArray should have same size as Data"); - static_assert( - alignof(absl::FixedArray) == alignof(Data), - "default-sized absl::FixedArray should have same alignment as Data."); -} - -// PickyDelete EXPECTs its class-scope deallocation funcs are unused. -struct PickyDelete { - PickyDelete() {} - ~PickyDelete() {} - void operator delete(void* p) { - EXPECT_TRUE(false) << __FUNCTION__; - ::operator delete(p); - } - void operator delete[](void* p) { - EXPECT_TRUE(false) << __FUNCTION__; - ::operator delete[](p); - } -}; - -TEST(FixedArrayTest, UsesGlobalAlloc) { absl::FixedArray a(5); } - - -TEST(FixedArrayTest, Data) { - static const int kInput[] = { 2, 3, 5, 7, 11, 13, 17 }; - absl::FixedArray fa(std::begin(kInput), std::end(kInput)); - EXPECT_EQ(fa.data(), &*fa.begin()); - EXPECT_EQ(fa.data(), &fa[0]); - - const absl::FixedArray& cfa = fa; - EXPECT_EQ(cfa.data(), &*cfa.begin()); - EXPECT_EQ(cfa.data(), &cfa[0]); -} - -TEST(FixedArrayTest, Empty) { - absl::FixedArray empty(0); - absl::FixedArray inline_filled(1); - absl::FixedArray heap_filled(1); - EXPECT_TRUE(empty.empty()); - EXPECT_FALSE(inline_filled.empty()); - EXPECT_FALSE(heap_filled.empty()); -} - -TEST(FixedArrayTest, FrontAndBack) { - absl::FixedArray inlined = {1, 2, 3}; - EXPECT_EQ(inlined.front(), 1); - EXPECT_EQ(inlined.back(), 3); - - absl::FixedArray allocated = {1, 2, 3}; - EXPECT_EQ(allocated.front(), 1); - EXPECT_EQ(allocated.back(), 3); - - absl::FixedArray one_element = {1}; - EXPECT_EQ(one_element.front(), one_element.back()); -} - -TEST(FixedArrayTest, ReverseIteratorInlined) { - absl::FixedArray a = {0, 1, 2, 3, 4}; - - int counter = 5; - for (absl::FixedArray::reverse_iterator iter = a.rbegin(); - iter != a.rend(); ++iter) { - counter--; - EXPECT_EQ(counter, *iter); - } - EXPECT_EQ(counter, 0); - - counter = 5; - for (absl::FixedArray::const_reverse_iterator iter = a.rbegin(); - iter != a.rend(); ++iter) { - counter--; - EXPECT_EQ(counter, *iter); - } - EXPECT_EQ(counter, 0); - - counter = 5; - for (auto iter = a.crbegin(); iter != a.crend(); ++iter) { - counter--; - EXPECT_EQ(counter, *iter); - } - EXPECT_EQ(counter, 0); -} - -TEST(FixedArrayTest, ReverseIteratorAllocated) { - absl::FixedArray a = {0, 1, 2, 3, 4}; - - int counter = 5; - for (absl::FixedArray::reverse_iterator iter = a.rbegin(); - iter != a.rend(); ++iter) { - counter--; - EXPECT_EQ(counter, *iter); - } - EXPECT_EQ(counter, 0); - - counter = 5; - for (absl::FixedArray::const_reverse_iterator iter = a.rbegin(); - iter != a.rend(); ++iter) { - counter--; - EXPECT_EQ(counter, *iter); - } - EXPECT_EQ(counter, 0); - - counter = 5; - for (auto iter = a.crbegin(); iter != a.crend(); ++iter) { - counter--; - EXPECT_EQ(counter, *iter); - } - EXPECT_EQ(counter, 0); -} - -TEST(FixedArrayTest, Fill) { - absl::FixedArray inlined(5); - int fill_val = 42; - inlined.fill(fill_val); - for (int i : inlined) EXPECT_EQ(i, fill_val); - - absl::FixedArray allocated(5); - allocated.fill(fill_val); - for (int i : allocated) EXPECT_EQ(i, fill_val); - - // It doesn't do anything, just make sure this compiles. - absl::FixedArray empty(0); - empty.fill(fill_val); -} - -// TODO(johnsoncj): Investigate InlinedStorage default initialization in GCC 4.x -#ifndef __GNUC__ -TEST(FixedArrayTest, DefaultCtorDoesNotValueInit) { - using T = char; - constexpr auto capacity = 10; - using FixedArrType = absl::FixedArray; - using FixedArrBuffType = - absl::aligned_storage_t; - constexpr auto scrubbed_bits = 0x95; - constexpr auto length = capacity / 2; - - FixedArrBuffType buff; - std::memset(std::addressof(buff), scrubbed_bits, sizeof(FixedArrBuffType)); - - FixedArrType* arr = - ::new (static_cast(std::addressof(buff))) FixedArrType(length); - EXPECT_THAT(*arr, testing::Each(scrubbed_bits)); - arr->~FixedArrType(); -} -#endif // __GNUC__ - -// This is a stateful allocator, but the state lives outside of the -// allocator (in whatever test is using the allocator). This is odd -// but helps in tests where the allocator is propagated into nested -// containers - that chain of allocators uses the same state and is -// thus easier to query for aggregate allocation information. -template -class CountingAllocator : public std::allocator { - public: - using Alloc = std::allocator; - using pointer = typename Alloc::pointer; - using size_type = typename Alloc::size_type; - - CountingAllocator() : bytes_used_(nullptr), instance_count_(nullptr) {} - explicit CountingAllocator(int64_t* b) - : bytes_used_(b), instance_count_(nullptr) {} - CountingAllocator(int64_t* b, int64_t* a) - : bytes_used_(b), instance_count_(a) {} - - template - explicit CountingAllocator(const CountingAllocator& x) - : Alloc(x), - bytes_used_(x.bytes_used_), - instance_count_(x.instance_count_) {} - - pointer allocate(size_type n, const void* const hint = nullptr) { - assert(bytes_used_ != nullptr); - *bytes_used_ += n * sizeof(T); - return Alloc::allocate(n, hint); - } - - void deallocate(pointer p, size_type n) { - Alloc::deallocate(p, n); - assert(bytes_used_ != nullptr); - *bytes_used_ -= n * sizeof(T); - } - - template - void construct(pointer p, Args&&... args) { - Alloc::construct(p, absl::forward(args)...); - if (instance_count_) { - *instance_count_ += 1; - } - } - - void destroy(pointer p) { - Alloc::destroy(p); - if (instance_count_) { - *instance_count_ -= 1; - } - } - - template - class rebind { - public: - using other = CountingAllocator; - }; - - int64_t* bytes_used_; - int64_t* instance_count_; -}; - -TEST(AllocatorSupportTest, CountInlineAllocations) { - constexpr size_t inlined_size = 4; - using Alloc = CountingAllocator; - using AllocFxdArr = absl::FixedArray; - - int64_t allocated = 0; - int64_t active_instances = 0; - - { - const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7}; - - Alloc alloc(&allocated, &active_instances); - - AllocFxdArr arr(ia, ia + inlined_size, alloc); - static_cast(arr); - } - - EXPECT_EQ(allocated, 0); - EXPECT_EQ(active_instances, 0); -} - -TEST(AllocatorSupportTest, CountOutoflineAllocations) { - constexpr size_t inlined_size = 4; - using Alloc = CountingAllocator; - using AllocFxdArr = absl::FixedArray; - - int64_t allocated = 0; - int64_t active_instances = 0; - - { - const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7}; - Alloc alloc(&allocated, &active_instances); - - AllocFxdArr arr(ia, ia + ABSL_ARRAYSIZE(ia), alloc); - - EXPECT_EQ(allocated, arr.size() * sizeof(int)); - static_cast(arr); - } - - EXPECT_EQ(active_instances, 0); -} - -TEST(AllocatorSupportTest, CountCopyInlineAllocations) { - constexpr size_t inlined_size = 4; - using Alloc = CountingAllocator; - using AllocFxdArr = absl::FixedArray; - - int64_t allocated1 = 0; - int64_t allocated2 = 0; - int64_t active_instances = 0; - Alloc alloc(&allocated1, &active_instances); - Alloc alloc2(&allocated2, &active_instances); - - { - int initial_value = 1; - - AllocFxdArr arr1(inlined_size / 2, initial_value, alloc); - - EXPECT_EQ(allocated1, 0); - - AllocFxdArr arr2(arr1, alloc2); - - EXPECT_EQ(allocated2, 0); - static_cast(arr1); - static_cast(arr2); - } - - EXPECT_EQ(active_instances, 0); -} - -TEST(AllocatorSupportTest, CountCopyOutoflineAllocations) { - constexpr size_t inlined_size = 4; - using Alloc = CountingAllocator; - using AllocFxdArr = absl::FixedArray; - - int64_t allocated1 = 0; - int64_t allocated2 = 0; - int64_t active_instances = 0; - Alloc alloc(&allocated1, &active_instances); - Alloc alloc2(&allocated2, &active_instances); - - { - int initial_value = 1; - - AllocFxdArr arr1(inlined_size * 2, initial_value, alloc); - - EXPECT_EQ(allocated1, arr1.size() * sizeof(int)); - - AllocFxdArr arr2(arr1, alloc2); - - EXPECT_EQ(allocated2, inlined_size * 2 * sizeof(int)); - static_cast(arr1); - static_cast(arr2); - } - - EXPECT_EQ(active_instances, 0); -} - -TEST(AllocatorSupportTest, SizeValAllocConstructor) { - using testing::AllOf; - using testing::Each; - using testing::SizeIs; - - constexpr size_t inlined_size = 4; - using Alloc = CountingAllocator; - using AllocFxdArr = absl::FixedArray; - - { - auto len = inlined_size / 2; - auto val = 0; - int64_t allocated = 0; - AllocFxdArr arr(len, val, Alloc(&allocated)); - - EXPECT_EQ(allocated, 0); - EXPECT_THAT(arr, AllOf(SizeIs(len), Each(0))); - } - - { - auto len = inlined_size * 2; - auto val = 0; - int64_t allocated = 0; - AllocFxdArr arr(len, val, Alloc(&allocated)); - - EXPECT_EQ(allocated, len * sizeof(int)); - EXPECT_THAT(arr, AllOf(SizeIs(len), Each(0))); - } -} - -#ifdef ADDRESS_SANITIZER -TEST(FixedArrayTest, AddressSanitizerAnnotations1) { - absl::FixedArray a(10); - int *raw = a.data(); - raw[0] = 0; - raw[9] = 0; - EXPECT_DEATH(raw[-2] = 0, "container-overflow"); - EXPECT_DEATH(raw[-1] = 0, "container-overflow"); - EXPECT_DEATH(raw[10] = 0, "container-overflow"); - EXPECT_DEATH(raw[31] = 0, "container-overflow"); -} - -TEST(FixedArrayTest, AddressSanitizerAnnotations2) { - absl::FixedArray a(12); - char *raw = a.data(); - raw[0] = 0; - raw[11] = 0; - EXPECT_DEATH(raw[-7] = 0, "container-overflow"); - EXPECT_DEATH(raw[-1] = 0, "container-overflow"); - EXPECT_DEATH(raw[12] = 0, "container-overflow"); - EXPECT_DEATH(raw[17] = 0, "container-overflow"); -} - -TEST(FixedArrayTest, AddressSanitizerAnnotations3) { - absl::FixedArray a(20); - uint64_t *raw = a.data(); - raw[0] = 0; - raw[19] = 0; - EXPECT_DEATH(raw[-1] = 0, "container-overflow"); - EXPECT_DEATH(raw[20] = 0, "container-overflow"); -} - -TEST(FixedArrayTest, AddressSanitizerAnnotations4) { - absl::FixedArray a(10); - ThreeInts *raw = a.data(); - raw[0] = ThreeInts(); - raw[9] = ThreeInts(); - // Note: raw[-1] is pointing to 12 bytes before the container range. However, - // there is only a 8-byte red zone before the container range, so we only - // access the last 4 bytes of the struct to make sure it stays within the red - // zone. - EXPECT_DEATH(raw[-1].z_ = 0, "container-overflow"); - EXPECT_DEATH(raw[10] = ThreeInts(), "container-overflow"); - // The actual size of storage is kDefaultBytes=256, 21*12 = 252, - // so reading raw[21] should still trigger the correct warning. - EXPECT_DEATH(raw[21] = ThreeInts(), "container-overflow"); -} -#endif // ADDRESS_SANITIZER - -} // namespace diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/flat_hash_map.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/flat_hash_map.h deleted file mode 100644 index de632be..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/flat_hash_map.h +++ /dev/null @@ -1,568 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. -// -// ----------------------------------------------------------------------------- -// File: flat_hash_map.h -// ----------------------------------------------------------------------------- -// -// An `absl::flat_hash_map` is an unordered associative container of -// unique keys and associated values designed to be a more efficient replacement -// for `std::unordered_map`. Like `unordered_map`, search, insertion, and -// deletion of map elements can be done as an `O(1)` operation. However, -// `flat_hash_map` (and other unordered associative containers known as the -// collection of Abseil "Swiss tables") contain other optimizations that result -// in both memory and computation advantages. -// -// In most cases, your default choice for a hash map should be a map of type -// `flat_hash_map`. - -#ifndef ABSL_CONTAINER_FLAT_HASH_MAP_H_ -#define ABSL_CONTAINER_FLAT_HASH_MAP_H_ - -#include -#include -#include -#include - -#include "absl/container/internal/container_memory.h" -#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export -#include "absl/container/internal/raw_hash_map.h" // IWYU pragma: export -#include "absl/memory/memory.h" - -namespace absl { -namespace container_internal { -template -struct FlatHashMapPolicy; -} // namespace container_internal - -// ----------------------------------------------------------------------------- -// absl::flat_hash_map -// ----------------------------------------------------------------------------- -// -// An `absl::flat_hash_map` is an unordered associative container which -// has been optimized for both speed and memory footprint in most common use -// cases. Its interface is similar to that of `std::unordered_map` with -// the following notable differences: -// -// * Requires keys that are CopyConstructible -// * Requires values that are MoveConstructible -// * Supports heterogeneous lookup, through `find()`, `operator[]()` and -// `insert()`, provided that the map is provided a compatible heterogeneous -// hashing function and equality operator. -// * Invalidates any references and pointers to elements within the table after -// `rehash()`. -// * Contains a `capacity()` member function indicating the number of element -// slots (open, deleted, and empty) within the hash map. -// * Returns `void` from the `erase(iterator)` overload. -// -// By default, `flat_hash_map` uses the `absl::Hash` hashing framework. -// All fundamental and Abseil types that support the `absl::Hash` framework have -// a compatible equality operator for comparing insertions into `flat_hash_map`. -// If your type is not yet supported by the `asbl::Hash` framework, see -// absl/hash/hash.h for information on extending Abseil hashing to user-defined -// types. -// -// NOTE: A `flat_hash_map` stores its value types directly inside its -// implementation array to avoid memory indirection. Because a `flat_hash_map` -// is designed to move data when rehashed, map values will not retain pointer -// stability. If you require pointer stability, or your values are large, -// consider using `absl::flat_hash_map>` instead. -// If your types are not moveable or you require pointer stability for keys, -// consider `absl::node_hash_map`. -// -// Example: -// -// // Create a flat hash map of three strings (that map to strings) -// absl::flat_hash_map ducks = -// {{"a", "huey"}, {"b", "dewey"}, {"c", "louie"}}; -// -// // Insert a new element into the flat hash map -// ducks.insert({"d", "donald"}); -// -// // Force a rehash of the flat hash map -// ducks.rehash(0); -// -// // Find the element with the key "b" -// std::string search_key = "b"; -// auto result = ducks.find(search_key); -// if (result != ducks.end()) { -// std::cout << "Result: " << result->second << std::endl; -// } -template , - class Eq = absl::container_internal::hash_default_eq, - class Allocator = std::allocator>> -class flat_hash_map : public absl::container_internal::raw_hash_map< - absl::container_internal::FlatHashMapPolicy, - Hash, Eq, Allocator> { - using Base = typename flat_hash_map::raw_hash_map; - - public: - // Constructors and Assignment Operators - // - // A flat_hash_map supports the same overload set as `std::unordered_map` - // for construction and assignment: - // - // * Default constructor - // - // // No allocation for the table's elements is made. - // absl::flat_hash_map map1; - // - // * Initializer List constructor - // - // absl::flat_hash_map map2 = - // {{1, "huey"}, {2, "dewey"}, {3, "louie"},}; - // - // * Copy constructor - // - // absl::flat_hash_map map3(map2); - // - // * Copy assignment operator - // - // // Hash functor and Comparator are copied as well - // absl::flat_hash_map map4; - // map4 = map3; - // - // * Move constructor - // - // // Move is guaranteed efficient - // absl::flat_hash_map map5(std::move(map4)); - // - // * Move assignment operator - // - // // May be efficient if allocators are compatible - // absl::flat_hash_map map6; - // map6 = std::move(map5); - // - // * Range constructor - // - // std::vector> v = {{1, "a"}, {2, "b"}}; - // absl::flat_hash_map map7(v.begin(), v.end()); - flat_hash_map() {} - using Base::Base; - - // flat_hash_map::begin() - // - // Returns an iterator to the beginning of the `flat_hash_map`. - using Base::begin; - - // flat_hash_map::cbegin() - // - // Returns a const iterator to the beginning of the `flat_hash_map`. - using Base::cbegin; - - // flat_hash_map::cend() - // - // Returns a const iterator to the end of the `flat_hash_map`. - using Base::cend; - - // flat_hash_map::end() - // - // Returns an iterator to the end of the `flat_hash_map`. - using Base::end; - - // flat_hash_map::capacity() - // - // Returns the number of element slots (assigned, deleted, and empty) - // available within the `flat_hash_map`. - // - // NOTE: this member function is particular to `absl::flat_hash_map` and is - // not provided in the `std::unordered_map` API. - using Base::capacity; - - // flat_hash_map::empty() - // - // Returns whether or not the `flat_hash_map` is empty. - using Base::empty; - - // flat_hash_map::max_size() - // - // Returns the largest theoretical possible number of elements within a - // `flat_hash_map` under current memory constraints. This value can be thought - // of the largest value of `std::distance(begin(), end())` for a - // `flat_hash_map`. - using Base::max_size; - - // flat_hash_map::size() - // - // Returns the number of elements currently within the `flat_hash_map`. - using Base::size; - - // flat_hash_map::clear() - // - // Removes all elements from the `flat_hash_map`. Invalidates any references, - // pointers, or iterators referring to contained elements. - // - // NOTE: this operation may shrink the underlying buffer. To avoid shrinking - // the underlying buffer call `erase(begin(), end())`. - using Base::clear; - - // flat_hash_map::erase() - // - // Erases elements within the `flat_hash_map`. Erasing does not trigger a - // rehash. Overloads are listed below. - // - // void erase(const_iterator pos): - // - // Erases the element at `position` of the `flat_hash_map`, returning - // `void`. - // - // NOTE: this return behavior is different than that of STL containers in - // general and `std::unordered_map` in particular. - // - // iterator erase(const_iterator first, const_iterator last): - // - // Erases the elements in the open interval [`first`, `last`), returning an - // iterator pointing to `last`. - // - // size_type erase(const key_type& key): - // - // Erases the element with the matching key, if it exists. - using Base::erase; - - // flat_hash_map::insert() - // - // Inserts an element of the specified value into the `flat_hash_map`, - // returning an iterator pointing to the newly inserted element, provided that - // an element with the given key does not already exist. If rehashing occurs - // due to the insertion, all iterators are invalidated. Overloads are listed - // below. - // - // std::pair insert(const init_type& value): - // - // Inserts a value into the `flat_hash_map`. Returns a pair consisting of an - // iterator to the inserted element (or to the element that prevented the - // insertion) and a bool denoting whether the insertion took place. - // - // std::pair insert(T&& value): - // std::pair insert(init_type&& value): - // - // Inserts a moveable value into the `flat_hash_map`. Returns a pair - // consisting of an iterator to the inserted element (or to the element that - // prevented the insertion) and a bool denoting whether the insertion took - // place. - // - // iterator insert(const_iterator hint, const init_type& value): - // iterator insert(const_iterator hint, T&& value): - // iterator insert(const_iterator hint, init_type&& value); - // - // Inserts a value, using the position of `hint` as a non-binding suggestion - // for where to begin the insertion search. Returns an iterator to the - // inserted element, or to the existing element that prevented the - // insertion. - // - // void insert(InputIterator first, InputIterator last): - // - // Inserts a range of values [`first`, `last`). - // - // NOTE: Although the STL does not specify which element may be inserted if - // multiple keys compare equivalently, for `flat_hash_map` we guarantee the - // first match is inserted. - // - // void insert(std::initializer_list ilist): - // - // Inserts the elements within the initializer list `ilist`. - // - // NOTE: Although the STL does not specify which element may be inserted if - // multiple keys compare equivalently within the initializer list, for - // `flat_hash_map` we guarantee the first match is inserted. - using Base::insert; - - // flat_hash_map::insert_or_assign() - // - // Inserts an element of the specified value into the `flat_hash_map` provided - // that a value with the given key does not already exist, or replaces it with - // the element value if a key for that value already exists, returning an - // iterator pointing to the newly inserted element. If rehashing occurs due - // to the insertion, all existing iterators are invalidated. Overloads are - // listed below. - // - // pair insert_or_assign(const init_type& k, T&& obj): - // pair insert_or_assign(init_type&& k, T&& obj): - // - // Inserts/Assigns (or moves) the element of the specified key into the - // `flat_hash_map`. - // - // iterator insert_or_assign(const_iterator hint, - // const init_type& k, T&& obj): - // iterator insert_or_assign(const_iterator hint, init_type&& k, T&& obj): - // - // Inserts/Assigns (or moves) the element of the specified key into the - // `flat_hash_map` using the position of `hint` as a non-binding suggestion - // for where to begin the insertion search. - using Base::insert_or_assign; - - // flat_hash_map::emplace() - // - // Inserts an element of the specified value by constructing it in-place - // within the `flat_hash_map`, provided that no element with the given key - // already exists. - // - // The element may be constructed even if there already is an element with the - // key in the container, in which case the newly constructed element will be - // destroyed immediately. Prefer `try_emplace()` unless your key is not - // copyable or moveable. - // - // If rehashing occurs due to the insertion, all iterators are invalidated. - using Base::emplace; - - // flat_hash_map::emplace_hint() - // - // Inserts an element of the specified value by constructing it in-place - // within the `flat_hash_map`, using the position of `hint` as a non-binding - // suggestion for where to begin the insertion search, and only inserts - // provided that no element with the given key already exists. - // - // The element may be constructed even if there already is an element with the - // key in the container, in which case the newly constructed element will be - // destroyed immediately. Prefer `try_emplace()` unless your key is not - // copyable or moveable. - // - // If rehashing occurs due to the insertion, all iterators are invalidated. - using Base::emplace_hint; - - // flat_hash_map::try_emplace() - // - // Inserts an element of the specified value by constructing it in-place - // within the `flat_hash_map`, provided that no element with the given key - // already exists. Unlike `emplace()`, if an element with the given key - // already exists, we guarantee that no element is constructed. - // - // If rehashing occurs due to the insertion, all iterators are invalidated. - // Overloads are listed below. - // - // pair try_emplace(const key_type& k, Args&&... args): - // pair try_emplace(key_type&& k, Args&&... args): - // - // Inserts (via copy or move) the element of the specified key into the - // `flat_hash_map`. - // - // iterator try_emplace(const_iterator hint, - // const init_type& k, Args&&... args): - // iterator try_emplace(const_iterator hint, init_type&& k, Args&&... args): - // - // Inserts (via copy or move) the element of the specified key into the - // `flat_hash_map` using the position of `hint` as a non-binding suggestion - // for where to begin the insertion search. - using Base::try_emplace; - - // flat_hash_map::extract() - // - // Extracts the indicated element, erasing it in the process, and returns it - // as a C++17-compatible node handle. Overloads are listed below. - // - // node_type extract(const_iterator position): - // - // Extracts the key,value pair of the element at the indicated position and - // returns a node handle owning that extracted data. - // - // node_type extract(const key_type& x): - // - // Extracts the key,value pair of the element with a key matching the passed - // key value and returns a node handle owning that extracted data. If the - // `flat_hash_map` does not contain an element with a matching key, this - // function returns an empty node handle. - using Base::extract; - - // flat_hash_map::merge() - // - // Extracts elements from a given `source` flat hash map into this - // `flat_hash_map`. If the destination `flat_hash_map` already contains an - // element with an equivalent key, that element is not extracted. - using Base::merge; - - // flat_hash_map::swap(flat_hash_map& other) - // - // Exchanges the contents of this `flat_hash_map` with those of the `other` - // flat hash map, avoiding invocation of any move, copy, or swap operations on - // individual elements. - // - // All iterators and references on the `flat_hash_map` remain valid, excepting - // for the past-the-end iterator, which is invalidated. - // - // `swap()` requires that the flat hash map's hashing and key equivalence - // functions be Swappable, and are exchaged using unqualified calls to - // non-member `swap()`. If the map's allocator has - // `std::allocator_traits::propagate_on_container_swap::value` - // set to `true`, the allocators are also exchanged using an unqualified call - // to non-member `swap()`; otherwise, the allocators are not swapped. - using Base::swap; - - // flat_hash_map::rehash(count) - // - // Rehashes the `flat_hash_map`, setting the number of slots to be at least - // the passed value. If the new number of slots increases the load factor more - // than the current maximum load factor - // (`count` < `size()` / `max_load_factor()`), then the new number of slots - // will be at least `size()` / `max_load_factor()`. - // - // To force a rehash, pass rehash(0). - // - // NOTE: unlike behavior in `std::unordered_map`, references are also - // invalidated upon a `rehash()`. - using Base::rehash; - - // flat_hash_map::reserve(count) - // - // Sets the number of slots in the `flat_hash_map` to the number needed to - // accommodate at least `count` total elements without exceeding the current - // maximum load factor, and may rehash the container if needed. - using Base::reserve; - - // flat_hash_map::at() - // - // Returns a reference to the mapped value of the element with key equivalent - // to the passed key. - using Base::at; - - // flat_hash_map::contains() - // - // Determines whether an element with a key comparing equal to the given `key` - // exists within the `flat_hash_map`, returning `true` if so or `false` - // otherwise. - using Base::contains; - - // flat_hash_map::count(const Key& key) const - // - // Returns the number of elements with a key comparing equal to the given - // `key` within the `flat_hash_map`. note that this function will return - // either `1` or `0` since duplicate keys are not allowed within a - // `flat_hash_map`. - using Base::count; - - // flat_hash_map::equal_range() - // - // Returns a closed range [first, last], defined by a `std::pair` of two - // iterators, containing all elements with the passed key in the - // `flat_hash_map`. - using Base::equal_range; - - // flat_hash_map::find() - // - // Finds an element with the passed `key` within the `flat_hash_map`. - using Base::find; - - // flat_hash_map::operator[]() - // - // Returns a reference to the value mapped to the passed key within the - // `flat_hash_map`, performing an `insert()` if the key does not already - // exist. - // - // If an insertion occurs and results in a rehashing of the container, all - // iterators are invalidated. Otherwise iterators are not affected and - // references are not invalidated. Overloads are listed below. - // - // T& operator[](const Key& key): - // - // Inserts an init_type object constructed in-place if the element with the - // given key does not exist. - // - // T& operator[](Key&& key): - // - // Inserts an init_type object constructed in-place provided that an element - // with the given key does not exist. - using Base::operator[]; - - // flat_hash_map::bucket_count() - // - // Returns the number of "buckets" within the `flat_hash_map`. Note that - // because a flat hash map contains all elements within its internal storage, - // this value simply equals the current capacity of the `flat_hash_map`. - using Base::bucket_count; - - // flat_hash_map::load_factor() - // - // Returns the current load factor of the `flat_hash_map` (the average number - // of slots occupied with a value within the hash map). - using Base::load_factor; - - // flat_hash_map::max_load_factor() - // - // Manages the maximum load factor of the `flat_hash_map`. Overloads are - // listed below. - // - // float flat_hash_map::max_load_factor() - // - // Returns the current maximum load factor of the `flat_hash_map`. - // - // void flat_hash_map::max_load_factor(float ml) - // - // Sets the maximum load factor of the `flat_hash_map` to the passed value. - // - // NOTE: This overload is provided only for API compatibility with the STL; - // `flat_hash_map` will ignore any set load factor and manage its rehashing - // internally as an implementation detail. - using Base::max_load_factor; - - // flat_hash_map::get_allocator() - // - // Returns the allocator function associated with this `flat_hash_map`. - using Base::get_allocator; - - // flat_hash_map::hash_function() - // - // Returns the hashing function used to hash the keys within this - // `flat_hash_map`. - using Base::hash_function; - - // flat_hash_map::key_eq() - // - // Returns the function used for comparing keys equality. - using Base::key_eq; -}; - -namespace container_internal { - -template -struct FlatHashMapPolicy { - using slot_type = container_internal::slot_type; - using key_type = K; - using mapped_type = V; - using init_type = std::pair; - - template - static void construct(Allocator* alloc, slot_type* slot, Args&&... args) { - slot_type::construct(alloc, slot, std::forward(args)...); - } - - template - static void destroy(Allocator* alloc, slot_type* slot) { - slot_type::destroy(alloc, slot); - } - - template - static void transfer(Allocator* alloc, slot_type* new_slot, - slot_type* old_slot) { - slot_type::transfer(alloc, new_slot, old_slot); - } - - template - static decltype(absl::container_internal::DecomposePair( - std::declval(), std::declval()...)) - apply(F&& f, Args&&... args) { - return absl::container_internal::DecomposePair(std::forward(f), - std::forward(args)...); - } - - static size_t space_used(const slot_type*) { return 0; } - - static std::pair& element(slot_type* slot) { return slot->value; } - - static V& value(std::pair* kv) { return kv->second; } - static const V& value(const std::pair* kv) { return kv->second; } -}; - -} // namespace container_internal -} // namespace absl -#endif // ABSL_CONTAINER_FLAT_HASH_MAP_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/flat_hash_map_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/flat_hash_map_test.cc deleted file mode 100644 index 2c6f251..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/flat_hash_map_test.cc +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include "absl/container/flat_hash_map.h" - -#include "absl/container/internal/hash_generator_testing.h" -#include "absl/container/internal/unordered_map_constructor_test.h" -#include "absl/container/internal/unordered_map_lookup_test.h" -#include "absl/container/internal/unordered_map_modifiers_test.h" -#include "absl/types/any.h" - -namespace absl { -namespace container_internal { -namespace { -using ::absl::container_internal::hash_internal::Enum; -using ::absl::container_internal::hash_internal::EnumClass; -using ::testing::_; -using ::testing::Pair; -using ::testing::UnorderedElementsAre; - -template -using Map = - flat_hash_map>; - -static_assert(!std::is_standard_layout(), ""); - -using MapTypes = - ::testing::Types, Map, Map, - Map, Map, - Map>; - -INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, ConstructorTest, MapTypes); -INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, LookupTest, MapTypes); -INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, ModifiersTest, MapTypes); - -TEST(FlatHashMap, StandardLayout) { - struct Int { - explicit Int(size_t value) : value(value) {} - Int() : value(0) { ADD_FAILURE(); } - Int(const Int& other) : value(other.value) { ADD_FAILURE(); } - Int(Int&&) = default; - bool operator==(const Int& other) const { return value == other.value; } - size_t value; - }; - static_assert(std::is_standard_layout(), ""); - - struct Hash { - size_t operator()(const Int& obj) const { return obj.value; } - }; - - // Verify that neither the key nor the value get default-constructed or - // copy-constructed. - { - flat_hash_map m; - m.try_emplace(Int(1), Int(2)); - m.try_emplace(Int(3), Int(4)); - m.erase(Int(1)); - m.rehash(2 * m.bucket_count()); - } - { - flat_hash_map m; - m.try_emplace(Int(1), Int(2)); - m.try_emplace(Int(3), Int(4)); - m.erase(Int(1)); - m.clear(); - } -} - -// gcc becomes unhappy if this is inside the method, so pull it out here. -struct balast {}; - -TEST(FlatHashMap, IteratesMsan) { - // Because SwissTable randomizes on pointer addresses, we keep old tables - // around to ensure we don't reuse old memory. - std::vector> garbage; - for (int i = 0; i < 100; ++i) { - absl::flat_hash_map t; - for (int j = 0; j < 100; ++j) { - t[j]; - for (const auto& p : t) EXPECT_THAT(p, Pair(_, _)); - } - garbage.push_back(std::move(t)); - } -} - -// Demonstration of the "Lazy Key" pattern. This uses heterogeneous insert to -// avoid creating expensive key elements when the item is already present in the -// map. -struct LazyInt { - explicit LazyInt(size_t value, int* tracker) - : value(value), tracker(tracker) {} - - explicit operator size_t() const { - ++*tracker; - return value; - } - - size_t value; - int* tracker; -}; - -struct Hash { - using is_transparent = void; - int* tracker; - size_t operator()(size_t obj) const { - ++*tracker; - return obj; - } - size_t operator()(const LazyInt& obj) const { - ++*tracker; - return obj.value; - } -}; - -struct Eq { - using is_transparent = void; - bool operator()(size_t lhs, size_t rhs) const { - return lhs == rhs; - } - bool operator()(size_t lhs, const LazyInt& rhs) const { - return lhs == rhs.value; - } -}; - -TEST(FlatHashMap, LazyKeyPattern) { - // hashes are only guaranteed in opt mode, we use assertions to track internal - // state that can cause extra calls to hash. - int conversions = 0; - int hashes = 0; - flat_hash_map m(0, Hash{&hashes}); - - m[LazyInt(1, &conversions)] = 1; - EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 1))); - EXPECT_EQ(conversions, 1); -#ifdef NDEBUG - EXPECT_EQ(hashes, 1); -#endif - - m[LazyInt(1, &conversions)] = 2; - EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 2))); - EXPECT_EQ(conversions, 1); -#ifdef NDEBUG - EXPECT_EQ(hashes, 2); -#endif - - m.try_emplace(LazyInt(2, &conversions), 3); - EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 2), Pair(2, 3))); - EXPECT_EQ(conversions, 2); -#ifdef NDEBUG - EXPECT_EQ(hashes, 3); -#endif - - m.try_emplace(LazyInt(2, &conversions), 4); - EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 2), Pair(2, 3))); - EXPECT_EQ(conversions, 2); -#ifdef NDEBUG - EXPECT_EQ(hashes, 4); -#endif -} - -TEST(FlatHashMap, BitfieldArgument) { - union { - int n : 1; - }; - n = 0; - flat_hash_map m; - m.erase(n); - m.count(n); - m.prefetch(n); - m.find(n); - m.contains(n); - m.equal_range(n); - m.insert_or_assign(n, n); - m.insert_or_assign(m.end(), n, n); - m.try_emplace(n); - m.try_emplace(m.end(), n); - m.at(n); - m[n]; -} - -TEST(FlatHashMap, MergeExtractInsert) { - // We can't test mutable keys, or non-copyable keys with flat_hash_map. - // Test that the nodes have the proper API. - absl::flat_hash_map m = {{1, 7}, {2, 9}}; - auto node = m.extract(1); - EXPECT_TRUE(node); - EXPECT_EQ(node.key(), 1); - EXPECT_EQ(node.mapped(), 7); - EXPECT_THAT(m, UnorderedElementsAre(Pair(2, 9))); - - node.mapped() = 17; - m.insert(std::move(node)); - EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 17), Pair(2, 9))); -} -#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__) -TEST(FlatHashMap, Any) { - absl::flat_hash_map m; - m.emplace(1, 7); - auto it = m.find(1); - ASSERT_NE(it, m.end()); - EXPECT_EQ(7, absl::any_cast(it->second)); - - m.emplace(std::piecewise_construct, std::make_tuple(2), std::make_tuple(8)); - it = m.find(2); - ASSERT_NE(it, m.end()); - EXPECT_EQ(8, absl::any_cast(it->second)); - - m.emplace(std::piecewise_construct, std::make_tuple(3), - std::make_tuple(absl::any(9))); - it = m.find(3); - ASSERT_NE(it, m.end()); - EXPECT_EQ(9, absl::any_cast(it->second)); - - struct H { - size_t operator()(const absl::any&) const { return 0; } - }; - struct E { - bool operator()(const absl::any&, const absl::any&) const { return true; } - }; - absl::flat_hash_map m2; - m2.emplace(1, 7); - auto it2 = m2.find(1); - ASSERT_NE(it2, m2.end()); - EXPECT_EQ(7, it2->second); -} -#endif // __ANDROID__ - -} // namespace -} // namespace container_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/flat_hash_set.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/flat_hash_set.h deleted file mode 100644 index a2584d6..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/flat_hash_set.h +++ /dev/null @@ -1,479 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. -// -// ----------------------------------------------------------------------------- -// File: flat_hash_set.h -// ----------------------------------------------------------------------------- -// -// An `absl::flat_hash_set` is an unordered associative container designed to -// be a more efficient replacement for `std::unordered_set`. Like -// `unordered_set`, search, insertion, and deletion of set elements can be done -// as an `O(1)` operation. However, `flat_hash_set` (and other unordered -// associative containers known as the collection of Abseil "Swiss tables") -// contain other optimizations that result in both memory and computation -// advantages. -// -// In most cases, your default choice for a hash set should be a set of type -// `flat_hash_set`. -#ifndef ABSL_CONTAINER_FLAT_HASH_SET_H_ -#define ABSL_CONTAINER_FLAT_HASH_SET_H_ - -#include -#include - -#include "absl/base/macros.h" -#include "absl/container/internal/container_memory.h" -#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export -#include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export -#include "absl/memory/memory.h" - -namespace absl { -namespace container_internal { -template -struct FlatHashSetPolicy; -} // namespace container_internal - -// ----------------------------------------------------------------------------- -// absl::flat_hash_set -// ----------------------------------------------------------------------------- -// -// An `absl::flat_hash_set` is an unordered associative container which has -// been optimized for both speed and memory footprint in most common use cases. -// Its interface is similar to that of `std::unordered_set` with the -// following notable differences: -// -// * Requires keys that are CopyConstructible -// * Supports heterogeneous lookup, through `find()`, `operator[]()` and -// `insert()`, provided that the set is provided a compatible heterogeneous -// hashing function and equality operator. -// * Invalidates any references and pointers to elements within the table after -// `rehash()`. -// * Contains a `capacity()` member function indicating the number of element -// slots (open, deleted, and empty) within the hash set. -// * Returns `void` from the `erase(iterator)` overload. -// -// By default, `flat_hash_set` uses the `absl::Hash` hashing framework. All -// fundamental and Abseil types that support the `absl::Hash` framework have a -// compatible equality operator for comparing insertions into `flat_hash_map`. -// If your type is not yet supported by the `asbl::Hash` framework, see -// absl/hash/hash.h for information on extending Abseil hashing to user-defined -// types. -// -// NOTE: A `flat_hash_set` stores its keys directly inside its implementation -// array to avoid memory indirection. Because a `flat_hash_set` is designed to -// move data when rehashed, set keys will not retain pointer stability. If you -// require pointer stability, consider using -// `absl::flat_hash_set>`. If your type is not moveable and -// you require pointer stability, consider `absl::node_hash_set` instead. -// -// Example: -// -// // Create a flat hash set of three strings -// absl::flat_hash_set ducks = -// {"huey", "dewey", "louie"}; -// -// // Insert a new element into the flat hash set -// ducks.insert("donald"); -// -// // Force a rehash of the flat hash set -// ducks.rehash(0); -// -// // See if "dewey" is present -// if (ducks.contains("dewey")) { -// std::cout << "We found dewey!" << std::endl; -// } -template , - class Eq = absl::container_internal::hash_default_eq, - class Allocator = std::allocator> -class flat_hash_set - : public absl::container_internal::raw_hash_set< - absl::container_internal::FlatHashSetPolicy, Hash, Eq, Allocator> { - using Base = typename flat_hash_set::raw_hash_set; - - public: - // Constructors and Assignment Operators - // - // A flat_hash_set supports the same overload set as `std::unordered_map` - // for construction and assignment: - // - // * Default constructor - // - // // No allocation for the table's elements is made. - // absl::flat_hash_set set1; - // - // * Initializer List constructor - // - // absl::flat_hash_set set2 = - // {{"huey"}, {"dewey"}, {"louie"},}; - // - // * Copy constructor - // - // absl::flat_hash_set set3(set2); - // - // * Copy assignment operator - // - // // Hash functor and Comparator are copied as well - // absl::flat_hash_set set4; - // set4 = set3; - // - // * Move constructor - // - // // Move is guaranteed efficient - // absl::flat_hash_set set5(std::move(set4)); - // - // * Move assignment operator - // - // // May be efficient if allocators are compatible - // absl::flat_hash_set set6; - // set6 = std::move(set5); - // - // * Range constructor - // - // std::vector v = {"a", "b"}; - // absl::flat_hash_set set7(v.begin(), v.end()); - flat_hash_set() {} - using Base::Base; - - // flat_hash_set::begin() - // - // Returns an iterator to the beginning of the `flat_hash_set`. - using Base::begin; - - // flat_hash_set::cbegin() - // - // Returns a const iterator to the beginning of the `flat_hash_set`. - using Base::cbegin; - - // flat_hash_set::cend() - // - // Returns a const iterator to the end of the `flat_hash_set`. - using Base::cend; - - // flat_hash_set::end() - // - // Returns an iterator to the end of the `flat_hash_set`. - using Base::end; - - // flat_hash_set::capacity() - // - // Returns the number of element slots (assigned, deleted, and empty) - // available within the `flat_hash_set`. - // - // NOTE: this member function is particular to `absl::flat_hash_set` and is - // not provided in the `std::unordered_map` API. - using Base::capacity; - - // flat_hash_set::empty() - // - // Returns whether or not the `flat_hash_set` is empty. - using Base::empty; - - // flat_hash_set::max_size() - // - // Returns the largest theoretical possible number of elements within a - // `flat_hash_set` under current memory constraints. This value can be thought - // of the largest value of `std::distance(begin(), end())` for a - // `flat_hash_set`. - using Base::max_size; - - // flat_hash_set::size() - // - // Returns the number of elements currently within the `flat_hash_set`. - using Base::size; - - // flat_hash_set::clear() - // - // Removes all elements from the `flat_hash_set`. Invalidates any references, - // pointers, or iterators referring to contained elements. - // - // NOTE: this operation may shrink the underlying buffer. To avoid shrinking - // the underlying buffer call `erase(begin(), end())`. - using Base::clear; - - // flat_hash_set::erase() - // - // Erases elements within the `flat_hash_set`. Erasing does not trigger a - // rehash. Overloads are listed below. - // - // void erase(const_iterator pos): - // - // Erases the element at `position` of the `flat_hash_set`, returning - // `void`. - // - // NOTE: this return behavior is different than that of STL containers in - // general and `std::unordered_map` in particular. - // - // iterator erase(const_iterator first, const_iterator last): - // - // Erases the elements in the open interval [`first`, `last`), returning an - // iterator pointing to `last`. - // - // size_type erase(const key_type& key): - // - // Erases the element with the matching key, if it exists. - using Base::erase; - - // flat_hash_set::insert() - // - // Inserts an element of the specified value into the `flat_hash_set`, - // returning an iterator pointing to the newly inserted element, provided that - // an element with the given key does not already exist. If rehashing occurs - // due to the insertion, all iterators are invalidated. Overloads are listed - // below. - // - // std::pair insert(const T& value): - // - // Inserts a value into the `flat_hash_set`. Returns a pair consisting of an - // iterator to the inserted element (or to the element that prevented the - // insertion) and a bool denoting whether the insertion took place. - // - // std::pair insert(T&& value): - // - // Inserts a moveable value into the `flat_hash_set`. Returns a pair - // consisting of an iterator to the inserted element (or to the element that - // prevented the insertion) and a bool denoting whether the insertion took - // place. - // - // iterator insert(const_iterator hint, const T& value): - // iterator insert(const_iterator hint, T&& value): - // - // Inserts a value, using the position of `hint` as a non-binding suggestion - // for where to begin the insertion search. Returns an iterator to the - // inserted element, or to the existing element that prevented the - // insertion. - // - // void insert(InputIterator first, InputIterator last): - // - // Inserts a range of values [`first`, `last`). - // - // NOTE: Although the STL does not specify which element may be inserted if - // multiple keys compare equivalently, for `flat_hash_set` we guarantee the - // first match is inserted. - // - // void insert(std::initializer_list ilist): - // - // Inserts the elements within the initializer list `ilist`. - // - // NOTE: Although the STL does not specify which element may be inserted if - // multiple keys compare equivalently within the initializer list, for - // `flat_hash_set` we guarantee the first match is inserted. - using Base::insert; - - // flat_hash_set::emplace() - // - // Inserts an element of the specified value by constructing it in-place - // within the `flat_hash_set`, provided that no element with the given key - // already exists. - // - // The element may be constructed even if there already is an element with the - // key in the container, in which case the newly constructed element will be - // destroyed immediately. Prefer `try_emplace()` unless your key is not - // copyable or moveable. - // - // If rehashing occurs due to the insertion, all iterators are invalidated. - using Base::emplace; - - // flat_hash_set::emplace_hint() - // - // Inserts an element of the specified value by constructing it in-place - // within the `flat_hash_set`, using the position of `hint` as a non-binding - // suggestion for where to begin the insertion search, and only inserts - // provided that no element with the given key already exists. - // - // The element may be constructed even if there already is an element with the - // key in the container, in which case the newly constructed element will be - // destroyed immediately. Prefer `try_emplace()` unless your key is not - // copyable or moveable. - // - // If rehashing occurs due to the insertion, all iterators are invalidated. - using Base::emplace_hint; - - // flat_hash_set::extract() - // - // Extracts the indicated element, erasing it in the process, and returns it - // as a C++17-compatible node handle. Overloads are listed below. - // - // node_type extract(const_iterator position): - // - // Extracts the element at the indicated position and returns a node handle - // owning that extracted data. - // - // node_type extract(const key_type& x): - // - // Extracts the element with the key matching the passed key value and - // returns a node handle owning that extracted data. If the `flat_hash_set` - // does not contain an element with a matching key, this function returns an - // empty node handle. - using Base::extract; - - // flat_hash_set::merge() - // - // Extracts elements from a given `source` flat hash map into this - // `flat_hash_set`. If the destination `flat_hash_set` already contains an - // element with an equivalent key, that element is not extracted. - using Base::merge; - - // flat_hash_set::swap(flat_hash_set& other) - // - // Exchanges the contents of this `flat_hash_set` with those of the `other` - // flat hash map, avoiding invocation of any move, copy, or swap operations on - // individual elements. - // - // All iterators and references on the `flat_hash_set` remain valid, excepting - // for the past-the-end iterator, which is invalidated. - // - // `swap()` requires that the flat hash set's hashing and key equivalence - // functions be Swappable, and are exchaged using unqualified calls to - // non-member `swap()`. If the map's allocator has - // `std::allocator_traits::propagate_on_container_swap::value` - // set to `true`, the allocators are also exchanged using an unqualified call - // to non-member `swap()`; otherwise, the allocators are not swapped. - using Base::swap; - - // flat_hash_set::rehash(count) - // - // Rehashes the `flat_hash_set`, setting the number of slots to be at least - // the passed value. If the new number of slots increases the load factor more - // than the current maximum load factor - // (`count` < `size()` / `max_load_factor()`), then the new number of slots - // will be at least `size()` / `max_load_factor()`. - // - // To force a rehash, pass rehash(0). - // - // NOTE: unlike behavior in `std::unordered_set`, references are also - // invalidated upon a `rehash()`. - using Base::rehash; - - // flat_hash_set::reserve(count) - // - // Sets the number of slots in the `flat_hash_set` to the number needed to - // accommodate at least `count` total elements without exceeding the current - // maximum load factor, and may rehash the container if needed. - using Base::reserve; - - // flat_hash_set::contains() - // - // Determines whether an element comparing equal to the given `key` exists - // within the `flat_hash_set`, returning `true` if so or `false` otherwise. - using Base::contains; - - // flat_hash_set::count(const Key& key) const - // - // Returns the number of elements comparing equal to the given `key` within - // the `flat_hash_set`. note that this function will return either `1` or `0` - // since duplicate elements are not allowed within a `flat_hash_set`. - using Base::count; - - // flat_hash_set::equal_range() - // - // Returns a closed range [first, last], defined by a `std::pair` of two - // iterators, containing all elements with the passed key in the - // `flat_hash_set`. - using Base::equal_range; - - // flat_hash_set::find() - // - // Finds an element with the passed `key` within the `flat_hash_set`. - using Base::find; - - // flat_hash_set::bucket_count() - // - // Returns the number of "buckets" within the `flat_hash_set`. Note that - // because a flat hash map contains all elements within its internal storage, - // this value simply equals the current capacity of the `flat_hash_set`. - using Base::bucket_count; - - // flat_hash_set::load_factor() - // - // Returns the current load factor of the `flat_hash_set` (the average number - // of slots occupied with a value within the hash map). - using Base::load_factor; - - // flat_hash_set::max_load_factor() - // - // Manages the maximum load factor of the `flat_hash_set`. Overloads are - // listed below. - // - // float flat_hash_set::max_load_factor() - // - // Returns the current maximum load factor of the `flat_hash_set`. - // - // void flat_hash_set::max_load_factor(float ml) - // - // Sets the maximum load factor of the `flat_hash_set` to the passed value. - // - // NOTE: This overload is provided only for API compatibility with the STL; - // `flat_hash_set` will ignore any set load factor and manage its rehashing - // internally as an implementation detail. - using Base::max_load_factor; - - // flat_hash_set::get_allocator() - // - // Returns the allocator function associated with this `flat_hash_set`. - using Base::get_allocator; - - // flat_hash_set::hash_function() - // - // Returns the hashing function used to hash the keys within this - // `flat_hash_set`. - using Base::hash_function; - - // flat_hash_set::key_eq() - // - // Returns the function used for comparing keys equality. - using Base::key_eq; -}; - -namespace container_internal { - -template -struct FlatHashSetPolicy { - using slot_type = T; - using key_type = T; - using init_type = T; - using constant_iterators = std::true_type; - - template - static void construct(Allocator* alloc, slot_type* slot, Args&&... args) { - absl::allocator_traits::construct(*alloc, slot, - std::forward(args)...); - } - - template - static void destroy(Allocator* alloc, slot_type* slot) { - absl::allocator_traits::destroy(*alloc, slot); - } - - template - static void transfer(Allocator* alloc, slot_type* new_slot, - slot_type* old_slot) { - construct(alloc, new_slot, std::move(*old_slot)); - destroy(alloc, old_slot); - } - - static T& element(slot_type* slot) { return *slot; } - - template - static decltype(absl::container_internal::DecomposeValue( - std::declval(), std::declval()...)) - apply(F&& f, Args&&... args) { - return absl::container_internal::DecomposeValue( - std::forward(f), std::forward(args)...); - } - - static size_t space_used(const T*) { return 0; } -}; -} // namespace container_internal -} // namespace absl -#endif // ABSL_CONTAINER_FLAT_HASH_SET_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/flat_hash_set_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/flat_hash_set_test.cc deleted file mode 100644 index e52fd53..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/flat_hash_set_test.cc +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include "absl/container/flat_hash_set.h" - -#include - -#include "absl/container/internal/hash_generator_testing.h" -#include "absl/container/internal/unordered_set_constructor_test.h" -#include "absl/container/internal/unordered_set_lookup_test.h" -#include "absl/container/internal/unordered_set_modifiers_test.h" -#include "absl/memory/memory.h" -#include "absl/strings/string_view.h" - -namespace absl { -namespace container_internal { -namespace { - -using ::absl::container_internal::hash_internal::Enum; -using ::absl::container_internal::hash_internal::EnumClass; -using ::testing::Pointee; -using ::testing::UnorderedElementsAre; -using ::testing::UnorderedElementsAreArray; - -template -using Set = - absl::flat_hash_set>; - -using SetTypes = - ::testing::Types, Set, Set, Set>; - -INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, ConstructorTest, SetTypes); -INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, LookupTest, SetTypes); -INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, ModifiersTest, SetTypes); - -TEST(FlatHashSet, EmplaceString) { - std::vector v = {"a", "b"}; - absl::flat_hash_set hs(v.begin(), v.end()); - EXPECT_THAT(hs, UnorderedElementsAreArray(v)); -} - -TEST(FlatHashSet, BitfieldArgument) { - union { - int n : 1; - }; - n = 0; - absl::flat_hash_set s = {n}; - s.insert(n); - s.insert(s.end(), n); - s.insert({n}); - s.erase(n); - s.count(n); - s.prefetch(n); - s.find(n); - s.contains(n); - s.equal_range(n); -} - -TEST(FlatHashSet, MergeExtractInsert) { - struct Hash { - size_t operator()(const std::unique_ptr& p) const { return *p; } - }; - struct Eq { - bool operator()(const std::unique_ptr& a, - const std::unique_ptr& b) const { - return *a == *b; - } - }; - absl::flat_hash_set, Hash, Eq> set1, set2; - set1.insert(absl::make_unique(7)); - set1.insert(absl::make_unique(17)); - - set2.insert(absl::make_unique(7)); - set2.insert(absl::make_unique(19)); - - EXPECT_THAT(set1, UnorderedElementsAre(Pointee(7), Pointee(17))); - EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7), Pointee(19))); - - set1.merge(set2); - - EXPECT_THAT(set1, UnorderedElementsAre(Pointee(7), Pointee(17), Pointee(19))); - EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7))); - - auto node = set1.extract(absl::make_unique(7)); - EXPECT_TRUE(node); - EXPECT_THAT(node.value(), Pointee(7)); - EXPECT_THAT(set1, UnorderedElementsAre(Pointee(17), Pointee(19))); - - auto insert_result = set2.insert(std::move(node)); - EXPECT_FALSE(node); - EXPECT_FALSE(insert_result.inserted); - EXPECT_TRUE(insert_result.node); - EXPECT_THAT(insert_result.node.value(), Pointee(7)); - EXPECT_EQ(**insert_result.position, 7); - EXPECT_NE(insert_result.position->get(), insert_result.node.value().get()); - EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7))); - - node = set1.extract(absl::make_unique(17)); - EXPECT_TRUE(node); - EXPECT_THAT(node.value(), Pointee(17)); - EXPECT_THAT(set1, UnorderedElementsAre(Pointee(19))); - - node.value() = absl::make_unique(23); - - insert_result = set2.insert(std::move(node)); - EXPECT_FALSE(node); - EXPECT_TRUE(insert_result.inserted); - EXPECT_FALSE(insert_result.node); - EXPECT_EQ(**insert_result.position, 23); - EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7), Pointee(23))); -} - -} // namespace -} // namespace container_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/inlined_vector.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/inlined_vector.h deleted file mode 100644 index ea8cb02..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/inlined_vector.h +++ /dev/null @@ -1,1452 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. -// -// ----------------------------------------------------------------------------- -// File: inlined_vector.h -// ----------------------------------------------------------------------------- -// -// This header file contains the declaration and definition of an "inlined -// vector" which behaves in an equivalent fashion to a `std::vector`, except -// that storage for small sequences of the vector are provided inline without -// requiring any heap allocation. - -// An `absl::InlinedVector` specifies the size N at which to inline as one -// of its template parameters. Vectors of length <= N are provided inline. -// Typically N is very small (e.g., 4) so that sequences that are expected to be -// short do not require allocations. - -// An `absl::InlinedVector` does not usually require a specific allocator; if -// the inlined vector grows beyond its initial constraints, it will need to -// allocate (as any normal `std::vector` would) and it will generally use the -// default allocator in that case; optionally, a custom allocator may be -// specified using an `absl::InlinedVector` construction. - -#ifndef ABSL_CONTAINER_INLINED_VECTOR_H_ -#define ABSL_CONTAINER_INLINED_VECTOR_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "absl/algorithm/algorithm.h" -#include "absl/base/internal/throw_delegate.h" -#include "absl/base/optimization.h" -#include "absl/base/port.h" -#include "absl/memory/memory.h" - -namespace absl { - -// ----------------------------------------------------------------------------- -// InlinedVector -// ----------------------------------------------------------------------------- -// -// An `absl::InlinedVector` is designed to be a drop-in replacement for -// `std::vector` for use cases where the vector's size is sufficiently small -// that it can be inlined. If the inlined vector does grow beyond its estimated -// size, it will trigger an initial allocation on the heap, and will behave as a -// `std:vector`. The API of the `absl::InlinedVector` within this file is -// designed to cover the same API footprint as covered by `std::vector`. -template > -class InlinedVector { - constexpr static typename A::size_type inlined_capacity() { - return static_cast(N); - } - - static_assert(inlined_capacity() > 0, "InlinedVector needs inlined capacity"); - - template - using DisableIfIntegral = - absl::enable_if_t::value>; - - template - using EnableIfInputIterator = absl::enable_if_t::iterator_category, - std::input_iterator_tag>::value>; - - template - using IteratorCategory = - typename std::iterator_traits::iterator_category; - - using rvalue_reference = typename A::value_type&&; - - public: - using allocator_type = A; - using value_type = typename allocator_type::value_type; - using pointer = typename allocator_type::pointer; - using const_pointer = typename allocator_type::const_pointer; - using reference = typename allocator_type::reference; - using const_reference = typename allocator_type::const_reference; - using size_type = typename allocator_type::size_type; - using difference_type = typename allocator_type::difference_type; - using iterator = pointer; - using const_iterator = const_pointer; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - - - // --------------------------------------------------------------------------- - // InlinedVector Constructors and Destructor - // --------------------------------------------------------------------------- - - // Creates an empty inlined vector with a default initialized allocator. - InlinedVector() noexcept(noexcept(allocator_type())) - : allocator_and_tag_(allocator_type()) {} - - // Creates an empty inlined vector with a specified allocator. - explicit InlinedVector(const allocator_type& alloc) noexcept - : allocator_and_tag_(alloc) {} - - // Creates an inlined vector with `n` copies of `value_type()`. - explicit InlinedVector(size_type n, - const allocator_type& alloc = allocator_type()) - : allocator_and_tag_(alloc) { - InitAssign(n); - } - - // Creates an inlined vector with `n` copies of `v`. - InlinedVector(size_type n, const_reference v, - const allocator_type& alloc = allocator_type()) - : allocator_and_tag_(alloc) { - InitAssign(n, v); - } - - // Creates an inlined vector of copies of the values in `init_list`. - InlinedVector(std::initializer_list init_list, - const allocator_type& alloc = allocator_type()) - : allocator_and_tag_(alloc) { - AppendRange(init_list.begin(), init_list.end()); - } - - // Creates and initialize with the elements [`first`, `last`). - // - // NOTE: The `enable_if` prevents ambiguous interpretation between a call to - // this constructor with two integral arguments and a call to the preceding - // `InlinedVector(n, v)` constructor. - template * = nullptr> - InlinedVector(InputIterator first, InputIterator last, - const allocator_type& alloc = allocator_type()) - : allocator_and_tag_(alloc) { - AppendRange(first, last); - } - - // Creates a copy of `other` using `other`'s allocator. - InlinedVector(const InlinedVector& other); - - // Creates a copy of `other` but with a specified allocator. - InlinedVector(const InlinedVector& other, const allocator_type& alloc); - - // Creates an inlined vector with the contents of `other`. - // - // NOTE: This move constructor does not allocate and only moves the underlying - // objects, so its `noexcept` specification depends on whether moving the - // underlying objects can throw or not. We assume - // a) move constructors should only throw due to allocation failure and - // b) if `value_type`'s move constructor allocates, it uses the same - // allocation function as the `InlinedVector`'s allocator, so the move - // constructor is non-throwing if the allocator is non-throwing or - // `value_type`'s move constructor is specified as `noexcept`. - InlinedVector(InlinedVector&& v) noexcept( - absl::allocator_is_nothrow::value || - std::is_nothrow_move_constructible::value); - - // Creates an inlined vector with the contents of `other`. - // - // NOTE: This move constructor allocates and also moves the underlying - // objects, so its `noexcept` specification depends on whether the allocation - // can throw and whether moving the underlying objects can throw. Based on the - // same assumptions as above, the `noexcept` specification is dominated by - // whether the allocation can throw regardless of whether `value_type`'s move - // constructor is specified as `noexcept`. - InlinedVector(InlinedVector&& v, const allocator_type& alloc) noexcept( - absl::allocator_is_nothrow::value); - - ~InlinedVector() { clear(); } - - - // --------------------------------------------------------------------------- - // InlinedVector Member Accessors - // --------------------------------------------------------------------------- - - // `InlinedVector::empty()` - // - // Checks if the inlined vector has no elements. - bool empty() const noexcept { return !size(); } - - // `InlinedVector::size()` - // - // Returns the number of elements in the inlined vector. - size_type size() const noexcept { return tag().size(); } - - // `InlinedVector::max_size()` - // - // Returns the maximum number of elements the vector can hold. - size_type max_size() const noexcept { - // One bit of the size storage is used to indicate whether the inlined - // vector is allocated. As a result, the maximum size of the container that - // we can express is half of the max for `size_type`. - return (std::numeric_limits::max)() / 2; - } - - // `InlinedVector::capacity()` - // - // Returns the number of elements that can be stored in the inlined vector - // without requiring a reallocation of underlying memory. - // - // NOTE: For most inlined vectors, `capacity()` should equal - // `inlined_capacity()`. For inlined vectors which exceed this capacity, they - // will no longer be inlined and `capacity()` will equal its capacity on the - // allocated heap. - size_type capacity() const noexcept { - return allocated() ? allocation().capacity() : inlined_capacity(); - } - - // `InlinedVector::data()` - // - // Returns a `pointer` to elements of the inlined vector. This pointer can be - // used to access and modify the contained elements. - // Only results within the range [`0`, `size()`) are defined. - pointer data() noexcept { - return allocated() ? allocated_space() : inlined_space(); - } - - // Overload of `InlinedVector::data()` to return a `const_pointer` to elements - // of the inlined vector. This pointer can be used to access (but not modify) - // the contained elements. - const_pointer data() const noexcept { - return allocated() ? allocated_space() : inlined_space(); - } - - // `InlinedVector::operator[]()` - // - // Returns a `reference` to the `i`th element of the inlined vector using the - // array operator. - reference operator[](size_type i) { - assert(i < size()); - return data()[i]; - } - - // Overload of `InlinedVector::operator[]()` to return a `const_reference` to - // the `i`th element of the inlined vector. - const_reference operator[](size_type i) const { - assert(i < size()); - return data()[i]; - } - - // `InlinedVector::at()` - // - // Returns a `reference` to the `i`th element of the inlined vector. - reference at(size_type i) { - if (ABSL_PREDICT_FALSE(i >= size())) { - base_internal::ThrowStdOutOfRange( - "InlinedVector::at() failed bounds check"); - } - return data()[i]; - } - - // Overload of `InlinedVector::at()` to return a `const_reference` to the - // `i`th element of the inlined vector. - const_reference at(size_type i) const { - if (ABSL_PREDICT_FALSE(i >= size())) { - base_internal::ThrowStdOutOfRange( - "InlinedVector::at() failed bounds check"); - } - return data()[i]; - } - - // `InlinedVector::front()` - // - // Returns a `reference` to the first element of the inlined vector. - reference front() { - assert(!empty()); - return at(0); - } - - // Overload of `InlinedVector::front()` returns a `const_reference` to the - // first element of the inlined vector. - const_reference front() const { - assert(!empty()); - return at(0); - } - - // `InlinedVector::back()` - // - // Returns a `reference` to the last element of the inlined vector. - reference back() { - assert(!empty()); - return at(size() - 1); - } - - // Overload of `InlinedVector::back()` to return a `const_reference` to the - // last element of the inlined vector. - const_reference back() const { - assert(!empty()); - return at(size() - 1); - } - - // `InlinedVector::begin()` - // - // Returns an `iterator` to the beginning of the inlined vector. - iterator begin() noexcept { return data(); } - - // Overload of `InlinedVector::begin()` to return a `const_iterator` to - // the beginning of the inlined vector. - const_iterator begin() const noexcept { return data(); } - - // `InlinedVector::end()` - // - // Returns an `iterator` to the end of the inlined vector. - iterator end() noexcept { return data() + size(); } - - // Overload of `InlinedVector::end()` to return a `const_iterator` to the - // end of the inlined vector. - const_iterator end() const noexcept { return data() + size(); } - - // `InlinedVector::cbegin()` - // - // Returns a `const_iterator` to the beginning of the inlined vector. - const_iterator cbegin() const noexcept { return begin(); } - - // `InlinedVector::cend()` - // - // Returns a `const_iterator` to the end of the inlined vector. - const_iterator cend() const noexcept { return end(); } - - // `InlinedVector::rbegin()` - // - // Returns a `reverse_iterator` from the end of the inlined vector. - reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } - - // Overload of `InlinedVector::rbegin()` to return a - // `const_reverse_iterator` from the end of the inlined vector. - const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); - } - - // `InlinedVector::rend()` - // - // Returns a `reverse_iterator` from the beginning of the inlined vector. - reverse_iterator rend() noexcept { return reverse_iterator(begin()); } - - // Overload of `InlinedVector::rend()` to return a `const_reverse_iterator` - // from the beginning of the inlined vector. - const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); - } - - // `InlinedVector::crbegin()` - // - // Returns a `const_reverse_iterator` from the end of the inlined vector. - const_reverse_iterator crbegin() const noexcept { return rbegin(); } - - // `InlinedVector::crend()` - // - // Returns a `const_reverse_iterator` from the beginning of the inlined - // vector. - const_reverse_iterator crend() const noexcept { return rend(); } - - // `InlinedVector::get_allocator()` - // - // Returns a copy of the allocator of the inlined vector. - allocator_type get_allocator() const { return allocator(); } - - - // --------------------------------------------------------------------------- - // InlinedVector Member Mutators - // --------------------------------------------------------------------------- - - // `InlinedVector::operator=()` - // - // Replaces the contents of the inlined vector with copies of the elements in - // the provided `std::initializer_list`. - InlinedVector& operator=(std::initializer_list init_list) { - AssignRange(init_list.begin(), init_list.end()); - return *this; - } - - // Overload of `InlinedVector::operator=()` to replace the contents of the - // inlined vector with the contents of `other`. - InlinedVector& operator=(const InlinedVector& other) { - if (ABSL_PREDICT_FALSE(this == &other)) return *this; - - // Optimized to avoid reallocation. - // Prefer reassignment to copy construction for elements. - if (size() < other.size()) { // grow - reserve(other.size()); - std::copy(other.begin(), other.begin() + size(), begin()); - std::copy(other.begin() + size(), other.end(), std::back_inserter(*this)); - } else { // maybe shrink - erase(begin() + other.size(), end()); - std::copy(other.begin(), other.end(), begin()); - } - return *this; - } - - // Overload of `InlinedVector::operator=()` to replace the contents of the - // inlined vector with the contents of `other`. - // - // NOTE: As a result of calling this overload, `other` may be empty or it's - // contents may be left in a moved-from state. - InlinedVector& operator=(InlinedVector&& other) { - if (ABSL_PREDICT_FALSE(this == &other)) return *this; - - if (other.allocated()) { - clear(); - tag().set_allocated_size(other.size()); - init_allocation(other.allocation()); - other.tag() = Tag(); - } else { - if (allocated()) clear(); - // Both are inlined now. - if (size() < other.size()) { - auto mid = std::make_move_iterator(other.begin() + size()); - std::copy(std::make_move_iterator(other.begin()), mid, begin()); - UninitializedCopy(mid, std::make_move_iterator(other.end()), end()); - } else { - auto new_end = std::copy(std::make_move_iterator(other.begin()), - std::make_move_iterator(other.end()), begin()); - Destroy(new_end, end()); - } - tag().set_inline_size(other.size()); - } - return *this; - } - - // `InlinedVector::assign()` - // - // Replaces the contents of the inlined vector with `n` copies of `v`. - void assign(size_type n, const_reference v) { - if (n <= size()) { // Possibly shrink - std::fill_n(begin(), n, v); - erase(begin() + n, end()); - return; - } - // Grow - reserve(n); - std::fill_n(begin(), size(), v); - if (allocated()) { - UninitializedFill(allocated_space() + size(), allocated_space() + n, v); - tag().set_allocated_size(n); - } else { - UninitializedFill(inlined_space() + size(), inlined_space() + n, v); - tag().set_inline_size(n); - } - } - - // Overload of `InlinedVector::assign()` to replace the contents of the - // inlined vector with copies of the values in the provided - // `std::initializer_list`. - void assign(std::initializer_list init_list) { - AssignRange(init_list.begin(), init_list.end()); - } - - // Overload of `InlinedVector::assign()` to replace the contents of the - // inlined vector with values constructed from the range [`first`, `last`). - template * = nullptr> - void assign(InputIterator first, InputIterator last) { - AssignRange(first, last); - } - - // `InlinedVector::resize()` - // - // Resizes the inlined vector to contain `n` elements. If `n` is smaller than - // the inlined vector's current size, extra elements are destroyed. If `n` is - // larger than the initial size, new elements are value-initialized. - void resize(size_type n); - - // Overload of `InlinedVector::resize()` to resize the inlined vector to - // contain `n` elements where, if `n` is larger than `size()`, the new values - // will be copy-constructed from `v`. - void resize(size_type n, const_reference v); - - // `InlinedVector::insert()` - // - // Copies `v` into `position`, returning an `iterator` pointing to the newly - // inserted element. - iterator insert(const_iterator position, const_reference v) { - return emplace(position, v); - } - - // Overload of `InlinedVector::insert()` for moving `v` into `position`, - // returning an iterator pointing to the newly inserted element. - iterator insert(const_iterator position, rvalue_reference v) { - return emplace(position, std::move(v)); - } - - // Overload of `InlinedVector::insert()` for inserting `n` contiguous copies - // of `v` starting at `position`. Returns an `iterator` pointing to the first - // of the newly inserted elements. - iterator insert(const_iterator position, size_type n, const_reference v) { - return InsertWithCount(position, n, v); - } - - // Overload of `InlinedVector::insert()` for copying the contents of the - // `std::initializer_list` into the vector starting at `position`. Returns an - // `iterator` pointing to the first of the newly inserted elements. - iterator insert(const_iterator position, - std::initializer_list init_list) { - return insert(position, init_list.begin(), init_list.end()); - } - - // Overload of `InlinedVector::insert()` for inserting elements constructed - // from the range [`first`, `last`). Returns an `iterator` pointing to the - // first of the newly inserted elements. - // - // NOTE: The `enable_if` is intended to disambiguate the two three-argument - // overloads of `insert()`. - template > - iterator insert(const_iterator position, InputIterator first, - InputIterator last) { - return InsertWithRange(position, first, last, - IteratorCategory()); - } - - // `InlinedVector::emplace()` - // - // Constructs and inserts an object in the inlined vector at the given - // `position`, returning an `iterator` pointing to the newly emplaced element. - template - iterator emplace(const_iterator position, Args&&... args); - - // `InlinedVector::emplace_back()` - // - // Constructs and appends a new element to the end of the inlined vector, - // returning a `reference` to the emplaced element. - template - reference emplace_back(Args&&... args) { - size_type s = size(); - assert(s <= capacity()); - if (ABSL_PREDICT_FALSE(s == capacity())) { - return GrowAndEmplaceBack(std::forward(args)...); - } - assert(s < capacity()); - - pointer space; - if (allocated()) { - tag().set_allocated_size(s + 1); - space = allocated_space(); - } else { - tag().set_inline_size(s + 1); - space = inlined_space(); - } - return Construct(space + s, std::forward(args)...); - } - - // `InlinedVector::push_back()` - // - // Appends a copy of `v` to the end of the inlined vector. - void push_back(const_reference v) { static_cast(emplace_back(v)); } - - // Overload of `InlinedVector::push_back()` for moving `v` into a newly - // appended element. - void push_back(rvalue_reference v) { - static_cast(emplace_back(std::move(v))); - } - - // `InlinedVector::pop_back()` - // - // Destroys the element at the end of the inlined vector and shrinks the size - // by `1` (unless the inlined vector is empty, in which case this is a no-op). - void pop_back() noexcept { - assert(!empty()); - size_type s = size(); - if (allocated()) { - Destroy(allocated_space() + s - 1, allocated_space() + s); - tag().set_allocated_size(s - 1); - } else { - Destroy(inlined_space() + s - 1, inlined_space() + s); - tag().set_inline_size(s - 1); - } - } - - // `InlinedVector::erase()` - // - // Erases the element at `position` of the inlined vector, returning an - // `iterator` pointing to the first element following the erased element. - // - // NOTE: May return the end iterator, which is not dereferencable. - iterator erase(const_iterator position) { - assert(position >= begin()); - assert(position < end()); - - iterator pos = const_cast(position); - std::move(pos + 1, end(), pos); - pop_back(); - return pos; - } - - // Overload of `InlinedVector::erase()` for erasing all elements in the - // range [`from`, `to`) in the inlined vector. Returns an `iterator` pointing - // to the first element following the range erased or the end iterator if `to` - // was the end iterator. - iterator erase(const_iterator from, const_iterator to); - - // `InlinedVector::clear()` - // - // Destroys all elements in the inlined vector, sets the size of `0` and - // deallocates the heap allocation if the inlined vector was allocated. - void clear() noexcept { - size_type s = size(); - if (allocated()) { - Destroy(allocated_space(), allocated_space() + s); - allocation().Dealloc(allocator()); - } else if (s != 0) { // do nothing for empty vectors - Destroy(inlined_space(), inlined_space() + s); - } - tag() = Tag(); - } - - // `InlinedVector::reserve()` - // - // Enlarges the underlying representation of the inlined vector so it can hold - // at least `n` elements. This method does not change `size()` or the actual - // contents of the vector. - // - // NOTE: If `n` does not exceed `capacity()`, `reserve()` will have no - // effects. Otherwise, `reserve()` will reallocate, performing an n-time - // element-wise move of everything contained. - void reserve(size_type n) { - if (n > capacity()) { - // Make room for new elements - EnlargeBy(n - size()); - } - } - - // `InlinedVector::shrink_to_fit()` - // - // Reduces memory usage by freeing unused memory. After this call, calls to - // `capacity()` will be equal to `(std::max)(inlined_capacity(), size())`. - // - // If `size() <= inlined_capacity()` and the elements are currently stored on - // the heap, they will be moved to the inlined storage and the heap memory - // will be deallocated. - // - // If `size() > inlined_capacity()` and `size() < capacity()` the elements - // will be moved to a smaller heap allocation. - void shrink_to_fit() { - const auto s = size(); - if (ABSL_PREDICT_FALSE(!allocated() || s == capacity())) return; - - if (s <= inlined_capacity()) { - // Move the elements to the inlined storage. - // We have to do this using a temporary, because `inlined_storage` and - // `allocation_storage` are in a union field. - auto temp = std::move(*this); - assign(std::make_move_iterator(temp.begin()), - std::make_move_iterator(temp.end())); - return; - } - - // Reallocate storage and move elements. - // We can't simply use the same approach as above, because `assign()` would - // call into `reserve()` internally and reserve larger capacity than we need - Allocation new_allocation(allocator(), s); - UninitializedCopy(std::make_move_iterator(allocated_space()), - std::make_move_iterator(allocated_space() + s), - new_allocation.buffer()); - ResetAllocation(new_allocation, s); - } - - // `InlinedVector::swap()` - // - // Swaps the contents of this inlined vector with the contents of `other`. - void swap(InlinedVector& other); - - template - friend Hash AbslHashValue(Hash hash, const InlinedVector& inlined_vector) { - const_pointer p = inlined_vector.data(); - size_type n = inlined_vector.size(); - return Hash::combine(Hash::combine_contiguous(std::move(hash), p, n), n); - } - - private: - // Holds whether the vector is allocated or not in the lowest bit and the size - // in the high bits: - // `size_ = (size << 1) | is_allocated;` - class Tag { - public: - Tag() : size_(0) {} - size_type size() const { return size_ / 2; } - void add_size(size_type n) { size_ += n * 2; } - void set_inline_size(size_type n) { size_ = n * 2; } - void set_allocated_size(size_type n) { size_ = (n * 2) + 1; } - bool allocated() const { return size_ % 2; } - - private: - size_type size_; - }; - - // Derives from `allocator_type` to use the empty base class optimization. - // If the `allocator_type` is stateless, we can store our instance for free. - class AllocatorAndTag : private allocator_type { - public: - explicit AllocatorAndTag(const allocator_type& a) : allocator_type(a) {} - - Tag& tag() { return tag_; } - const Tag& tag() const { return tag_; } - - allocator_type& allocator() { return *this; } - const allocator_type& allocator() const { return *this; } - - private: - Tag tag_; - }; - - class Allocation { - public: - Allocation(allocator_type& a, size_type capacity) - : capacity_(capacity), buffer_(Create(a, capacity)) {} - - void Dealloc(allocator_type& a) { - std::allocator_traits::deallocate(a, buffer_, capacity_); - } - - size_type capacity() const { return capacity_; } - - const_pointer buffer() const { return buffer_; } - - pointer buffer() { return buffer_; } - - private: - static pointer Create(allocator_type& a, size_type n) { - return std::allocator_traits::allocate(a, n); - } - - size_type capacity_; - pointer buffer_; - }; - - const Tag& tag() const { return allocator_and_tag_.tag(); } - - Tag& tag() { return allocator_and_tag_.tag(); } - - Allocation& allocation() { - return reinterpret_cast(rep_.allocation_storage.allocation); - } - - const Allocation& allocation() const { - return reinterpret_cast( - rep_.allocation_storage.allocation); - } - - void init_allocation(const Allocation& allocation) { - new (&rep_.allocation_storage.allocation) Allocation(allocation); - } - - // TODO(absl-team): investigate whether the reinterpret_cast is appropriate. - pointer inlined_space() { - return reinterpret_cast( - std::addressof(rep_.inlined_storage.inlined[0])); - } - - const_pointer inlined_space() const { - return reinterpret_cast( - std::addressof(rep_.inlined_storage.inlined[0])); - } - - pointer allocated_space() { return allocation().buffer(); } - - const_pointer allocated_space() const { return allocation().buffer(); } - - const allocator_type& allocator() const { - return allocator_and_tag_.allocator(); - } - - allocator_type& allocator() { return allocator_and_tag_.allocator(); } - - bool allocated() const { return tag().allocated(); } - - // Enlarge the underlying representation so we can store `size_ + delta` elems - // in allocated space. The size is not changed, and any newly added memory is - // not initialized. - void EnlargeBy(size_type delta); - - // Shift all elements from `position` to `end()` by `n` places to the right. - // If the vector needs to be enlarged, memory will be allocated. - // Returns `iterator`s pointing to the start of the previously-initialized - // portion and the start of the uninitialized portion of the created gap. - // The number of initialized spots is `pair.second - pair.first`. The number - // of raw spots is `n - (pair.second - pair.first)`. - // - // Updates the size of the InlinedVector internally. - std::pair ShiftRight(const_iterator position, - size_type n); - - void ResetAllocation(Allocation new_allocation, size_type new_size) { - if (allocated()) { - Destroy(allocated_space(), allocated_space() + size()); - assert(begin() == allocated_space()); - allocation().Dealloc(allocator()); - allocation() = new_allocation; - } else { - Destroy(inlined_space(), inlined_space() + size()); - init_allocation(new_allocation); // bug: only init once - } - tag().set_allocated_size(new_size); - } - - template - reference GrowAndEmplaceBack(Args&&... args) { - assert(size() == capacity()); - const size_type s = size(); - - Allocation new_allocation(allocator(), 2 * capacity()); - - reference new_element = - Construct(new_allocation.buffer() + s, std::forward(args)...); - UninitializedCopy(std::make_move_iterator(data()), - std::make_move_iterator(data() + s), - new_allocation.buffer()); - - ResetAllocation(new_allocation, s + 1); - - return new_element; - } - - void InitAssign(size_type n); - - void InitAssign(size_type n, const_reference v); - - template - reference Construct(pointer p, Args&&... args) { - std::allocator_traits::construct( - allocator(), p, std::forward(args)...); - return *p; - } - - template - void UninitializedCopy(Iterator src, Iterator src_last, pointer dst) { - for (; src != src_last; ++dst, ++src) Construct(dst, *src); - } - - template - void UninitializedFill(pointer dst, pointer dst_last, const Args&... args) { - for (; dst != dst_last; ++dst) Construct(dst, args...); - } - - // Destroy [`from`, `to`) in place. - void Destroy(pointer from, pointer to); - - template - void AppendRange(Iterator first, Iterator last, std::input_iterator_tag) { - std::copy(first, last, std::back_inserter(*this)); - } - - template - void AppendRange(Iterator first, Iterator last, std::forward_iterator_tag); - - template - void AppendRange(Iterator first, Iterator last) { - AppendRange(first, last, IteratorCategory()); - } - - template - void AssignRange(Iterator first, Iterator last, std::input_iterator_tag); - - template - void AssignRange(Iterator first, Iterator last, std::forward_iterator_tag); - - template - void AssignRange(Iterator first, Iterator last) { - AssignRange(first, last, IteratorCategory()); - } - - iterator InsertWithCount(const_iterator position, size_type n, - const_reference v); - - template - iterator InsertWithRange(const_iterator position, InputIterator first, - InputIterator last, std::input_iterator_tag); - - template - iterator InsertWithRange(const_iterator position, ForwardIterator first, - ForwardIterator last, std::forward_iterator_tag); - - // Stores either the inlined or allocated representation - union Rep { - using ValueTypeBuffer = - absl::aligned_storage_t; - using AllocationBuffer = - absl::aligned_storage_t; - - // Structs wrap the buffers to perform indirection that solves a bizarre - // compilation error on Visual Studio (all known versions). - struct InlinedRep { - ValueTypeBuffer inlined[inlined_capacity()]; - }; - struct AllocatedRep { - AllocationBuffer allocation; - }; - - InlinedRep inlined_storage; - AllocatedRep allocation_storage; - }; - - AllocatorAndTag allocator_and_tag_; - Rep rep_; -}; - -// ----------------------------------------------------------------------------- -// InlinedVector Non-Member Functions -// ----------------------------------------------------------------------------- - -// `swap()` -// -// Swaps the contents of two inlined vectors. This convenience function -// simply calls `InlinedVector::swap()`. -template -void swap(InlinedVector& a, - InlinedVector& b) noexcept(noexcept(a.swap(b))) { - a.swap(b); -} - -// `operator==()` -// -// Tests the equivalency of the contents of two inlined vectors. -template -bool operator==(const InlinedVector& a, - const InlinedVector& b) { - return absl::equal(a.begin(), a.end(), b.begin(), b.end()); -} - -// `operator!=()` -// -// Tests the inequality of the contents of two inlined vectors. -template -bool operator!=(const InlinedVector& a, - const InlinedVector& b) { - return !(a == b); -} - -// `operator<()` -// -// Tests whether the contents of one inlined vector are less than the contents -// of another through a lexicographical comparison operation. -template -bool operator<(const InlinedVector& a, - const InlinedVector& b) { - return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); -} - -// `operator>()` -// -// Tests whether the contents of one inlined vector are greater than the -// contents of another through a lexicographical comparison operation. -template -bool operator>(const InlinedVector& a, - const InlinedVector& b) { - return b < a; -} - -// `operator<=()` -// -// Tests whether the contents of one inlined vector are less than or equal to -// the contents of another through a lexicographical comparison operation. -template -bool operator<=(const InlinedVector& a, - const InlinedVector& b) { - return !(b < a); -} - -// `operator>=()` -// -// Tests whether the contents of one inlined vector are greater than or equal to -// the contents of another through a lexicographical comparison operation. -template -bool operator>=(const InlinedVector& a, - const InlinedVector& b) { - return !(a < b); -} - -// ----------------------------------------------------------------------------- -// Implementation of InlinedVector -// -// Do not depend on any below implementation details! -// ----------------------------------------------------------------------------- - -template -InlinedVector::InlinedVector(const InlinedVector& other) - : allocator_and_tag_(other.allocator()) { - reserve(other.size()); - if (allocated()) { - UninitializedCopy(other.begin(), other.end(), allocated_space()); - tag().set_allocated_size(other.size()); - } else { - UninitializedCopy(other.begin(), other.end(), inlined_space()); - tag().set_inline_size(other.size()); - } -} - -template -InlinedVector::InlinedVector(const InlinedVector& other, - const allocator_type& alloc) - : allocator_and_tag_(alloc) { - reserve(other.size()); - if (allocated()) { - UninitializedCopy(other.begin(), other.end(), allocated_space()); - tag().set_allocated_size(other.size()); - } else { - UninitializedCopy(other.begin(), other.end(), inlined_space()); - tag().set_inline_size(other.size()); - } -} - -template -InlinedVector::InlinedVector(InlinedVector&& other) noexcept( - absl::allocator_is_nothrow::value || - std::is_nothrow_move_constructible::value) - : allocator_and_tag_(other.allocator_and_tag_) { - if (other.allocated()) { - // We can just steal the underlying buffer from the source. - // That leaves the source empty, so we clear its size. - init_allocation(other.allocation()); - other.tag() = Tag(); - } else { - UninitializedCopy( - std::make_move_iterator(other.inlined_space()), - std::make_move_iterator(other.inlined_space() + other.size()), - inlined_space()); - } -} - -template -InlinedVector::InlinedVector(InlinedVector&& other, - const allocator_type& alloc) noexcept( // - absl::allocator_is_nothrow::value) - : allocator_and_tag_(alloc) { - if (other.allocated()) { - if (alloc == other.allocator()) { - // We can just steal the allocation from the source. - tag() = other.tag(); - init_allocation(other.allocation()); - other.tag() = Tag(); - } else { - // We need to use our own allocator - reserve(other.size()); - UninitializedCopy(std::make_move_iterator(other.begin()), - std::make_move_iterator(other.end()), - allocated_space()); - tag().set_allocated_size(other.size()); - } - } else { - UninitializedCopy( - std::make_move_iterator(other.inlined_space()), - std::make_move_iterator(other.inlined_space() + other.size()), - inlined_space()); - tag().set_inline_size(other.size()); - } -} - -template -void InlinedVector::InitAssign(size_type n, const_reference v) { - if (n > inlined_capacity()) { - Allocation new_allocation(allocator(), n); - init_allocation(new_allocation); - UninitializedFill(allocated_space(), allocated_space() + n, v); - tag().set_allocated_size(n); - } else { - UninitializedFill(inlined_space(), inlined_space() + n, v); - tag().set_inline_size(n); - } -} - -template -void InlinedVector::InitAssign(size_type n) { - if (n > inlined_capacity()) { - Allocation new_allocation(allocator(), n); - init_allocation(new_allocation); - UninitializedFill(allocated_space(), allocated_space() + n); - tag().set_allocated_size(n); - } else { - UninitializedFill(inlined_space(), inlined_space() + n); - tag().set_inline_size(n); - } -} - -template -void InlinedVector::resize(size_type n) { - size_type s = size(); - if (n < s) { - erase(begin() + n, end()); - return; - } - reserve(n); - assert(capacity() >= n); - - // Fill new space with elements constructed in-place. - if (allocated()) { - UninitializedFill(allocated_space() + s, allocated_space() + n); - tag().set_allocated_size(n); - } else { - UninitializedFill(inlined_space() + s, inlined_space() + n); - tag().set_inline_size(n); - } -} - -template -void InlinedVector::resize(size_type n, const_reference v) { - size_type s = size(); - if (n < s) { - erase(begin() + n, end()); - return; - } - reserve(n); - assert(capacity() >= n); - - // Fill new space with copies of 'v'. - if (allocated()) { - UninitializedFill(allocated_space() + s, allocated_space() + n, v); - tag().set_allocated_size(n); - } else { - UninitializedFill(inlined_space() + s, inlined_space() + n, v); - tag().set_inline_size(n); - } -} - -template -template -auto InlinedVector::emplace(const_iterator position, Args&&... args) - -> iterator { - assert(position >= begin()); - assert(position <= end()); - if (ABSL_PREDICT_FALSE(position == end())) { - emplace_back(std::forward(args)...); - return end() - 1; - } - - T new_t = T(std::forward(args)...); - - auto range = ShiftRight(position, 1); - if (range.first == range.second) { - // constructing into uninitialized memory - Construct(range.first, std::move(new_t)); - } else { - // assigning into moved-from object - *range.first = T(std::move(new_t)); - } - - return range.first; -} - -template -auto InlinedVector::erase(const_iterator from, const_iterator to) - -> iterator { - assert(begin() <= from); - assert(from <= to); - assert(to <= end()); - - iterator range_start = const_cast(from); - iterator range_end = const_cast(to); - - size_type s = size(); - ptrdiff_t erase_gap = std::distance(range_start, range_end); - if (erase_gap > 0) { - pointer space; - if (allocated()) { - space = allocated_space(); - tag().set_allocated_size(s - erase_gap); - } else { - space = inlined_space(); - tag().set_inline_size(s - erase_gap); - } - std::move(range_end, space + s, range_start); - Destroy(space + s - erase_gap, space + s); - } - return range_start; -} - -template -void InlinedVector::swap(InlinedVector& other) { - using std::swap; // Augment ADL with `std::swap`. - if (ABSL_PREDICT_FALSE(this == &other)) return; - - if (allocated() && other.allocated()) { - // Both out of line, so just swap the tag, allocation, and allocator. - swap(tag(), other.tag()); - swap(allocation(), other.allocation()); - swap(allocator(), other.allocator()); - return; - } - if (!allocated() && !other.allocated()) { - // Both inlined: swap up to smaller size, then move remaining elements. - InlinedVector* a = this; - InlinedVector* b = &other; - if (size() < other.size()) { - swap(a, b); - } - - const size_type a_size = a->size(); - const size_type b_size = b->size(); - assert(a_size >= b_size); - // `a` is larger. Swap the elements up to the smaller array size. - std::swap_ranges(a->inlined_space(), a->inlined_space() + b_size, - b->inlined_space()); - - // Move the remaining elements: - // [`b_size`, `a_size`) from `a` -> [`b_size`, `a_size`) from `b` - b->UninitializedCopy(a->inlined_space() + b_size, - a->inlined_space() + a_size, - b->inlined_space() + b_size); - a->Destroy(a->inlined_space() + b_size, a->inlined_space() + a_size); - - swap(a->tag(), b->tag()); - swap(a->allocator(), b->allocator()); - assert(b->size() == a_size); - assert(a->size() == b_size); - return; - } - - // One is out of line, one is inline. - // We first move the elements from the inlined vector into the - // inlined space in the other vector. We then put the other vector's - // pointer/capacity into the originally inlined vector and swap - // the tags. - InlinedVector* a = this; - InlinedVector* b = &other; - if (a->allocated()) { - swap(a, b); - } - assert(!a->allocated()); - assert(b->allocated()); - const size_type a_size = a->size(); - const size_type b_size = b->size(); - // In an optimized build, `b_size` would be unused. - static_cast(b_size); - - // Made Local copies of `size()`, don't need `tag()` accurate anymore - swap(a->tag(), b->tag()); - - // Copy `b_allocation` out before `b`'s union gets clobbered by `inline_space` - Allocation b_allocation = b->allocation(); - - b->UninitializedCopy(a->inlined_space(), a->inlined_space() + a_size, - b->inlined_space()); - a->Destroy(a->inlined_space(), a->inlined_space() + a_size); - - a->allocation() = b_allocation; - - if (a->allocator() != b->allocator()) { - swap(a->allocator(), b->allocator()); - } - - assert(b->size() == a_size); - assert(a->size() == b_size); -} - -template -void InlinedVector::EnlargeBy(size_type delta) { - const size_type s = size(); - assert(s <= capacity()); - - size_type target = std::max(inlined_capacity(), s + delta); - - // Compute new capacity by repeatedly doubling current capacity - // TODO(psrc): Check and avoid overflow? - size_type new_capacity = capacity(); - while (new_capacity < target) { - new_capacity <<= 1; - } - - Allocation new_allocation(allocator(), new_capacity); - - UninitializedCopy(std::make_move_iterator(data()), - std::make_move_iterator(data() + s), - new_allocation.buffer()); - - ResetAllocation(new_allocation, s); -} - -template -auto InlinedVector::ShiftRight(const_iterator position, size_type n) - -> std::pair { - iterator start_used = const_cast(position); - iterator start_raw = const_cast(position); - size_type s = size(); - size_type required_size = s + n; - - if (required_size > capacity()) { - // Compute new capacity by repeatedly doubling current capacity - size_type new_capacity = capacity(); - while (new_capacity < required_size) { - new_capacity <<= 1; - } - // Move everyone into the new allocation, leaving a gap of `n` for the - // requested shift. - Allocation new_allocation(allocator(), new_capacity); - size_type index = position - begin(); - UninitializedCopy(std::make_move_iterator(data()), - std::make_move_iterator(data() + index), - new_allocation.buffer()); - UninitializedCopy(std::make_move_iterator(data() + index), - std::make_move_iterator(data() + s), - new_allocation.buffer() + index + n); - ResetAllocation(new_allocation, s); - - // New allocation means our iterator is invalid, so we'll recalculate. - // Since the entire gap is in new space, there's no used space to reuse. - start_raw = begin() + index; - start_used = start_raw; - } else { - // If we had enough space, it's a two-part move. Elements going into - // previously-unoccupied space need an `UninitializedCopy()`. Elements - // going into a previously-occupied space are just a `std::move()`. - iterator pos = const_cast(position); - iterator raw_space = end(); - size_type slots_in_used_space = raw_space - pos; - size_type new_elements_in_used_space = std::min(n, slots_in_used_space); - size_type new_elements_in_raw_space = n - new_elements_in_used_space; - size_type old_elements_in_used_space = - slots_in_used_space - new_elements_in_used_space; - - UninitializedCopy(std::make_move_iterator(pos + old_elements_in_used_space), - std::make_move_iterator(raw_space), - raw_space + new_elements_in_raw_space); - std::move_backward(pos, pos + old_elements_in_used_space, raw_space); - - // If the gap is entirely in raw space, the used space starts where the raw - // space starts, leaving no elements in used space. If the gap is entirely - // in used space, the raw space starts at the end of the gap, leaving all - // elements accounted for within the used space. - start_used = pos; - start_raw = pos + new_elements_in_used_space; - } - tag().add_size(n); - return std::make_pair(start_used, start_raw); -} - -template -void InlinedVector::Destroy(pointer from, pointer to) { - for (pointer cur = from; cur != to; ++cur) { - std::allocator_traits::destroy(allocator(), cur); - } -#ifndef NDEBUG - // Overwrite unused memory with `0xab` so we can catch uninitialized usage. - // Cast to `void*` to tell the compiler that we don't care that we might be - // scribbling on a vtable pointer. - if (from != to) { - auto len = sizeof(value_type) * std::distance(from, to); - std::memset(reinterpret_cast(from), 0xab, len); - } -#endif -} - -template -template -void InlinedVector::AppendRange(Iterator first, Iterator last, - std::forward_iterator_tag) { - auto length = std::distance(first, last); - reserve(size() + length); - if (allocated()) { - UninitializedCopy(first, last, allocated_space() + size()); - tag().set_allocated_size(size() + length); - } else { - UninitializedCopy(first, last, inlined_space() + size()); - tag().set_inline_size(size() + length); - } -} - -template -template -void InlinedVector::AssignRange(Iterator first, Iterator last, - std::input_iterator_tag) { - // Optimized to avoid reallocation. - // Prefer reassignment to copy construction for elements. - iterator out = begin(); - for (; first != last && out != end(); ++first, ++out) { - *out = *first; - } - erase(out, end()); - std::copy(first, last, std::back_inserter(*this)); -} - -template -template -void InlinedVector::AssignRange(Iterator first, Iterator last, - std::forward_iterator_tag) { - auto length = std::distance(first, last); - // Prefer reassignment to copy construction for elements. - if (static_cast(length) <= size()) { - erase(std::copy(first, last, begin()), end()); - return; - } - reserve(length); - iterator out = begin(); - for (; out != end(); ++first, ++out) *out = *first; - if (allocated()) { - UninitializedCopy(first, last, out); - tag().set_allocated_size(length); - } else { - UninitializedCopy(first, last, out); - tag().set_inline_size(length); - } -} - -template -auto InlinedVector::InsertWithCount(const_iterator position, - size_type n, const_reference v) - -> iterator { - assert(position >= begin() && position <= end()); - if (ABSL_PREDICT_FALSE(n == 0)) return const_cast(position); - - value_type copy = v; - std::pair it_pair = ShiftRight(position, n); - std::fill(it_pair.first, it_pair.second, copy); - UninitializedFill(it_pair.second, it_pair.first + n, copy); - - return it_pair.first; -} - -template -template -auto InlinedVector::InsertWithRange(const_iterator position, - InputIterator first, - InputIterator last, - std::input_iterator_tag) - -> iterator { - assert(position >= begin() && position <= end()); - size_type index = position - cbegin(); - size_type i = index; - while (first != last) insert(begin() + i++, *first++); - return begin() + index; -} - -template -template -auto InlinedVector::InsertWithRange(const_iterator position, - ForwardIterator first, - ForwardIterator last, - std::forward_iterator_tag) - -> iterator { - assert(position >= begin() && position <= end()); - if (ABSL_PREDICT_FALSE(first == last)) return const_cast(position); - - auto n = std::distance(first, last); - std::pair it_pair = ShiftRight(position, n); - size_type used_spots = it_pair.second - it_pair.first; - ForwardIterator open_spot = std::next(first, used_spots); - std::copy(first, open_spot, it_pair.first); - UninitializedCopy(open_spot, last, it_pair.second); - return it_pair.first; -} - -} // namespace absl - -#endif // ABSL_CONTAINER_INLINED_VECTOR_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc deleted file mode 100644 index a3ad0f8..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/container/inlined_vector.h" - -#include -#include - -#include "benchmark/benchmark.h" -#include "absl/base/internal/raw_logging.h" -#include "absl/strings/str_cat.h" - -namespace { - -using IntVec = absl::InlinedVector; - -void BM_InlinedVectorFill(benchmark::State& state) { - const int len = state.range(0); - for (auto _ : state) { - IntVec v; - for (int i = 0; i < len; i++) { - v.push_back(i); - } - } - state.SetItemsProcessed(static_cast(state.iterations()) * len); -} -BENCHMARK(BM_InlinedVectorFill)->Range(0, 1024); - -void BM_InlinedVectorFillRange(benchmark::State& state) { - const int len = state.range(0); - std::unique_ptr ia(new int[len]); - for (int i = 0; i < len; i++) { - ia[i] = i; - } - for (auto _ : state) { - IntVec v(ia.get(), ia.get() + len); - benchmark::DoNotOptimize(v); - } - state.SetItemsProcessed(static_cast(state.iterations()) * len); -} -BENCHMARK(BM_InlinedVectorFillRange)->Range(0, 1024); - -void BM_StdVectorFill(benchmark::State& state) { - const int len = state.range(0); - for (auto _ : state) { - std::vector v; - for (int i = 0; i < len; i++) { - v.push_back(i); - } - } - state.SetItemsProcessed(static_cast(state.iterations()) * len); -} -BENCHMARK(BM_StdVectorFill)->Range(0, 1024); - -// The purpose of the next two benchmarks is to verify that -// absl::InlinedVector is efficient when moving is more efficent than -// copying. To do so, we use strings that are larger than the short -// string optimization. -bool StringRepresentedInline(std::string s) { - const char* chars = s.data(); - std::string s1 = std::move(s); - return s1.data() != chars; -} - -int GetNonShortStringOptimizationSize() { - for (int i = 24; i <= 192; i *= 2) { - if (!StringRepresentedInline(std::string(i, 'A'))) { - return i; - } - } - ABSL_RAW_LOG( - FATAL, - "Failed to find a std::string larger than the short std::string optimization"); - return -1; -} - -void BM_InlinedVectorFillString(benchmark::State& state) { - const int len = state.range(0); - const int no_sso = GetNonShortStringOptimizationSize(); - std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'), - std::string(no_sso, 'C'), std::string(no_sso, 'D')}; - - for (auto _ : state) { - absl::InlinedVector v; - for (int i = 0; i < len; i++) { - v.push_back(strings[i & 3]); - } - } - state.SetItemsProcessed(static_cast(state.iterations()) * len); -} -BENCHMARK(BM_InlinedVectorFillString)->Range(0, 1024); - -void BM_StdVectorFillString(benchmark::State& state) { - const int len = state.range(0); - const int no_sso = GetNonShortStringOptimizationSize(); - std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'), - std::string(no_sso, 'C'), std::string(no_sso, 'D')}; - - for (auto _ : state) { - std::vector v; - for (int i = 0; i < len; i++) { - v.push_back(strings[i & 3]); - } - } - state.SetItemsProcessed(static_cast(state.iterations()) * len); -} -BENCHMARK(BM_StdVectorFillString)->Range(0, 1024); - -struct Buffer { // some arbitrary structure for benchmarking. - char* base; - int length; - int capacity; - void* user_data; -}; - -void BM_InlinedVectorTenAssignments(benchmark::State& state) { - const int len = state.range(0); - using BufferVec = absl::InlinedVector; - - BufferVec src; - src.resize(len); - - BufferVec dst; - for (auto _ : state) { - for (int i = 0; i < 10; ++i) { - dst = src; - } - } -} -BENCHMARK(BM_InlinedVectorTenAssignments) - ->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(20); - -void BM_CreateFromContainer(benchmark::State& state) { - for (auto _ : state) { - absl::InlinedVector x(absl::InlinedVector{1, 2, 3}); - benchmark::DoNotOptimize(x); - } -} -BENCHMARK(BM_CreateFromContainer); - -struct LargeCopyableOnly { - LargeCopyableOnly() : d(1024, 17) {} - LargeCopyableOnly(const LargeCopyableOnly& o) = default; - LargeCopyableOnly& operator=(const LargeCopyableOnly& o) = default; - - std::vector d; -}; - -struct LargeCopyableSwappable { - LargeCopyableSwappable() : d(1024, 17) {} - LargeCopyableSwappable(const LargeCopyableSwappable& o) = default; - LargeCopyableSwappable(LargeCopyableSwappable&& o) = delete; - - LargeCopyableSwappable& operator=(LargeCopyableSwappable o) { - using std::swap; - swap(*this, o); - return *this; - } - LargeCopyableSwappable& operator=(LargeCopyableSwappable&& o) = delete; - - friend void swap(LargeCopyableSwappable& a, LargeCopyableSwappable& b) { - using std::swap; - swap(a.d, b.d); - } - - std::vector d; -}; - -struct LargeCopyableMovable { - LargeCopyableMovable() : d(1024, 17) {} - // Use implicitly defined copy and move. - - std::vector d; -}; - -struct LargeCopyableMovableSwappable { - LargeCopyableMovableSwappable() : d(1024, 17) {} - LargeCopyableMovableSwappable(const LargeCopyableMovableSwappable& o) = - default; - LargeCopyableMovableSwappable(LargeCopyableMovableSwappable&& o) = default; - - LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable o) { - using std::swap; - swap(*this, o); - return *this; - } - LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable&& o) = - default; - - friend void swap(LargeCopyableMovableSwappable& a, - LargeCopyableMovableSwappable& b) { - using std::swap; - swap(a.d, b.d); - } - - std::vector d; -}; - -template -void BM_SwapElements(benchmark::State& state) { - const int len = state.range(0); - using Vec = absl::InlinedVector; - Vec a(len); - Vec b; - for (auto _ : state) { - using std::swap; - swap(a, b); - } -} -BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableOnly)->Range(0, 1024); -BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableSwappable)->Range(0, 1024); -BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovable)->Range(0, 1024); -BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovableSwappable) - ->Range(0, 1024); - -// The following benchmark is meant to track the efficiency of the vector size -// as a function of stored type via the benchmark label. It is not meant to -// output useful sizeof operator performance. The loop is a dummy operation -// to fulfill the requirement of running the benchmark. -template -void BM_Sizeof(benchmark::State& state) { - int size = 0; - for (auto _ : state) { - VecType vec; - size = sizeof(vec); - } - state.SetLabel(absl::StrCat("sz=", size)); -} -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); - -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); - -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); - -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); -BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector); - -void BM_InlinedVectorIndexInlined(benchmark::State& state) { - absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7}; - for (auto _ : state) { - for (int i = 0; i < 1000; ++i) { - benchmark::DoNotOptimize(v); - benchmark::DoNotOptimize(v[4]); - } - } - state.SetItemsProcessed(1000 * static_cast(state.iterations())); -} -BENCHMARK(BM_InlinedVectorIndexInlined); - -void BM_InlinedVectorIndexExternal(benchmark::State& state) { - absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - for (auto _ : state) { - for (int i = 0; i < 1000; ++i) { - benchmark::DoNotOptimize(v); - benchmark::DoNotOptimize(v[4]); - } - } - state.SetItemsProcessed(1000 * static_cast(state.iterations())); -} -BENCHMARK(BM_InlinedVectorIndexExternal); - -void BM_StdVectorIndex(benchmark::State& state) { - std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - for (auto _ : state) { - for (int i = 0; i < 1000; ++i) { - benchmark::DoNotOptimize(v); - benchmark::DoNotOptimize(v[4]); - } - } - state.SetItemsProcessed(1000 * static_cast(state.iterations())); -} -BENCHMARK(BM_StdVectorIndex); - -#define UNROLL_2(x) \ - benchmark::DoNotOptimize(x); \ - benchmark::DoNotOptimize(x); - -#define UNROLL_4(x) UNROLL_2(x) UNROLL_2(x) -#define UNROLL_8(x) UNROLL_4(x) UNROLL_4(x) -#define UNROLL_16(x) UNROLL_8(x) UNROLL_8(x); - -void BM_InlinedVectorDataInlined(benchmark::State& state) { - absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7}; - for (auto _ : state) { - UNROLL_16(v.data()); - } - state.SetItemsProcessed(16 * static_cast(state.iterations())); -} -BENCHMARK(BM_InlinedVectorDataInlined); - -void BM_InlinedVectorDataExternal(benchmark::State& state) { - absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - for (auto _ : state) { - UNROLL_16(v.data()); - } - state.SetItemsProcessed(16 * static_cast(state.iterations())); -} -BENCHMARK(BM_InlinedVectorDataExternal); - -void BM_StdVectorData(benchmark::State& state) { - std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - for (auto _ : state) { - UNROLL_16(v.data()); - } - state.SetItemsProcessed(16 * static_cast(state.iterations())); -} -BENCHMARK(BM_StdVectorData); - -void BM_InlinedVectorSizeInlined(benchmark::State& state) { - absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7}; - for (auto _ : state) { - UNROLL_16(v.size()); - } - state.SetItemsProcessed(16 * static_cast(state.iterations())); -} -BENCHMARK(BM_InlinedVectorSizeInlined); - -void BM_InlinedVectorSizeExternal(benchmark::State& state) { - absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - for (auto _ : state) { - UNROLL_16(v.size()); - } - state.SetItemsProcessed(16 * static_cast(state.iterations())); -} -BENCHMARK(BM_InlinedVectorSizeExternal); - -void BM_StdVectorSize(benchmark::State& state) { - std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - for (auto _ : state) { - UNROLL_16(v.size()); - } - state.SetItemsProcessed(16 * static_cast(state.iterations())); -} -BENCHMARK(BM_StdVectorSize); - -void BM_InlinedVectorEmptyInlined(benchmark::State& state) { - absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7}; - for (auto _ : state) { - UNROLL_16(v.empty()); - } - state.SetItemsProcessed(16 * static_cast(state.iterations())); -} -BENCHMARK(BM_InlinedVectorEmptyInlined); - -void BM_InlinedVectorEmptyExternal(benchmark::State& state) { - absl::InlinedVector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - for (auto _ : state) { - UNROLL_16(v.empty()); - } - state.SetItemsProcessed(16 * static_cast(state.iterations())); -} -BENCHMARK(BM_InlinedVectorEmptyExternal); - -void BM_StdVectorEmpty(benchmark::State& state) { - std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - for (auto _ : state) { - UNROLL_16(v.empty()); - } - state.SetItemsProcessed(16 * static_cast(state.iterations())); -} -BENCHMARK(BM_StdVectorEmpty); - -} // namespace diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/inlined_vector_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/inlined_vector_test.cc deleted file mode 100644 index 5485f45..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/inlined_vector_test.cc +++ /dev/null @@ -1,1795 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// 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. - -#include "absl/container/inlined_vector.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/base/attributes.h" -#include "absl/base/internal/exception_testing.h" -#include "absl/base/internal/raw_logging.h" -#include "absl/base/macros.h" -#include "absl/container/internal/test_instance_tracker.h" -#include "absl/hash/hash_testing.h" -#include "absl/memory/memory.h" -#include "absl/strings/str_cat.h" - -namespace { - -using absl::test_internal::CopyableMovableInstance; -using absl::test_internal::CopyableOnlyInstance; -using absl::test_internal::InstanceTracker; -using testing::AllOf; -using testing::Each; -using testing::ElementsAre; -using testing::ElementsAreArray; -using testing::Eq; -using testing::Gt; -using testing::PrintToString; - -using IntVec = absl::InlinedVector; - -MATCHER_P(SizeIs, n, "") { - return testing::ExplainMatchResult(n, arg.size(), result_listener); -} - -MATCHER_P(CapacityIs, n, "") { - return testing::ExplainMatchResult(n, arg.capacity(), result_listener); -} - -MATCHER_P(ValueIs, e, "") { - return testing::ExplainMatchResult(e, arg.value(), result_listener); -} - -// TODO(bsamwel): Add support for movable-only types. - -// Test fixture for typed tests on BaseCountedInstance derived classes, see -// test_instance_tracker.h. -template -class InstanceTest : public ::testing::Test {}; -TYPED_TEST_CASE_P(InstanceTest); - -// A simple reference counted class to make sure that the proper elements are -// destroyed in the erase(begin, end) test. -class RefCounted { - public: - RefCounted(int value, int* count) : value_(value), count_(count) { - Ref(); - } - - RefCounted(const RefCounted& v) - : value_(v.value_), count_(v.count_) { - Ref(); - } - - ~RefCounted() { - Unref(); - count_ = nullptr; - } - - friend void swap(RefCounted& a, RefCounted& b) { - using std::swap; - swap(a.value_, b.value_); - swap(a.count_, b.count_); - } - - RefCounted& operator=(RefCounted v) { - using std::swap; - swap(*this, v); - return *this; - } - - void Ref() const { - ABSL_RAW_CHECK(count_ != nullptr, ""); - ++(*count_); - } - - void Unref() const { - --(*count_); - ABSL_RAW_CHECK(*count_ >= 0, ""); - } - - int value_; - int* count_; -}; - -using RefCountedVec = absl::InlinedVector; - -// A class with a vtable pointer -class Dynamic { - public: - virtual ~Dynamic() {} -}; - -using DynamicVec = absl::InlinedVector; - -// Append 0..len-1 to *v -template -static void Fill(Container* v, int len, int offset = 0) { - for (int i = 0; i < len; i++) { - v->push_back(i + offset); - } -} - -static IntVec Fill(int len, int offset = 0) { - IntVec v; - Fill(&v, len, offset); - return v; -} - -// This is a stateful allocator, but the state lives outside of the -// allocator (in whatever test is using the allocator). This is odd -// but helps in tests where the allocator is propagated into nested -// containers - that chain of allocators uses the same state and is -// thus easier to query for aggregate allocation information. -template -class CountingAllocator : public std::allocator { - public: - using Alloc = std::allocator; - using pointer = typename Alloc::pointer; - using size_type = typename Alloc::size_type; - - CountingAllocator() : bytes_used_(nullptr) {} - explicit CountingAllocator(int64_t* b) : bytes_used_(b) {} - - template - CountingAllocator(const CountingAllocator& x) - : Alloc(x), bytes_used_(x.bytes_used_) {} - - pointer allocate(size_type n, - std::allocator::const_pointer hint = nullptr) { - assert(bytes_used_ != nullptr); - *bytes_used_ += n * sizeof(T); - return Alloc::allocate(n, hint); - } - - void deallocate(pointer p, size_type n) { - Alloc::deallocate(p, n); - assert(bytes_used_ != nullptr); - *bytes_used_ -= n * sizeof(T); - } - - template - class rebind { - public: - using other = CountingAllocator; - }; - - friend bool operator==(const CountingAllocator& a, - const CountingAllocator& b) { - return a.bytes_used_ == b.bytes_used_; - } - - friend bool operator!=(const CountingAllocator& a, - const CountingAllocator& b) { - return !(a == b); - } - - int64_t* bytes_used_; -}; - -TEST(IntVec, SimpleOps) { - for (int len = 0; len < 20; len++) { - IntVec v; - const IntVec& cv = v; // const alias - - Fill(&v, len); - EXPECT_EQ(len, v.size()); - EXPECT_LE(len, v.capacity()); - - for (int i = 0; i < len; i++) { - EXPECT_EQ(i, v[i]); - EXPECT_EQ(i, v.at(i)); - } - EXPECT_EQ(v.begin(), v.data()); - EXPECT_EQ(cv.begin(), cv.data()); - - int counter = 0; - for (IntVec::iterator iter = v.begin(); iter != v.end(); ++iter) { - EXPECT_EQ(counter, *iter); - counter++; - } - EXPECT_EQ(counter, len); - - counter = 0; - for (IntVec::const_iterator iter = v.begin(); iter != v.end(); ++iter) { - EXPECT_EQ(counter, *iter); - counter++; - } - EXPECT_EQ(counter, len); - - counter = 0; - for (IntVec::const_iterator iter = v.cbegin(); iter != v.cend(); ++iter) { - EXPECT_EQ(counter, *iter); - counter++; - } - EXPECT_EQ(counter, len); - - if (len > 0) { - EXPECT_EQ(0, v.front()); - EXPECT_EQ(len - 1, v.back()); - v.pop_back(); - EXPECT_EQ(len - 1, v.size()); - for (int i = 0; i < v.size(); ++i) { - EXPECT_EQ(i, v[i]); - EXPECT_EQ(i, v.at(i)); - } - } - } -} - -TEST(IntVec, AtThrows) { - IntVec v = {1, 2, 3}; - EXPECT_EQ(v.at(2), 3); - ABSL_BASE_INTERNAL_EXPECT_FAIL(v.at(3), std::out_of_range, - "failed bounds check"); -} - -TEST(IntVec, ReverseIterator) { - for (int len = 0; len < 20; len++) { - IntVec v; - Fill(&v, len); - - int counter = len; - for (IntVec::reverse_iterator iter = v.rbegin(); iter != v.rend(); ++iter) { - counter--; - EXPECT_EQ(counter, *iter); - } - EXPECT_EQ(counter, 0); - - counter = len; - for (IntVec::const_reverse_iterator iter = v.rbegin(); iter != v.rend(); - ++iter) { - counter--; - EXPECT_EQ(counter, *iter); - } - EXPECT_EQ(counter, 0); - - counter = len; - for (IntVec::const_reverse_iterator iter = v.crbegin(); iter != v.crend(); - ++iter) { - counter--; - EXPECT_EQ(counter, *iter); - } - EXPECT_EQ(counter, 0); - } -} - -TEST(IntVec, Erase) { - for (int len = 1; len < 20; len++) { - for (int i = 0; i < len; ++i) { - IntVec v; - Fill(&v, len); - v.erase(v.begin() + i); - EXPECT_EQ(len - 1, v.size()); - for (int j = 0; j < i; ++j) { - EXPECT_EQ(j, v[j]); - } - for (int j = i; j < len - 1; ++j) { - EXPECT_EQ(j + 1, v[j]); - } - } - } -} - -// At the end of this test loop, the elements between [erase_begin, erase_end) -// should have reference counts == 0, and all others elements should have -// reference counts == 1. -TEST(RefCountedVec, EraseBeginEnd) { - for (int len = 1; len < 20; ++len) { - for (int erase_begin = 0; erase_begin < len; ++erase_begin) { - for (int erase_end = erase_begin; erase_end <= len; ++erase_end) { - std::vector counts(len, 0); - RefCountedVec v; - for (int i = 0; i < len; ++i) { - v.push_back(RefCounted(i, &counts[i])); - } - - int erase_len = erase_end - erase_begin; - - v.erase(v.begin() + erase_begin, v.begin() + erase_end); - - EXPECT_EQ(len - erase_len, v.size()); - - // Check the elements before the first element erased. - for (int i = 0; i < erase_begin; ++i) { - EXPECT_EQ(i, v[i].value_); - } - - // Check the elements after the first element erased. - for (int i = erase_begin; i < v.size(); ++i) { - EXPECT_EQ(i + erase_len, v[i].value_); - } - - // Check that the elements at the beginning are preserved. - for (int i = 0; i < erase_begin; ++i) { - EXPECT_EQ(1, counts[i]); - } - - // Check that the erased elements are destroyed - for (int i = erase_begin; i < erase_end; ++i) { - EXPECT_EQ(0, counts[i]); - } - - // Check that the elements at the end are preserved. - for (int i = erase_end; i< len; ++i) { - EXPECT_EQ(1, counts[i]); - } - } - } - } -} - -struct NoDefaultCtor { - explicit NoDefaultCtor(int) {} -}; -struct NoCopy { - NoCopy() {} - NoCopy(const NoCopy&) = delete; -}; -struct NoAssign { - NoAssign() {} - NoAssign& operator=(const NoAssign&) = delete; -}; -struct MoveOnly { - MoveOnly() {} - MoveOnly(MoveOnly&&) = default; - MoveOnly& operator=(MoveOnly&&) = default; -}; -TEST(InlinedVectorTest, NoDefaultCtor) { - absl::InlinedVector v(10, NoDefaultCtor(2)); - (void)v; -} -TEST(InlinedVectorTest, NoCopy) { - absl::InlinedVector v(10); - (void)v; -} -TEST(InlinedVectorTest, NoAssign) { - absl::InlinedVector v(10); - (void)v; -} -TEST(InlinedVectorTest, MoveOnly) { - absl::InlinedVector v; - v.push_back(MoveOnly{}); - v.push_back(MoveOnly{}); - v.push_back(MoveOnly{}); - v.erase(v.begin()); - v.push_back(MoveOnly{}); - v.erase(v.begin(), v.begin() + 1); - v.insert(v.begin(), MoveOnly{}); - v.emplace(v.begin()); - v.emplace(v.begin(), MoveOnly{}); -} -TEST(InlinedVectorTest, Noexcept) { - EXPECT_TRUE(std::is_nothrow_move_constructible::value); - EXPECT_TRUE((std::is_nothrow_move_constructible< - absl::InlinedVector>::value)); - - struct MoveCanThrow { - MoveCanThrow(MoveCanThrow&&) {} - }; - EXPECT_EQ(absl::default_allocator_is_nothrow::value, - (std::is_nothrow_move_constructible< - absl::InlinedVector>::value)); -} - -TEST(InlinedVectorTest, EmplaceBack) { - absl::InlinedVector, 1> v; - - auto& inlined_element = v.emplace_back("answer", 42); - EXPECT_EQ(&inlined_element, &v[0]); - EXPECT_EQ(inlined_element.first, "answer"); - EXPECT_EQ(inlined_element.second, 42); - - auto& allocated_element = v.emplace_back("taxicab", 1729); - EXPECT_EQ(&allocated_element, &v[1]); - EXPECT_EQ(allocated_element.first, "taxicab"); - EXPECT_EQ(allocated_element.second, 1729); -} - -TEST(InlinedVectorTest, ShrinkToFitGrowingVector) { - absl::InlinedVector, 1> v; - - v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 1); - - v.emplace_back("answer", 42); - v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 1); - - v.emplace_back("taxicab", 1729); - EXPECT_GE(v.capacity(), 2); - v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); - - v.reserve(100); - EXPECT_GE(v.capacity(), 100); - v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); -} - -TEST(InlinedVectorTest, ShrinkToFitEdgeCases) { - { - absl::InlinedVector, 1> v; - v.emplace_back("answer", 42); - v.emplace_back("taxicab", 1729); - EXPECT_GE(v.capacity(), 2); - v.pop_back(); - v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 1); - EXPECT_EQ(v[0].first, "answer"); - EXPECT_EQ(v[0].second, 42); - } - - { - absl::InlinedVector v(100); - v.resize(0); - v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); // inlined capacity - } - - { - absl::InlinedVector v(100); - v.resize(1); - v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); // inlined capacity - } - - { - absl::InlinedVector v(100); - v.resize(2); - v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); - } - - { - absl::InlinedVector v(100); - v.resize(3); - v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 3); - } -} - -TEST(IntVec, Insert) { - for (int len = 0; len < 20; len++) { - for (int pos = 0; pos <= len; pos++) { - { - // Single element - std::vector std_v; - Fill(&std_v, len); - IntVec v; - Fill(&v, len); - - std_v.insert(std_v.begin() + pos, 9999); - IntVec::iterator it = v.insert(v.cbegin() + pos, 9999); - EXPECT_THAT(v, ElementsAreArray(std_v)); - EXPECT_EQ(it, v.cbegin() + pos); - } - { - // n elements - std::vector std_v; - Fill(&std_v, len); - IntVec v; - Fill(&v, len); - - IntVec::size_type n = 5; - std_v.insert(std_v.begin() + pos, n, 9999); - IntVec::iterator it = v.insert(v.cbegin() + pos, n, 9999); - EXPECT_THAT(v, ElementsAreArray(std_v)); - EXPECT_EQ(it, v.cbegin() + pos); - } - { - // Iterator range (random access iterator) - std::vector std_v; - Fill(&std_v, len); - IntVec v; - Fill(&v, len); - - const std::vector input = {9999, 8888, 7777}; - std_v.insert(std_v.begin() + pos, input.cbegin(), input.cend()); - IntVec::iterator it = - v.insert(v.cbegin() + pos, input.cbegin(), input.cend()); - EXPECT_THAT(v, ElementsAreArray(std_v)); - EXPECT_EQ(it, v.cbegin() + pos); - } - { - // Iterator range (forward iterator) - std::vector std_v; - Fill(&std_v, len); - IntVec v; - Fill(&v, len); - - const std::forward_list input = {9999, 8888, 7777}; - std_v.insert(std_v.begin() + pos, input.cbegin(), input.cend()); - IntVec::iterator it = - v.insert(v.cbegin() + pos, input.cbegin(), input.cend()); - EXPECT_THAT(v, ElementsAreArray(std_v)); - EXPECT_EQ(it, v.cbegin() + pos); - } - { - // Iterator range (input iterator) - std::vector std_v; - Fill(&std_v, len); - IntVec v; - Fill(&v, len); - - std_v.insert(std_v.begin() + pos, {9999, 8888, 7777}); - std::istringstream input("9999 8888 7777"); - IntVec::iterator it = - v.insert(v.cbegin() + pos, std::istream_iterator(input), - std::istream_iterator()); - EXPECT_THAT(v, ElementsAreArray(std_v)); - EXPECT_EQ(it, v.cbegin() + pos); - } - { - // Initializer list - std::vector std_v; - Fill(&std_v, len); - IntVec v; - Fill(&v, len); - - std_v.insert(std_v.begin() + pos, {9999, 8888}); - IntVec::iterator it = v.insert(v.cbegin() + pos, {9999, 8888}); - EXPECT_THAT(v, ElementsAreArray(std_v)); - EXPECT_EQ(it, v.cbegin() + pos); - } - } - } -} - -TEST(RefCountedVec, InsertConstructorDestructor) { - // Make sure the proper construction/destruction happen during insert - // operations. - for (int len = 0; len < 20; len++) { - SCOPED_TRACE(len); - for (int pos = 0; pos <= len; pos++) { - SCOPED_TRACE(pos); - std::vector counts(len, 0); - int inserted_count = 0; - RefCountedVec v; - for (int i = 0; i < len; ++i) { - SCOPED_TRACE(i); - v.push_back(RefCounted(i, &counts[i])); - } - - EXPECT_THAT(counts, Each(Eq(1))); - - RefCounted insert_element(9999, &inserted_count); - EXPECT_EQ(1, inserted_count); - v.insert(v.begin() + pos, insert_element); - EXPECT_EQ(2, inserted_count); - // Check that the elements at the end are preserved. - EXPECT_THAT(counts, Each(Eq(1))); - EXPECT_EQ(2, inserted_count); - } - } -} - -TEST(IntVec, Resize) { - for (int len = 0; len < 20; len++) { - IntVec v; - Fill(&v, len); - - // Try resizing up and down by k elements - static const int kResizeElem = 1000000; - for (int k = 0; k < 10; k++) { - // Enlarging resize - v.resize(len+k, kResizeElem); - EXPECT_EQ(len+k, v.size()); - EXPECT_LE(len+k, v.capacity()); - for (int i = 0; i < len+k; i++) { - if (i < len) { - EXPECT_EQ(i, v[i]); - } else { - EXPECT_EQ(kResizeElem, v[i]); - } - } - - // Shrinking resize - v.resize(len, kResizeElem); - EXPECT_EQ(len, v.size()); - EXPECT_LE(len, v.capacity()); - for (int i = 0; i < len; i++) { - EXPECT_EQ(i, v[i]); - } - } - } -} - -TEST(IntVec, InitWithLength) { - for (int len = 0; len < 20; len++) { - IntVec v(len, 7); - EXPECT_EQ(len, v.size()); - EXPECT_LE(len, v.capacity()); - for (int i = 0; i < len; i++) { - EXPECT_EQ(7, v[i]); - } - } -} - -TEST(IntVec, CopyConstructorAndAssignment) { - for (int len = 0; len < 20; len++) { - IntVec v; - Fill(&v, len); - EXPECT_EQ(len, v.size()); - EXPECT_LE(len, v.capacity()); - - IntVec v2(v); - EXPECT_TRUE(v == v2) << PrintToString(v) << PrintToString(v2); - - for (int start_len = 0; start_len < 20; start_len++) { - IntVec v3; - Fill(&v3, start_len, 99); // Add dummy elements that should go away - v3 = v; - EXPECT_TRUE(v == v3) << PrintToString(v) << PrintToString(v3); - } - } -} - -TEST(IntVec, AliasingCopyAssignment) { - for (int len = 0; len < 20; ++len) { - IntVec original; - Fill(&original, len); - IntVec dup = original; - dup = *&dup; - EXPECT_EQ(dup, original); - } -} - -TEST(IntVec, MoveConstructorAndAssignment) { - for (int len = 0; len < 20; len++) { - IntVec v_in; - const int inlined_capacity = v_in.capacity(); - Fill(&v_in, len); - EXPECT_EQ(len, v_in.size()); - EXPECT_LE(len, v_in.capacity()); - - { - IntVec v_temp(v_in); - auto* old_data = v_temp.data(); - IntVec v_out(std::move(v_temp)); - EXPECT_TRUE(v_in == v_out) << PrintToString(v_in) << PrintToString(v_out); - if (v_in.size() > inlined_capacity) { - // Allocation is moved as a whole, data stays in place. - EXPECT_TRUE(v_out.data() == old_data); - } else { - EXPECT_FALSE(v_out.data() == old_data); - } - } - for (int start_len = 0; start_len < 20; start_len++) { - IntVec v_out; - Fill(&v_out, start_len, 99); // Add dummy elements that should go away - IntVec v_temp(v_in); - auto* old_data = v_temp.data(); - v_out = std::move(v_temp); - EXPECT_TRUE(v_in == v_out) << PrintToString(v_in) << PrintToString(v_out); - if (v_in.size() > inlined_capacity) { - // Allocation is moved as a whole, data stays in place. - EXPECT_TRUE(v_out.data() == old_data); - } else { - EXPECT_FALSE(v_out.data() == old_data); - } - } - } -} - -class NotTriviallyDestructible { - public: - NotTriviallyDestructible() : p_(new int(1)) {} - explicit NotTriviallyDestructible(int i) : p_(new int(i)) {} - - NotTriviallyDestructible(const NotTriviallyDestructible& other) - : p_(new int(*other.p_)) {} - - NotTriviallyDestructible& operator=(const NotTriviallyDestructible& other) { - p_ = absl::make_unique(*other.p_); - return *this; - } - - bool operator==(const NotTriviallyDestructible& other) const { - return *p_ == *other.p_; - } - - private: - std::unique_ptr p_; -}; - -TEST(AliasingTest, Emplace) { - for (int i = 2; i < 20; ++i) { - absl::InlinedVector vec; - for (int j = 0; j < i; ++j) { - vec.push_back(NotTriviallyDestructible(j)); - } - vec.emplace(vec.begin(), vec[0]); - EXPECT_EQ(vec[0], vec[1]); - vec.emplace(vec.begin() + i / 2, vec[i / 2]); - EXPECT_EQ(vec[i / 2], vec[i / 2 + 1]); - vec.emplace(vec.end() - 1, vec.back()); - EXPECT_EQ(vec[vec.size() - 2], vec.back()); - } -} - -TEST(AliasingTest, InsertWithCount) { - for (int i = 1; i < 20; ++i) { - absl::InlinedVector vec; - for (int j = 0; j < i; ++j) { - vec.push_back(NotTriviallyDestructible(j)); - } - for (int n = 0; n < 5; ++n) { - // We use back where we can because it's guaranteed to become invalidated - vec.insert(vec.begin(), n, vec.back()); - auto b = vec.begin(); - EXPECT_TRUE( - std::all_of(b, b + n, [&vec](const NotTriviallyDestructible& x) { - return x == vec.back(); - })); - - auto m_idx = vec.size() / 2; - vec.insert(vec.begin() + m_idx, n, vec.back()); - auto m = vec.begin() + m_idx; - EXPECT_TRUE( - std::all_of(m, m + n, [&vec](const NotTriviallyDestructible& x) { - return x == vec.back(); - })); - - // We want distinct values so the equality test is meaningful, - // vec[vec.size() - 1] is also almost always invalidated. - auto old_e = vec.size() - 1; - auto val = vec[old_e]; - vec.insert(vec.end(), n, vec[old_e]); - auto e = vec.begin() + old_e; - EXPECT_TRUE(std::all_of( - e, e + n, - [&val](const NotTriviallyDestructible& x) { return x == val; })); - } - } -} - -TEST(OverheadTest, Storage) { - // Check for size overhead. - // In particular, ensure that std::allocator doesn't cost anything to store. - // The union should be absorbing some of the allocation bookkeeping overhead - // in the larger vectors, leaving only the size_ field as overhead. - EXPECT_EQ(2 * sizeof(int*), - sizeof(absl::InlinedVector) - 1 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector) - 2 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector) - 3 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector) - 4 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector) - 5 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector) - 6 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector) - 7 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector) - 8 * sizeof(int*)); -} - -TEST(IntVec, Clear) { - for (int len = 0; len < 20; len++) { - SCOPED_TRACE(len); - IntVec v; - Fill(&v, len); - v.clear(); - EXPECT_EQ(0, v.size()); - EXPECT_EQ(v.begin(), v.end()); - } -} - -TEST(IntVec, Reserve) { - for (int len = 0; len < 20; len++) { - IntVec v; - Fill(&v, len); - - for (int newlen = 0; newlen < 100; newlen++) { - const int* start_rep = v.data(); - v.reserve(newlen); - const int* final_rep = v.data(); - if (newlen <= len) { - EXPECT_EQ(start_rep, final_rep); - } - EXPECT_LE(newlen, v.capacity()); - - // Filling up to newlen should not change rep - while (v.size() < newlen) { - v.push_back(0); - } - EXPECT_EQ(final_rep, v.data()); - } - } -} - -TEST(StringVec, SelfRefPushBack) { - std::vector std_v; - absl::InlinedVector v; - const std::string s = "A quite long std::string to ensure heap."; - std_v.push_back(s); - v.push_back(s); - for (int i = 0; i < 20; ++i) { - EXPECT_THAT(v, ElementsAreArray(std_v)); - - v.push_back(v.back()); - std_v.push_back(std_v.back()); - } - EXPECT_THAT(v, ElementsAreArray(std_v)); -} - -TEST(StringVec, SelfRefPushBackWithMove) { - std::vector std_v; - absl::InlinedVector v; - const std::string s = "A quite long std::string to ensure heap."; - std_v.push_back(s); - v.push_back(s); - for (int i = 0; i < 20; ++i) { - EXPECT_EQ(v.back(), std_v.back()); - - v.push_back(std::move(v.back())); - std_v.push_back(std::move(std_v.back())); - } - EXPECT_EQ(v.back(), std_v.back()); -} - -TEST(StringVec, SelfMove) { - const std::string s = "A quite long std::string to ensure heap."; - for (int len = 0; len < 20; len++) { - SCOPED_TRACE(len); - absl::InlinedVector v; - for (int i = 0; i < len; ++i) { - SCOPED_TRACE(i); - v.push_back(s); - } - // Indirection necessary to avoid compiler warning. - v = std::move(*(&v)); - // Ensure that the inlined vector is still in a valid state by copying it. - // We don't expect specific contents since a self-move results in an - // unspecified valid state. - std::vector copy(v.begin(), v.end()); - } -} - -TEST(IntVec, Swap) { - for (int l1 = 0; l1 < 20; l1++) { - SCOPED_TRACE(l1); - for (int l2 = 0; l2 < 20; l2++) { - SCOPED_TRACE(l2); - IntVec a = Fill(l1, 0); - IntVec b = Fill(l2, 100); - { - using std::swap; - swap(a, b); - } - EXPECT_EQ(l1, b.size()); - EXPECT_EQ(l2, a.size()); - for (int i = 0; i < l1; i++) { - SCOPED_TRACE(i); - EXPECT_EQ(i, b[i]); - } - for (int i = 0; i < l2; i++) { - SCOPED_TRACE(i); - EXPECT_EQ(100 + i, a[i]); - } - } - } -} - -TYPED_TEST_P(InstanceTest, Swap) { - using Instance = TypeParam; - using InstanceVec = absl::InlinedVector; - for (int l1 = 0; l1 < 20; l1++) { - SCOPED_TRACE(l1); - for (int l2 = 0; l2 < 20; l2++) { - SCOPED_TRACE(l2); - InstanceTracker tracker; - InstanceVec a, b; - const size_t inlined_capacity = a.capacity(); - auto min_len = std::min(l1, l2); - auto max_len = std::max(l1, l2); - for (int i = 0; i < l1; i++) a.push_back(Instance(i)); - for (int i = 0; i < l2; i++) b.push_back(Instance(100+i)); - EXPECT_EQ(tracker.instances(), l1 + l2); - tracker.ResetCopiesMovesSwaps(); - { - using std::swap; - swap(a, b); - } - EXPECT_EQ(tracker.instances(), l1 + l2); - if (a.size() > inlined_capacity && b.size() > inlined_capacity) { - EXPECT_EQ(tracker.swaps(), 0); // Allocations are swapped. - EXPECT_EQ(tracker.moves(), 0); - } else if (a.size() <= inlined_capacity && b.size() <= inlined_capacity) { - EXPECT_EQ(tracker.swaps(), min_len); - EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()), - max_len - min_len); - } else { - // One is allocated and the other isn't. The allocation is transferred - // without copying elements, and the inlined instances are copied/moved. - EXPECT_EQ(tracker.swaps(), 0); - EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()), - min_len); - } - - EXPECT_EQ(l1, b.size()); - EXPECT_EQ(l2, a.size()); - for (int i = 0; i < l1; i++) { - EXPECT_EQ(i, b[i].value()); - } - for (int i = 0; i < l2; i++) { - EXPECT_EQ(100 + i, a[i].value()); - } - } - } -} - -TEST(IntVec, EqualAndNotEqual) { - IntVec a, b; - EXPECT_TRUE(a == b); - EXPECT_FALSE(a != b); - - a.push_back(3); - EXPECT_FALSE(a == b); - EXPECT_TRUE(a != b); - - b.push_back(3); - EXPECT_TRUE(a == b); - EXPECT_FALSE(a != b); - - b.push_back(7); - EXPECT_FALSE(a == b); - EXPECT_TRUE(a != b); - - a.push_back(6); - EXPECT_FALSE(a == b); - EXPECT_TRUE(a != b); - - a.clear(); - b.clear(); - for (int i = 0; i < 100; i++) { - a.push_back(i); - b.push_back(i); - EXPECT_TRUE(a == b); - EXPECT_FALSE(a != b); - - b[i] = b[i] + 1; - EXPECT_FALSE(a == b); - EXPECT_TRUE(a != b); - - b[i] = b[i] - 1; // Back to before - EXPECT_TRUE(a == b); - EXPECT_FALSE(a != b); - } -} - -TEST(IntVec, RelationalOps) { - IntVec a, b; - EXPECT_FALSE(a < b); - EXPECT_FALSE(b < a); - EXPECT_FALSE(a > b); - EXPECT_FALSE(b > a); - EXPECT_TRUE(a <= b); - EXPECT_TRUE(b <= a); - EXPECT_TRUE(a >= b); - EXPECT_TRUE(b >= a); - b.push_back(3); - EXPECT_TRUE(a < b); - EXPECT_FALSE(b < a); - EXPECT_FALSE(a > b); - EXPECT_TRUE(b > a); - EXPECT_TRUE(a <= b); - EXPECT_FALSE(b <= a); - EXPECT_FALSE(a >= b); - EXPECT_TRUE(b >= a); -} - -TYPED_TEST_P(InstanceTest, CountConstructorsDestructors) { - using Instance = TypeParam; - using InstanceVec = absl::InlinedVector; - InstanceTracker tracker; - for (int len = 0; len < 20; len++) { - SCOPED_TRACE(len); - tracker.ResetCopiesMovesSwaps(); - - InstanceVec v; - const size_t inlined_capacity = v.capacity(); - for (int i = 0; i < len; i++) { - v.push_back(Instance(i)); - } - EXPECT_EQ(tracker.instances(), len); - EXPECT_GE(tracker.copies() + tracker.moves(), - len); // More due to reallocation. - tracker.ResetCopiesMovesSwaps(); - - // Enlarging resize() must construct some objects - tracker.ResetCopiesMovesSwaps(); - v.resize(len + 10, Instance(100)); - EXPECT_EQ(tracker.instances(), len + 10); - if (len <= inlined_capacity && len + 10 > inlined_capacity) { - EXPECT_EQ(tracker.copies() + tracker.moves(), 10 + len); - } else { - // Only specify a minimum number of copies + moves. We don't want to - // depend on the reallocation policy here. - EXPECT_GE(tracker.copies() + tracker.moves(), - 10); // More due to reallocation. - } - - // Shrinking resize() must destroy some objects - tracker.ResetCopiesMovesSwaps(); - v.resize(len, Instance(100)); - EXPECT_EQ(tracker.instances(), len); - EXPECT_EQ(tracker.copies(), 0); - EXPECT_EQ(tracker.moves(), 0); - - // reserve() must not increase the number of initialized objects - SCOPED_TRACE("reserve"); - v.reserve(len+1000); - EXPECT_EQ(tracker.instances(), len); - EXPECT_EQ(tracker.copies() + tracker.moves(), len); - - // pop_back() and erase() must destroy one object - if (len > 0) { - tracker.ResetCopiesMovesSwaps(); - v.pop_back(); - EXPECT_EQ(tracker.instances(), len - 1); - EXPECT_EQ(tracker.copies(), 0); - EXPECT_EQ(tracker.moves(), 0); - - if (!v.empty()) { - tracker.ResetCopiesMovesSwaps(); - v.erase(v.begin()); - EXPECT_EQ(tracker.instances(), len - 2); - EXPECT_EQ(tracker.copies() + tracker.moves(), len - 2); - } - } - - tracker.ResetCopiesMovesSwaps(); - int instances_before_empty_erase = tracker.instances(); - v.erase(v.begin(), v.begin()); - EXPECT_EQ(tracker.instances(), instances_before_empty_erase); - EXPECT_EQ(tracker.copies() + tracker.moves(), 0); - } -} - -TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnCopyConstruction) { - using Instance = TypeParam; - using InstanceVec = absl::InlinedVector; - InstanceTracker tracker; - for (int len = 0; len < 20; len++) { - SCOPED_TRACE(len); - tracker.ResetCopiesMovesSwaps(); - - InstanceVec v; - for (int i = 0; i < len; i++) { - v.push_back(Instance(i)); - } - EXPECT_EQ(tracker.instances(), len); - EXPECT_GE(tracker.copies() + tracker.moves(), - len); // More due to reallocation. - tracker.ResetCopiesMovesSwaps(); - { // Copy constructor should create 'len' more instances. - InstanceVec v_copy(v); - EXPECT_EQ(tracker.instances(), len + len); - EXPECT_EQ(tracker.copies(), len); - EXPECT_EQ(tracker.moves(), 0); - } - EXPECT_EQ(tracker.instances(), len); - } -} - -TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveConstruction) { - using Instance = TypeParam; - using InstanceVec = absl::InlinedVector; - InstanceTracker tracker; - for (int len = 0; len < 20; len++) { - SCOPED_TRACE(len); - tracker.ResetCopiesMovesSwaps(); - - InstanceVec v; - const size_t inlined_capacity = v.capacity(); - for (int i = 0; i < len; i++) { - v.push_back(Instance(i)); - } - EXPECT_EQ(tracker.instances(), len); - EXPECT_GE(tracker.copies() + tracker.moves(), - len); // More due to reallocation. - tracker.ResetCopiesMovesSwaps(); - { - InstanceVec v_copy(std::move(v)); - if (len > inlined_capacity) { - // Allocation is moved as a whole. - EXPECT_EQ(tracker.instances(), len); - EXPECT_EQ(tracker.live_instances(), len); - // Tests an implementation detail, don't rely on this in your code. - EXPECT_EQ(v.size(), 0); // NOLINT misc-use-after-move - EXPECT_EQ(tracker.copies(), 0); - EXPECT_EQ(tracker.moves(), 0); - } else { - EXPECT_EQ(tracker.instances(), len + len); - if (Instance::supports_move()) { - EXPECT_EQ(tracker.live_instances(), len); - EXPECT_EQ(tracker.copies(), 0); - EXPECT_EQ(tracker.moves(), len); - } else { - EXPECT_EQ(tracker.live_instances(), len + len); - EXPECT_EQ(tracker.copies(), len); - EXPECT_EQ(tracker.moves(), 0); - } - } - EXPECT_EQ(tracker.swaps(), 0); - } - } -} - -TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnAssignment) { - using Instance = TypeParam; - using InstanceVec = absl::InlinedVector; - InstanceTracker tracker; - for (int len = 0; len < 20; len++) { - SCOPED_TRACE(len); - for (int longorshort = 0; longorshort <= 1; ++longorshort) { - SCOPED_TRACE(longorshort); - tracker.ResetCopiesMovesSwaps(); - - InstanceVec longer, shorter; - for (int i = 0; i < len; i++) { - longer.push_back(Instance(i)); - shorter.push_back(Instance(i)); - } - longer.push_back(Instance(len)); - EXPECT_EQ(tracker.instances(), len + len + 1); - EXPECT_GE(tracker.copies() + tracker.moves(), - len + len + 1); // More due to reallocation. - - tracker.ResetCopiesMovesSwaps(); - if (longorshort) { - shorter = longer; - EXPECT_EQ(tracker.instances(), (len + 1) + (len + 1)); - EXPECT_GE(tracker.copies() + tracker.moves(), - len + 1); // More due to reallocation. - } else { - longer = shorter; - EXPECT_EQ(tracker.instances(), len + len); - EXPECT_EQ(tracker.copies() + tracker.moves(), len); - } - } - } -} - -TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveAssignment) { - using Instance = TypeParam; - using InstanceVec = absl::InlinedVector; - InstanceTracker tracker; - for (int len = 0; len < 20; len++) { - SCOPED_TRACE(len); - for (int longorshort = 0; longorshort <= 1; ++longorshort) { - SCOPED_TRACE(longorshort); - tracker.ResetCopiesMovesSwaps(); - - InstanceVec longer, shorter; - const int inlined_capacity = longer.capacity(); - for (int i = 0; i < len; i++) { - longer.push_back(Instance(i)); - shorter.push_back(Instance(i)); - } - longer.push_back(Instance(len)); - EXPECT_EQ(tracker.instances(), len + len + 1); - EXPECT_GE(tracker.copies() + tracker.moves(), - len + len + 1); // More due to reallocation. - - tracker.ResetCopiesMovesSwaps(); - int src_len; - if (longorshort) { - src_len = len + 1; - shorter = std::move(longer); - } else { - src_len = len; - longer = std::move(shorter); - } - if (src_len > inlined_capacity) { - // Allocation moved as a whole. - EXPECT_EQ(tracker.instances(), src_len); - EXPECT_EQ(tracker.live_instances(), src_len); - EXPECT_EQ(tracker.copies(), 0); - EXPECT_EQ(tracker.moves(), 0); - } else { - // Elements are all copied. - EXPECT_EQ(tracker.instances(), src_len + src_len); - if (Instance::supports_move()) { - EXPECT_EQ(tracker.copies(), 0); - EXPECT_EQ(tracker.moves(), src_len); - EXPECT_EQ(tracker.live_instances(), src_len); - } else { - EXPECT_EQ(tracker.copies(), src_len); - EXPECT_EQ(tracker.moves(), 0); - EXPECT_EQ(tracker.live_instances(), src_len + src_len); - } - } - EXPECT_EQ(tracker.swaps(), 0); - } - } -} - -TEST(CountElemAssign, SimpleTypeWithInlineBacking) { - for (size_t original_size = 0; original_size <= 5; ++original_size) { - SCOPED_TRACE(original_size); - // Original contents are [12345, 12345, ...] - std::vector original_contents(original_size, 12345); - - absl::InlinedVector v(original_contents.begin(), - original_contents.end()); - v.assign(2, 123); - EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(123, 123))); - if (original_size <= 2) { - // If the original had inline backing, it should stay inline. - EXPECT_EQ(2, v.capacity()); - } - } -} - -TEST(CountElemAssign, SimpleTypeWithAllocation) { - for (size_t original_size = 0; original_size <= 5; ++original_size) { - SCOPED_TRACE(original_size); - // Original contents are [12345, 12345, ...] - std::vector original_contents(original_size, 12345); - - absl::InlinedVector v(original_contents.begin(), - original_contents.end()); - v.assign(3, 123); - EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(123, 123, 123))); - EXPECT_LE(v.size(), v.capacity()); - } -} - -TYPED_TEST_P(InstanceTest, CountElemAssignInlineBacking) { - using Instance = TypeParam; - for (size_t original_size = 0; original_size <= 5; ++original_size) { - SCOPED_TRACE(original_size); - // Original contents are [12345, 12345, ...] - std::vector original_contents(original_size, Instance(12345)); - - absl::InlinedVector v(original_contents.begin(), - original_contents.end()); - v.assign(2, Instance(123)); - EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(ValueIs(123), ValueIs(123)))); - if (original_size <= 2) { - // If the original had inline backing, it should stay inline. - EXPECT_EQ(2, v.capacity()); - } - } -} - -template -void InstanceCountElemAssignWithAllocationTest() { - for (size_t original_size = 0; original_size <= 5; ++original_size) { - SCOPED_TRACE(original_size); - // Original contents are [12345, 12345, ...] - std::vector original_contents(original_size, Instance(12345)); - - absl::InlinedVector v(original_contents.begin(), - original_contents.end()); - v.assign(3, Instance(123)); - EXPECT_THAT(v, - AllOf(SizeIs(3), - ElementsAre(ValueIs(123), ValueIs(123), ValueIs(123)))); - EXPECT_LE(v.size(), v.capacity()); - } -} -TEST(CountElemAssign, WithAllocationCopyableInstance) { - InstanceCountElemAssignWithAllocationTest(); -} -TEST(CountElemAssign, WithAllocationCopyableMovableInstance) { - InstanceCountElemAssignWithAllocationTest(); -} - -TEST(RangedConstructor, SimpleType) { - std::vector source_v = {4, 5, 6}; - // First try to fit in inline backing - absl::InlinedVector v(source_v.begin(), source_v.end()); - EXPECT_EQ(3, v.size()); - EXPECT_EQ(4, v.capacity()); // Indication that we're still on inlined storage - EXPECT_EQ(4, v[0]); - EXPECT_EQ(5, v[1]); - EXPECT_EQ(6, v[2]); - - // Now, force a re-allocate - absl::InlinedVector realloc_v(source_v.begin(), source_v.end()); - EXPECT_EQ(3, realloc_v.size()); - EXPECT_LT(2, realloc_v.capacity()); - EXPECT_EQ(4, realloc_v[0]); - EXPECT_EQ(5, realloc_v[1]); - EXPECT_EQ(6, realloc_v[2]); -} - -// Test for ranged constructors using Instance as the element type and -// SourceContainer as the source container type. -template -void InstanceRangedConstructorTestForContainer() { - InstanceTracker tracker; - SourceContainer source_v = {Instance(0), Instance(1)}; - tracker.ResetCopiesMovesSwaps(); - absl::InlinedVector v(source_v.begin(), - source_v.end()); - EXPECT_EQ(2, v.size()); - EXPECT_LT(1, v.capacity()); - EXPECT_EQ(0, v[0].value()); - EXPECT_EQ(1, v[1].value()); - EXPECT_EQ(tracker.copies(), 2); - EXPECT_EQ(tracker.moves(), 0); -} - -template -void InstanceRangedConstructorTestWithCapacity() { - // Test with const and non-const, random access and non-random-access sources. - // TODO(bsamwel): Test with an input iterator source. - { - SCOPED_TRACE("std::list"); - InstanceRangedConstructorTestForContainer, - inlined_capacity>(); - { - SCOPED_TRACE("const std::list"); - InstanceRangedConstructorTestForContainer< - Instance, const std::list, inlined_capacity>(); - } - { - SCOPED_TRACE("std::vector"); - InstanceRangedConstructorTestForContainer, - inlined_capacity>(); - } - { - SCOPED_TRACE("const std::vector"); - InstanceRangedConstructorTestForContainer< - Instance, const std::vector, inlined_capacity>(); - } - } -} - -TYPED_TEST_P(InstanceTest, RangedConstructor) { - using Instance = TypeParam; - SCOPED_TRACE("capacity=1"); - InstanceRangedConstructorTestWithCapacity(); - SCOPED_TRACE("capacity=2"); - InstanceRangedConstructorTestWithCapacity(); -} - -TEST(RangedConstructor, ElementsAreConstructed) { - std::vector source_v = {"cat", "dog"}; - - // Force expansion and re-allocation of v. Ensures that when the vector is - // expanded that new elements are constructed. - absl::InlinedVector v(source_v.begin(), source_v.end()); - EXPECT_EQ("cat", v[0]); - EXPECT_EQ("dog", v[1]); -} - -TEST(RangedAssign, SimpleType) { - // Test for all combinations of original sizes (empty and non-empty inline, - // and out of line) and target sizes. - for (size_t original_size = 0; original_size <= 5; ++original_size) { - SCOPED_TRACE(original_size); - // Original contents are [12345, 12345, ...] - std::vector original_contents(original_size, 12345); - - for (size_t target_size = 0; target_size <= 5; ++target_size) { - SCOPED_TRACE(target_size); - - // New contents are [3, 4, ...] - std::vector new_contents; - for (size_t i = 0; i < target_size; ++i) { - new_contents.push_back(i + 3); - } - - absl::InlinedVector v(original_contents.begin(), - original_contents.end()); - v.assign(new_contents.begin(), new_contents.end()); - - EXPECT_EQ(new_contents.size(), v.size()); - EXPECT_LE(new_contents.size(), v.capacity()); - if (target_size <= 3 && original_size <= 3) { - // Storage should stay inline when target size is small. - EXPECT_EQ(3, v.capacity()); - } - EXPECT_THAT(v, ElementsAreArray(new_contents)); - } - } -} - -// Returns true if lhs and rhs have the same value. -template -static bool InstanceValuesEqual(const Instance& lhs, const Instance& rhs) { - return lhs.value() == rhs.value(); -} - -// Test for ranged assign() using Instance as the element type and -// SourceContainer as the source container type. -template -void InstanceRangedAssignTestForContainer() { - // Test for all combinations of original sizes (empty and non-empty inline, - // and out of line) and target sizes. - for (size_t original_size = 0; original_size <= 5; ++original_size) { - SCOPED_TRACE(original_size); - // Original contents are [12345, 12345, ...] - std::vector original_contents(original_size, Instance(12345)); - - for (size_t target_size = 0; target_size <= 5; ++target_size) { - SCOPED_TRACE(target_size); - - // New contents are [3, 4, ...] - // Generate data using a non-const container, because SourceContainer - // itself may be const. - // TODO(bsamwel): Test with an input iterator. - std::vector new_contents_in; - for (size_t i = 0; i < target_size; ++i) { - new_contents_in.push_back(Instance(i + 3)); - } - SourceContainer new_contents(new_contents_in.begin(), - new_contents_in.end()); - - absl::InlinedVector v(original_contents.begin(), - original_contents.end()); - v.assign(new_contents.begin(), new_contents.end()); - - EXPECT_EQ(new_contents.size(), v.size()); - EXPECT_LE(new_contents.size(), v.capacity()); - if (target_size <= 3 && original_size <= 3) { - // Storage should stay inline when target size is small. - EXPECT_EQ(3, v.capacity()); - } - EXPECT_TRUE(std::equal(v.begin(), v.end(), new_contents.begin(), - InstanceValuesEqual)); - } - } -} - -TYPED_TEST_P(InstanceTest, RangedAssign) { - using Instance = TypeParam; - // Test with const and non-const, random access and non-random-access sources. - // TODO(bsamwel): Test with an input iterator source. - SCOPED_TRACE("std::list"); - InstanceRangedAssignTestForContainer>(); - SCOPED_TRACE("const std::list"); - InstanceRangedAssignTestForContainer>(); - SCOPED_TRACE("std::vector"); - InstanceRangedAssignTestForContainer>(); - SCOPED_TRACE("const std::vector"); - InstanceRangedAssignTestForContainer>(); -} - -TEST(InitializerListConstructor, SimpleTypeWithInlineBacking) { - EXPECT_THAT((absl::InlinedVector{4, 5, 6}), - AllOf(SizeIs(3), CapacityIs(4), ElementsAre(4, 5, 6))); -} - -TEST(InitializerListConstructor, SimpleTypeWithReallocationRequired) { - EXPECT_THAT((absl::InlinedVector{4, 5, 6}), - AllOf(SizeIs(3), CapacityIs(Gt(2)), ElementsAre(4, 5, 6))); -} - -TEST(InitializerListConstructor, DisparateTypesInList) { - EXPECT_THAT((absl::InlinedVector{-7, 8ULL}), ElementsAre(-7, 8)); - - EXPECT_THAT((absl::InlinedVector{"foo", std::string("bar")}), - ElementsAre("foo", "bar")); -} - -TEST(InitializerListConstructor, ComplexTypeWithInlineBacking) { - EXPECT_THAT((absl::InlinedVector{ - CopyableMovableInstance(0)}), - AllOf(SizeIs(1), CapacityIs(1), ElementsAre(ValueIs(0)))); -} - -TEST(InitializerListConstructor, ComplexTypeWithReallocationRequired) { - EXPECT_THAT( - (absl::InlinedVector{ - CopyableMovableInstance(0), CopyableMovableInstance(1)}), - AllOf(SizeIs(2), CapacityIs(Gt(1)), ElementsAre(ValueIs(0), ValueIs(1)))); -} - -TEST(InitializerListAssign, SimpleTypeFitsInlineBacking) { - for (size_t original_size = 0; original_size <= 4; ++original_size) { - SCOPED_TRACE(original_size); - - absl::InlinedVector v1(original_size, 12345); - const size_t original_capacity_v1 = v1.capacity(); - v1.assign({3}); - EXPECT_THAT( - v1, AllOf(SizeIs(1), CapacityIs(original_capacity_v1), ElementsAre(3))); - - absl::InlinedVector v2(original_size, 12345); - const size_t original_capacity_v2 = v2.capacity(); - v2 = {3}; - EXPECT_THAT( - v2, AllOf(SizeIs(1), CapacityIs(original_capacity_v2), ElementsAre(3))); - } -} - -TEST(InitializerListAssign, SimpleTypeDoesNotFitInlineBacking) { - for (size_t original_size = 0; original_size <= 4; ++original_size) { - SCOPED_TRACE(original_size); - absl::InlinedVector v1(original_size, 12345); - v1.assign({3, 4, 5}); - EXPECT_THAT(v1, AllOf(SizeIs(3), ElementsAre(3, 4, 5))); - EXPECT_LE(3, v1.capacity()); - - absl::InlinedVector v2(original_size, 12345); - v2 = {3, 4, 5}; - EXPECT_THAT(v2, AllOf(SizeIs(3), ElementsAre(3, 4, 5))); - EXPECT_LE(3, v2.capacity()); - } -} - -TEST(InitializerListAssign, DisparateTypesInList) { - absl::InlinedVector v_int1; - v_int1.assign({-7, 8ULL}); - EXPECT_THAT(v_int1, ElementsAre(-7, 8)); - - absl::InlinedVector v_int2; - v_int2 = {-7, 8ULL}; - EXPECT_THAT(v_int2, ElementsAre(-7, 8)); - - absl::InlinedVector v_string1; - v_string1.assign({"foo", std::string("bar")}); - EXPECT_THAT(v_string1, ElementsAre("foo", "bar")); - - absl::InlinedVector v_string2; - v_string2 = {"foo", std::string("bar")}; - EXPECT_THAT(v_string2, ElementsAre("foo", "bar")); -} - -TYPED_TEST_P(InstanceTest, InitializerListAssign) { - using Instance = TypeParam; - for (size_t original_size = 0; original_size <= 4; ++original_size) { - SCOPED_TRACE(original_size); - absl::InlinedVector v(original_size, Instance(12345)); - const size_t original_capacity = v.capacity(); - v.assign({Instance(3)}); - EXPECT_THAT(v, AllOf(SizeIs(1), CapacityIs(original_capacity), - ElementsAre(ValueIs(3)))); - } - for (size_t original_size = 0; original_size <= 4; ++original_size) { - SCOPED_TRACE(original_size); - absl::InlinedVector v(original_size, Instance(12345)); - v.assign({Instance(3), Instance(4), Instance(5)}); - EXPECT_THAT(v, AllOf(SizeIs(3), - ElementsAre(ValueIs(3), ValueIs(4), ValueIs(5)))); - EXPECT_LE(3, v.capacity()); - } -} - -REGISTER_TYPED_TEST_CASE_P(InstanceTest, Swap, CountConstructorsDestructors, - CountConstructorsDestructorsOnCopyConstruction, - CountConstructorsDestructorsOnMoveConstruction, - CountConstructorsDestructorsOnAssignment, - CountConstructorsDestructorsOnMoveAssignment, - CountElemAssignInlineBacking, RangedConstructor, - RangedAssign, InitializerListAssign); - -using InstanceTypes = - ::testing::Types; -INSTANTIATE_TYPED_TEST_CASE_P(InstanceTestOnTypes, InstanceTest, InstanceTypes); - -TEST(DynamicVec, DynamicVecCompiles) { - DynamicVec v; - (void)v; -} - -TEST(AllocatorSupportTest, Constructors) { - using MyAlloc = CountingAllocator; - using AllocVec = absl::InlinedVector; - const int ia[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - int64_t allocated = 0; - MyAlloc alloc(&allocated); - { AllocVec ABSL_ATTRIBUTE_UNUSED v; } - { AllocVec ABSL_ATTRIBUTE_UNUSED v(alloc); } - { AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc); } - { AllocVec ABSL_ATTRIBUTE_UNUSED v({1, 2, 3}, alloc); } - - AllocVec v2; - { AllocVec ABSL_ATTRIBUTE_UNUSED v(v2, alloc); } - { AllocVec ABSL_ATTRIBUTE_UNUSED v(std::move(v2), alloc); } -} - -TEST(AllocatorSupportTest, CountAllocations) { - using MyAlloc = CountingAllocator; - using AllocVec = absl::InlinedVector; - const int ia[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - int64_t allocated = 0; - MyAlloc alloc(&allocated); - { - AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + 4, alloc); - EXPECT_THAT(allocated, 0); - } - EXPECT_THAT(allocated, 0); - { - AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc); - EXPECT_THAT(allocated, v.size() * sizeof(int)); - } - EXPECT_THAT(allocated, 0); - { - AllocVec v(4, 1, alloc); - EXPECT_THAT(allocated, 0); - - int64_t allocated2 = 0; - MyAlloc alloc2(&allocated2); - AllocVec v2(v, alloc2); - EXPECT_THAT(allocated2, 0); - - int64_t allocated3 = 0; - MyAlloc alloc3(&allocated3); - AllocVec v3(std::move(v), alloc3); - EXPECT_THAT(allocated3, 0); - } - EXPECT_THAT(allocated, 0); - { - AllocVec v(8, 2, alloc); - EXPECT_THAT(allocated, v.size() * sizeof(int)); - - int64_t allocated2 = 0; - MyAlloc alloc2(&allocated2); - AllocVec v2(v, alloc2); - EXPECT_THAT(allocated2, v2.size() * sizeof(int)); - - int64_t allocated3 = 0; - MyAlloc alloc3(&allocated3); - AllocVec v3(std::move(v), alloc3); - EXPECT_THAT(allocated3, v3.size() * sizeof(int)); - } - EXPECT_EQ(allocated, 0); - { - // Test shrink_to_fit deallocations. - AllocVec v(8, 2, alloc); - EXPECT_EQ(allocated, 8 * sizeof(int)); - v.resize(5); - EXPECT_EQ(allocated, 8 * sizeof(int)); - v.shrink_to_fit(); - EXPECT_EQ(allocated, 5 * sizeof(int)); - v.resize(4); - EXPECT_EQ(allocated, 5 * sizeof(int)); - v.shrink_to_fit(); - EXPECT_EQ(allocated, 0); - } -} - -TEST(AllocatorSupportTest, SwapBothAllocated) { - using MyAlloc = CountingAllocator; - using AllocVec = absl::InlinedVector; - int64_t allocated1 = 0; - int64_t allocated2 = 0; - { - const int ia1[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - const int ia2[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; - MyAlloc a1(&allocated1); - MyAlloc a2(&allocated2); - AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1); - AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2); - EXPECT_LT(v1.capacity(), v2.capacity()); - EXPECT_THAT(allocated1, v1.capacity() * sizeof(int)); - EXPECT_THAT(allocated2, v2.capacity() * sizeof(int)); - v1.swap(v2); - EXPECT_THAT(v1, ElementsAreArray(ia2)); - EXPECT_THAT(v2, ElementsAreArray(ia1)); - EXPECT_THAT(allocated1, v2.capacity() * sizeof(int)); - EXPECT_THAT(allocated2, v1.capacity() * sizeof(int)); - } - EXPECT_THAT(allocated1, 0); - EXPECT_THAT(allocated2, 0); -} - -TEST(AllocatorSupportTest, SwapOneAllocated) { - using MyAlloc = CountingAllocator; - using AllocVec = absl::InlinedVector; - int64_t allocated1 = 0; - int64_t allocated2 = 0; - { - const int ia1[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - const int ia2[] = { 0, 1, 2, 3 }; - MyAlloc a1(&allocated1); - MyAlloc a2(&allocated2); - AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1); - AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2); - EXPECT_THAT(allocated1, v1.capacity() * sizeof(int)); - EXPECT_THAT(allocated2, 0); - v1.swap(v2); - EXPECT_THAT(v1, ElementsAreArray(ia2)); - EXPECT_THAT(v2, ElementsAreArray(ia1)); - EXPECT_THAT(allocated1, v2.capacity() * sizeof(int)); - EXPECT_THAT(allocated2, 0); - EXPECT_TRUE(v2.get_allocator() == a1); - EXPECT_TRUE(v1.get_allocator() == a2); - } - EXPECT_THAT(allocated1, 0); - EXPECT_THAT(allocated2, 0); -} - -TEST(AllocatorSupportTest, ScopedAllocatorWorks) { - using StdVector = std::vector>; - using MyAlloc = - std::scoped_allocator_adaptor>; - using AllocVec = absl::InlinedVector; - - int64_t allocated = 0; - AllocVec vec(MyAlloc{CountingAllocator{&allocated}}); - EXPECT_EQ(allocated, 0); - - // This default constructs a vector, but the allocator should pass itself - // into the vector. - // The absl::InlinedVector does not allocate any memory. - // The vector does not allocate any memory. - vec.resize(1); - EXPECT_EQ(allocated, 0); - - // We make vector allocate memory. - // It must go through the allocator even though we didn't construct the - // vector directly. - vec[0].push_back(1); - EXPECT_EQ(allocated, sizeof(int) * 1); - - // Another allocating vector. - vec.push_back(vec[0]); - EXPECT_EQ(allocated, sizeof(int) * 2); - - // Overflow the inlined memory. - // The absl::InlinedVector will now allocate. - vec.resize(5); - EXPECT_EQ(allocated, sizeof(int) * 2 + sizeof(StdVector) * 8); - - // Adding one more in external mode should also work. - vec.push_back(vec[0]); - EXPECT_EQ(allocated, sizeof(int) * 3 + sizeof(StdVector) * 8); - - // And extending these should still work. - vec[0].push_back(1); - EXPECT_EQ(allocated, sizeof(int) * 4 + sizeof(StdVector) * 8); - - vec.clear(); - EXPECT_EQ(allocated, 0); -} - -TEST(AllocatorSupportTest, SizeAllocConstructor) { - constexpr int inlined_size = 4; - using Alloc = CountingAllocator; - using AllocVec = absl::InlinedVector; - - { - auto len = inlined_size / 2; - int64_t allocated = 0; - auto v = AllocVec(len, Alloc(&allocated)); - - // Inline storage used; allocator should not be invoked - EXPECT_THAT(allocated, 0); - EXPECT_THAT(v, AllOf(SizeIs(len), Each(0))); - } - - { - auto len = inlined_size * 2; - int64_t allocated = 0; - auto v = AllocVec(len, Alloc(&allocated)); - - // Out of line storage used; allocation of 8 elements expected - EXPECT_THAT(allocated, len * sizeof(int)); - EXPECT_THAT(v, AllOf(SizeIs(len), Each(0))); - } -} - -} // anonymous namespace diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h deleted file mode 100644 index cc52614..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. -// -// Helper class to perform the Empty Base Optimization. -// Ts can contain classes and non-classes, empty or not. For the ones that -// are empty classes, we perform the optimization. If all types in Ts are empty -// classes, then CompressedTuple is itself an empty class. -// -// To access the members, use member get() function. -// -// Eg: -// absl::container_internal::CompressedTuple value(7, t1, t2, -// t3); -// assert(value.get<0>() == 7); -// T1& t1 = value.get<1>(); -// const T2& t2 = value.get<2>(); -// ... -// -// http://en.cppreference.com/w/cpp/language/ebo - -#ifndef ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_ -#define ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_ - -#include -#include -#include - -#include "absl/utility/utility.h" - -#ifdef _MSC_VER -// We need to mark these classes with this declspec to ensure that -// CompressedTuple happens. -#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC __declspec(empty_bases) -#else // _MSC_VER -#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC -#endif // _MSC_VER - -namespace absl { -namespace container_internal { - -template -class CompressedTuple; - -namespace internal_compressed_tuple { - -template -struct Elem; -template -struct Elem, I> - : std::tuple_element> {}; -template -using ElemT = typename Elem::type; - -// Use the __is_final intrinsic if available. Where it's not available, classes -// declared with the 'final' specifier cannot be used as CompressedTuple -// elements. -// TODO(sbenza): Replace this with std::is_final in C++14. -template -constexpr bool IsFinal() { -#if defined(__clang__) || defined(__GNUC__) - return __is_final(T); -#else - return false; -#endif -} - -template -constexpr bool ShouldUseBase() { - return std::is_class::value && std::is_empty::value && !IsFinal(); -} - -// The storage class provides two specializations: -// - For empty classes, it stores T as a base class. -// - For everything else, it stores T as a member. -template >()> -struct Storage { - using T = ElemT; - T value; - constexpr Storage() = default; - explicit constexpr Storage(T&& v) : value(absl::forward(v)) {} - constexpr const T& get() const { return value; } - T& get() { return value; } -}; - -template -struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage - : ElemT { - using T = internal_compressed_tuple::ElemT; - constexpr Storage() = default; - explicit constexpr Storage(T&& v) : T(absl::forward(v)) {} - constexpr const T& get() const { return *this; } - T& get() { return *this; } -}; - -template -struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl; - -template -struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC - CompressedTupleImpl, absl::index_sequence> - // We use the dummy identity function through std::integral_constant to - // convince MSVC of accepting and expanding I in that context. Without it - // you would get: - // error C3548: 'I': parameter pack cannot be used in this context - : Storage, - std::integral_constant::value>... { - constexpr CompressedTupleImpl() = default; - explicit constexpr CompressedTupleImpl(Ts&&... args) - : Storage, I>(absl::forward(args))... {} -}; - -} // namespace internal_compressed_tuple - -// Helper class to perform the Empty Base Class Optimization. -// Ts can contain classes and non-classes, empty or not. For the ones that -// are empty classes, we perform the CompressedTuple. If all types in Ts are -// empty classes, then CompressedTuple is itself an empty class. -// -// To access the members, use member .get() function. -// -// Eg: -// absl::container_internal::CompressedTuple value(7, t1, t2, -// t3); -// assert(value.get<0>() == 7); -// T1& t1 = value.get<1>(); -// const T2& t2 = value.get<2>(); -// ... -// -// http://en.cppreference.com/w/cpp/language/ebo -template -class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple - : private internal_compressed_tuple::CompressedTupleImpl< - CompressedTuple, absl::index_sequence_for> { - private: - template - using ElemT = internal_compressed_tuple::ElemT; - - public: - constexpr CompressedTuple() = default; - explicit constexpr CompressedTuple(Ts... base) - : CompressedTuple::CompressedTupleImpl(absl::forward(base)...) {} - - template - ElemT& get() { - return internal_compressed_tuple::Storage::get(); - } - - template - constexpr const ElemT& get() const { - return internal_compressed_tuple::Storage::get(); - } -}; - -// Explicit specialization for a zero-element tuple -// (needed to avoid ambiguous overloads for the default constructor). -template <> -class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple<> {}; - -} // namespace container_internal -} // namespace absl - -#undef ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC - -#endif // ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/compressed_tuple_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/compressed_tuple_test.cc deleted file mode 100644 index 45030c6..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/compressed_tuple_test.cc +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include "absl/container/internal/compressed_tuple.h" - -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace absl { -namespace container_internal { -namespace { - -template -struct Empty {}; - -template -struct NotEmpty { - T value; -}; - -template -struct TwoValues { - T value1; - U value2; -}; - -TEST(CompressedTupleTest, Sizeof) { - EXPECT_EQ(sizeof(int), sizeof(CompressedTuple)); - EXPECT_EQ(sizeof(int), sizeof(CompressedTuple>)); - EXPECT_EQ(sizeof(int), sizeof(CompressedTuple, Empty<1>>)); - EXPECT_EQ(sizeof(int), - sizeof(CompressedTuple, Empty<1>, Empty<2>>)); - - EXPECT_EQ(sizeof(TwoValues), - sizeof(CompressedTuple>)); - EXPECT_EQ(sizeof(TwoValues), - sizeof(CompressedTuple, NotEmpty>)); - EXPECT_EQ(sizeof(TwoValues), - sizeof(CompressedTuple, NotEmpty, Empty<1>>)); -} - -TEST(CompressedTupleTest, Access) { - struct S { - std::string x; - }; - CompressedTuple, S> x(7, {}, S{"ABC"}); - EXPECT_EQ(sizeof(x), sizeof(TwoValues)); - EXPECT_EQ(7, x.get<0>()); - EXPECT_EQ("ABC", x.get<2>().x); -} - -TEST(CompressedTupleTest, NonClasses) { - CompressedTuple x(7, "ABC"); - EXPECT_EQ(7, x.get<0>()); - EXPECT_STREQ("ABC", x.get<1>()); -} - -TEST(CompressedTupleTest, MixClassAndNonClass) { - CompressedTuple, NotEmpty> x(7, "ABC", {}, - {1.25}); - struct Mock { - int v; - const char* p; - double d; - }; - EXPECT_EQ(sizeof(x), sizeof(Mock)); - EXPECT_EQ(7, x.get<0>()); - EXPECT_STREQ("ABC", x.get<1>()); - EXPECT_EQ(1.25, x.get<3>().value); -} - -TEST(CompressedTupleTest, Nested) { - CompressedTuple, - CompressedTuple>> - x(1, CompressedTuple(2), - CompressedTuple>(3, CompressedTuple(4))); - EXPECT_EQ(1, x.get<0>()); - EXPECT_EQ(2, x.get<1>().get<0>()); - EXPECT_EQ(3, x.get<2>().get<0>()); - EXPECT_EQ(4, x.get<2>().get<1>().get<0>()); - - CompressedTuple, Empty<0>, - CompressedTuple, CompressedTuple>>> - y; - std::set*> empties{&y.get<0>(), &y.get<1>(), &y.get<2>().get<0>(), - &y.get<2>().get<1>().get<0>()}; -#ifdef _MSC_VER - // MSVC has a bug where many instances of the same base class are layed out in - // the same address when using __declspec(empty_bases). - // This will be fixed in a future version of MSVC. - int expected = 1; -#else - int expected = 4; -#endif - EXPECT_EQ(expected, sizeof(y)); - EXPECT_EQ(expected, empties.size()); - EXPECT_EQ(sizeof(y), sizeof(Empty<0>) * empties.size()); - - EXPECT_EQ(4 * sizeof(char), - sizeof(CompressedTuple, - CompressedTuple>)); - EXPECT_TRUE( - (std::is_empty>, - CompressedTuple>>>::value)); -} - -TEST(CompressedTupleTest, Reference) { - int i = 7; - std::string s = "Very long std::string that goes in the heap"; - CompressedTuple x(i, i, s, s); - - // Sanity check. We should have not moved from `s` - EXPECT_EQ(s, "Very long std::string that goes in the heap"); - - EXPECT_EQ(x.get<0>(), x.get<1>()); - EXPECT_NE(&x.get<0>(), &x.get<1>()); - EXPECT_EQ(&x.get<1>(), &i); - - EXPECT_EQ(x.get<2>(), x.get<3>()); - EXPECT_NE(&x.get<2>(), &x.get<3>()); - EXPECT_EQ(&x.get<3>(), &s); -} - -TEST(CompressedTupleTest, NoElements) { - CompressedTuple<> x; - static_cast(x); // Silence -Wunused-variable. - EXPECT_TRUE(std::is_empty>::value); -} - -TEST(CompressedTupleTest, Constexpr) { - constexpr CompressedTuple> x( - 7, 1.25, CompressedTuple(5)); - constexpr int x0 = x.get<0>(); - constexpr double x1 = x.get<1>(); - constexpr int x2 = x.get<2>().get<0>(); - EXPECT_EQ(x0, 7); - EXPECT_EQ(x1, 1.25); - EXPECT_EQ(x2, 5); -} - -#if defined(__clang__) || defined(__GNUC__) -TEST(CompressedTupleTest, EmptyFinalClass) { - struct S final { - int f() const { return 5; } - }; - CompressedTuple x; - EXPECT_EQ(x.get<0>().f(), 5); -} -#endif - -} // namespace -} // namespace container_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/container_memory.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/container_memory.h deleted file mode 100644 index 56c5d2d..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/container_memory.h +++ /dev/null @@ -1,405 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_ -#define ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_ - -#ifdef ADDRESS_SANITIZER -#include -#endif - -#ifdef MEMORY_SANITIZER -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "absl/memory/memory.h" -#include "absl/utility/utility.h" - -namespace absl { -namespace container_internal { - -// Allocates at least n bytes aligned to the specified alignment. -// Alignment must be a power of 2. It must be positive. -// -// Note that many allocators don't honor alignment requirements above certain -// threshold (usually either alignof(std::max_align_t) or alignof(void*)). -// Allocate() doesn't apply alignment corrections. If the underlying allocator -// returns insufficiently alignment pointer, that's what you are going to get. -template -void* Allocate(Alloc* alloc, size_t n) { - static_assert(Alignment > 0, ""); - assert(n && "n must be positive"); - struct alignas(Alignment) M {}; - using A = typename absl::allocator_traits::template rebind_alloc; - using AT = typename absl::allocator_traits::template rebind_traits; - A mem_alloc(*alloc); - void* p = AT::allocate(mem_alloc, (n + sizeof(M) - 1) / sizeof(M)); - assert(reinterpret_cast(p) % Alignment == 0 && - "allocator does not respect alignment"); - return p; -} - -// The pointer must have been previously obtained by calling -// Allocate(alloc, n). -template -void Deallocate(Alloc* alloc, void* p, size_t n) { - static_assert(Alignment > 0, ""); - assert(n && "n must be positive"); - struct alignas(Alignment) M {}; - using A = typename absl::allocator_traits::template rebind_alloc; - using AT = typename absl::allocator_traits::template rebind_traits; - A mem_alloc(*alloc); - AT::deallocate(mem_alloc, static_cast(p), - (n + sizeof(M) - 1) / sizeof(M)); -} - -namespace memory_internal { - -// Constructs T into uninitialized storage pointed by `ptr` using the args -// specified in the tuple. -template -void ConstructFromTupleImpl(Alloc* alloc, T* ptr, Tuple&& t, - absl::index_sequence) { - absl::allocator_traits::construct( - *alloc, ptr, std::get(std::forward(t))...); -} - -template -struct WithConstructedImplF { - template - decltype(std::declval()(std::declval())) operator()( - Args&&... args) const { - return std::forward(f)(T(std::forward(args)...)); - } - F&& f; -}; - -template -decltype(std::declval()(std::declval())) WithConstructedImpl( - Tuple&& t, absl::index_sequence, F&& f) { - return WithConstructedImplF{std::forward(f)}( - std::get(std::forward(t))...); -} - -template -auto TupleRefImpl(T&& t, absl::index_sequence) - -> decltype(std::forward_as_tuple(std::get(std::forward(t))...)) { - return std::forward_as_tuple(std::get(std::forward(t))...); -} - -// Returns a tuple of references to the elements of the input tuple. T must be a -// tuple. -template -auto TupleRef(T&& t) -> decltype( - TupleRefImpl(std::forward(t), - absl::make_index_sequence< - std::tuple_size::type>::value>())) { - return TupleRefImpl( - std::forward(t), - absl::make_index_sequence< - std::tuple_size::type>::value>()); -} - -template -decltype(std::declval()(std::declval(), std::piecewise_construct, - std::declval>(), std::declval())) -DecomposePairImpl(F&& f, std::pair, V> p) { - const auto& key = std::get<0>(p.first); - return std::forward(f)(key, std::piecewise_construct, std::move(p.first), - std::move(p.second)); -} - -} // namespace memory_internal - -// Constructs T into uninitialized storage pointed by `ptr` using the args -// specified in the tuple. -template -void ConstructFromTuple(Alloc* alloc, T* ptr, Tuple&& t) { - memory_internal::ConstructFromTupleImpl( - alloc, ptr, std::forward(t), - absl::make_index_sequence< - std::tuple_size::type>::value>()); -} - -// Constructs T using the args specified in the tuple and calls F with the -// constructed value. -template -decltype(std::declval()(std::declval())) WithConstructed( - Tuple&& t, F&& f) { - return memory_internal::WithConstructedImpl( - std::forward(t), - absl::make_index_sequence< - std::tuple_size::type>::value>(), - std::forward(f)); -} - -// Given arguments of an std::pair's consructor, PairArgs() returns a pair of -// tuples with references to the passed arguments. The tuples contain -// constructor arguments for the first and the second elements of the pair. -// -// The following two snippets are equivalent. -// -// 1. std::pair p(args...); -// -// 2. auto a = PairArgs(args...); -// std::pair p(std::piecewise_construct, -// std::move(p.first), std::move(p.second)); -inline std::pair, std::tuple<>> PairArgs() { return {}; } -template -std::pair, std::tuple> PairArgs(F&& f, S&& s) { - return {std::piecewise_construct, std::forward_as_tuple(std::forward(f)), - std::forward_as_tuple(std::forward(s))}; -} -template -std::pair, std::tuple> PairArgs( - const std::pair& p) { - return PairArgs(p.first, p.second); -} -template -std::pair, std::tuple> PairArgs(std::pair&& p) { - return PairArgs(std::forward(p.first), std::forward(p.second)); -} -template -auto PairArgs(std::piecewise_construct_t, F&& f, S&& s) - -> decltype(std::make_pair(memory_internal::TupleRef(std::forward(f)), - memory_internal::TupleRef(std::forward(s)))) { - return std::make_pair(memory_internal::TupleRef(std::forward(f)), - memory_internal::TupleRef(std::forward(s))); -} - -// A helper function for implementing apply() in map policies. -template -auto DecomposePair(F&& f, Args&&... args) - -> decltype(memory_internal::DecomposePairImpl( - std::forward(f), PairArgs(std::forward(args)...))) { - return memory_internal::DecomposePairImpl( - std::forward(f), PairArgs(std::forward(args)...)); -} - -// A helper function for implementing apply() in set policies. -template -decltype(std::declval()(std::declval(), std::declval())) -DecomposeValue(F&& f, Arg&& arg) { - const auto& key = arg; - return std::forward(f)(key, std::forward(arg)); -} - -// Helper functions for asan and msan. -inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) { -#ifdef ADDRESS_SANITIZER - ASAN_POISON_MEMORY_REGION(m, s); -#endif -#ifdef MEMORY_SANITIZER - __msan_poison(m, s); -#endif - (void)m; - (void)s; -} - -inline void SanitizerUnpoisonMemoryRegion(const void* m, size_t s) { -#ifdef ADDRESS_SANITIZER - ASAN_UNPOISON_MEMORY_REGION(m, s); -#endif -#ifdef MEMORY_SANITIZER - __msan_unpoison(m, s); -#endif - (void)m; - (void)s; -} - -template -inline void SanitizerPoisonObject(const T* object) { - SanitizerPoisonMemoryRegion(object, sizeof(T)); -} - -template -inline void SanitizerUnpoisonObject(const T* object) { - SanitizerUnpoisonMemoryRegion(object, sizeof(T)); -} - -namespace memory_internal { - -// If Pair is a standard-layout type, OffsetOf::kFirst and -// OffsetOf::kSecond are equivalent to offsetof(Pair, first) and -// offsetof(Pair, second) respectively. Otherwise they are -1. -// -// The purpose of OffsetOf is to avoid calling offsetof() on non-standard-layout -// type, which is non-portable. -template -struct OffsetOf { - static constexpr size_t kFirst = -1; - static constexpr size_t kSecond = -1; -}; - -template -struct OffsetOf::type> { - static constexpr size_t kFirst = offsetof(Pair, first); - static constexpr size_t kSecond = offsetof(Pair, second); -}; - -template -struct IsLayoutCompatible { - private: - struct Pair { - K first; - V second; - }; - - // Is P layout-compatible with Pair? - template - static constexpr bool LayoutCompatible() { - return std::is_standard_layout

() && sizeof(P) == sizeof(Pair) && - alignof(P) == alignof(Pair) && - memory_internal::OffsetOf

::kFirst == - memory_internal::OffsetOf::kFirst && - memory_internal::OffsetOf

::kSecond == - memory_internal::OffsetOf::kSecond; - } - - public: - // Whether pair and pair are layout-compatible. If they are, - // then it is safe to store them in a union and read from either. - static constexpr bool value = std::is_standard_layout() && - std::is_standard_layout() && - memory_internal::OffsetOf::kFirst == 0 && - LayoutCompatible>() && - LayoutCompatible>(); -}; - -} // namespace memory_internal - -// If kMutableKeys is false, only the value member is accessed. -// -// If kMutableKeys is true, key is accessed through all slots while value and -// mutable_value are accessed only via INITIALIZED slots. Slots are created and -// destroyed via mutable_value so that the key can be moved later. -template -union slot_type { - private: - static void emplace(slot_type* slot) { - // The construction of union doesn't do anything at runtime but it allows us - // to access its members without violating aliasing rules. - new (slot) slot_type; - } - // If pair and pair are layout-compatible, we can accept one - // or the other via slot_type. We are also free to access the key via - // slot_type::key in this case. - using kMutableKeys = - std::integral_constant::value>; - - public: - slot_type() {} - ~slot_type() = delete; - using value_type = std::pair; - using mutable_value_type = std::pair; - - value_type value; - mutable_value_type mutable_value; - K key; - - template - static void construct(Allocator* alloc, slot_type* slot, Args&&... args) { - emplace(slot); - if (kMutableKeys::value) { - absl::allocator_traits::construct(*alloc, &slot->mutable_value, - std::forward(args)...); - } else { - absl::allocator_traits::construct(*alloc, &slot->value, - std::forward(args)...); - } - } - - // Construct this slot by moving from another slot. - template - static void construct(Allocator* alloc, slot_type* slot, slot_type* other) { - emplace(slot); - if (kMutableKeys::value) { - absl::allocator_traits::construct( - *alloc, &slot->mutable_value, std::move(other->mutable_value)); - } else { - absl::allocator_traits::construct(*alloc, &slot->value, - std::move(other->value)); - } - } - - template - static void destroy(Allocator* alloc, slot_type* slot) { - if (kMutableKeys::value) { - absl::allocator_traits::destroy(*alloc, &slot->mutable_value); - } else { - absl::allocator_traits::destroy(*alloc, &slot->value); - } - } - - template - static void transfer(Allocator* alloc, slot_type* new_slot, - slot_type* old_slot) { - emplace(new_slot); - if (kMutableKeys::value) { - absl::allocator_traits::construct( - *alloc, &new_slot->mutable_value, std::move(old_slot->mutable_value)); - } else { - absl::allocator_traits::construct(*alloc, &new_slot->value, - std::move(old_slot->value)); - } - destroy(alloc, old_slot); - } - - template - static void swap(Allocator* alloc, slot_type* a, slot_type* b) { - if (kMutableKeys::value) { - using std::swap; - swap(a->mutable_value, b->mutable_value); - } else { - value_type tmp = std::move(a->value); - absl::allocator_traits::destroy(*alloc, &a->value); - absl::allocator_traits::construct(*alloc, &a->value, - std::move(b->value)); - absl::allocator_traits::destroy(*alloc, &b->value); - absl::allocator_traits::construct(*alloc, &b->value, - std::move(tmp)); - } - } - - template - static void move(Allocator* alloc, slot_type* src, slot_type* dest) { - if (kMutableKeys::value) { - dest->mutable_value = std::move(src->mutable_value); - } else { - absl::allocator_traits::destroy(*alloc, &dest->value); - absl::allocator_traits::construct(*alloc, &dest->value, - std::move(src->value)); - } - } - - template - static void move(Allocator* alloc, slot_type* first, slot_type* last, - slot_type* result) { - for (slot_type *src = first, *dest = result; src != last; ++src, ++dest) - move(alloc, src, dest); - } -}; - -} // namespace container_internal -} // namespace absl - -#endif // ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc deleted file mode 100644 index f1c4058..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include "absl/container/internal/container_memory.h" - -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/strings/string_view.h" - -namespace absl { -namespace container_internal { -namespace { - -using ::testing::Pair; - -TEST(Memory, AlignmentLargerThanBase) { - std::allocator alloc; - void* mem = Allocate<2>(&alloc, 3); - EXPECT_EQ(0, reinterpret_cast(mem) % 2); - memcpy(mem, "abc", 3); - Deallocate<2>(&alloc, mem, 3); -} - -TEST(Memory, AlignmentSmallerThanBase) { - std::allocator alloc; - void* mem = Allocate<2>(&alloc, 3); - EXPECT_EQ(0, reinterpret_cast(mem) % 2); - memcpy(mem, "abc", 3); - Deallocate<2>(&alloc, mem, 3); -} - -class Fixture : public ::testing::Test { - using Alloc = std::allocator; - - public: - Fixture() { ptr_ = std::allocator_traits::allocate(*alloc(), 1); } - ~Fixture() override { - std::allocator_traits::destroy(*alloc(), ptr_); - std::allocator_traits::deallocate(*alloc(), ptr_, 1); - } - std::string* ptr() { return ptr_; } - Alloc* alloc() { return &alloc_; } - - private: - Alloc alloc_; - std::string* ptr_; -}; - -TEST_F(Fixture, ConstructNoArgs) { - ConstructFromTuple(alloc(), ptr(), std::forward_as_tuple()); - EXPECT_EQ(*ptr(), ""); -} - -TEST_F(Fixture, ConstructOneArg) { - ConstructFromTuple(alloc(), ptr(), std::forward_as_tuple("abcde")); - EXPECT_EQ(*ptr(), "abcde"); -} - -TEST_F(Fixture, ConstructTwoArg) { - ConstructFromTuple(alloc(), ptr(), std::forward_as_tuple(5, 'a')); - EXPECT_EQ(*ptr(), "aaaaa"); -} - -TEST(PairArgs, NoArgs) { - EXPECT_THAT(PairArgs(), - Pair(std::forward_as_tuple(), std::forward_as_tuple())); -} - -TEST(PairArgs, TwoArgs) { - EXPECT_EQ( - std::make_pair(std::forward_as_tuple(1), std::forward_as_tuple('A')), - PairArgs(1, 'A')); -} - -TEST(PairArgs, Pair) { - EXPECT_EQ( - std::make_pair(std::forward_as_tuple(1), std::forward_as_tuple('A')), - PairArgs(std::make_pair(1, 'A'))); -} - -TEST(PairArgs, Piecewise) { - EXPECT_EQ( - std::make_pair(std::forward_as_tuple(1), std::forward_as_tuple('A')), - PairArgs(std::piecewise_construct, std::forward_as_tuple(1), - std::forward_as_tuple('A'))); -} - -TEST(WithConstructed, Simple) { - EXPECT_EQ(1, WithConstructed( - std::make_tuple(std::string("a")), - [](absl::string_view str) { return str.size(); })); -} - -template -decltype(DecomposeValue(std::declval(), std::declval())) -DecomposeValueImpl(int, F&& f, Arg&& arg) { - return DecomposeValue(std::forward(f), std::forward(arg)); -} - -template -const char* DecomposeValueImpl(char, F&& f, Arg&& arg) { - return "not decomposable"; -} - -template -decltype(DecomposeValueImpl(0, std::declval(), std::declval())) -TryDecomposeValue(F&& f, Arg&& arg) { - return DecomposeValueImpl(0, std::forward(f), std::forward(arg)); -} - -TEST(DecomposeValue, Decomposable) { - auto f = [](const int& x, int&& y) { - EXPECT_EQ(&x, &y); - EXPECT_EQ(42, x); - return 'A'; - }; - EXPECT_EQ('A', TryDecomposeValue(f, 42)); -} - -TEST(DecomposeValue, NotDecomposable) { - auto f = [](void*) { - ADD_FAILURE() << "Must not be called"; - return 'A'; - }; - EXPECT_STREQ("not decomposable", TryDecomposeValue(f, 42)); -} - -template -decltype(DecomposePair(std::declval(), std::declval()...)) -DecomposePairImpl(int, F&& f, Args&&... args) { - return DecomposePair(std::forward(f), std::forward(args)...); -} - -template -const char* DecomposePairImpl(char, F&& f, Args&&... args) { - return "not decomposable"; -} - -template -decltype(DecomposePairImpl(0, std::declval(), std::declval()...)) -TryDecomposePair(F&& f, Args&&... args) { - return DecomposePairImpl(0, std::forward(f), std::forward(args)...); -} - -TEST(DecomposePair, Decomposable) { - auto f = [](const int& x, std::piecewise_construct_t, std::tuple k, - std::tuple&& v) { - EXPECT_EQ(&x, &std::get<0>(k)); - EXPECT_EQ(42, x); - EXPECT_EQ(0.5, std::get<0>(v)); - return 'A'; - }; - EXPECT_EQ('A', TryDecomposePair(f, 42, 0.5)); - EXPECT_EQ('A', TryDecomposePair(f, std::make_pair(42, 0.5))); - EXPECT_EQ('A', TryDecomposePair(f, std::piecewise_construct, - std::make_tuple(42), std::make_tuple(0.5))); -} - -TEST(DecomposePair, NotDecomposable) { - auto f = [](...) { - ADD_FAILURE() << "Must not be called"; - return 'A'; - }; - EXPECT_STREQ("not decomposable", - TryDecomposePair(f)); - EXPECT_STREQ("not decomposable", - TryDecomposePair(f, std::piecewise_construct, std::make_tuple(), - std::make_tuple(0.5))); -} - -} // namespace -} // namespace container_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h deleted file mode 100644 index 1f0d794..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. -// -// Define the default Hash and Eq functions for SwissTable containers. -// -// std::hash and std::equal_to are not appropriate hash and equal -// functions for SwissTable containers. There are two reasons for this. -// -// SwissTable containers are power of 2 sized containers: -// -// This means they use the lower bits of the hash value to find the slot for -// each entry. The typical hash function for integral types is the identity. -// This is a very weak hash function for SwissTable and any power of 2 sized -// hashtable implementation which will lead to excessive collisions. For -// SwissTable we use murmur3 style mixing to reduce collisions to a minimum. -// -// SwissTable containers support heterogeneous lookup: -// -// In order to make heterogeneous lookup work, hash and equal functions must be -// polymorphic. At the same time they have to satisfy the same requirements the -// C++ standard imposes on hash functions and equality operators. That is: -// -// if hash_default_eq(a, b) returns true for any a and b of type T, then -// hash_default_hash(a) must equal hash_default_hash(b) -// -// For SwissTable containers this requirement is relaxed to allow a and b of -// any and possibly different types. Note that like the standard the hash and -// equal functions are still bound to T. This is important because some type U -// can be hashed by/tested for equality differently depending on T. A notable -// example is `const char*`. `const char*` is treated as a c-style string when -// the hash function is hash but as a pointer when the hash function is -// hash. -// -#ifndef ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_ -#define ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_ - -#include -#include -#include -#include -#include - -#include "absl/base/config.h" -#include "absl/hash/hash.h" -#include "absl/strings/string_view.h" - -namespace absl { -namespace container_internal { - -// The hash of an object of type T is computed by using absl::Hash. -template -struct HashEq { - using Hash = absl::Hash; - using Eq = std::equal_to; -}; - -struct StringHash { - using is_transparent = void; - - size_t operator()(absl::string_view v) const { - return absl::Hash{}(v); - } -}; - -// Supports heterogeneous lookup for string-like elements. -struct StringHashEq { - using Hash = StringHash; - struct Eq { - using is_transparent = void; - bool operator()(absl::string_view lhs, absl::string_view rhs) const { - return lhs == rhs; - } - }; -}; -template <> -struct HashEq : StringHashEq {}; -template <> -struct HashEq : StringHashEq {}; - -// Supports heterogeneous lookup for pointers and smart pointers. -template -struct HashEq { - struct Hash { - using is_transparent = void; - template - size_t operator()(const U& ptr) const { - return absl::Hash{}(HashEq::ToPtr(ptr)); - } - }; - struct Eq { - using is_transparent = void; - template - bool operator()(const A& a, const B& b) const { - return HashEq::ToPtr(a) == HashEq::ToPtr(b); - } - }; - - private: - static const T* ToPtr(const T* ptr) { return ptr; } - template - static const T* ToPtr(const std::unique_ptr& ptr) { - return ptr.get(); - } - template - static const T* ToPtr(const std::shared_ptr& ptr) { - return ptr.get(); - } -}; - -template -struct HashEq> : HashEq {}; -template -struct HashEq> : HashEq {}; - -// This header's visibility is restricted. If you need to access the default -// hasher please use the container's ::hasher alias instead. -// -// Example: typename Hash = typename absl::flat_hash_map::hasher -template -using hash_default_hash = typename container_internal::HashEq::Hash; - -// This header's visibility is restricted. If you need to access the default -// key equal please use the container's ::key_equal alias instead. -// -// Example: typename Eq = typename absl::flat_hash_map::key_equal -template -using hash_default_eq = typename container_internal::HashEq::Eq; - -} // namespace container_internal -} // namespace absl - -#endif // ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc deleted file mode 100644 index 464baae..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include "absl/container/internal/hash_function_defaults.h" - -#include -#include -#include - -#include "gtest/gtest.h" -#include "absl/strings/string_view.h" - -namespace absl { -namespace container_internal { -namespace { - -using ::testing::Types; - -TEST(Eq, Int32) { - hash_default_eq eq; - EXPECT_TRUE(eq(1, 1u)); - EXPECT_TRUE(eq(1, char{1})); - EXPECT_TRUE(eq(1, true)); - EXPECT_TRUE(eq(1, double{1.1})); - EXPECT_FALSE(eq(1, char{2})); - EXPECT_FALSE(eq(1, 2u)); - EXPECT_FALSE(eq(1, false)); - EXPECT_FALSE(eq(1, 2.)); -} - -TEST(Hash, Int32) { - hash_default_hash hash; - auto h = hash(1); - EXPECT_EQ(h, hash(1u)); - EXPECT_EQ(h, hash(char{1})); - EXPECT_EQ(h, hash(true)); - EXPECT_EQ(h, hash(double{1.1})); - EXPECT_NE(h, hash(2u)); - EXPECT_NE(h, hash(char{2})); - EXPECT_NE(h, hash(false)); - EXPECT_NE(h, hash(2.)); -} - -enum class MyEnum { A, B, C, D }; - -TEST(Eq, Enum) { - hash_default_eq eq; - EXPECT_TRUE(eq(MyEnum::A, MyEnum::A)); - EXPECT_FALSE(eq(MyEnum::A, MyEnum::B)); -} - -TEST(Hash, Enum) { - hash_default_hash hash; - - for (MyEnum e : {MyEnum::A, MyEnum::B, MyEnum::C}) { - auto h = hash(e); - EXPECT_EQ(h, hash_default_hash{}(static_cast(e))); - EXPECT_NE(h, hash(MyEnum::D)); - } -} - -using StringTypes = ::testing::Types; - -template -struct EqString : ::testing::Test { - hash_default_eq key_eq; -}; - -TYPED_TEST_CASE(EqString, StringTypes); - -template -struct HashString : ::testing::Test { - hash_default_hash hasher; -}; - -TYPED_TEST_CASE(HashString, StringTypes); - -TYPED_TEST(EqString, Works) { - auto eq = this->key_eq; - EXPECT_TRUE(eq("a", "a")); - EXPECT_TRUE(eq("a", absl::string_view("a"))); - EXPECT_TRUE(eq("a", std::string("a"))); - EXPECT_FALSE(eq("a", "b")); - EXPECT_FALSE(eq("a", absl::string_view("b"))); - EXPECT_FALSE(eq("a", std::string("b"))); -} - -TYPED_TEST(HashString, Works) { - auto hash = this->hasher; - auto h = hash("a"); - EXPECT_EQ(h, hash(absl::string_view("a"))); - EXPECT_EQ(h, hash(std::string("a"))); - EXPECT_NE(h, hash(absl::string_view("b"))); - EXPECT_NE(h, hash(std::string("b"))); -} - -struct NoDeleter { - template - void operator()(const T* ptr) const {} -}; - -using PointerTypes = - ::testing::Types, - std::unique_ptr, - std::unique_ptr, std::unique_ptr, - std::shared_ptr, std::shared_ptr>; - -template -struct EqPointer : ::testing::Test { - hash_default_eq key_eq; -}; - -TYPED_TEST_CASE(EqPointer, PointerTypes); - -template -struct HashPointer : ::testing::Test { - hash_default_hash hasher; -}; - -TYPED_TEST_CASE(HashPointer, PointerTypes); - -TYPED_TEST(EqPointer, Works) { - int dummy; - auto eq = this->key_eq; - auto sptr = std::make_shared(); - std::shared_ptr csptr = sptr; - int* ptr = sptr.get(); - const int* cptr = ptr; - std::unique_ptr uptr(ptr); - std::unique_ptr cuptr(ptr); - - EXPECT_TRUE(eq(ptr, cptr)); - EXPECT_TRUE(eq(ptr, sptr)); - EXPECT_TRUE(eq(ptr, uptr)); - EXPECT_TRUE(eq(ptr, csptr)); - EXPECT_TRUE(eq(ptr, cuptr)); - EXPECT_FALSE(eq(&dummy, cptr)); - EXPECT_FALSE(eq(&dummy, sptr)); - EXPECT_FALSE(eq(&dummy, uptr)); - EXPECT_FALSE(eq(&dummy, csptr)); - EXPECT_FALSE(eq(&dummy, cuptr)); -} - -TEST(Hash, DerivedAndBase) { - struct Base {}; - struct Derived : Base {}; - - hash_default_hash hasher; - - Base base; - Derived derived; - EXPECT_NE(hasher(&base), hasher(&derived)); - EXPECT_EQ(hasher(static_cast(&derived)), hasher(&derived)); - - auto dp = std::make_shared(); - EXPECT_EQ(hasher(static_cast(dp.get())), hasher(dp)); -} - -TEST(Hash, FunctionPointer) { - using Func = int (*)(); - hash_default_hash hasher; - hash_default_eq eq; - - Func p1 = [] { return 1; }, p2 = [] { return 2; }; - EXPECT_EQ(hasher(p1), hasher(p1)); - EXPECT_TRUE(eq(p1, p1)); - - EXPECT_NE(hasher(p1), hasher(p2)); - EXPECT_FALSE(eq(p1, p2)); -} - -TYPED_TEST(HashPointer, Works) { - int dummy; - auto hash = this->hasher; - auto sptr = std::make_shared(); - std::shared_ptr csptr = sptr; - int* ptr = sptr.get(); - const int* cptr = ptr; - std::unique_ptr uptr(ptr); - std::unique_ptr cuptr(ptr); - - EXPECT_EQ(hash(ptr), hash(cptr)); - EXPECT_EQ(hash(ptr), hash(sptr)); - EXPECT_EQ(hash(ptr), hash(uptr)); - EXPECT_EQ(hash(ptr), hash(csptr)); - EXPECT_EQ(hash(ptr), hash(cuptr)); - EXPECT_NE(hash(&dummy), hash(cptr)); - EXPECT_NE(hash(&dummy), hash(sptr)); - EXPECT_NE(hash(&dummy), hash(uptr)); - EXPECT_NE(hash(&dummy), hash(csptr)); - EXPECT_NE(hash(&dummy), hash(cuptr)); -} - -// Cartesian product of (string, std::string, absl::string_view) -// with (string, std::string, absl::string_view, const char*). -using StringTypesCartesianProduct = Types< - // clang-format off - - std::pair, - std::pair, - std::pair, - - std::pair, - std::pair, - std::pair>; -// clang-format on - -constexpr char kFirstString[] = "abc123"; -constexpr char kSecondString[] = "ijk456"; - -template -struct StringLikeTest : public ::testing::Test { - typename T::first_type a1{kFirstString}; - typename T::second_type b1{kFirstString}; - typename T::first_type a2{kSecondString}; - typename T::second_type b2{kSecondString}; - hash_default_eq eq; - hash_default_hash hash; -}; - -TYPED_TEST_CASE_P(StringLikeTest); - -TYPED_TEST_P(StringLikeTest, Eq) { - EXPECT_TRUE(this->eq(this->a1, this->b1)); - EXPECT_TRUE(this->eq(this->b1, this->a1)); -} - -TYPED_TEST_P(StringLikeTest, NotEq) { - EXPECT_FALSE(this->eq(this->a1, this->b2)); - EXPECT_FALSE(this->eq(this->b2, this->a1)); -} - -TYPED_TEST_P(StringLikeTest, HashEq) { - EXPECT_EQ(this->hash(this->a1), this->hash(this->b1)); - EXPECT_EQ(this->hash(this->a2), this->hash(this->b2)); - // It would be a poor hash function which collides on these strings. - EXPECT_NE(this->hash(this->a1), this->hash(this->b2)); -} - -TYPED_TEST_CASE(StringLikeTest, StringTypesCartesianProduct); - -} // namespace -} // namespace container_internal -} // namespace absl - -enum Hash : size_t { - kStd = 0x2, // std::hash -#ifdef _MSC_VER - kExtension = kStd, // In MSVC, std::hash == ::hash -#else // _MSC_VER - kExtension = 0x4, // ::hash (GCC extension) -#endif // _MSC_VER -}; - -// H is a bitmask of Hash enumerations. -// Hashable is hashable via all means specified in H. -template -struct Hashable { - static constexpr bool HashableBy(Hash h) { return h & H; } -}; - -namespace std { -template -struct hash> { - template , - class = typename std::enable_if::type> - size_t operator()(E) const { - return kStd; - } -}; -} // namespace std - -namespace absl { -namespace container_internal { -namespace { - -template -size_t Hash(const T& v) { - return hash_default_hash()(v); -} - -TEST(Delegate, HashDispatch) { - EXPECT_EQ(Hash(kStd), Hash(Hashable())); -} - -} // namespace -} // namespace container_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_generator_testing.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_generator_testing.cc deleted file mode 100644 index 0d6a9df..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_generator_testing.cc +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include "absl/container/internal/hash_generator_testing.h" - -#include - -namespace absl { -namespace container_internal { -namespace hash_internal { -namespace { - -class RandomDeviceSeedSeq { - public: - using result_type = typename std::random_device::result_type; - - template - void generate(Iterator start, Iterator end) { - while (start != end) { - *start = gen_(); - ++start; - } - } - - private: - std::random_device gen_; -}; - -} // namespace - -std::mt19937_64* GetThreadLocalRng() { - RandomDeviceSeedSeq seed_seq; - thread_local auto* rng = new std::mt19937_64(seed_seq); - return rng; -} - -std::string Generator::operator()() const { - // NOLINTNEXTLINE(runtime/int) - std::uniform_int_distribution chars(0x20, 0x7E); - std::string res; - res.resize(32); - std::generate(res.begin(), res.end(), - [&]() { return chars(*GetThreadLocalRng()); }); - return res; -} - -absl::string_view Generator::operator()() const { - static auto* arena = new std::deque(); - // NOLINTNEXTLINE(runtime/int) - std::uniform_int_distribution chars(0x20, 0x7E); - arena->emplace_back(); - auto& res = arena->back(); - res.resize(32); - std::generate(res.begin(), res.end(), - [&]() { return chars(*GetThreadLocalRng()); }); - return res; -} - -} // namespace hash_internal -} // namespace container_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_generator_testing.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_generator_testing.h deleted file mode 100644 index 50d7710..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_generator_testing.h +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. -// -// Generates random values for testing. Specialized only for the few types we -// care about. - -#ifndef ABSL_CONTAINER_INTERNAL_HASH_GENERATOR_TESTING_H_ -#define ABSL_CONTAINER_INTERNAL_HASH_GENERATOR_TESTING_H_ - -#include -#include -#include -#include -#include -#include -#include - -#include "absl/container/internal/hash_policy_testing.h" -#include "absl/meta/type_traits.h" -#include "absl/strings/string_view.h" - -namespace absl { -namespace container_internal { -namespace hash_internal { -namespace generator_internal { - -template -struct IsMap : std::false_type {}; - -template -struct IsMap> : std::true_type {}; - -} // namespace generator_internal - -std::mt19937_64* GetThreadLocalRng(); - -enum Enum { - kEnumEmpty, - kEnumDeleted, -}; - -enum class EnumClass : uint64_t { - kEmpty, - kDeleted, -}; - -inline std::ostream& operator<<(std::ostream& o, const EnumClass& ec) { - return o << static_cast(ec); -} - -template -struct Generator; - -template -struct Generator::value>::type> { - T operator()() const { - std::uniform_int_distribution dist; - return dist(*GetThreadLocalRng()); - } -}; - -template <> -struct Generator { - Enum operator()() const { - std::uniform_int_distribution::type> - dist; - while (true) { - auto variate = dist(*GetThreadLocalRng()); - if (variate != kEnumEmpty && variate != kEnumDeleted) - return static_cast(variate); - } - } -}; - -template <> -struct Generator { - EnumClass operator()() const { - std::uniform_int_distribution< - typename std::underlying_type::type> - dist; - while (true) { - EnumClass variate = static_cast(dist(*GetThreadLocalRng())); - if (variate != EnumClass::kEmpty && variate != EnumClass::kDeleted) - return static_cast(variate); - } - } -}; - -template <> -struct Generator { - std::string operator()() const; -}; - -template <> -struct Generator { - absl::string_view operator()() const; -}; - -template <> -struct Generator { - NonStandardLayout operator()() const { - return NonStandardLayout(Generator()()); - } -}; - -template -struct Generator> { - std::pair operator()() const { - return std::pair(Generator::type>()(), - Generator::type>()()); - } -}; - -template -struct Generator> { - std::tuple operator()() const { - return std::tuple(Generator::type>()()...); - } -}; - -template -struct Generator().key()), - decltype(std::declval().value())>> - : Generator().key())>::type, - typename std::decay().value())>::type>> {}; - -template -using GeneratedType = decltype( - std::declval::value, - typename Container::value_type, - typename Container::key_type>::type>&>()()); - -} // namespace hash_internal -} // namespace container_internal -} // namespace absl - -#endif // ABSL_CONTAINER_INTERNAL_HASH_GENERATOR_TESTING_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_policy_testing.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_policy_testing.h deleted file mode 100644 index 38bbec7..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_policy_testing.h +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. -// -// Utilities to help tests verify that hash tables properly handle stateful -// allocators and hash functions. - -#ifndef ABSL_CONTAINER_INTERNAL_HASH_POLICY_TESTING_H_ -#define ABSL_CONTAINER_INTERNAL_HASH_POLICY_TESTING_H_ - -#include -#include -#include -#include -#include -#include -#include - -#include "absl/hash/hash.h" -#include "absl/strings/string_view.h" - -namespace absl { -namespace container_internal { -namespace hash_testing_internal { - -template -struct WithId { - WithId() : id_(next_id()) {} - WithId(const WithId& that) : id_(that.id_) {} - WithId(WithId&& that) : id_(that.id_) { that.id_ = 0; } - WithId& operator=(const WithId& that) { - id_ = that.id_; - return *this; - } - WithId& operator=(WithId&& that) { - id_ = that.id_; - that.id_ = 0; - return *this; - } - - size_t id() const { return id_; } - - friend bool operator==(const WithId& a, const WithId& b) { - return a.id_ == b.id_; - } - friend bool operator!=(const WithId& a, const WithId& b) { return !(a == b); } - - protected: - explicit WithId(size_t id) : id_(id) {} - - private: - size_t id_; - - template - static size_t next_id() { - // 0 is reserved for moved from state. - static size_t gId = 1; - return gId++; - } -}; - -} // namespace hash_testing_internal - -struct NonStandardLayout { - NonStandardLayout() {} - explicit NonStandardLayout(std::string s) : value(std::move(s)) {} - virtual ~NonStandardLayout() {} - - friend bool operator==(const NonStandardLayout& a, - const NonStandardLayout& b) { - return a.value == b.value; - } - friend bool operator!=(const NonStandardLayout& a, - const NonStandardLayout& b) { - return a.value != b.value; - } - - template - friend H AbslHashValue(H h, const NonStandardLayout& v) { - return H::combine(std::move(h), v.value); - } - - std::string value; -}; - -struct StatefulTestingHash - : absl::container_internal::hash_testing_internal::WithId< - StatefulTestingHash> { - template - size_t operator()(const T& t) const { - return absl::Hash{}(t); - } -}; - -struct StatefulTestingEqual - : absl::container_internal::hash_testing_internal::WithId< - StatefulTestingEqual> { - template - bool operator()(const T& t, const U& u) const { - return t == u; - } -}; - -// It is expected that Alloc() == Alloc() for all allocators so we cannot use -// WithId base. We need to explicitly assign ids. -template -struct Alloc : std::allocator { - using propagate_on_container_swap = std::true_type; - - // Using old paradigm for this to ensure compatibility. - explicit Alloc(size_t id = 0) : id_(id) {} - - Alloc(const Alloc&) = default; - Alloc& operator=(const Alloc&) = default; - - template - Alloc(const Alloc& that) : std::allocator(that), id_(that.id()) {} - - template - struct rebind { - using other = Alloc; - }; - - size_t id() const { return id_; } - - friend bool operator==(const Alloc& a, const Alloc& b) { - return a.id_ == b.id_; - } - friend bool operator!=(const Alloc& a, const Alloc& b) { return !(a == b); } - - private: - size_t id_ = (std::numeric_limits::max)(); -}; - -template -auto items(const Map& m) -> std::vector< - std::pair> { - using std::get; - std::vector> res; - res.reserve(m.size()); - for (const auto& v : m) res.emplace_back(get<0>(v), get<1>(v)); - return res; -} - -template -auto keys(const Set& s) - -> std::vector::type> { - std::vector::type> res; - res.reserve(s.size()); - for (const auto& v : s) res.emplace_back(v); - return res; -} - -} // namespace container_internal -} // namespace absl - -// ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS is false for glibcxx versions -// where the unordered containers are missing certain constructors that -// take allocator arguments. This test is defined ad-hoc for the platforms -// we care about (notably Crosstool 17) because libstdcxx's useless -// versioning scheme precludes a more principled solution. -#if defined(__GLIBCXX__) && __GLIBCXX__ <= 20140425 -#define ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS 0 -#else -#define ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS 1 -#endif - -#endif // ABSL_CONTAINER_INTERNAL_HASH_POLICY_TESTING_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_policy_testing_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_policy_testing_test.cc deleted file mode 100644 index c215c42..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_policy_testing_test.cc +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include "absl/container/internal/hash_policy_testing.h" - -#include "gtest/gtest.h" - -namespace absl { -namespace container_internal { -namespace { - -TEST(_, Hash) { - StatefulTestingHash h1; - EXPECT_EQ(1, h1.id()); - StatefulTestingHash h2; - EXPECT_EQ(2, h2.id()); - StatefulTestingHash h1c(h1); - EXPECT_EQ(1, h1c.id()); - StatefulTestingHash h2m(std::move(h2)); - EXPECT_EQ(2, h2m.id()); - EXPECT_EQ(0, h2.id()); - StatefulTestingHash h3; - EXPECT_EQ(3, h3.id()); - h3 = StatefulTestingHash(); - EXPECT_EQ(4, h3.id()); - h3 = std::move(h1); - EXPECT_EQ(1, h3.id()); -} - -} // namespace -} // namespace container_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_policy_traits.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_policy_traits.h deleted file mode 100644 index ace50a6..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_policy_traits.h +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#ifndef ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_ -#define ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_ - -#include -#include -#include -#include - -#include "absl/meta/type_traits.h" - -namespace absl { -namespace container_internal { - -// Defines how slots are initialized/destroyed/moved. -template -struct hash_policy_traits { - private: - struct ReturnKey { - // We return `Key` here. - // When Key=T&, we forward the lvalue reference. - // When Key=T, we return by value to avoid a dangling reference. - // eg, for string_hash_map. - template - Key operator()(Key&& k, const Args&...) const { - return std::forward(k); - } - }; - - template - struct ConstantIteratorsImpl : std::false_type {}; - - template - struct ConstantIteratorsImpl> - : P::constant_iterators {}; - - public: - // The actual object stored in the hash table. - using slot_type = typename Policy::slot_type; - - // The type of the keys stored in the hashtable. - using key_type = typename Policy::key_type; - - // The argument type for insertions into the hashtable. This is different - // from value_type for increased performance. See initializer_list constructor - // and insert() member functions for more details. - using init_type = typename Policy::init_type; - - using reference = decltype(Policy::element(std::declval())); - using pointer = typename std::remove_reference::type*; - using value_type = typename std::remove_reference::type; - - // Policies can set this variable to tell raw_hash_set that all iterators - // should be constant, even `iterator`. This is useful for set-like - // containers. - // Defaults to false if not provided by the policy. - using constant_iterators = ConstantIteratorsImpl<>; - - // PRECONDITION: `slot` is UNINITIALIZED - // POSTCONDITION: `slot` is INITIALIZED - template - static void construct(Alloc* alloc, slot_type* slot, Args&&... args) { - Policy::construct(alloc, slot, std::forward(args)...); - } - - // PRECONDITION: `slot` is INITIALIZED - // POSTCONDITION: `slot` is UNINITIALIZED - template - static void destroy(Alloc* alloc, slot_type* slot) { - Policy::destroy(alloc, slot); - } - - // Transfers the `old_slot` to `new_slot`. Any memory allocated by the - // allocator inside `old_slot` to `new_slot` can be transferred. - // - // OPTIONAL: defaults to: - // - // clone(new_slot, std::move(*old_slot)); - // destroy(old_slot); - // - // PRECONDITION: `new_slot` is UNINITIALIZED and `old_slot` is INITIALIZED - // POSTCONDITION: `new_slot` is INITIALIZED and `old_slot` is - // UNINITIALIZED - template - static void transfer(Alloc* alloc, slot_type* new_slot, slot_type* old_slot) { - transfer_impl(alloc, new_slot, old_slot, 0); - } - - // PRECONDITION: `slot` is INITIALIZED - // POSTCONDITION: `slot` is INITIALIZED - template - static auto element(slot_type* slot) -> decltype(P::element(slot)) { - return P::element(slot); - } - - // Returns the amount of memory owned by `slot`, exclusive of `sizeof(*slot)`. - // - // If `slot` is nullptr, returns the constant amount of memory owned by any - // full slot or -1 if slots own variable amounts of memory. - // - // PRECONDITION: `slot` is INITIALIZED or nullptr - template - static size_t space_used(const slot_type* slot) { - return P::space_used(slot); - } - - // Provides generalized access to the key for elements, both for elements in - // the table and for elements that have not yet been inserted (or even - // constructed). We would like an API that allows us to say: `key(args...)` - // but we cannot do that for all cases, so we use this more general API that - // can be used for many things, including the following: - // - // - Given an element in a table, get its key. - // - Given an element initializer, get its key. - // - Given `emplace()` arguments, get the element key. - // - // Implementations of this must adhere to a very strict technical - // specification around aliasing and consuming arguments: - // - // Let `value_type` be the result type of `element()` without ref- and - // cv-qualifiers. The first argument is a functor, the rest are constructor - // arguments for `value_type`. Returns `std::forward(f)(k, xs...)`, where - // `k` is the element key, and `xs...` are the new constructor arguments for - // `value_type`. It's allowed for `k` to alias `xs...`, and for both to alias - // `ts...`. The key won't be touched once `xs...` are used to construct an - // element; `ts...` won't be touched at all, which allows `apply()` to consume - // any rvalues among them. - // - // If `value_type` is constructible from `Ts&&...`, `Policy::apply()` must not - // trigger a hard compile error unless it originates from `f`. In other words, - // `Policy::apply()` must be SFINAE-friendly. If `value_type` is not - // constructible from `Ts&&...`, either SFINAE or a hard compile error is OK. - // - // If `Ts...` is `[cv] value_type[&]` or `[cv] init_type[&]`, - // `Policy::apply()` must work. A compile error is not allowed, SFINAE or not. - template - static auto apply(F&& f, Ts&&... ts) - -> decltype(P::apply(std::forward(f), std::forward(ts)...)) { - return P::apply(std::forward(f), std::forward(ts)...); - } - - // Returns the "key" portion of the slot. - // Used for node handle manipulation. - template - static auto key(slot_type* slot) - -> decltype(P::apply(ReturnKey(), element(slot))) { - return P::apply(ReturnKey(), element(slot)); - } - - // Returns the "value" (as opposed to the "key") portion of the element. Used - // by maps to implement `operator[]`, `at()` and `insert_or_assign()`. - template - static auto value(T* elem) -> decltype(P::value(elem)) { - return P::value(elem); - } - - private: - // Use auto -> decltype as an enabler. - template - static auto transfer_impl(Alloc* alloc, slot_type* new_slot, - slot_type* old_slot, int) - -> decltype((void)P::transfer(alloc, new_slot, old_slot)) { - P::transfer(alloc, new_slot, old_slot); - } - template - static void transfer_impl(Alloc* alloc, slot_type* new_slot, - slot_type* old_slot, char) { - construct(alloc, new_slot, std::move(element(old_slot))); - destroy(alloc, old_slot); - } -}; - -} // namespace container_internal -} // namespace absl - -#endif // ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_policy_traits_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_policy_traits_test.cc deleted file mode 100644 index 423f154..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hash_policy_traits_test.cc +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include "absl/container/internal/hash_policy_traits.h" - -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace absl { -namespace container_internal { -namespace { - -using ::testing::MockFunction; -using ::testing::Return; -using ::testing::ReturnRef; - -using Alloc = std::allocator; -using Slot = int; - -struct PolicyWithoutOptionalOps { - using slot_type = Slot; - using key_type = Slot; - using init_type = Slot; - - static std::function construct; - static std::function destroy; - - static std::function element; - static int apply(int v) { return apply_impl(v); } - static std::function apply_impl; - static std::function value; -}; - -std::function PolicyWithoutOptionalOps::construct; -std::function PolicyWithoutOptionalOps::destroy; - -std::function PolicyWithoutOptionalOps::element; -std::function PolicyWithoutOptionalOps::apply_impl; -std::function PolicyWithoutOptionalOps::value; - -struct PolicyWithOptionalOps : PolicyWithoutOptionalOps { - static std::function transfer; -}; - -std::function PolicyWithOptionalOps::transfer; - -struct Test : ::testing::Test { - Test() { - PolicyWithoutOptionalOps::construct = [&](void* a1, Slot* a2, Slot a3) { - construct.Call(a1, a2, std::move(a3)); - }; - PolicyWithoutOptionalOps::destroy = [&](void* a1, Slot* a2) { - destroy.Call(a1, a2); - }; - - PolicyWithoutOptionalOps::element = [&](Slot* a1) -> Slot& { - return element.Call(a1); - }; - PolicyWithoutOptionalOps::apply_impl = [&](int a1) -> int { - return apply.Call(a1); - }; - PolicyWithoutOptionalOps::value = [&](Slot* a1) -> Slot& { - return value.Call(a1); - }; - - PolicyWithOptionalOps::transfer = [&](void* a1, Slot* a2, Slot* a3) { - return transfer.Call(a1, a2, a3); - }; - } - - std::allocator alloc; - int a = 53; - - MockFunction construct; - MockFunction destroy; - - MockFunction element; - MockFunction apply; - MockFunction value; - - MockFunction transfer; -}; - -TEST_F(Test, construct) { - EXPECT_CALL(construct, Call(&alloc, &a, 53)); - hash_policy_traits::construct(&alloc, &a, 53); -} - -TEST_F(Test, destroy) { - EXPECT_CALL(destroy, Call(&alloc, &a)); - hash_policy_traits::destroy(&alloc, &a); -} - -TEST_F(Test, element) { - int b = 0; - EXPECT_CALL(element, Call(&a)).WillOnce(ReturnRef(b)); - EXPECT_EQ(&b, &hash_policy_traits::element(&a)); -} - -TEST_F(Test, apply) { - EXPECT_CALL(apply, Call(42)).WillOnce(Return(1337)); - EXPECT_EQ(1337, (hash_policy_traits::apply(42))); -} - -TEST_F(Test, value) { - int b = 0; - EXPECT_CALL(value, Call(&a)).WillOnce(ReturnRef(b)); - EXPECT_EQ(&b, &hash_policy_traits::value(&a)); -} - -TEST_F(Test, without_transfer) { - int b = 42; - EXPECT_CALL(element, Call(&b)).WillOnce(::testing::ReturnRef(b)); - EXPECT_CALL(construct, Call(&alloc, &a, b)); - EXPECT_CALL(destroy, Call(&alloc, &b)); - hash_policy_traits::transfer(&alloc, &a, &b); -} - -TEST_F(Test, with_transfer) { - int b = 42; - EXPECT_CALL(transfer, Call(&alloc, &a, &b)); - hash_policy_traits::transfer(&alloc, &a, &b); -} - -} // namespace -} // namespace container_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hashtable_debug.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hashtable_debug.h deleted file mode 100644 index c3bd65c..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hashtable_debug.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. -// -// This library provides APIs to debug the probing behavior of hash tables. -// -// In general, the probing behavior is a black box for users and only the -// side effects can be measured in the form of performance differences. -// These APIs give a glimpse on the actual behavior of the probing algorithms in -// these hashtables given a specified hash function and a set of elements. -// -// The probe count distribution can be used to assess the quality of the hash -// function for that particular hash table. Note that a hash function that -// performs well in one hash table implementation does not necessarily performs -// well in a different one. -// -// This library supports std::unordered_{set,map}, dense_hash_{set,map} and -// absl::{flat,node,string}_hash_{set,map}. - -#ifndef ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_H_ -#define ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_H_ - -#include -#include -#include -#include - -#include "absl/container/internal/hashtable_debug_hooks.h" - -namespace absl { -namespace container_internal { - -// Returns the number of probes required to lookup `key`. Returns 0 for a -// search with no collisions. Higher values mean more hash collisions occurred; -// however, the exact meaning of this number varies according to the container -// type. -template -size_t GetHashtableDebugNumProbes( - const C& c, const typename C::key_type& key) { - return absl::container_internal::hashtable_debug_internal:: - HashtableDebugAccess::GetNumProbes(c, key); -} - -// Gets a histogram of the number of probes for each elements in the container. -// The sum of all the values in the vector is equal to container.size(). -template -std::vector GetHashtableDebugNumProbesHistogram(const C& container) { - std::vector v; - for (auto it = container.begin(); it != container.end(); ++it) { - size_t num_probes = GetHashtableDebugNumProbes( - container, - absl::container_internal::hashtable_debug_internal::GetKey(*it, 0)); - v.resize(std::max(v.size(), num_probes + 1)); - v[num_probes]++; - } - return v; -} - -struct HashtableDebugProbeSummary { - size_t total_elements; - size_t total_num_probes; - double mean; -}; - -// Gets a summary of the probe count distribution for the elements in the -// container. -template -HashtableDebugProbeSummary GetHashtableDebugProbeSummary(const C& container) { - auto probes = GetHashtableDebugNumProbesHistogram(container); - HashtableDebugProbeSummary summary = {}; - for (size_t i = 0; i < probes.size(); ++i) { - summary.total_elements += probes[i]; - summary.total_num_probes += probes[i] * i; - } - summary.mean = 1.0 * summary.total_num_probes / summary.total_elements; - return summary; -} - -// Returns the number of bytes requested from the allocator by the container -// and not freed. -template -size_t AllocatedByteSize(const C& c) { - return absl::container_internal::hashtable_debug_internal:: - HashtableDebugAccess::AllocatedByteSize(c); -} - -// Returns a tight lower bound for AllocatedByteSize(c) where `c` is of type `C` -// and `c.size()` is equal to `num_elements`. -template -size_t LowerBoundAllocatedByteSize(size_t num_elements) { - return absl::container_internal::hashtable_debug_internal:: - HashtableDebugAccess::LowerBoundAllocatedByteSize(num_elements); -} - -} // namespace container_internal -} // namespace absl - -#endif // ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hashtable_debug_hooks.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hashtable_debug_hooks.h deleted file mode 100644 index 8f21972..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/hashtable_debug_hooks.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. -// -// Provides the internal API for hashtable_debug.h. - -#ifndef ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_HOOKS_H_ -#define ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_HOOKS_H_ - -#include - -#include -#include -#include - -namespace absl { -namespace container_internal { -namespace hashtable_debug_internal { - -// If it is a map, call get<0>(). -using std::get; -template -auto GetKey(const typename T::value_type& pair, int) -> decltype(get<0>(pair)) { - return get<0>(pair); -} - -// If it is not a map, return the value directly. -template -const typename T::key_type& GetKey(const typename T::key_type& key, char) { - return key; -} - -// Containers should specialize this to provide debug information for that -// container. -template -struct HashtableDebugAccess { - // Returns the number of probes required to find `key` in `c`. The "number of - // probes" is a concept that can vary by container. Implementations should - // return 0 when `key` was found in the minimum number of operations and - // should increment the result for each non-trivial operation required to find - // `key`. - // - // The default implementation uses the bucket api from the standard and thus - // works for `std::unordered_*` containers. - static size_t GetNumProbes(const Container& c, - const typename Container::key_type& key) { - if (!c.bucket_count()) return {}; - size_t num_probes = 0; - size_t bucket = c.bucket(key); - for (auto it = c.begin(bucket), e = c.end(bucket);; ++it, ++num_probes) { - if (it == e) return num_probes; - if (c.key_eq()(key, GetKey(*it, 0))) return num_probes; - } - } - - // Returns the number of bytes requested from the allocator by the container - // and not freed. - // - // static size_t AllocatedByteSize(const Container& c); - - // Returns a tight lower bound for AllocatedByteSize(c) where `c` is of type - // `Container` and `c.size()` is equal to `num_elements`. - // - // static size_t LowerBoundAllocatedByteSize(size_t num_elements); -}; - -} // namespace hashtable_debug_internal -} // namespace container_internal -} // namespace absl - -#endif // ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_HOOKS_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/layout.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/layout.h deleted file mode 100644 index 676c7d6..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/layout.h +++ /dev/null @@ -1,732 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. -// -// MOTIVATION AND TUTORIAL -// -// If you want to put in a single heap allocation N doubles followed by M ints, -// it's easy if N and M are known at compile time. -// -// struct S { -// double a[N]; -// int b[M]; -// }; -// -// S* p = new S; -// -// But what if N and M are known only in run time? Class template Layout to the -// rescue! It's a portable generalization of the technique known as struct hack. -// -// // This object will tell us everything we need to know about the memory -// // layout of double[N] followed by int[M]. It's structurally identical to -// // size_t[2] that stores N and M. It's very cheap to create. -// const Layout layout(N, M); -// -// // Allocate enough memory for both arrays. `AllocSize()` tells us how much -// // memory is needed. We are free to use any allocation function we want as -// // long as it returns aligned memory. -// std::unique_ptr p(new unsigned char[layout.AllocSize()]); -// -// // Obtain the pointer to the array of doubles. -// // Equivalent to `reinterpret_cast(p.get())`. -// // -// // We could have written layout.Pointer<0>(p) instead. If all the types are -// // unique you can use either form, but if some types are repeated you must -// // use the index form. -// double* a = layout.Pointer(p.get()); -// -// // Obtain the pointer to the array of ints. -// // Equivalent to `reinterpret_cast(p.get() + N * 8)`. -// int* b = layout.Pointer(p); -// -// If we are unable to specify sizes of all fields, we can pass as many sizes as -// we can to `Partial()`. In return, it'll allow us to access the fields whose -// locations and sizes can be computed from the provided information. -// `Partial()` comes in handy when the array sizes are embedded into the -// allocation. -// -// // size_t[1] containing N, size_t[1] containing M, double[N], int[M]. -// using L = Layout; -// -// unsigned char* Allocate(size_t n, size_t m) { -// const L layout(1, 1, n, m); -// unsigned char* p = new unsigned char[layout.AllocSize()]; -// *layout.Pointer<0>(p) = n; -// *layout.Pointer<1>(p) = m; -// return p; -// } -// -// void Use(unsigned char* p) { -// // First, extract N and M. -// // Specify that the first array has only one element. Using `prefix` we -// // can access the first two arrays but not more. -// constexpr auto prefix = L::Partial(1); -// size_t n = *prefix.Pointer<0>(p); -// size_t m = *prefix.Pointer<1>(p); -// -// // Now we can get pointers to the payload. -// const L layout(1, 1, n, m); -// double* a = layout.Pointer(p); -// int* b = layout.Pointer(p); -// } -// -// The layout we used above combines fixed-size with dynamically-sized fields. -// This is quite common. Layout is optimized for this use case and generates -// optimal code. All computations that can be performed at compile time are -// indeed performed at compile time. -// -// Efficiency tip: The order of fields matters. In `Layout` try to -// ensure that `alignof(T1) >= ... >= alignof(TN)`. This way you'll have no -// padding in between arrays. -// -// You can manually override the alignment of an array by wrapping the type in -// `Aligned`. `Layout<..., Aligned, ...>` has exactly the same API -// and behavior as `Layout<..., T, ...>` except that the first element of the -// array of `T` is aligned to `N` (the rest of the elements follow without -// padding). `N` cannot be less than `alignof(T)`. -// -// `AllocSize()` and `Pointer()` are the most basic methods for dealing with -// memory layouts. Check out the reference or code below to discover more. -// -// EXAMPLE -// -// // Immutable move-only string with sizeof equal to sizeof(void*). The -// // string size and the characters are kept in the same heap allocation. -// class CompactString { -// public: -// CompactString(const char* s = "") { -// const size_t size = strlen(s); -// // size_t[1] followed by char[size + 1]. -// const L layout(1, size + 1); -// p_.reset(new unsigned char[layout.AllocSize()]); -// // If running under ASAN, mark the padding bytes, if any, to catch -// // memory errors. -// layout.PoisonPadding(p_.get()); -// // Store the size in the allocation. -// *layout.Pointer(p_.get()) = size; -// // Store the characters in the allocation. -// memcpy(layout.Pointer(p_.get()), s, size + 1); -// } -// -// size_t size() const { -// // Equivalent to reinterpret_cast(*p). -// return *L::Partial().Pointer(p_.get()); -// } -// -// const char* c_str() const { -// // Equivalent to reinterpret_cast(p.get() + sizeof(size_t)). -// // The argument in Partial(1) specifies that we have size_t[1] in front -// // of the characters. -// return L::Partial(1).Pointer(p_.get()); -// } -// -// private: -// // Our heap allocation contains a size_t followed by an array of chars. -// using L = Layout; -// std::unique_ptr p_; -// }; -// -// int main() { -// CompactString s = "hello"; -// assert(s.size() == 5); -// assert(strcmp(s.c_str(), "hello") == 0); -// } -// -// DOCUMENTATION -// -// The interface exported by this file consists of: -// - class `Layout<>` and its public members. -// - The public members of class `internal_layout::LayoutImpl<>`. That class -// isn't intended to be used directly, and its name and template parameter -// list are internal implementation details, but the class itself provides -// most of the functionality in this file. See comments on its members for -// detailed documentation. -// -// `Layout::Partial(count1,..., countm)` (where `m` <= `n`) returns a -// `LayoutImpl<>` object. `Layout layout(count1,..., countn)` -// creates a `Layout` object, which exposes the same functionality by inheriting -// from `LayoutImpl<>`. - -#ifndef ABSL_CONTAINER_INTERNAL_LAYOUT_H_ -#define ABSL_CONTAINER_INTERNAL_LAYOUT_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef ADDRESS_SANITIZER -#include -#endif - -#include "absl/meta/type_traits.h" -#include "absl/strings/str_cat.h" -#include "absl/types/span.h" -#include "absl/utility/utility.h" - -#if defined(__GXX_RTTI) -#define ABSL_INTERNAL_HAS_CXA_DEMANGLE -#endif - -#ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE -#include -#endif - -namespace absl { -namespace container_internal { - -// A type wrapper that instructs `Layout` to use the specific alignment for the -// array. `Layout<..., Aligned, ...>` has exactly the same API -// and behavior as `Layout<..., T, ...>` except that the first element of the -// array of `T` is aligned to `N` (the rest of the elements follow without -// padding). -// -// Requires: `N >= alignof(T)` and `N` is a power of 2. -template -struct Aligned; - -namespace internal_layout { - -template -struct NotAligned {}; - -template -struct NotAligned> { - static_assert(sizeof(T) == 0, "Aligned cannot be const-qualified"); -}; - -template -using IntToSize = size_t; - -template -using TypeToSize = size_t; - -template -struct Type : NotAligned { - using type = T; -}; - -template -struct Type> { - using type = T; -}; - -template -struct SizeOf : NotAligned, std::integral_constant {}; - -template -struct SizeOf> : std::integral_constant {}; - -template -struct AlignOf : NotAligned, std::integral_constant {}; - -template -struct AlignOf> : std::integral_constant { - static_assert(N % alignof(T) == 0, - "Custom alignment can't be lower than the type's alignment"); -}; - -// Does `Ts...` contain `T`? -template -using Contains = absl::disjunction...>; - -template -using CopyConst = - typename std::conditional::value, const To, To>::type; - -template -using SliceType = absl::Span; - -// This namespace contains no types. It prevents functions defined in it from -// being found by ADL. -namespace adl_barrier { - -template -constexpr size_t Find(Needle, Needle, Ts...) { - static_assert(!Contains(), "Duplicate element type"); - return 0; -} - -template -constexpr size_t Find(Needle, T, Ts...) { - return adl_barrier::Find(Needle(), Ts()...) + 1; -} - -constexpr bool IsPow2(size_t n) { return !(n & (n - 1)); } - -// Returns `q * m` for the smallest `q` such that `q * m >= n`. -// Requires: `m` is a power of two. It's enforced by IsLegalElementType below. -constexpr size_t Align(size_t n, size_t m) { return (n + m - 1) & ~(m - 1); } - -constexpr size_t Min(size_t a, size_t b) { return b < a ? b : a; } - -constexpr size_t Max(size_t a) { return a; } - -template -constexpr size_t Max(size_t a, size_t b, Ts... rest) { - return adl_barrier::Max(b < a ? a : b, rest...); -} - -template -std::string TypeName() { - std::string out; - int status = 0; - char* demangled = nullptr; -#ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE - demangled = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status); -#endif - if (status == 0 && demangled != nullptr) { // Demangling succeeeded. - absl::StrAppend(&out, "<", demangled, ">"); - free(demangled); - } else { -#if defined(__GXX_RTTI) || defined(_CPPRTTI) - absl::StrAppend(&out, "<", typeid(T).name(), ">"); -#endif - } - return out; -} - -} // namespace adl_barrier - -template -using EnableIf = typename std::enable_if::type; - -// Can `T` be a template argument of `Layout`? -template -using IsLegalElementType = std::integral_constant< - bool, !std::is_reference::value && !std::is_volatile::value && - !std::is_reference::type>::value && - !std::is_volatile::type>::value && - adl_barrier::IsPow2(AlignOf::value)>; - -template -class LayoutImpl; - -// Public base class of `Layout` and the result type of `Layout::Partial()`. -// -// `Elements...` contains all template arguments of `Layout` that created this -// instance. -// -// `SizeSeq...` is `[0, NumSizes)` where `NumSizes` is the number of arguments -// passed to `Layout::Partial()` or `Layout::Layout()`. -// -// `OffsetSeq...` is `[0, NumOffsets)` where `NumOffsets` is -// `Min(sizeof...(Elements), NumSizes + 1)` (the number of arrays for which we -// can compute offsets). -template -class LayoutImpl, absl::index_sequence, - absl::index_sequence> { - private: - static_assert(sizeof...(Elements) > 0, "At least one field is required"); - static_assert(absl::conjunction...>::value, - "Invalid element type (see IsLegalElementType)"); - - enum { - NumTypes = sizeof...(Elements), - NumSizes = sizeof...(SizeSeq), - NumOffsets = sizeof...(OffsetSeq), - }; - - // These are guaranteed by `Layout`. - static_assert(NumOffsets == adl_barrier::Min(NumTypes, NumSizes + 1), - "Internal error"); - static_assert(NumTypes > 0, "Internal error"); - - // Returns the index of `T` in `Elements...`. Results in a compilation error - // if `Elements...` doesn't contain exactly one instance of `T`. - template - static constexpr size_t ElementIndex() { - static_assert(Contains, Type::type>...>(), - "Type not found"); - return adl_barrier::Find(Type(), - Type::type>()...); - } - - template - using ElementAlignment = - AlignOf>::type>; - - public: - // Element types of all arrays packed in a tuple. - using ElementTypes = std::tuple::type...>; - - // Element type of the Nth array. - template - using ElementType = typename std::tuple_element::type; - - constexpr explicit LayoutImpl(IntToSize... sizes) - : size_{sizes...} {} - - // Alignment of the layout, equal to the strictest alignment of all elements. - // All pointers passed to the methods of layout must be aligned to this value. - static constexpr size_t Alignment() { - return adl_barrier::Max(AlignOf::value...); - } - - // Offset in bytes of the Nth array. - // - // // int[3], 4 bytes of padding, double[4]. - // Layout x(3, 4); - // assert(x.Offset<0>() == 0); // The ints starts from 0. - // assert(x.Offset<1>() == 16); // The doubles starts from 16. - // - // Requires: `N <= NumSizes && N < sizeof...(Ts)`. - template = 0> - constexpr size_t Offset() const { - return 0; - } - - template = 0> - constexpr size_t Offset() const { - static_assert(N < NumOffsets, "Index out of bounds"); - return adl_barrier::Align( - Offset() + SizeOf>() * size_[N - 1], - ElementAlignment()); - } - - // Offset in bytes of the array with the specified element type. There must - // be exactly one such array and its zero-based index must be at most - // `NumSizes`. - // - // // int[3], 4 bytes of padding, double[4]. - // Layout x(3, 4); - // assert(x.Offset() == 0); // The ints starts from 0. - // assert(x.Offset() == 16); // The doubles starts from 16. - template - constexpr size_t Offset() const { - return Offset()>(); - } - - // Offsets in bytes of all arrays for which the offsets are known. - constexpr std::array Offsets() const { - return {{Offset()...}}; - } - - // The number of elements in the Nth array. This is the Nth argument of - // `Layout::Partial()` or `Layout::Layout()` (zero-based). - // - // // int[3], 4 bytes of padding, double[4]. - // Layout x(3, 4); - // assert(x.Size<0>() == 3); - // assert(x.Size<1>() == 4); - // - // Requires: `N < NumSizes`. - template - constexpr size_t Size() const { - static_assert(N < NumSizes, "Index out of bounds"); - return size_[N]; - } - - // The number of elements in the array with the specified element type. - // There must be exactly one such array and its zero-based index must be - // at most `NumSizes`. - // - // // int[3], 4 bytes of padding, double[4]. - // Layout x(3, 4); - // assert(x.Size() == 3); - // assert(x.Size() == 4); - template - constexpr size_t Size() const { - return Size()>(); - } - - // The number of elements of all arrays for which they are known. - constexpr std::array Sizes() const { - return {{Size()...}}; - } - - // Pointer to the beginning of the Nth array. - // - // `Char` must be `[const] [signed|unsigned] char`. - // - // // int[3], 4 bytes of padding, double[4]. - // Layout x(3, 4); - // unsigned char* p = new unsigned char[x.AllocSize()]; - // int* ints = x.Pointer<0>(p); - // double* doubles = x.Pointer<1>(p); - // - // Requires: `N <= NumSizes && N < sizeof...(Ts)`. - // Requires: `p` is aligned to `Alignment()`. - template - CopyConst>* Pointer(Char* p) const { - using C = typename std::remove_const::type; - static_assert( - std::is_same() || std::is_same() || - std::is_same(), - "The argument must be a pointer to [const] [signed|unsigned] char"); - constexpr size_t alignment = Alignment(); - (void)alignment; - assert(reinterpret_cast(p) % alignment == 0); - return reinterpret_cast>*>(p + Offset()); - } - - // Pointer to the beginning of the array with the specified element type. - // There must be exactly one such array and its zero-based index must be at - // most `NumSizes`. - // - // `Char` must be `[const] [signed|unsigned] char`. - // - // // int[3], 4 bytes of padding, double[4]. - // Layout x(3, 4); - // unsigned char* p = new unsigned char[x.AllocSize()]; - // int* ints = x.Pointer(p); - // double* doubles = x.Pointer(p); - // - // Requires: `p` is aligned to `Alignment()`. - template - CopyConst* Pointer(Char* p) const { - return Pointer()>(p); - } - - // Pointers to all arrays for which pointers are known. - // - // `Char` must be `[const] [signed|unsigned] char`. - // - // // int[3], 4 bytes of padding, double[4]. - // Layout x(3, 4); - // unsigned char* p = new unsigned char[x.AllocSize()]; - // - // int* ints; - // double* doubles; - // std::tie(ints, doubles) = x.Pointers(p); - // - // Requires: `p` is aligned to `Alignment()`. - // - // Note: We're not using ElementType alias here because it does not compile - // under MSVC. - template - std::tuple::type>*...> - Pointers(Char* p) const { - return std::tuple>*...>( - Pointer(p)...); - } - - // The Nth array. - // - // `Char` must be `[const] [signed|unsigned] char`. - // - // // int[3], 4 bytes of padding, double[4]. - // Layout x(3, 4); - // unsigned char* p = new unsigned char[x.AllocSize()]; - // Span ints = x.Slice<0>(p); - // Span doubles = x.Slice<1>(p); - // - // Requires: `N < NumSizes`. - // Requires: `p` is aligned to `Alignment()`. - template - SliceType>> Slice(Char* p) const { - return SliceType>>(Pointer(p), Size()); - } - - // The array with the specified element type. There must be exactly one - // such array and its zero-based index must be less than `NumSizes`. - // - // `Char` must be `[const] [signed|unsigned] char`. - // - // // int[3], 4 bytes of padding, double[4]. - // Layout x(3, 4); - // unsigned char* p = new unsigned char[x.AllocSize()]; - // Span ints = x.Slice(p); - // Span doubles = x.Slice(p); - // - // Requires: `p` is aligned to `Alignment()`. - template - SliceType> Slice(Char* p) const { - return Slice()>(p); - } - - // All arrays with known sizes. - // - // `Char` must be `[const] [signed|unsigned] char`. - // - // // int[3], 4 bytes of padding, double[4]. - // Layout x(3, 4); - // unsigned char* p = new unsigned char[x.AllocSize()]; - // - // Span ints; - // Span doubles; - // std::tie(ints, doubles) = x.Slices(p); - // - // Requires: `p` is aligned to `Alignment()`. - // - // Note: We're not using ElementType alias here because it does not compile - // under MSVC. - template - std::tuple::type>>...> - Slices(Char* p) const { - // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63875 (fixed - // in 6.1). - (void)p; - return std::tuple>>...>( - Slice(p)...); - } - - // The size of the allocation that fits all arrays. - // - // // int[3], 4 bytes of padding, double[4]. - // Layout x(3, 4); - // unsigned char* p = new unsigned char[x.AllocSize()]; // 48 bytes - // - // Requires: `NumSizes == sizeof...(Ts)`. - constexpr size_t AllocSize() const { - static_assert(NumTypes == NumSizes, "You must specify sizes of all fields"); - return Offset() + - SizeOf>() * size_[NumTypes - 1]; - } - - // If built with --config=asan, poisons padding bytes (if any) in the - // allocation. The pointer must point to a memory block at least - // `AllocSize()` bytes in length. - // - // `Char` must be `[const] [signed|unsigned] char`. - // - // Requires: `p` is aligned to `Alignment()`. - template = 0> - void PoisonPadding(const Char* p) const { - Pointer<0>(p); // verify the requirements on `Char` and `p` - } - - template = 0> - void PoisonPadding(const Char* p) const { - static_assert(N < NumOffsets, "Index out of bounds"); - (void)p; -#ifdef ADDRESS_SANITIZER - PoisonPadding(p); - // The `if` is an optimization. It doesn't affect the observable behaviour. - if (ElementAlignment() % ElementAlignment()) { - size_t start = - Offset() + SizeOf>() * size_[N - 1]; - ASAN_POISON_MEMORY_REGION(p + start, Offset() - start); - } -#endif - } - - // Human-readable description of the memory layout. Useful for debugging. - // Slow. - // - // // char[5], 3 bytes of padding, int[3], 4 bytes of padding, followed - // // by an unknown number of doubles. - // auto x = Layout::Partial(5, 3); - // assert(x.DebugString() == - // "@0(1)[5]; @8(4)[3]; @24(8)"); - // - // Each field is in the following format: @offset(sizeof)[size] ( - // may be missing depending on the target platform). For example, - // @8(4)[3] means that at offset 8 we have an array of ints, where each - // int is 4 bytes, and we have 3 of those ints. The size of the last field may - // be missing (as in the example above). Only fields with known offsets are - // described. Type names may differ across platforms: one compiler might - // produce "unsigned*" where another produces "unsigned int *". - std::string DebugString() const { - const auto offsets = Offsets(); - const size_t sizes[] = {SizeOf>()...}; - const std::string types[] = {adl_barrier::TypeName>()...}; - std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")"); - for (size_t i = 0; i != NumOffsets - 1; ++i) { - absl::StrAppend(&res, "[", size_[i], "]; @", offsets[i + 1], types[i + 1], - "(", sizes[i + 1], ")"); - } - // NumSizes is a constant that may be zero. Some compilers cannot see that - // inside the if statement "size_[NumSizes - 1]" must be valid. - int last = static_cast(NumSizes) - 1; - if (NumTypes == NumSizes && last >= 0) { - absl::StrAppend(&res, "[", size_[last], "]"); - } - return res; - } - - private: - // Arguments of `Layout::Partial()` or `Layout::Layout()`. - size_t size_[NumSizes > 0 ? NumSizes : 1]; -}; - -template -using LayoutType = LayoutImpl< - std::tuple, absl::make_index_sequence, - absl::make_index_sequence>; - -} // namespace internal_layout - -// Descriptor of arrays of various types and sizes laid out in memory one after -// another. See the top of the file for documentation. -// -// Check out the public API of internal_layout::LayoutImpl above. The type is -// internal to the library but its methods are public, and they are inherited -// by `Layout`. -template -class Layout : public internal_layout::LayoutType { - public: - static_assert(sizeof...(Ts) > 0, "At least one field is required"); - static_assert( - absl::conjunction...>::value, - "Invalid element type (see IsLegalElementType)"); - - // The result type of `Partial()` with `NumSizes` arguments. - template - using PartialType = internal_layout::LayoutType; - - // `Layout` knows the element types of the arrays we want to lay out in - // memory but not the number of elements in each array. - // `Partial(size1, ..., sizeN)` allows us to specify the latter. The - // resulting immutable object can be used to obtain pointers to the - // individual arrays. - // - // It's allowed to pass fewer array sizes than the number of arrays. E.g., - // if all you need is to the offset of the second array, you only need to - // pass one argument -- the number of elements in the first arrays. - // - // // int[3] followed by 4 bytes of padding and an unknown number of - // // doubles. - // auto x = Layout::Partial(3); - // // doubles start at byte 16. - // assert(x.Offset<1>() == 16); - // - // If you know the number of elements in all arrays, you can still call - // `Partial()` but it's more convenient to use the constructor of `Layout`. - // - // Layout x(3, 5); - // - // Note: The sizes of the arrays must be specified in number of elements, - // not in bytes. - // - // Requires: `sizeof...(Sizes) <= sizeof...(Ts)`. - // Requires: all arguments are convertible to `size_t`. - template - static constexpr PartialType Partial(Sizes&&... sizes) { - static_assert(sizeof...(Sizes) <= sizeof...(Ts), ""); - return PartialType(absl::forward(sizes)...); - } - - // Creates a layout with the sizes of all arrays specified. If you know - // only the sizes of the first N arrays (where N can be zero), you can use - // `Partial()` defined above. The constructor is essentially equivalent to - // calling `Partial()` and passing in all array sizes; the constructor is - // provided as a convenient abbreviation. - // - // Note: The sizes of the arrays must be specified in number of elements, - // not in bytes. - constexpr explicit Layout(internal_layout::TypeToSize... sizes) - : internal_layout::LayoutType(sizes...) {} -}; - -} // namespace container_internal -} // namespace absl - -#endif // ABSL_CONTAINER_INTERNAL_LAYOUT_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/layout_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/layout_test.cc deleted file mode 100644 index f35157a..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/layout_test.cc +++ /dev/null @@ -1,1552 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include "absl/container/internal/layout.h" - -// We need ::max_align_t because some libstdc++ versions don't provide -// std::max_align_t -#include -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" -#include "absl/types/span.h" - -namespace absl { -namespace container_internal { -namespace { - -using ::absl::Span; -using ::testing::ElementsAre; - -size_t Distance(const void* from, const void* to) { - ABSL_RAW_CHECK(from <= to, "Distance must be non-negative"); - return static_cast(to) - static_cast(from); -} - -template -Expected Type(Actual val) { - static_assert(std::is_same(), ""); - return val; -} - -using Int128 = int64_t[2]; - -// Properties of types that this test relies on. -static_assert(sizeof(int8_t) == 1, ""); -static_assert(alignof(int8_t) == 1, ""); -static_assert(sizeof(int16_t) == 2, ""); -static_assert(alignof(int16_t) == 2, ""); -static_assert(sizeof(int32_t) == 4, ""); -static_assert(alignof(int32_t) == 4, ""); -static_assert(sizeof(Int128) == 16, ""); -static_assert(alignof(Int128) == 8, ""); - -template -void SameType() { - static_assert(std::is_same(), ""); -} - -TEST(Layout, ElementType) { - { - using L = Layout; - SameType>(); - SameType>(); - SameType>(); - } - { - using L = Layout; - SameType>(); - SameType>(); - SameType>(); - SameType>(); - SameType>(); - SameType>(); - } - { - using L = Layout; - SameType>(); - SameType>(); - SameType>(); - SameType>(); - SameType>(); - SameType>(); - SameType>(); - SameType>(); - SameType>(); - SameType>(); - SameType>(); - SameType>(); - } -} - -TEST(Layout, ElementTypes) { - { - using L = Layout; - SameType, L::ElementTypes>(); - SameType, decltype(L::Partial())::ElementTypes>(); - SameType, decltype(L::Partial(0))::ElementTypes>(); - } - { - using L = Layout; - SameType, L::ElementTypes>(); - SameType, decltype(L::Partial())::ElementTypes>(); - SameType, decltype(L::Partial(0))::ElementTypes>(); - } - { - using L = Layout; - SameType, L::ElementTypes>(); - SameType, - decltype(L::Partial())::ElementTypes>(); - SameType, - decltype(L::Partial(0))::ElementTypes>(); - SameType, - decltype(L::Partial(0, 0))::ElementTypes>(); - SameType, - decltype(L::Partial(0, 0, 0))::ElementTypes>(); - } -} - -TEST(Layout, OffsetByIndex) { - { - using L = Layout; - EXPECT_EQ(0, L::Partial().Offset<0>()); - EXPECT_EQ(0, L::Partial(3).Offset<0>()); - EXPECT_EQ(0, L(3).Offset<0>()); - } - { - using L = Layout; - EXPECT_EQ(0, L::Partial().Offset<0>()); - EXPECT_EQ(0, L::Partial(3).Offset<0>()); - EXPECT_EQ(12, L::Partial(3).Offset<1>()); - EXPECT_EQ(0, L::Partial(3, 5).Offset<0>()); - EXPECT_EQ(12, L::Partial(3, 5).Offset<1>()); - EXPECT_EQ(0, L(3, 5).Offset<0>()); - EXPECT_EQ(12, L(3, 5).Offset<1>()); - } - { - using L = Layout; - EXPECT_EQ(0, L::Partial().Offset<0>()); - EXPECT_EQ(0, L::Partial(0).Offset<0>()); - EXPECT_EQ(0, L::Partial(0).Offset<1>()); - EXPECT_EQ(0, L::Partial(1).Offset<0>()); - EXPECT_EQ(4, L::Partial(1).Offset<1>()); - EXPECT_EQ(0, L::Partial(5).Offset<0>()); - EXPECT_EQ(8, L::Partial(5).Offset<1>()); - EXPECT_EQ(0, L::Partial(0, 0).Offset<0>()); - EXPECT_EQ(0, L::Partial(0, 0).Offset<1>()); - EXPECT_EQ(0, L::Partial(0, 0).Offset<2>()); - EXPECT_EQ(0, L::Partial(1, 0).Offset<0>()); - EXPECT_EQ(4, L::Partial(1, 0).Offset<1>()); - EXPECT_EQ(8, L::Partial(1, 0).Offset<2>()); - EXPECT_EQ(0, L::Partial(5, 3).Offset<0>()); - EXPECT_EQ(8, L::Partial(5, 3).Offset<1>()); - EXPECT_EQ(24, L::Partial(5, 3).Offset<2>()); - EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<0>()); - EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<1>()); - EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<2>()); - EXPECT_EQ(0, L::Partial(1, 0, 0).Offset<0>()); - EXPECT_EQ(4, L::Partial(1, 0, 0).Offset<1>()); - EXPECT_EQ(8, L::Partial(1, 0, 0).Offset<2>()); - EXPECT_EQ(0, L::Partial(5, 3, 1).Offset<0>()); - EXPECT_EQ(24, L::Partial(5, 3, 1).Offset<2>()); - EXPECT_EQ(8, L::Partial(5, 3, 1).Offset<1>()); - EXPECT_EQ(0, L(5, 3, 1).Offset<0>()); - EXPECT_EQ(24, L(5, 3, 1).Offset<2>()); - EXPECT_EQ(8, L(5, 3, 1).Offset<1>()); - } -} - -TEST(Layout, OffsetByType) { - { - using L = Layout; - EXPECT_EQ(0, L::Partial().Offset()); - EXPECT_EQ(0, L::Partial(3).Offset()); - EXPECT_EQ(0, L(3).Offset()); - } - { - using L = Layout; - EXPECT_EQ(0, L::Partial().Offset()); - EXPECT_EQ(0, L::Partial(0).Offset()); - EXPECT_EQ(0, L::Partial(0).Offset()); - EXPECT_EQ(0, L::Partial(1).Offset()); - EXPECT_EQ(4, L::Partial(1).Offset()); - EXPECT_EQ(0, L::Partial(5).Offset()); - EXPECT_EQ(8, L::Partial(5).Offset()); - EXPECT_EQ(0, L::Partial(0, 0).Offset()); - EXPECT_EQ(0, L::Partial(0, 0).Offset()); - EXPECT_EQ(0, L::Partial(0, 0).Offset()); - EXPECT_EQ(0, L::Partial(1, 0).Offset()); - EXPECT_EQ(4, L::Partial(1, 0).Offset()); - EXPECT_EQ(8, L::Partial(1, 0).Offset()); - EXPECT_EQ(0, L::Partial(5, 3).Offset()); - EXPECT_EQ(8, L::Partial(5, 3).Offset()); - EXPECT_EQ(24, L::Partial(5, 3).Offset()); - EXPECT_EQ(0, L::Partial(0, 0, 0).Offset()); - EXPECT_EQ(0, L::Partial(0, 0, 0).Offset()); - EXPECT_EQ(0, L::Partial(0, 0, 0).Offset()); - EXPECT_EQ(0, L::Partial(1, 0, 0).Offset()); - EXPECT_EQ(4, L::Partial(1, 0, 0).Offset()); - EXPECT_EQ(8, L::Partial(1, 0, 0).Offset()); - EXPECT_EQ(0, L::Partial(5, 3, 1).Offset()); - EXPECT_EQ(24, L::Partial(5, 3, 1).Offset()); - EXPECT_EQ(8, L::Partial(5, 3, 1).Offset()); - EXPECT_EQ(0, L(5, 3, 1).Offset()); - EXPECT_EQ(24, L(5, 3, 1).Offset()); - EXPECT_EQ(8, L(5, 3, 1).Offset()); - } -} - -TEST(Layout, Offsets) { - { - using L = Layout; - EXPECT_THAT(L::Partial().Offsets(), ElementsAre(0)); - EXPECT_THAT(L::Partial(3).Offsets(), ElementsAre(0)); - EXPECT_THAT(L(3).Offsets(), ElementsAre(0)); - } - { - using L = Layout; - EXPECT_THAT(L::Partial().Offsets(), ElementsAre(0)); - EXPECT_THAT(L::Partial(3).Offsets(), ElementsAre(0, 12)); - EXPECT_THAT(L::Partial(3, 5).Offsets(), ElementsAre(0, 12)); - EXPECT_THAT(L(3, 5).Offsets(), ElementsAre(0, 12)); - } - { - using L = Layout; - EXPECT_THAT(L::Partial().Offsets(), ElementsAre(0)); - EXPECT_THAT(L::Partial(1).Offsets(), ElementsAre(0, 4)); - EXPECT_THAT(L::Partial(5).Offsets(), ElementsAre(0, 8)); - EXPECT_THAT(L::Partial(0, 0).Offsets(), ElementsAre(0, 0, 0)); - EXPECT_THAT(L::Partial(1, 0).Offsets(), ElementsAre(0, 4, 8)); - EXPECT_THAT(L::Partial(5, 3).Offsets(), ElementsAre(0, 8, 24)); - EXPECT_THAT(L::Partial(0, 0, 0).Offsets(), ElementsAre(0, 0, 0)); - EXPECT_THAT(L::Partial(1, 0, 0).Offsets(), ElementsAre(0, 4, 8)); - EXPECT_THAT(L::Partial(5, 3, 1).Offsets(), ElementsAre(0, 8, 24)); - EXPECT_THAT(L(5, 3, 1).Offsets(), ElementsAre(0, 8, 24)); - } -} - -TEST(Layout, AllocSize) { - { - using L = Layout; - EXPECT_EQ(0, L::Partial(0).AllocSize()); - EXPECT_EQ(12, L::Partial(3).AllocSize()); - EXPECT_EQ(12, L(3).AllocSize()); - } - { - using L = Layout; - EXPECT_EQ(32, L::Partial(3, 5).AllocSize()); - EXPECT_EQ(32, L(3, 5).AllocSize()); - } - { - using L = Layout; - EXPECT_EQ(0, L::Partial(0, 0, 0).AllocSize()); - EXPECT_EQ(8, L::Partial(1, 0, 0).AllocSize()); - EXPECT_EQ(8, L::Partial(0, 1, 0).AllocSize()); - EXPECT_EQ(16, L::Partial(0, 0, 1).AllocSize()); - EXPECT_EQ(24, L::Partial(1, 1, 1).AllocSize()); - EXPECT_EQ(136, L::Partial(3, 5, 7).AllocSize()); - EXPECT_EQ(136, L(3, 5, 7).AllocSize()); - } -} - -TEST(Layout, SizeByIndex) { - { - using L = Layout; - EXPECT_EQ(0, L::Partial(0).Size<0>()); - EXPECT_EQ(3, L::Partial(3).Size<0>()); - EXPECT_EQ(3, L(3).Size<0>()); - } - { - using L = Layout; - EXPECT_EQ(0, L::Partial(0).Size<0>()); - EXPECT_EQ(3, L::Partial(3).Size<0>()); - EXPECT_EQ(3, L::Partial(3, 5).Size<0>()); - EXPECT_EQ(5, L::Partial(3, 5).Size<1>()); - EXPECT_EQ(3, L(3, 5).Size<0>()); - EXPECT_EQ(5, L(3, 5).Size<1>()); - } - { - using L = Layout; - EXPECT_EQ(3, L::Partial(3).Size<0>()); - EXPECT_EQ(3, L::Partial(3, 5).Size<0>()); - EXPECT_EQ(5, L::Partial(3, 5).Size<1>()); - EXPECT_EQ(3, L::Partial(3, 5, 7).Size<0>()); - EXPECT_EQ(5, L::Partial(3, 5, 7).Size<1>()); - EXPECT_EQ(7, L::Partial(3, 5, 7).Size<2>()); - EXPECT_EQ(3, L(3, 5, 7).Size<0>()); - EXPECT_EQ(5, L(3, 5, 7).Size<1>()); - EXPECT_EQ(7, L(3, 5, 7).Size<2>()); - } -} - -TEST(Layout, SizeByType) { - { - using L = Layout; - EXPECT_EQ(0, L::Partial(0).Size()); - EXPECT_EQ(3, L::Partial(3).Size()); - EXPECT_EQ(3, L(3).Size()); - } - { - using L = Layout; - EXPECT_EQ(3, L::Partial(3).Size()); - EXPECT_EQ(3, L::Partial(3, 5).Size()); - EXPECT_EQ(5, L::Partial(3, 5).Size()); - EXPECT_EQ(3, L::Partial(3, 5, 7).Size()); - EXPECT_EQ(5, L::Partial(3, 5, 7).Size()); - EXPECT_EQ(7, L::Partial(3, 5, 7).Size()); - EXPECT_EQ(3, L(3, 5, 7).Size()); - EXPECT_EQ(5, L(3, 5, 7).Size()); - EXPECT_EQ(7, L(3, 5, 7).Size()); - } -} - -TEST(Layout, Sizes) { - { - using L = Layout; - EXPECT_THAT(L::Partial().Sizes(), ElementsAre()); - EXPECT_THAT(L::Partial(3).Sizes(), ElementsAre(3)); - EXPECT_THAT(L(3).Sizes(), ElementsAre(3)); - } - { - using L = Layout; - EXPECT_THAT(L::Partial().Sizes(), ElementsAre()); - EXPECT_THAT(L::Partial(3).Sizes(), ElementsAre(3)); - EXPECT_THAT(L::Partial(3, 5).Sizes(), ElementsAre(3, 5)); - EXPECT_THAT(L(3, 5).Sizes(), ElementsAre(3, 5)); - } - { - using L = Layout; - EXPECT_THAT(L::Partial().Sizes(), ElementsAre()); - EXPECT_THAT(L::Partial(3).Sizes(), ElementsAre(3)); - EXPECT_THAT(L::Partial(3, 5).Sizes(), ElementsAre(3, 5)); - EXPECT_THAT(L::Partial(3, 5, 7).Sizes(), ElementsAre(3, 5, 7)); - EXPECT_THAT(L(3, 5, 7).Sizes(), ElementsAre(3, 5, 7)); - } -} - -TEST(Layout, PointerByIndex) { - alignas(max_align_t) const unsigned char p[100] = {}; - { - using L = Layout; - EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(3).Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L(3).Pointer<0>(p)))); - } - { - using L = Layout; - EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(3).Pointer<0>(p)))); - EXPECT_EQ(12, Distance(p, Type(L::Partial(3).Pointer<1>(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(3, 5).Pointer<0>(p)))); - EXPECT_EQ(12, - Distance(p, Type(L::Partial(3, 5).Pointer<1>(p)))); - EXPECT_EQ(0, Distance(p, Type(L(3, 5).Pointer<0>(p)))); - EXPECT_EQ(12, Distance(p, Type(L(3, 5).Pointer<1>(p)))); - } - { - using L = Layout; - EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0).Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0).Pointer<1>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(1).Pointer<0>(p)))); - EXPECT_EQ(4, Distance(p, Type(L::Partial(1).Pointer<1>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(5).Pointer<0>(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(5).Pointer<1>(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0, 0).Pointer<0>(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0, 0).Pointer<1>(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0, 0).Pointer<2>(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(1, 0).Pointer<0>(p)))); - EXPECT_EQ(4, - Distance(p, Type(L::Partial(1, 0).Pointer<1>(p)))); - EXPECT_EQ(8, - Distance(p, Type(L::Partial(1, 0).Pointer<2>(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(5, 3).Pointer<0>(p)))); - EXPECT_EQ(8, - Distance(p, Type(L::Partial(5, 3).Pointer<1>(p)))); - EXPECT_EQ(24, - Distance(p, Type(L::Partial(5, 3).Pointer<2>(p)))); - EXPECT_EQ( - 0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<0>(p)))); - EXPECT_EQ( - 0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<1>(p)))); - EXPECT_EQ( - 0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<2>(p)))); - EXPECT_EQ( - 0, Distance(p, Type(L::Partial(1, 0, 0).Pointer<0>(p)))); - EXPECT_EQ( - 4, Distance(p, Type(L::Partial(1, 0, 0).Pointer<1>(p)))); - EXPECT_EQ( - 8, Distance(p, Type(L::Partial(1, 0, 0).Pointer<2>(p)))); - EXPECT_EQ( - 0, Distance(p, Type(L::Partial(5, 3, 1).Pointer<0>(p)))); - EXPECT_EQ( - 24, - Distance(p, Type(L::Partial(5, 3, 1).Pointer<2>(p)))); - EXPECT_EQ( - 8, Distance(p, Type(L::Partial(5, 3, 1).Pointer<1>(p)))); - EXPECT_EQ(0, Distance(p, Type(L(5, 3, 1).Pointer<0>(p)))); - EXPECT_EQ(24, Distance(p, Type(L(5, 3, 1).Pointer<2>(p)))); - EXPECT_EQ(8, Distance(p, Type(L(5, 3, 1).Pointer<1>(p)))); - } -} - -TEST(Layout, PointerByType) { - alignas(max_align_t) const unsigned char p[100] = {}; - { - using L = Layout; - EXPECT_EQ(0, - Distance(p, Type(L::Partial().Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(3).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L(3).Pointer(p)))); - } - { - using L = Layout; - EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(1).Pointer(p)))); - EXPECT_EQ(4, - Distance(p, Type(L::Partial(1).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(5).Pointer(p)))); - EXPECT_EQ(8, - Distance(p, Type(L::Partial(5).Pointer(p)))); - EXPECT_EQ( - 0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); - EXPECT_EQ( - 0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); - EXPECT_EQ( - 0, - Distance(p, Type(L::Partial(0, 0).Pointer(p)))); - EXPECT_EQ( - 0, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); - EXPECT_EQ( - 4, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); - EXPECT_EQ( - 8, - Distance(p, Type(L::Partial(1, 0).Pointer(p)))); - EXPECT_EQ( - 0, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); - EXPECT_EQ( - 8, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); - EXPECT_EQ( - 24, - Distance(p, Type(L::Partial(5, 3).Pointer(p)))); - EXPECT_EQ( - 0, - Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); - EXPECT_EQ( - 0, - Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type( - L::Partial(0, 0, 0).Pointer(p)))); - EXPECT_EQ( - 0, - Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); - EXPECT_EQ( - 4, - Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); - EXPECT_EQ(8, Distance(p, Type( - L::Partial(1, 0, 0).Pointer(p)))); - EXPECT_EQ( - 0, - Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); - EXPECT_EQ(24, Distance(p, Type( - L::Partial(5, 3, 1).Pointer(p)))); - EXPECT_EQ( - 8, - Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); - EXPECT_EQ(24, - Distance(p, Type(L(5, 3, 1).Pointer(p)))); - EXPECT_EQ(8, Distance(p, Type(L(5, 3, 1).Pointer(p)))); - } -} - -TEST(Layout, MutablePointerByIndex) { - alignas(max_align_t) unsigned char p[100]; - { - using L = Layout; - EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(3).Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L(3).Pointer<0>(p)))); - } - { - using L = Layout; - EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(3).Pointer<0>(p)))); - EXPECT_EQ(12, Distance(p, Type(L::Partial(3).Pointer<1>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(3, 5).Pointer<0>(p)))); - EXPECT_EQ(12, Distance(p, Type(L::Partial(3, 5).Pointer<1>(p)))); - EXPECT_EQ(0, Distance(p, Type(L(3, 5).Pointer<0>(p)))); - EXPECT_EQ(12, Distance(p, Type(L(3, 5).Pointer<1>(p)))); - } - { - using L = Layout; - EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0).Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0).Pointer<1>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(1).Pointer<0>(p)))); - EXPECT_EQ(4, Distance(p, Type(L::Partial(1).Pointer<1>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(5).Pointer<0>(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(5).Pointer<1>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer<1>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer<2>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(1, 0).Pointer<0>(p)))); - EXPECT_EQ(4, Distance(p, Type(L::Partial(1, 0).Pointer<1>(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(1, 0).Pointer<2>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(5, 3).Pointer<0>(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(5, 3).Pointer<1>(p)))); - EXPECT_EQ(24, Distance(p, Type(L::Partial(5, 3).Pointer<2>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<1>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<2>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(1, 0, 0).Pointer<0>(p)))); - EXPECT_EQ(4, Distance(p, Type(L::Partial(1, 0, 0).Pointer<1>(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(1, 0, 0).Pointer<2>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(5, 3, 1).Pointer<0>(p)))); - EXPECT_EQ(24, - Distance(p, Type(L::Partial(5, 3, 1).Pointer<2>(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(5, 3, 1).Pointer<1>(p)))); - EXPECT_EQ(0, Distance(p, Type(L(5, 3, 1).Pointer<0>(p)))); - EXPECT_EQ(24, Distance(p, Type(L(5, 3, 1).Pointer<2>(p)))); - EXPECT_EQ(8, Distance(p, Type(L(5, 3, 1).Pointer<1>(p)))); - } -} - -TEST(Layout, MutablePointerByType) { - alignas(max_align_t) unsigned char p[100]; - { - using L = Layout; - EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(3).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L(3).Pointer(p)))); - } - { - using L = Layout; - EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(1).Pointer(p)))); - EXPECT_EQ(4, Distance(p, Type(L::Partial(1).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(5).Pointer(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(5).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0, 0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); - EXPECT_EQ(4, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); - EXPECT_EQ(8, - Distance(p, Type(L::Partial(1, 0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); - EXPECT_EQ(24, - Distance(p, Type(L::Partial(5, 3).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); - EXPECT_EQ( - 0, Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); - EXPECT_EQ(4, - Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); - EXPECT_EQ( - 8, Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); - EXPECT_EQ( - 24, Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); - EXPECT_EQ(8, - Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L(5, 3, 1).Pointer(p)))); - EXPECT_EQ(24, Distance(p, Type(L(5, 3, 1).Pointer(p)))); - EXPECT_EQ(8, Distance(p, Type(L(5, 3, 1).Pointer(p)))); - } -} - -TEST(Layout, Pointers) { - alignas(max_align_t) const unsigned char p[100] = {}; - using L = Layout; - { - const auto x = L::Partial(); - EXPECT_EQ(std::make_tuple(x.Pointer<0>(p)), - Type>(x.Pointers(p))); - } - { - const auto x = L::Partial(1); - EXPECT_EQ(std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p)), - (Type>(x.Pointers(p)))); - } - { - const auto x = L::Partial(1, 2); - EXPECT_EQ( - std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)), - (Type>( - x.Pointers(p)))); - } - { - const auto x = L::Partial(1, 2, 3); - EXPECT_EQ( - std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)), - (Type>( - x.Pointers(p)))); - } - { - const L x(1, 2, 3); - EXPECT_EQ( - std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)), - (Type>( - x.Pointers(p)))); - } -} - -TEST(Layout, MutablePointers) { - alignas(max_align_t) unsigned char p[100]; - using L = Layout; - { - const auto x = L::Partial(); - EXPECT_EQ(std::make_tuple(x.Pointer<0>(p)), - Type>(x.Pointers(p))); - } - { - const auto x = L::Partial(1); - EXPECT_EQ(std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p)), - (Type>(x.Pointers(p)))); - } - { - const auto x = L::Partial(1, 2); - EXPECT_EQ( - std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)), - (Type>(x.Pointers(p)))); - } - { - const auto x = L::Partial(1, 2, 3); - EXPECT_EQ( - std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)), - (Type>(x.Pointers(p)))); - } - { - const L x(1, 2, 3); - EXPECT_EQ( - std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)), - (Type>(x.Pointers(p)))); - } -} - -TEST(Layout, SliceByIndexSize) { - alignas(max_align_t) const unsigned char p[100] = {}; - { - using L = Layout; - EXPECT_EQ(0, L::Partial(0).Slice<0>(p).size()); - EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size()); - EXPECT_EQ(3, L(3).Slice<0>(p).size()); - } - { - using L = Layout; - EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size()); - EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size()); - EXPECT_EQ(5, L(3, 5).Slice<1>(p).size()); - } - { - using L = Layout; - EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size()); - EXPECT_EQ(3, L::Partial(3, 5).Slice<0>(p).size()); - EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size()); - EXPECT_EQ(3, L::Partial(3, 5, 7).Slice<0>(p).size()); - EXPECT_EQ(5, L::Partial(3, 5, 7).Slice<1>(p).size()); - EXPECT_EQ(7, L::Partial(3, 5, 7).Slice<2>(p).size()); - EXPECT_EQ(3, L(3, 5, 7).Slice<0>(p).size()); - EXPECT_EQ(5, L(3, 5, 7).Slice<1>(p).size()); - EXPECT_EQ(7, L(3, 5, 7).Slice<2>(p).size()); - } -} - -TEST(Layout, SliceByTypeSize) { - alignas(max_align_t) const unsigned char p[100] = {}; - { - using L = Layout; - EXPECT_EQ(0, L::Partial(0).Slice(p).size()); - EXPECT_EQ(3, L::Partial(3).Slice(p).size()); - EXPECT_EQ(3, L(3).Slice(p).size()); - } - { - using L = Layout; - EXPECT_EQ(3, L::Partial(3).Slice(p).size()); - EXPECT_EQ(3, L::Partial(3, 5).Slice(p).size()); - EXPECT_EQ(5, L::Partial(3, 5).Slice(p).size()); - EXPECT_EQ(3, L::Partial(3, 5, 7).Slice(p).size()); - EXPECT_EQ(5, L::Partial(3, 5, 7).Slice(p).size()); - EXPECT_EQ(7, L::Partial(3, 5, 7).Slice(p).size()); - EXPECT_EQ(3, L(3, 5, 7).Slice(p).size()); - EXPECT_EQ(5, L(3, 5, 7).Slice(p).size()); - EXPECT_EQ(7, L(3, 5, 7).Slice(p).size()); - } -} - -TEST(Layout, MutableSliceByIndexSize) { - alignas(max_align_t) unsigned char p[100]; - { - using L = Layout; - EXPECT_EQ(0, L::Partial(0).Slice<0>(p).size()); - EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size()); - EXPECT_EQ(3, L(3).Slice<0>(p).size()); - } - { - using L = Layout; - EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size()); - EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size()); - EXPECT_EQ(5, L(3, 5).Slice<1>(p).size()); - } - { - using L = Layout; - EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size()); - EXPECT_EQ(3, L::Partial(3, 5).Slice<0>(p).size()); - EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size()); - EXPECT_EQ(3, L::Partial(3, 5, 7).Slice<0>(p).size()); - EXPECT_EQ(5, L::Partial(3, 5, 7).Slice<1>(p).size()); - EXPECT_EQ(7, L::Partial(3, 5, 7).Slice<2>(p).size()); - EXPECT_EQ(3, L(3, 5, 7).Slice<0>(p).size()); - EXPECT_EQ(5, L(3, 5, 7).Slice<1>(p).size()); - EXPECT_EQ(7, L(3, 5, 7).Slice<2>(p).size()); - } -} - -TEST(Layout, MutableSliceByTypeSize) { - alignas(max_align_t) unsigned char p[100]; - { - using L = Layout; - EXPECT_EQ(0, L::Partial(0).Slice(p).size()); - EXPECT_EQ(3, L::Partial(3).Slice(p).size()); - EXPECT_EQ(3, L(3).Slice(p).size()); - } - { - using L = Layout; - EXPECT_EQ(3, L::Partial(3).Slice(p).size()); - EXPECT_EQ(3, L::Partial(3, 5).Slice(p).size()); - EXPECT_EQ(5, L::Partial(3, 5).Slice(p).size()); - EXPECT_EQ(3, L::Partial(3, 5, 7).Slice(p).size()); - EXPECT_EQ(5, L::Partial(3, 5, 7).Slice(p).size()); - EXPECT_EQ(7, L::Partial(3, 5, 7).Slice(p).size()); - EXPECT_EQ(3, L(3, 5, 7).Slice(p).size()); - EXPECT_EQ(5, L(3, 5, 7).Slice(p).size()); - EXPECT_EQ(7, L(3, 5, 7).Slice(p).size()); - } -} - -TEST(Layout, SliceByIndexData) { - alignas(max_align_t) const unsigned char p[100] = {}; - { - using L = Layout; - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); - EXPECT_EQ(0, Distance(p, Type>(L(3).Slice<0>(p)).data())); - } - { - using L = Layout; - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); - EXPECT_EQ( - 0, - Distance(p, - Type>(L::Partial(3, 5).Slice<0>(p)).data())); - EXPECT_EQ( - 12, - Distance(p, - Type>(L::Partial(3, 5).Slice<1>(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L(3, 5).Slice<0>(p)).data())); - EXPECT_EQ(12, - Distance(p, Type>(L(3, 5).Slice<1>(p)).data())); - } - { - using L = Layout; - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(1).Slice<0>(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(5).Slice<0>(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(0, 0).Slice<0>(p)).data())); - EXPECT_EQ( - 0, - Distance(p, - Type>(L::Partial(0, 0).Slice<1>(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(1, 0).Slice<0>(p)).data())); - EXPECT_EQ( - 4, - Distance(p, - Type>(L::Partial(1, 0).Slice<1>(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(5, 3).Slice<0>(p)).data())); - EXPECT_EQ( - 8, - Distance(p, - Type>(L::Partial(5, 3).Slice<1>(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, Type>(L::Partial(0, 0, 0).Slice<0>(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, - Type>(L::Partial(0, 0, 0).Slice<1>(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, - Type>(L::Partial(0, 0, 0).Slice<2>(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, Type>(L::Partial(1, 0, 0).Slice<0>(p)).data())); - EXPECT_EQ( - 4, - Distance( - p, - Type>(L::Partial(1, 0, 0).Slice<1>(p)).data())); - EXPECT_EQ( - 8, - Distance( - p, - Type>(L::Partial(1, 0, 0).Slice<2>(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, Type>(L::Partial(5, 3, 1).Slice<0>(p)).data())); - EXPECT_EQ( - 24, - Distance( - p, - Type>(L::Partial(5, 3, 1).Slice<2>(p)).data())); - EXPECT_EQ( - 8, - Distance( - p, - Type>(L::Partial(5, 3, 1).Slice<1>(p)).data())); - EXPECT_EQ( - 0, Distance(p, Type>(L(5, 3, 1).Slice<0>(p)).data())); - EXPECT_EQ( - 24, - Distance(p, Type>(L(5, 3, 1).Slice<2>(p)).data())); - EXPECT_EQ( - 8, Distance(p, Type>(L(5, 3, 1).Slice<1>(p)).data())); - } -} - -TEST(Layout, SliceByTypeData) { - alignas(max_align_t) const unsigned char p[100] = {}; - { - using L = Layout; - EXPECT_EQ( - 0, - Distance( - p, Type>(L::Partial(0).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, Type>(L::Partial(3).Slice(p)).data())); - EXPECT_EQ( - 0, Distance(p, Type>(L(3).Slice(p)).data())); - } - { - using L = Layout; - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(0).Slice(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(1).Slice(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(5).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, Type>(L::Partial(0, 0).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, - Type>(L::Partial(0, 0).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, Type>(L::Partial(1, 0).Slice(p)).data())); - EXPECT_EQ( - 4, - Distance( - p, - Type>(L::Partial(1, 0).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, Type>(L::Partial(5, 3).Slice(p)).data())); - EXPECT_EQ( - 8, - Distance( - p, - Type>(L::Partial(5, 3).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, - Type>(L::Partial(0, 0, 0).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(0, 0, 0).Slice(p)) - .data())); - EXPECT_EQ(0, Distance(p, Type>( - L::Partial(0, 0, 0).Slice(p)) - .data())); - EXPECT_EQ( - 0, - Distance( - p, - Type>(L::Partial(1, 0, 0).Slice(p)).data())); - EXPECT_EQ( - 4, - Distance(p, Type>(L::Partial(1, 0, 0).Slice(p)) - .data())); - EXPECT_EQ(8, Distance(p, Type>( - L::Partial(1, 0, 0).Slice(p)) - .data())); - EXPECT_EQ( - 0, - Distance( - p, - Type>(L::Partial(5, 3, 1).Slice(p)).data())); - EXPECT_EQ(24, Distance(p, Type>( - L::Partial(5, 3, 1).Slice(p)) - .data())); - EXPECT_EQ( - 8, - Distance(p, Type>(L::Partial(5, 3, 1).Slice(p)) - .data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); - EXPECT_EQ( - 24, - Distance(p, - Type>(L(5, 3, 1).Slice(p)).data())); - EXPECT_EQ( - 8, Distance( - p, Type>(L(5, 3, 1).Slice(p)).data())); - } -} - -TEST(Layout, MutableSliceByIndexData) { - alignas(max_align_t) unsigned char p[100]; - { - using L = Layout; - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); - EXPECT_EQ(0, Distance(p, Type>(L(3).Slice<0>(p)).data())); - } - { - using L = Layout; - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); - EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(3, 5).Slice<0>(p)).data())); - EXPECT_EQ( - 12, - Distance(p, Type>(L::Partial(3, 5).Slice<1>(p)).data())); - EXPECT_EQ(0, Distance(p, Type>(L(3, 5).Slice<0>(p)).data())); - EXPECT_EQ(12, Distance(p, Type>(L(3, 5).Slice<1>(p)).data())); - } - { - using L = Layout; - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(1).Slice<0>(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(5).Slice<0>(p)).data())); - EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(0, 0).Slice<0>(p)).data())); - EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(0, 0).Slice<1>(p)).data())); - EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(1, 0).Slice<0>(p)).data())); - EXPECT_EQ( - 4, Distance(p, Type>(L::Partial(1, 0).Slice<1>(p)).data())); - EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(5, 3).Slice<0>(p)).data())); - EXPECT_EQ( - 8, Distance(p, Type>(L::Partial(5, 3).Slice<1>(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(0, 0, 0).Slice<0>(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(0, 0, 0).Slice<1>(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(0, 0, 0).Slice<2>(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(1, 0, 0).Slice<0>(p)).data())); - EXPECT_EQ( - 4, - Distance(p, Type>(L::Partial(1, 0, 0).Slice<1>(p)).data())); - EXPECT_EQ( - 8, Distance( - p, Type>(L::Partial(1, 0, 0).Slice<2>(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(5, 3, 1).Slice<0>(p)).data())); - EXPECT_EQ( - 24, Distance( - p, Type>(L::Partial(5, 3, 1).Slice<2>(p)).data())); - EXPECT_EQ( - 8, - Distance(p, Type>(L::Partial(5, 3, 1).Slice<1>(p)).data())); - EXPECT_EQ(0, Distance(p, Type>(L(5, 3, 1).Slice<0>(p)).data())); - EXPECT_EQ(24, - Distance(p, Type>(L(5, 3, 1).Slice<2>(p)).data())); - EXPECT_EQ(8, Distance(p, Type>(L(5, 3, 1).Slice<1>(p)).data())); - } -} - -TEST(Layout, MutableSliceByTypeData) { - alignas(max_align_t) unsigned char p[100]; - { - using L = Layout; - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(0).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(3).Slice(p)).data())); - EXPECT_EQ(0, Distance(p, Type>(L(3).Slice(p)).data())); - } - { - using L = Layout; - EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(0).Slice(p)).data())); - EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(1).Slice(p)).data())); - EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(5).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(0, 0).Slice(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(0, 0).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(1, 0).Slice(p)).data())); - EXPECT_EQ( - 4, Distance( - p, Type>(L::Partial(1, 0).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(5, 3).Slice(p)).data())); - EXPECT_EQ( - 8, Distance( - p, Type>(L::Partial(5, 3).Slice(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(0, 0, 0).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, Type>(L::Partial(0, 0, 0).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, - Type>(L::Partial(0, 0, 0).Slice(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(1, 0, 0).Slice(p)).data())); - EXPECT_EQ( - 4, - Distance( - p, Type>(L::Partial(1, 0, 0).Slice(p)).data())); - EXPECT_EQ( - 8, - Distance( - p, - Type>(L::Partial(1, 0, 0).Slice(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(5, 3, 1).Slice(p)).data())); - EXPECT_EQ( - 24, - Distance( - p, - Type>(L::Partial(5, 3, 1).Slice(p)).data())); - EXPECT_EQ( - 8, - Distance( - p, Type>(L::Partial(5, 3, 1).Slice(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); - EXPECT_EQ( - 24, - Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); - EXPECT_EQ( - 8, Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); - } -} - -MATCHER_P(IsSameSlice, slice, "") { - return arg.size() == slice.size() && arg.data() == slice.data(); -} - -template -class TupleMatcher { - public: - explicit TupleMatcher(M... matchers) : matchers_(std::move(matchers)...) {} - - template - bool MatchAndExplain(const Tuple& p, - testing::MatchResultListener* /* listener */) const { - static_assert(std::tuple_size::value == sizeof...(M), ""); - return MatchAndExplainImpl( - p, absl::make_index_sequence::value>{}); - } - - // For the matcher concept. Left empty as we don't really need the diagnostics - // right now. - void DescribeTo(::std::ostream* os) const {} - void DescribeNegationTo(::std::ostream* os) const {} - - private: - template - bool MatchAndExplainImpl(const Tuple& p, absl::index_sequence) const { - // Using std::min as a simple variadic "and". - return std::min( - {true, testing::SafeMatcherCast< - const typename std::tuple_element::type&>( - std::get(matchers_)) - .Matches(std::get(p))...}); - } - - std::tuple matchers_; -}; - -template -testing::PolymorphicMatcher> Tuple(M... matchers) { - return testing::MakePolymorphicMatcher( - TupleMatcher(std::move(matchers)...)); -} - -TEST(Layout, Slices) { - alignas(max_align_t) const unsigned char p[100] = {}; - using L = Layout; - { - const auto x = L::Partial(); - EXPECT_THAT(Type>(x.Slices(p)), Tuple()); - } - { - const auto x = L::Partial(1); - EXPECT_THAT(Type>>(x.Slices(p)), - Tuple(IsSameSlice(x.Slice<0>(p)))); - } - { - const auto x = L::Partial(1, 2); - EXPECT_THAT( - (Type, Span>>(x.Slices(p))), - Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)))); - } - { - const auto x = L::Partial(1, 2, 3); - EXPECT_THAT((Type, Span, - Span>>(x.Slices(p))), - Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), - IsSameSlice(x.Slice<2>(p)))); - } - { - const L x(1, 2, 3); - EXPECT_THAT((Type, Span, - Span>>(x.Slices(p))), - Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), - IsSameSlice(x.Slice<2>(p)))); - } -} - -TEST(Layout, MutableSlices) { - alignas(max_align_t) unsigned char p[100] = {}; - using L = Layout; - { - const auto x = L::Partial(); - EXPECT_THAT(Type>(x.Slices(p)), Tuple()); - } - { - const auto x = L::Partial(1); - EXPECT_THAT(Type>>(x.Slices(p)), - Tuple(IsSameSlice(x.Slice<0>(p)))); - } - { - const auto x = L::Partial(1, 2); - EXPECT_THAT((Type, Span>>(x.Slices(p))), - Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)))); - } - { - const auto x = L::Partial(1, 2, 3); - EXPECT_THAT( - (Type, Span, Span>>(x.Slices(p))), - Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), - IsSameSlice(x.Slice<2>(p)))); - } - { - const L x(1, 2, 3); - EXPECT_THAT( - (Type, Span, Span>>(x.Slices(p))), - Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), - IsSameSlice(x.Slice<2>(p)))); - } -} - -TEST(Layout, UnalignedTypes) { - constexpr Layout x(1, 2, 3); - alignas(max_align_t) unsigned char p[x.AllocSize() + 1]; - EXPECT_THAT(x.Pointers(p + 1), Tuple(p + 1, p + 2, p + 4)); -} - -TEST(Layout, CustomAlignment) { - constexpr Layout> x(1, 2); - alignas(max_align_t) unsigned char p[x.AllocSize()]; - EXPECT_EQ(10, x.AllocSize()); - EXPECT_THAT(x.Pointers(p), Tuple(p + 0, p + 8)); -} - -TEST(Layout, OverAligned) { - constexpr size_t M = alignof(max_align_t); - constexpr Layout> x(1, 3); - alignas(2 * M) unsigned char p[x.AllocSize()]; - EXPECT_EQ(2 * M + 3, x.AllocSize()); - EXPECT_THAT(x.Pointers(p), Tuple(p + 0, p + 2 * M)); -} - -TEST(Layout, Alignment) { - static_assert(Layout::Alignment() == 1, ""); - static_assert(Layout::Alignment() == 4, ""); - static_assert(Layout::Alignment() == 8, ""); - static_assert(Layout>::Alignment() == 64, ""); - static_assert(Layout::Alignment() == 8, ""); - static_assert(Layout::Alignment() == 8, ""); - static_assert(Layout::Alignment() == 8, ""); - static_assert(Layout::Alignment() == 8, ""); - static_assert(Layout::Alignment() == 8, ""); - static_assert(Layout::Alignment() == 8, ""); -} - -TEST(Layout, ConstexprPartial) { - constexpr size_t M = alignof(max_align_t); - constexpr Layout> x(1, 3); - static_assert(x.Partial(1).template Offset<1>() == 2 * M, ""); -} -// [from, to) -struct Region { - size_t from; - size_t to; -}; - -void ExpectRegionPoisoned(const unsigned char* p, size_t n, bool poisoned) { -#ifdef ADDRESS_SANITIZER - for (size_t i = 0; i != n; ++i) { - EXPECT_EQ(poisoned, __asan_address_is_poisoned(p + i)); - } -#endif -} - -template -void ExpectPoisoned(const unsigned char (&buf)[N], - std::initializer_list reg) { - size_t prev = 0; - for (const Region& r : reg) { - ExpectRegionPoisoned(buf + prev, r.from - prev, false); - ExpectRegionPoisoned(buf + r.from, r.to - r.from, true); - prev = r.to; - } - ExpectRegionPoisoned(buf + prev, N - prev, false); -} - -TEST(Layout, PoisonPadding) { - using L = Layout; - - constexpr size_t n = L::Partial(1, 2, 3, 4).AllocSize(); - { - constexpr auto x = L::Partial(); - alignas(max_align_t) const unsigned char c[n] = {}; - x.PoisonPadding(c); - EXPECT_EQ(x.Slices(c), x.Slices(c)); - ExpectPoisoned(c, {}); - } - { - constexpr auto x = L::Partial(1); - alignas(max_align_t) const unsigned char c[n] = {}; - x.PoisonPadding(c); - EXPECT_EQ(x.Slices(c), x.Slices(c)); - ExpectPoisoned(c, {{1, 8}}); - } - { - constexpr auto x = L::Partial(1, 2); - alignas(max_align_t) const unsigned char c[n] = {}; - x.PoisonPadding(c); - EXPECT_EQ(x.Slices(c), x.Slices(c)); - ExpectPoisoned(c, {{1, 8}}); - } - { - constexpr auto x = L::Partial(1, 2, 3); - alignas(max_align_t) const unsigned char c[n] = {}; - x.PoisonPadding(c); - EXPECT_EQ(x.Slices(c), x.Slices(c)); - ExpectPoisoned(c, {{1, 8}, {36, 40}}); - } - { - constexpr auto x = L::Partial(1, 2, 3, 4); - alignas(max_align_t) const unsigned char c[n] = {}; - x.PoisonPadding(c); - EXPECT_EQ(x.Slices(c), x.Slices(c)); - ExpectPoisoned(c, {{1, 8}, {36, 40}}); - } - { - constexpr L x(1, 2, 3, 4); - alignas(max_align_t) const unsigned char c[n] = {}; - x.PoisonPadding(c); - EXPECT_EQ(x.Slices(c), x.Slices(c)); - ExpectPoisoned(c, {{1, 8}, {36, 40}}); - } -} - -TEST(Layout, DebugString) { - const std::string int64_type = -#ifdef _MSC_VER - "__int64"; -#else // _MSC_VER - std::is_same::value ? "long long" : "long"; // NOLINT -#endif // _MSC_VER - { - constexpr auto x = Layout::Partial(); - EXPECT_EQ("@0(1)", x.DebugString()); - } - { - constexpr auto x = Layout::Partial(1); - EXPECT_EQ("@0(1)[1]; @4(4)", x.DebugString()); - } - { - constexpr auto x = Layout::Partial(1, 2); - EXPECT_EQ("@0(1)[1]; @4(4)[2]; @12(1)", - x.DebugString()); - } - { - constexpr auto x = Layout::Partial(1, 2, 3); - EXPECT_EQ( - "@0(1)[1]; @4(4)[2]; @12(1)[3]; " - "@16<" + - int64_type + " [2]>(16)", - x.DebugString()); - } - { - constexpr auto x = Layout::Partial(1, 2, 3, 4); - EXPECT_EQ( - "@0(1)[1]; @4(4)[2]; @12(1)[3]; " - "@16<" + - int64_type + " [2]>(16)[4]", - x.DebugString()); - } - { - constexpr Layout x(1, 2, 3, 4); - EXPECT_EQ( - "@0(1)[1]; @4(4)[2]; @12(1)[3]; " - "@16<" + - int64_type + " [2]>(16)[4]", - x.DebugString()); - } -} - -TEST(Layout, CharTypes) { - constexpr Layout x(1); - alignas(max_align_t) char c[x.AllocSize()] = {}; - alignas(max_align_t) unsigned char uc[x.AllocSize()] = {}; - alignas(max_align_t) signed char sc[x.AllocSize()] = {}; - alignas(max_align_t) const char cc[x.AllocSize()] = {}; - alignas(max_align_t) const unsigned char cuc[x.AllocSize()] = {}; - alignas(max_align_t) const signed char csc[x.AllocSize()] = {}; - - Type(x.Pointer<0>(c)); - Type(x.Pointer<0>(uc)); - Type(x.Pointer<0>(sc)); - Type(x.Pointer<0>(cc)); - Type(x.Pointer<0>(cuc)); - Type(x.Pointer<0>(csc)); - - Type(x.Pointer(c)); - Type(x.Pointer(uc)); - Type(x.Pointer(sc)); - Type(x.Pointer(cc)); - Type(x.Pointer(cuc)); - Type(x.Pointer(csc)); - - Type>(x.Pointers(c)); - Type>(x.Pointers(uc)); - Type>(x.Pointers(sc)); - Type>(x.Pointers(cc)); - Type>(x.Pointers(cuc)); - Type>(x.Pointers(csc)); - - Type>(x.Slice<0>(c)); - Type>(x.Slice<0>(uc)); - Type>(x.Slice<0>(sc)); - Type>(x.Slice<0>(cc)); - Type>(x.Slice<0>(cuc)); - Type>(x.Slice<0>(csc)); - - Type>>(x.Slices(c)); - Type>>(x.Slices(uc)); - Type>>(x.Slices(sc)); - Type>>(x.Slices(cc)); - Type>>(x.Slices(cuc)); - Type>>(x.Slices(csc)); -} - -TEST(Layout, ConstElementType) { - constexpr Layout x(1); - alignas(int32_t) char c[x.AllocSize()] = {}; - const char* cc = c; - const int32_t* p = reinterpret_cast(cc); - - EXPECT_EQ(alignof(int32_t), x.Alignment()); - - EXPECT_EQ(0, x.Offset<0>()); - EXPECT_EQ(0, x.Offset()); - - EXPECT_THAT(x.Offsets(), ElementsAre(0)); - - EXPECT_EQ(1, x.Size<0>()); - EXPECT_EQ(1, x.Size()); - - EXPECT_THAT(x.Sizes(), ElementsAre(1)); - - EXPECT_EQ(sizeof(int32_t), x.AllocSize()); - - EXPECT_EQ(p, Type(x.Pointer<0>(c))); - EXPECT_EQ(p, Type(x.Pointer<0>(cc))); - - EXPECT_EQ(p, Type(x.Pointer(c))); - EXPECT_EQ(p, Type(x.Pointer(cc))); - - EXPECT_THAT(Type>(x.Pointers(c)), Tuple(p)); - EXPECT_THAT(Type>(x.Pointers(cc)), Tuple(p)); - - EXPECT_THAT(Type>(x.Slice<0>(c)), - IsSameSlice(Span(p, 1))); - EXPECT_THAT(Type>(x.Slice<0>(cc)), - IsSameSlice(Span(p, 1))); - - EXPECT_THAT(Type>(x.Slice(c)), - IsSameSlice(Span(p, 1))); - EXPECT_THAT(Type>(x.Slice(cc)), - IsSameSlice(Span(p, 1))); - - EXPECT_THAT(Type>>(x.Slices(c)), - Tuple(IsSameSlice(Span(p, 1)))); - EXPECT_THAT(Type>>(x.Slices(cc)), - Tuple(IsSameSlice(Span(p, 1)))); -} - -namespace example { - -// Immutable move-only string with sizeof equal to sizeof(void*). The string -// size and the characters are kept in the same heap allocation. -class CompactString { - public: - CompactString(const char* s = "") { // NOLINT - const size_t size = strlen(s); - // size_t[1], followed by char[size + 1]. - // This statement doesn't allocate memory. - const L layout(1, size + 1); - // AllocSize() tells us how much memory we need to allocate for all our - // data. - p_.reset(new unsigned char[layout.AllocSize()]); - // If running under ASAN, mark the padding bytes, if any, to catch memory - // errors. - layout.PoisonPadding(p_.get()); - // Store the size in the allocation. - // Pointer() is a synonym for Pointer<0>(). - *layout.Pointer(p_.get()) = size; - // Store the characters in the allocation. - memcpy(layout.Pointer(p_.get()), s, size + 1); - } - - size_t size() const { - // Equivalent to reinterpret_cast(*p). - return *L::Partial().Pointer(p_.get()); - } - - const char* c_str() const { - // Equivalent to reinterpret_cast(p.get() + sizeof(size_t)). - // The argument in Partial(1) specifies that we have size_t[1] in front of - // the - // characters. - return L::Partial(1).Pointer(p_.get()); - } - - private: - // Our heap allocation contains a size_t followed by an array of chars. - using L = Layout; - std::unique_ptr p_; -}; - -TEST(CompactString, Works) { - CompactString s = "hello"; - EXPECT_EQ(5, s.size()); - EXPECT_STREQ("hello", s.c_str()); -} - -} // namespace example - -} // namespace -} // namespace container_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/node_hash_policy.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/node_hash_policy.h deleted file mode 100644 index 065e700..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/node_hash_policy.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. -// -// Adapts a policy for nodes. -// -// The node policy should model: -// -// struct Policy { -// // Returns a new node allocated and constructed using the allocator, using -// // the specified arguments. -// template -// value_type* new_element(Alloc* alloc, Args&&... args) const; -// -// // Destroys and deallocates node using the allocator. -// template -// void delete_element(Alloc* alloc, value_type* node) const; -// }; -// -// It may also optionally define `value()` and `apply()`. For documentation on -// these, see hash_policy_traits.h. - -#ifndef ABSL_CONTAINER_INTERNAL_NODE_HASH_POLICY_H_ -#define ABSL_CONTAINER_INTERNAL_NODE_HASH_POLICY_H_ - -#include -#include -#include -#include -#include - -namespace absl { -namespace container_internal { - -template -struct node_hash_policy { - static_assert(std::is_lvalue_reference::value, ""); - - using slot_type = typename std::remove_cv< - typename std::remove_reference::type>::type*; - - template - static void construct(Alloc* alloc, slot_type* slot, Args&&... args) { - *slot = Policy::new_element(alloc, std::forward(args)...); - } - - template - static void destroy(Alloc* alloc, slot_type* slot) { - Policy::delete_element(alloc, *slot); - } - - template - static void transfer(Alloc*, slot_type* new_slot, slot_type* old_slot) { - *new_slot = *old_slot; - } - - static size_t space_used(const slot_type* slot) { - if (slot == nullptr) return Policy::element_space_used(nullptr); - return Policy::element_space_used(*slot); - } - - static Reference element(slot_type* slot) { return **slot; } - - template - static auto value(T* elem) -> decltype(P::value(elem)) { - return P::value(elem); - } - - template - static auto apply(Ts&&... ts) -> decltype(P::apply(std::forward(ts)...)) { - return P::apply(std::forward(ts)...); - } -}; - -} // namespace container_internal -} // namespace absl - -#endif // ABSL_CONTAINER_INTERNAL_NODE_HASH_POLICY_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/node_hash_policy_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/node_hash_policy_test.cc deleted file mode 100644 index 43d287e..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/node_hash_policy_test.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include "absl/container/internal/node_hash_policy.h" - -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/container/internal/hash_policy_traits.h" - -namespace absl { -namespace container_internal { -namespace { - -using ::testing::Pointee; - -struct Policy : node_hash_policy { - using key_type = int; - using init_type = int; - - template - static int* new_element(Alloc* alloc, int value) { - return new int(value); - } - - template - static void delete_element(Alloc* alloc, int* elem) { - delete elem; - } -}; - -using NodePolicy = hash_policy_traits; - -struct NodeTest : ::testing::Test { - std::allocator alloc; - int n = 53; - int* a = &n; -}; - -TEST_F(NodeTest, ConstructDestroy) { - NodePolicy::construct(&alloc, &a, 42); - EXPECT_THAT(a, Pointee(42)); - NodePolicy::destroy(&alloc, &a); -} - -TEST_F(NodeTest, transfer) { - int s = 42; - int* b = &s; - NodePolicy::transfer(&alloc, &a, &b); - EXPECT_EQ(&s, a); -} - -} // namespace -} // namespace container_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h deleted file mode 100644 index 05270ef..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#ifndef ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_ -#define ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_ - -#include -#include -#include - -#include "absl/container/internal/container_memory.h" -#include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export - -namespace absl { -namespace container_internal { - -template -class raw_hash_map : public raw_hash_set { - // P is Policy. It's passed as a template argument to support maps that have - // incomplete types as values, as in unordered_map. - // MappedReference<> may be a non-reference type. - template - using MappedReference = decltype(P::value( - std::addressof(std::declval()))); - - // MappedConstReference<> may be a non-reference type. - template - using MappedConstReference = decltype(P::value( - std::addressof(std::declval()))); - - using KeyArgImpl = container_internal::KeyArg::value && - IsTransparent::value>; - - public: - using key_type = typename Policy::key_type; - using mapped_type = typename Policy::mapped_type; - template - using key_arg = typename KeyArgImpl::template type; - - static_assert(!std::is_reference::value, ""); - // TODO(alkis): remove this assertion and verify that reference mapped_type is - // supported. - static_assert(!std::is_reference::value, ""); - - using iterator = typename raw_hash_map::raw_hash_set::iterator; - using const_iterator = typename raw_hash_map::raw_hash_set::const_iterator; - - raw_hash_map() {} - using raw_hash_map::raw_hash_set::raw_hash_set; - - // The last two template parameters ensure that both arguments are rvalues - // (lvalue arguments are handled by the overloads below). This is necessary - // for supporting bitfield arguments. - // - // union { int n : 1; }; - // flat_hash_map m; - // m.insert_or_assign(n, n); - template - std::pair insert_or_assign(key_arg&& k, V&& v) { - return insert_or_assign_impl(std::forward(k), std::forward(v)); - } - - template - std::pair insert_or_assign(key_arg&& k, const V& v) { - return insert_or_assign_impl(std::forward(k), v); - } - - template - std::pair insert_or_assign(const key_arg& k, V&& v) { - return insert_or_assign_impl(k, std::forward(v)); - } - - template - std::pair insert_or_assign(const key_arg& k, const V& v) { - return insert_or_assign_impl(k, v); - } - - template - iterator insert_or_assign(const_iterator, key_arg&& k, V&& v) { - return insert_or_assign(std::forward(k), std::forward(v)).first; - } - - template - iterator insert_or_assign(const_iterator, key_arg&& k, const V& v) { - return insert_or_assign(std::forward(k), v).first; - } - - template - iterator insert_or_assign(const_iterator, const key_arg& k, V&& v) { - return insert_or_assign(k, std::forward(v)).first; - } - - template - iterator insert_or_assign(const_iterator, const key_arg& k, const V& v) { - return insert_or_assign(k, v).first; - } - - template ::value, int>::type = 0, - K* = nullptr> - std::pair try_emplace(key_arg&& k, Args&&... args) { - return try_emplace_impl(std::forward(k), std::forward(args)...); - } - - template ::value, int>::type = 0> - std::pair try_emplace(const key_arg& k, Args&&... args) { - return try_emplace_impl(k, std::forward(args)...); - } - - template - iterator try_emplace(const_iterator, key_arg&& k, Args&&... args) { - return try_emplace(std::forward(k), std::forward(args)...).first; - } - - template - iterator try_emplace(const_iterator, const key_arg& k, Args&&... args) { - return try_emplace(k, std::forward(args)...).first; - } - - template - MappedReference

at(const key_arg& key) { - auto it = this->find(key); - if (it == this->end()) std::abort(); - return Policy::value(&*it); - } - - template - MappedConstReference

at(const key_arg& key) const { - auto it = this->find(key); - if (it == this->end()) std::abort(); - return Policy::value(&*it); - } - - template - MappedReference

operator[](key_arg&& key) { - return Policy::value(&*try_emplace(std::forward(key)).first); - } - - template - MappedReference

operator[](const key_arg& key) { - return Policy::value(&*try_emplace(key).first); - } - - private: - template - std::pair insert_or_assign_impl(K&& k, V&& v) { - auto res = this->find_or_prepare_insert(k); - if (res.second) - this->emplace_at(res.first, std::forward(k), std::forward(v)); - else - Policy::value(&*this->iterator_at(res.first)) = std::forward(v); - return {this->iterator_at(res.first), res.second}; - } - - template - std::pair try_emplace_impl(K&& k, Args&&... args) { - auto res = this->find_or_prepare_insert(k); - if (res.second) - this->emplace_at(res.first, std::piecewise_construct, - std::forward_as_tuple(std::forward(k)), - std::forward_as_tuple(std::forward(args)...)); - return {this->iterator_at(res.first), res.second}; - } -}; - -} // namespace container_internal -} // namespace absl - -#endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc deleted file mode 100644 index 1015312..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include "absl/container/internal/raw_hash_set.h" - -#include - -#include "absl/base/config.h" - -namespace absl { -namespace container_internal { - -constexpr size_t Group::kWidth; - -// Returns "random" seed. -inline size_t RandomSeed() { -#if ABSL_HAVE_THREAD_LOCAL - static thread_local size_t counter = 0; - size_t value = ++counter; -#else // ABSL_HAVE_THREAD_LOCAL - static std::atomic counter; - size_t value = counter.fetch_add(1, std::memory_order_relaxed); -#endif // ABSL_HAVE_THREAD_LOCAL - return value ^ static_cast(reinterpret_cast(&counter)); -} - -bool ShouldInsertBackwards(size_t hash, ctrl_t* ctrl) { - // To avoid problems with weak hashes and single bit tests, we use % 13. - // TODO(kfm,sbenza): revisit after we do unconditional mixing - return (H1(hash, ctrl) ^ RandomSeed()) % 13 > 6; -} - -} // namespace container_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h deleted file mode 100644 index 26d9972..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h +++ /dev/null @@ -1,1945 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. -// -// An open-addressing -// hashtable with quadratic probing. -// -// This is a low level hashtable on top of which different interfaces can be -// implemented, like flat_hash_set, node_hash_set, string_hash_set, etc. -// -// The table interface is similar to that of std::unordered_set. Notable -// differences are that most member functions support heterogeneous keys when -// BOTH the hash and eq functions are marked as transparent. They do so by -// providing a typedef called `is_transparent`. -// -// When heterogeneous lookup is enabled, functions that take key_type act as if -// they have an overload set like: -// -// iterator find(const key_type& key); -// template -// iterator find(const K& key); -// -// size_type erase(const key_type& key); -// template -// size_type erase(const K& key); -// -// std::pair equal_range(const key_type& key); -// template -// std::pair equal_range(const K& key); -// -// When heterogeneous lookup is disabled, only the explicit `key_type` overloads -// exist. -// -// find() also supports passing the hash explicitly: -// -// iterator find(const key_type& key, size_t hash); -// template -// iterator find(const U& key, size_t hash); -// -// In addition the pointer to element and iterator stability guarantees are -// weaker: all iterators and pointers are invalidated after a new element is -// inserted. -// -// IMPLEMENTATION DETAILS -// -// The table stores elements inline in a slot array. In addition to the slot -// array the table maintains some control state per slot. The extra state is one -// byte per slot and stores empty or deleted marks, or alternatively 7 bits from -// the hash of an occupied slot. The table is split into logical groups of -// slots, like so: -// -// Group 1 Group 2 Group 3 -// +---------------+---------------+---------------+ -// | | | | | | | | | | | | | | | | | | | | | | | | | -// +---------------+---------------+---------------+ -// -// On lookup the hash is split into two parts: -// - H2: 7 bits (those stored in the control bytes) -// - H1: the rest of the bits -// The groups are probed using H1. For each group the slots are matched to H2 in -// parallel. Because H2 is 7 bits (128 states) and the number of slots per group -// is low (8 or 16) in almost all cases a match in H2 is also a lookup hit. -// -// On insert, once the right group is found (as in lookup), its slots are -// filled in order. -// -// On erase a slot is cleared. In case the group did not have any empty slots -// before the erase, the erased slot is marked as deleted. -// -// Groups without empty slots (but maybe with deleted slots) extend the probe -// sequence. The probing algorithm is quadratic. Given N the number of groups, -// the probing function for the i'th probe is: -// -// P(0) = H1 % N -// -// P(i) = (P(i - 1) + i) % N -// -// This probing function guarantees that after N probes, all the groups of the -// table will be probed exactly once. - -#ifndef ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_ -#define ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_ - -#ifndef SWISSTABLE_HAVE_SSE2 -#if defined(__SSE2__) || \ - (defined(_MSC_VER) && \ - (defined(_M_X64) || (defined(_M_IX86) && _M_IX86_FP >= 2))) -#define SWISSTABLE_HAVE_SSE2 1 -#else -#define SWISSTABLE_HAVE_SSE2 0 -#endif -#endif - -#ifndef SWISSTABLE_HAVE_SSSE3 -#ifdef __SSSE3__ -#define SWISSTABLE_HAVE_SSSE3 1 -#else -#define SWISSTABLE_HAVE_SSSE3 0 -#endif -#endif - -#if SWISSTABLE_HAVE_SSSE3 && !SWISSTABLE_HAVE_SSE2 -#error "Bad configuration!" -#endif - -#if SWISSTABLE_HAVE_SSE2 -#include -#endif - -#if SWISSTABLE_HAVE_SSSE3 -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "absl/base/internal/bits.h" -#include "absl/base/internal/endian.h" -#include "absl/base/port.h" -#include "absl/container/internal/compressed_tuple.h" -#include "absl/container/internal/container_memory.h" -#include "absl/container/internal/hash_policy_traits.h" -#include "absl/container/internal/hashtable_debug_hooks.h" -#include "absl/container/internal/layout.h" -#include "absl/memory/memory.h" -#include "absl/meta/type_traits.h" -#include "absl/types/optional.h" -#include "absl/utility/utility.h" - -namespace absl { -namespace container_internal { - -template -class probe_seq { - public: - probe_seq(size_t hash, size_t mask) { - assert(((mask + 1) & mask) == 0 && "not a mask"); - mask_ = mask; - offset_ = hash & mask_; - } - size_t offset() const { return offset_; } - size_t offset(size_t i) const { return (offset_ + i) & mask_; } - - void next() { - index_ += Width; - offset_ += index_; - offset_ &= mask_; - } - // 0-based probe index. The i-th probe in the probe sequence. - size_t index() const { return index_; } - - private: - size_t mask_; - size_t offset_; - size_t index_ = 0; -}; - -template -struct RequireUsableKey { - template - std::pair< - decltype(std::declval()(std::declval())), - decltype(std::declval()(std::declval(), - std::declval()))>* - operator()(const PassedKey&, const Args&...) const; -}; - -template -struct IsDecomposable : std::false_type {}; - -template -struct IsDecomposable< - absl::void_t(), - std::declval()...))>, - Policy, Hash, Eq, Ts...> : std::true_type {}; - -template -struct IsTransparent : std::false_type {}; -template -struct IsTransparent> - : std::true_type {}; - -// TODO(alkis): Switch to std::is_nothrow_swappable when gcc/clang supports it. -template -constexpr bool IsNoThrowSwappable() { - using std::swap; - return noexcept(swap(std::declval(), std::declval())); -} - -template -int TrailingZeros(T x) { - return sizeof(T) == 8 ? base_internal::CountTrailingZerosNonZero64(x) - : base_internal::CountTrailingZerosNonZero32(x); -} - -template -int LeadingZeros(T x) { - return sizeof(T) == 8 ? base_internal::CountLeadingZeros64(x) - : base_internal::CountLeadingZeros32(x); -} - -// An abstraction over a bitmask. It provides an easy way to iterate through the -// indexes of the set bits of a bitmask. When Shift=0 (platforms with SSE), -// this is a true bitmask. On non-SSE, platforms the arithematic used to -// emulate the SSE behavior works in bytes (Shift=3) and leaves each bytes as -// either 0x00 or 0x80. -// -// For example: -// for (int i : BitMask(0x5)) -> yields 0, 2 -// for (int i : BitMask(0x0000000080800000)) -> yields 2, 3 -template -class BitMask { - static_assert(std::is_unsigned::value, ""); - static_assert(Shift == 0 || Shift == 3, ""); - - public: - // These are useful for unit tests (gunit). - using value_type = int; - using iterator = BitMask; - using const_iterator = BitMask; - - explicit BitMask(T mask) : mask_(mask) {} - BitMask& operator++() { - mask_ &= (mask_ - 1); - return *this; - } - explicit operator bool() const { return mask_ != 0; } - int operator*() const { return LowestBitSet(); } - int LowestBitSet() const { - return container_internal::TrailingZeros(mask_) >> Shift; - } - int HighestBitSet() const { - return (sizeof(T) * CHAR_BIT - container_internal::LeadingZeros(mask_) - - 1) >> - Shift; - } - - BitMask begin() const { return *this; } - BitMask end() const { return BitMask(0); } - - int TrailingZeros() const { - return container_internal::TrailingZeros(mask_) >> Shift; - } - - int LeadingZeros() const { - constexpr int total_significant_bits = SignificantBits << Shift; - constexpr int extra_bits = sizeof(T) * 8 - total_significant_bits; - return container_internal::LeadingZeros(mask_ << extra_bits) >> Shift; - } - - private: - friend bool operator==(const BitMask& a, const BitMask& b) { - return a.mask_ == b.mask_; - } - friend bool operator!=(const BitMask& a, const BitMask& b) { - return a.mask_ != b.mask_; - } - - T mask_; -}; - -using ctrl_t = signed char; -using h2_t = uint8_t; - -// The values here are selected for maximum performance. See the static asserts -// below for details. -enum Ctrl : ctrl_t { - kEmpty = -128, // 0b10000000 - kDeleted = -2, // 0b11111110 - kSentinel = -1, // 0b11111111 -}; -static_assert( - kEmpty & kDeleted & kSentinel & 0x80, - "Special markers need to have the MSB to make checking for them efficient"); -static_assert(kEmpty < kSentinel && kDeleted < kSentinel, - "kEmpty and kDeleted must be smaller than kSentinel to make the " - "SIMD test of IsEmptyOrDeleted() efficient"); -static_assert(kSentinel == -1, - "kSentinel must be -1 to elide loading it from memory into SIMD " - "registers (pcmpeqd xmm, xmm)"); -static_assert(kEmpty == -128, - "kEmpty must be -128 to make the SIMD check for its " - "existence efficient (psignb xmm, xmm)"); -static_assert(~kEmpty & ~kDeleted & kSentinel & 0x7F, - "kEmpty and kDeleted must share an unset bit that is not shared " - "by kSentinel to make the scalar test for MatchEmptyOrDeleted() " - "efficient"); -static_assert(kDeleted == -2, - "kDeleted must be -2 to make the implementation of " - "ConvertSpecialToEmptyAndFullToDeleted efficient"); - -// A single block of empty control bytes for tables without any slots allocated. -// This enables removing a branch in the hot path of find(). -inline ctrl_t* EmptyGroup() { - alignas(16) static constexpr ctrl_t empty_group[] = { - kSentinel, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, - kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty}; - return const_cast(empty_group); -} - -// Mixes a randomly generated per-process seed with `hash` and `ctrl` to -// randomize insertion order within groups. -bool ShouldInsertBackwards(size_t hash, ctrl_t* ctrl); - -// Returns a hash seed. -// -// The seed consists of the ctrl_ pointer, which adds enough entropy to ensure -// non-determinism of iteration order in most cases. -inline size_t HashSeed(const ctrl_t* ctrl) { - // The low bits of the pointer have little or no entropy because of - // alignment. We shift the pointer to try to use higher entropy bits. A - // good number seems to be 12 bits, because that aligns with page size. - return reinterpret_cast(ctrl) >> 12; -} - -inline size_t H1(size_t hash, const ctrl_t* ctrl) { - return (hash >> 7) ^ HashSeed(ctrl); -} -inline ctrl_t H2(size_t hash) { return hash & 0x7F; } - -inline bool IsEmpty(ctrl_t c) { return c == kEmpty; } -inline bool IsFull(ctrl_t c) { return c >= 0; } -inline bool IsDeleted(ctrl_t c) { return c == kDeleted; } -inline bool IsEmptyOrDeleted(ctrl_t c) { return c < kSentinel; } - -#if SWISSTABLE_HAVE_SSE2 - -// https://github.com/abseil/abseil-cpp/issues/209 -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87853 -// _mm_cmpgt_epi8 is broken under GCC with -funsigned-char -// Work around this by using the portable implementation of Group -// when using -funsigned-char under GCC. -inline __m128i _mm_cmpgt_epi8_fixed(__m128i a, __m128i b) { -#if defined(__GNUC__) && !defined(__clang__) - if (std::is_unsigned::value) { - const __m128i mask = _mm_set1_epi8(0x80); - const __m128i diff = _mm_subs_epi8(b, a); - return _mm_cmpeq_epi8(_mm_and_si128(diff, mask), mask); - } -#endif - return _mm_cmpgt_epi8(a, b); -} - -struct GroupSse2Impl { - static constexpr size_t kWidth = 16; // the number of slots per group - - explicit GroupSse2Impl(const ctrl_t* pos) { - ctrl = _mm_loadu_si128(reinterpret_cast(pos)); - } - - // Returns a bitmask representing the positions of slots that match hash. - BitMask Match(h2_t hash) const { - auto match = _mm_set1_epi8(hash); - return BitMask( - _mm_movemask_epi8(_mm_cmpeq_epi8(match, ctrl))); - } - - // Returns a bitmask representing the positions of empty slots. - BitMask MatchEmpty() const { -#if SWISSTABLE_HAVE_SSSE3 - // This only works because kEmpty is -128. - return BitMask( - _mm_movemask_epi8(_mm_sign_epi8(ctrl, ctrl))); -#else - return Match(kEmpty); -#endif - } - - // Returns a bitmask representing the positions of empty or deleted slots. - BitMask MatchEmptyOrDeleted() const { - auto special = _mm_set1_epi8(kSentinel); - return BitMask( - _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl))); - } - - // Returns the number of trailing empty or deleted elements in the group. - uint32_t CountLeadingEmptyOrDeleted() const { - auto special = _mm_set1_epi8(kSentinel); - return TrailingZeros( - _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1); - } - - void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const { - auto msbs = _mm_set1_epi8(0x80); - auto x126 = _mm_set1_epi8(126); -#if SWISSTABLE_HAVE_SSSE3 - auto res = _mm_or_si128(_mm_shuffle_epi8(x126, ctrl), msbs); -#else - auto zero = _mm_setzero_si128(); - auto special_mask = _mm_cmpgt_epi8_fixed(zero, ctrl); - auto res = _mm_or_si128(msbs, _mm_andnot_si128(special_mask, x126)); -#endif - _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), res); - } - - __m128i ctrl; -}; -#endif // SWISSTABLE_HAVE_SSE2 - -struct GroupPortableImpl { - static constexpr size_t kWidth = 8; - - explicit GroupPortableImpl(const ctrl_t* pos) - : ctrl(little_endian::Load64(pos)) {} - - BitMask Match(h2_t hash) const { - // For the technique, see: - // http://graphics.stanford.edu/~seander/bithacks.html##ValueInWord - // (Determine if a word has a byte equal to n). - // - // Caveat: there are false positives but: - // - they only occur if there is a real match - // - they never occur on kEmpty, kDeleted, kSentinel - // - they will be handled gracefully by subsequent checks in code - // - // Example: - // v = 0x1716151413121110 - // hash = 0x12 - // retval = (v - lsbs) & ~v & msbs = 0x0000000080800000 - constexpr uint64_t msbs = 0x8080808080808080ULL; - constexpr uint64_t lsbs = 0x0101010101010101ULL; - auto x = ctrl ^ (lsbs * hash); - return BitMask((x - lsbs) & ~x & msbs); - } - - BitMask MatchEmpty() const { - constexpr uint64_t msbs = 0x8080808080808080ULL; - return BitMask((ctrl & (~ctrl << 6)) & msbs); - } - - BitMask MatchEmptyOrDeleted() const { - constexpr uint64_t msbs = 0x8080808080808080ULL; - return BitMask((ctrl & (~ctrl << 7)) & msbs); - } - - uint32_t CountLeadingEmptyOrDeleted() const { - constexpr uint64_t gaps = 0x00FEFEFEFEFEFEFEULL; - return (TrailingZeros(((~ctrl & (ctrl >> 7)) | gaps) + 1) + 7) >> 3; - } - - void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const { - constexpr uint64_t msbs = 0x8080808080808080ULL; - constexpr uint64_t lsbs = 0x0101010101010101ULL; - auto x = ctrl & msbs; - auto res = (~x + (x >> 7)) & ~lsbs; - little_endian::Store64(dst, res); - } - - uint64_t ctrl; -}; - -#if SWISSTABLE_HAVE_SSE2 -using Group = GroupSse2Impl; -#else -using Group = GroupPortableImpl; -#endif - -template -class raw_hash_set; - -inline bool IsValidCapacity(size_t n) { - return ((n + 1) & n) == 0 && n >= Group::kWidth - 1; -} - -// PRECONDITION: -// IsValidCapacity(capacity) -// ctrl[capacity] == kSentinel -// ctrl[i] != kSentinel for all i < capacity -// Applies mapping for every byte in ctrl: -// DELETED -> EMPTY -// EMPTY -> EMPTY -// FULL -> DELETED -inline void ConvertDeletedToEmptyAndFullToDeleted( - ctrl_t* ctrl, size_t capacity) { - assert(ctrl[capacity] == kSentinel); - assert(IsValidCapacity(capacity)); - for (ctrl_t* pos = ctrl; pos != ctrl + capacity + 1; pos += Group::kWidth) { - Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos); - } - // Copy the cloned ctrl bytes. - std::memcpy(ctrl + capacity + 1, ctrl, Group::kWidth); - ctrl[capacity] = kSentinel; -} - -// Rounds up the capacity to the next power of 2 minus 1 and ensures it is -// greater or equal to Group::kWidth - 1. -inline size_t NormalizeCapacity(size_t n) { - constexpr size_t kMinCapacity = Group::kWidth - 1; - return n <= kMinCapacity - ? kMinCapacity - : (std::numeric_limits::max)() >> LeadingZeros(n); -} - -// The node_handle concept from C++17. -// We specialize node_handle for sets and maps. node_handle_base holds the -// common API of both. -template -class node_handle_base { - protected: - using PolicyTraits = hash_policy_traits; - using slot_type = typename PolicyTraits::slot_type; - - public: - using allocator_type = Alloc; - - constexpr node_handle_base() {} - node_handle_base(node_handle_base&& other) noexcept { - *this = std::move(other); - } - ~node_handle_base() { destroy(); } - node_handle_base& operator=(node_handle_base&& other) { - destroy(); - if (!other.empty()) { - alloc_ = other.alloc_; - PolicyTraits::transfer(alloc(), slot(), other.slot()); - other.reset(); - } - return *this; - } - - bool empty() const noexcept { return !alloc_; } - explicit operator bool() const noexcept { return !empty(); } - allocator_type get_allocator() const { return *alloc_; } - - protected: - template - friend class raw_hash_set; - - node_handle_base(const allocator_type& a, slot_type* s) : alloc_(a) { - PolicyTraits::transfer(alloc(), slot(), s); - } - - void destroy() { - if (!empty()) { - PolicyTraits::destroy(alloc(), slot()); - reset(); - } - } - - void reset() { - assert(alloc_.has_value()); - alloc_ = absl::nullopt; - } - - slot_type* slot() const { - assert(!empty()); - return reinterpret_cast(std::addressof(slot_space_)); - } - allocator_type* alloc() { return std::addressof(*alloc_); } - - private: - absl::optional alloc_; - mutable absl::aligned_storage_t - slot_space_; -}; - -// For sets. -template -class node_handle : public node_handle_base { - using Base = typename node_handle::node_handle_base; - - public: - using value_type = typename Base::PolicyTraits::value_type; - - constexpr node_handle() {} - - value_type& value() const { - return Base::PolicyTraits::element(this->slot()); - } - - private: - template - friend class raw_hash_set; - - node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {} -}; - -// For maps. -template -class node_handle> - : public node_handle_base { - using Base = typename node_handle::node_handle_base; - - public: - using key_type = typename Policy::key_type; - using mapped_type = typename Policy::mapped_type; - - constexpr node_handle() {} - - auto key() const -> decltype(Base::PolicyTraits::key(this->slot())) { - return Base::PolicyTraits::key(this->slot()); - } - - mapped_type& mapped() const { - return Base::PolicyTraits::value( - &Base::PolicyTraits::element(this->slot())); - } - - private: - template - friend class raw_hash_set; - - node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {} -}; - -// Implement the insert_return_type<> concept of C++17. -template -struct insert_return_type { - Iterator position; - bool inserted; - NodeType node; -}; - -// Helper trait to allow or disallow arbitrary keys when the hash and -// eq functions are transparent. -// It is very important that the inner template is an alias and that the type it -// produces is not a dependent type. Otherwise, type deduction would fail. -template -struct KeyArg { - // Transparent. Forward `K`. - template - using type = K; -}; - -template <> -struct KeyArg { - // Not transparent. Always use `key_type`. - template - using type = key_type; -}; - -// Policy: a policy defines how to perform different operations on -// the slots of the hashtable (see hash_policy_traits.h for the full interface -// of policy). -// -// Hash: a (possibly polymorphic) functor that hashes keys of the hashtable. The -// functor should accept a key and return size_t as hash. For best performance -// it is important that the hash function provides high entropy across all bits -// of the hash. -// -// Eq: a (possibly polymorphic) functor that compares two keys for equality. It -// should accept two (of possibly different type) keys and return a bool: true -// if they are equal, false if they are not. If two keys compare equal, then -// their hash values as defined by Hash MUST be equal. -// -// Allocator: an Allocator [http://devdocs.io/cpp/concept/allocator] with which -// the storage of the hashtable will be allocated and the elements will be -// constructed and destroyed. -template -class raw_hash_set { - using PolicyTraits = hash_policy_traits; - using KeyArgImpl = container_internal::KeyArg::value && - IsTransparent::value>; - - public: - using init_type = typename PolicyTraits::init_type; - using key_type = typename PolicyTraits::key_type; - // TODO(sbenza): Hide slot_type as it is an implementation detail. Needs user - // code fixes! - using slot_type = typename PolicyTraits::slot_type; - using allocator_type = Alloc; - using size_type = size_t; - using difference_type = ptrdiff_t; - using hasher = Hash; - using key_equal = Eq; - using policy_type = Policy; - using value_type = typename PolicyTraits::value_type; - using reference = value_type&; - using const_reference = const value_type&; - using pointer = typename absl::allocator_traits< - allocator_type>::template rebind_traits::pointer; - using const_pointer = typename absl::allocator_traits< - allocator_type>::template rebind_traits::const_pointer; - - // Alias used for heterogeneous lookup functions. - // `key_arg` evaluates to `K` when the functors are transparent and to - // `key_type` otherwise. It permits template argument deduction on `K` for the - // transparent case. - template - using key_arg = typename KeyArgImpl::template type; - - private: - // Give an early error when key_type is not hashable/eq. - auto KeyTypeCanBeHashed(const Hash& h, const key_type& k) -> decltype(h(k)); - auto KeyTypeCanBeEq(const Eq& eq, const key_type& k) -> decltype(eq(k, k)); - - using Layout = absl::container_internal::Layout; - - static Layout MakeLayout(size_t capacity) { - assert(IsValidCapacity(capacity)); - return Layout(capacity + Group::kWidth + 1, capacity); - } - - using AllocTraits = absl::allocator_traits; - using SlotAlloc = typename absl::allocator_traits< - allocator_type>::template rebind_alloc; - using SlotAllocTraits = typename absl::allocator_traits< - allocator_type>::template rebind_traits; - - static_assert(std::is_lvalue_reference::value, - "Policy::element() must return a reference"); - - template - struct SameAsElementReference - : std::is_same::type>::type, - typename std::remove_cv< - typename std::remove_reference::type>::type> {}; - - // An enabler for insert(T&&): T must be convertible to init_type or be the - // same as [cv] value_type [ref]. - // Note: we separate SameAsElementReference into its own type to avoid using - // reference unless we need to. MSVC doesn't seem to like it in some - // cases. - template - using RequiresInsertable = typename std::enable_if< - absl::disjunction, - SameAsElementReference>::value, - int>::type; - - // RequiresNotInit is a workaround for gcc prior to 7.1. - // See https://godbolt.org/g/Y4xsUh. - template - using RequiresNotInit = - typename std::enable_if::value, int>::type; - - template - using IsDecomposable = IsDecomposable; - - public: - static_assert(std::is_same::value, - "Allocators with custom pointer types are not supported"); - static_assert(std::is_same::value, - "Allocators with custom pointer types are not supported"); - - class iterator { - friend class raw_hash_set; - - public: - using iterator_category = std::forward_iterator_tag; - using value_type = typename raw_hash_set::value_type; - using reference = - absl::conditional_t; - using pointer = absl::remove_reference_t*; - using difference_type = typename raw_hash_set::difference_type; - - iterator() {} - - // PRECONDITION: not an end() iterator. - reference operator*() const { return PolicyTraits::element(slot_); } - - // PRECONDITION: not an end() iterator. - pointer operator->() const { return &operator*(); } - - // PRECONDITION: not an end() iterator. - iterator& operator++() { - ++ctrl_; - ++slot_; - skip_empty_or_deleted(); - return *this; - } - // PRECONDITION: not an end() iterator. - iterator operator++(int) { - auto tmp = *this; - ++*this; - return tmp; - } - - friend bool operator==(const iterator& a, const iterator& b) { - return a.ctrl_ == b.ctrl_; - } - friend bool operator!=(const iterator& a, const iterator& b) { - return !(a == b); - } - - private: - iterator(ctrl_t* ctrl) : ctrl_(ctrl) {} // for end() - iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) {} - - void skip_empty_or_deleted() { - while (IsEmptyOrDeleted(*ctrl_)) { - // ctrl is not necessarily aligned to Group::kWidth. It is also likely - // to read past the space for ctrl bytes and into slots. This is ok - // because ctrl has sizeof() == 1 and slot has sizeof() >= 1 so there - // is no way to read outside the combined slot array. - uint32_t shift = Group{ctrl_}.CountLeadingEmptyOrDeleted(); - ctrl_ += shift; - slot_ += shift; - } - } - - ctrl_t* ctrl_ = nullptr; - slot_type* slot_; - }; - - class const_iterator { - friend class raw_hash_set; - - public: - using iterator_category = typename iterator::iterator_category; - using value_type = typename raw_hash_set::value_type; - using reference = typename raw_hash_set::const_reference; - using pointer = typename raw_hash_set::const_pointer; - using difference_type = typename raw_hash_set::difference_type; - - const_iterator() {} - // Implicit construction from iterator. - const_iterator(iterator i) : inner_(std::move(i)) {} - - reference operator*() const { return *inner_; } - pointer operator->() const { return inner_.operator->(); } - - const_iterator& operator++() { - ++inner_; - return *this; - } - const_iterator operator++(int) { return inner_++; } - - friend bool operator==(const const_iterator& a, const const_iterator& b) { - return a.inner_ == b.inner_; - } - friend bool operator!=(const const_iterator& a, const const_iterator& b) { - return !(a == b); - } - - private: - const_iterator(const ctrl_t* ctrl, const slot_type* slot) - : inner_(const_cast(ctrl), const_cast(slot)) {} - - iterator inner_; - }; - - using node_type = container_internal::node_handle; - - raw_hash_set() noexcept( - std::is_nothrow_default_constructible::value&& - std::is_nothrow_default_constructible::value&& - std::is_nothrow_default_constructible::value) {} - - explicit raw_hash_set(size_t bucket_count, const hasher& hash = hasher(), - const key_equal& eq = key_equal(), - const allocator_type& alloc = allocator_type()) - : ctrl_(EmptyGroup()), settings_(0, hash, eq, alloc) { - if (bucket_count) { - capacity_ = NormalizeCapacity(bucket_count); - growth_left() = static_cast(capacity_ * kMaxLoadFactor); - initialize_slots(); - } - } - - raw_hash_set(size_t bucket_count, const hasher& hash, - const allocator_type& alloc) - : raw_hash_set(bucket_count, hash, key_equal(), alloc) {} - - raw_hash_set(size_t bucket_count, const allocator_type& alloc) - : raw_hash_set(bucket_count, hasher(), key_equal(), alloc) {} - - explicit raw_hash_set(const allocator_type& alloc) - : raw_hash_set(0, hasher(), key_equal(), alloc) {} - - template - raw_hash_set(InputIter first, InputIter last, size_t bucket_count = 0, - const hasher& hash = hasher(), const key_equal& eq = key_equal(), - const allocator_type& alloc = allocator_type()) - : raw_hash_set(bucket_count, hash, eq, alloc) { - insert(first, last); - } - - template - raw_hash_set(InputIter first, InputIter last, size_t bucket_count, - const hasher& hash, const allocator_type& alloc) - : raw_hash_set(first, last, bucket_count, hash, key_equal(), alloc) {} - - template - raw_hash_set(InputIter first, InputIter last, size_t bucket_count, - const allocator_type& alloc) - : raw_hash_set(first, last, bucket_count, hasher(), key_equal(), alloc) {} - - template - raw_hash_set(InputIter first, InputIter last, const allocator_type& alloc) - : raw_hash_set(first, last, 0, hasher(), key_equal(), alloc) {} - - // Instead of accepting std::initializer_list as the first - // argument like std::unordered_set does, we have two overloads - // that accept std::initializer_list and std::initializer_list. - // This is advantageous for performance. - // - // // Turns {"abc", "def"} into std::initializer_list, then copies - // // the strings into the set. - // std::unordered_set s = {"abc", "def"}; - // - // // Turns {"abc", "def"} into std::initializer_list, then - // // copies the strings into the set. - // absl::flat_hash_set s = {"abc", "def"}; - // - // The same trick is used in insert(). - // - // The enabler is necessary to prevent this constructor from triggering where - // the copy constructor is meant to be called. - // - // absl::flat_hash_set a, b{a}; - // - // RequiresNotInit is a workaround for gcc prior to 7.1. - template = 0, RequiresInsertable = 0> - raw_hash_set(std::initializer_list init, size_t bucket_count = 0, - const hasher& hash = hasher(), const key_equal& eq = key_equal(), - const allocator_type& alloc = allocator_type()) - : raw_hash_set(init.begin(), init.end(), bucket_count, hash, eq, alloc) {} - - raw_hash_set(std::initializer_list init, size_t bucket_count = 0, - const hasher& hash = hasher(), const key_equal& eq = key_equal(), - const allocator_type& alloc = allocator_type()) - : raw_hash_set(init.begin(), init.end(), bucket_count, hash, eq, alloc) {} - - template = 0, RequiresInsertable = 0> - raw_hash_set(std::initializer_list init, size_t bucket_count, - const hasher& hash, const allocator_type& alloc) - : raw_hash_set(init, bucket_count, hash, key_equal(), alloc) {} - - raw_hash_set(std::initializer_list init, size_t bucket_count, - const hasher& hash, const allocator_type& alloc) - : raw_hash_set(init, bucket_count, hash, key_equal(), alloc) {} - - template = 0, RequiresInsertable = 0> - raw_hash_set(std::initializer_list init, size_t bucket_count, - const allocator_type& alloc) - : raw_hash_set(init, bucket_count, hasher(), key_equal(), alloc) {} - - raw_hash_set(std::initializer_list init, size_t bucket_count, - const allocator_type& alloc) - : raw_hash_set(init, bucket_count, hasher(), key_equal(), alloc) {} - - template = 0, RequiresInsertable = 0> - raw_hash_set(std::initializer_list init, const allocator_type& alloc) - : raw_hash_set(init, 0, hasher(), key_equal(), alloc) {} - - raw_hash_set(std::initializer_list init, - const allocator_type& alloc) - : raw_hash_set(init, 0, hasher(), key_equal(), alloc) {} - - raw_hash_set(const raw_hash_set& that) - : raw_hash_set(that, AllocTraits::select_on_container_copy_construction( - that.alloc_ref())) {} - - raw_hash_set(const raw_hash_set& that, const allocator_type& a) - : raw_hash_set(0, that.hash_ref(), that.eq_ref(), a) { - reserve(that.size()); - // Because the table is guaranteed to be empty, we can do something faster - // than a full `insert`. - for (const auto& v : that) { - const size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, v); - const size_t i = find_first_non_full(hash); - set_ctrl(i, H2(hash)); - emplace_at(i, v); - } - size_ = that.size(); - growth_left() -= that.size(); - } - - raw_hash_set(raw_hash_set&& that) noexcept( - std::is_nothrow_copy_constructible::value&& - std::is_nothrow_copy_constructible::value&& - std::is_nothrow_copy_constructible::value) - : ctrl_(absl::exchange(that.ctrl_, EmptyGroup())), - slots_(absl::exchange(that.slots_, nullptr)), - size_(absl::exchange(that.size_, 0)), - capacity_(absl::exchange(that.capacity_, 0)), - // Hash, equality and allocator are copied instead of moved because - // `that` must be left valid. If Hash is std::function, moving it - // would create a nullptr functor that cannot be called. - settings_(that.settings_) { - // growth_left was copied above, reset the one from `that`. - that.growth_left() = 0; - } - - raw_hash_set(raw_hash_set&& that, const allocator_type& a) - : ctrl_(EmptyGroup()), - slots_(nullptr), - size_(0), - capacity_(0), - settings_(0, that.hash_ref(), that.eq_ref(), a) { - if (a == that.alloc_ref()) { - std::swap(ctrl_, that.ctrl_); - std::swap(slots_, that.slots_); - std::swap(size_, that.size_); - std::swap(capacity_, that.capacity_); - std::swap(growth_left(), that.growth_left()); - } else { - reserve(that.size()); - // Note: this will copy elements of dense_set and unordered_set instead of - // moving them. This can be fixed if it ever becomes an issue. - for (auto& elem : that) insert(std::move(elem)); - } - } - - raw_hash_set& operator=(const raw_hash_set& that) { - raw_hash_set tmp(that, - AllocTraits::propagate_on_container_copy_assignment::value - ? that.alloc_ref() - : alloc_ref()); - swap(tmp); - return *this; - } - - raw_hash_set& operator=(raw_hash_set&& that) noexcept( - absl::allocator_traits::is_always_equal::value&& - std::is_nothrow_move_assignable::value&& - std::is_nothrow_move_assignable::value) { - // TODO(sbenza): We should only use the operations from the noexcept clause - // to make sure we actually adhere to that contract. - return move_assign( - std::move(that), - typename AllocTraits::propagate_on_container_move_assignment()); - } - - ~raw_hash_set() { destroy_slots(); } - - iterator begin() { - auto it = iterator_at(0); - it.skip_empty_or_deleted(); - return it; - } - iterator end() { return {ctrl_ + capacity_}; } - - const_iterator begin() const { - return const_cast(this)->begin(); - } - const_iterator end() const { return const_cast(this)->end(); } - const_iterator cbegin() const { return begin(); } - const_iterator cend() const { return end(); } - - bool empty() const { return !size(); } - size_t size() const { return size_; } - size_t capacity() const { return capacity_; } - size_t max_size() const { return (std::numeric_limits::max)(); } - - void clear() { - // Iterating over this container is O(bucket_count()). When bucket_count() - // is much greater than size(), iteration becomes prohibitively expensive. - // For clear() it is more important to reuse the allocated array when the - // container is small because allocation takes comparatively long time - // compared to destruction of the elements of the container. So we pick the - // largest bucket_count() threshold for which iteration is still fast and - // past that we simply deallocate the array. - if (capacity_ > 127) { - destroy_slots(); - } else if (capacity_) { - for (size_t i = 0; i != capacity_; ++i) { - if (IsFull(ctrl_[i])) { - PolicyTraits::destroy(&alloc_ref(), slots_ + i); - } - } - size_ = 0; - reset_ctrl(); - growth_left() = static_cast(capacity_ * kMaxLoadFactor); - } - assert(empty()); - } - - // This overload kicks in when the argument is an rvalue of insertable and - // decomposable type other than init_type. - // - // flat_hash_map m; - // m.insert(std::make_pair("abc", 42)); - template = 0, - typename std::enable_if::value, int>::type = 0, - T* = nullptr> - std::pair insert(T&& value) { - return emplace(std::forward(value)); - } - - // This overload kicks in when the argument is a bitfield or an lvalue of - // insertable and decomposable type. - // - // union { int n : 1; }; - // flat_hash_set s; - // s.insert(n); - // - // flat_hash_set s; - // const char* p = "hello"; - // s.insert(p); - // - // TODO(romanp): Once we stop supporting gcc 5.1 and below, replace - // RequiresInsertable with RequiresInsertable. - // We are hitting this bug: https://godbolt.org/g/1Vht4f. - template < - class T, RequiresInsertable = 0, - typename std::enable_if::value, int>::type = 0> - std::pair insert(const T& value) { - return emplace(value); - } - - // This overload kicks in when the argument is an rvalue of init_type. Its - // purpose is to handle brace-init-list arguments. - // - // flat_hash_set s; - // s.insert({"abc", 42}); - std::pair insert(init_type&& value) { - return emplace(std::move(value)); - } - - template = 0, - typename std::enable_if::value, int>::type = 0, - T* = nullptr> - iterator insert(const_iterator, T&& value) { - return insert(std::forward(value)).first; - } - - // TODO(romanp): Once we stop supporting gcc 5.1 and below, replace - // RequiresInsertable with RequiresInsertable. - // We are hitting this bug: https://godbolt.org/g/1Vht4f. - template < - class T, RequiresInsertable = 0, - typename std::enable_if::value, int>::type = 0> - iterator insert(const_iterator, const T& value) { - return insert(value).first; - } - - iterator insert(const_iterator, init_type&& value) { - return insert(std::move(value)).first; - } - - template - void insert(InputIt first, InputIt last) { - for (; first != last; ++first) insert(*first); - } - - template = 0, RequiresInsertable = 0> - void insert(std::initializer_list ilist) { - insert(ilist.begin(), ilist.end()); - } - - void insert(std::initializer_list ilist) { - insert(ilist.begin(), ilist.end()); - } - - insert_return_type insert(node_type&& node) { - if (!node) return {end(), false, node_type()}; - const auto& elem = PolicyTraits::element(node.slot()); - auto res = PolicyTraits::apply( - InsertSlot{*this, std::move(*node.slot())}, elem); - if (res.second) { - node.reset(); - return {res.first, true, node_type()}; - } else { - return {res.first, false, std::move(node)}; - } - } - - iterator insert(const_iterator, node_type&& node) { - return insert(std::move(node)).first; - } - - // This overload kicks in if we can deduce the key from args. This enables us - // to avoid constructing value_type if an entry with the same key already - // exists. - // - // For example: - // - // flat_hash_map m = {{"abc", "def"}}; - // // Creates no std::string copies and makes no heap allocations. - // m.emplace("abc", "xyz"); - template ::value, int>::type = 0> - std::pair emplace(Args&&... args) { - return PolicyTraits::apply(EmplaceDecomposable{*this}, - std::forward(args)...); - } - - // This overload kicks in if we cannot deduce the key from args. It constructs - // value_type unconditionally and then either moves it into the table or - // destroys. - template ::value, int>::type = 0> - std::pair emplace(Args&&... args) { - typename std::aligned_storage::type - raw; - slot_type* slot = reinterpret_cast(&raw); - - PolicyTraits::construct(&alloc_ref(), slot, std::forward(args)...); - const auto& elem = PolicyTraits::element(slot); - return PolicyTraits::apply(InsertSlot{*this, std::move(*slot)}, elem); - } - - template - iterator emplace_hint(const_iterator, Args&&... args) { - return emplace(std::forward(args)...).first; - } - - // Extension API: support for lazy emplace. - // - // Looks up key in the table. If found, returns the iterator to the element. - // Otherwise calls f with one argument of type raw_hash_set::constructor. f - // MUST call raw_hash_set::constructor with arguments as if a - // raw_hash_set::value_type is constructed, otherwise the behavior is - // undefined. - // - // For example: - // - // std::unordered_set s; - // // Makes ArenaStr even if "abc" is in the map. - // s.insert(ArenaString(&arena, "abc")); - // - // flat_hash_set s; - // // Makes ArenaStr only if "abc" is not in the map. - // s.lazy_emplace("abc", [&](const constructor& ctor) { - // ctor(&arena, "abc"); - // }); - // - // WARNING: This API is currently experimental. If there is a way to implement - // the same thing with the rest of the API, prefer that. - class constructor { - friend class raw_hash_set; - - public: - template - void operator()(Args&&... args) const { - assert(*slot_); - PolicyTraits::construct(alloc_, *slot_, std::forward(args)...); - *slot_ = nullptr; - } - - private: - constructor(allocator_type* a, slot_type** slot) : alloc_(a), slot_(slot) {} - - allocator_type* alloc_; - slot_type** slot_; - }; - - template - iterator lazy_emplace(const key_arg& key, F&& f) { - auto res = find_or_prepare_insert(key); - if (res.second) { - slot_type* slot = slots_ + res.first; - std::forward(f)(constructor(&alloc_ref(), &slot)); - assert(!slot); - } - return iterator_at(res.first); - } - - // Extension API: support for heterogeneous keys. - // - // std::unordered_set s; - // // Turns "abc" into std::string. - // s.erase("abc"); - // - // flat_hash_set s; - // // Uses "abc" directly without copying it into std::string. - // s.erase("abc"); - template - size_type erase(const key_arg& key) { - auto it = find(key); - if (it == end()) return 0; - erase(it); - return 1; - } - - // Erases the element pointed to by `it`. Unlike `std::unordered_set::erase`, - // this method returns void to reduce algorithmic complexity to O(1). In - // order to erase while iterating across a map, use the following idiom (which - // also works for standard containers): - // - // for (auto it = m.begin(), end = m.end(); it != end;) { - // if () { - // m.erase(it++); - // } else { - // ++it; - // } - // } - void erase(const_iterator cit) { erase(cit.inner_); } - - // This overload is necessary because otherwise erase(const K&) would be - // a better match if non-const iterator is passed as an argument. - void erase(iterator it) { - assert(it != end()); - PolicyTraits::destroy(&alloc_ref(), it.slot_); - erase_meta_only(it); - } - - iterator erase(const_iterator first, const_iterator last) { - while (first != last) { - erase(first++); - } - return last.inner_; - } - - // Moves elements from `src` into `this`. - // If the element already exists in `this`, it is left unmodified in `src`. - template - void merge(raw_hash_set& src) { // NOLINT - assert(this != &src); - for (auto it = src.begin(), e = src.end(); it != e; ++it) { - if (PolicyTraits::apply(InsertSlot{*this, std::move(*it.slot_)}, - PolicyTraits::element(it.slot_)) - .second) { - src.erase_meta_only(it); - } - } - } - - template - void merge(raw_hash_set&& src) { - merge(src); - } - - node_type extract(const_iterator position) { - node_type node(alloc_ref(), position.inner_.slot_); - erase_meta_only(position); - return node; - } - - template < - class K = key_type, - typename std::enable_if::value, int>::type = 0> - node_type extract(const key_arg& key) { - auto it = find(key); - return it == end() ? node_type() : extract(const_iterator{it}); - } - - void swap(raw_hash_set& that) noexcept( - IsNoThrowSwappable() && IsNoThrowSwappable() && - (!AllocTraits::propagate_on_container_swap::value || - IsNoThrowSwappable())) { - using std::swap; - swap(ctrl_, that.ctrl_); - swap(slots_, that.slots_); - swap(size_, that.size_); - swap(capacity_, that.capacity_); - swap(growth_left(), that.growth_left()); - swap(hash_ref(), that.hash_ref()); - swap(eq_ref(), that.eq_ref()); - if (AllocTraits::propagate_on_container_swap::value) { - swap(alloc_ref(), that.alloc_ref()); - } else { - // If the allocators do not compare equal it is officially undefined - // behavior. We choose to do nothing. - } - } - - void rehash(size_t n) { - if (n == 0 && capacity_ == 0) return; - if (n == 0 && size_ == 0) return destroy_slots(); - auto m = NormalizeCapacity(std::max(n, NumSlotsFast(size()))); - // n == 0 unconditionally rehashes as per the standard. - if (n == 0 || m > capacity_) { - resize(m); - } - } - - void reserve(size_t n) { - rehash(NumSlotsFast(n)); - } - - // Extension API: support for heterogeneous keys. - // - // std::unordered_set s; - // // Turns "abc" into std::string. - // s.count("abc"); - // - // ch_set s; - // // Uses "abc" directly without copying it into std::string. - // s.count("abc"); - template - size_t count(const key_arg& key) const { - return find(key) == end() ? 0 : 1; - } - - // Issues CPU prefetch instructions for the memory needed to find or insert - // a key. Like all lookup functions, this support heterogeneous keys. - // - // NOTE: This is a very low level operation and should not be used without - // specific benchmarks indicating its importance. - template - void prefetch(const key_arg& key) const { - (void)key; -#if defined(__GNUC__) - auto seq = probe(hash_ref()(key)); - __builtin_prefetch(static_cast(ctrl_ + seq.offset())); - __builtin_prefetch(static_cast(slots_ + seq.offset())); -#endif // __GNUC__ - } - - // The API of find() has two extensions. - // - // 1. The hash can be passed by the user. It must be equal to the hash of the - // key. - // - // 2. The type of the key argument doesn't have to be key_type. This is so - // called heterogeneous key support. - template - iterator find(const key_arg& key, size_t hash) { - auto seq = probe(hash); - while (true) { - Group g{ctrl_ + seq.offset()}; - for (int i : g.Match(H2(hash))) { - if (ABSL_PREDICT_TRUE(PolicyTraits::apply( - EqualElement{key, eq_ref()}, - PolicyTraits::element(slots_ + seq.offset(i))))) - return iterator_at(seq.offset(i)); - } - if (ABSL_PREDICT_TRUE(g.MatchEmpty())) return end(); - seq.next(); - } - } - template - iterator find(const key_arg& key) { - return find(key, hash_ref()(key)); - } - - template - const_iterator find(const key_arg& key, size_t hash) const { - return const_cast(this)->find(key, hash); - } - template - const_iterator find(const key_arg& key) const { - return find(key, hash_ref()(key)); - } - - template - bool contains(const key_arg& key) const { - return find(key) != end(); - } - - template - std::pair equal_range(const key_arg& key) { - auto it = find(key); - if (it != end()) return {it, std::next(it)}; - return {it, it}; - } - template - std::pair equal_range( - const key_arg& key) const { - auto it = find(key); - if (it != end()) return {it, std::next(it)}; - return {it, it}; - } - - size_t bucket_count() const { return capacity_; } - float load_factor() const { - return capacity_ ? static_cast(size()) / capacity_ : 0.0; - } - float max_load_factor() const { return 1.0f; } - void max_load_factor(float) { - // Does nothing. - } - - hasher hash_function() const { return hash_ref(); } - key_equal key_eq() const { return eq_ref(); } - allocator_type get_allocator() const { return alloc_ref(); } - - friend bool operator==(const raw_hash_set& a, const raw_hash_set& b) { - if (a.size() != b.size()) return false; - const raw_hash_set* outer = &a; - const raw_hash_set* inner = &b; - if (outer->capacity() > inner->capacity()) std::swap(outer, inner); - for (const value_type& elem : *outer) - if (!inner->has_element(elem)) return false; - return true; - } - - friend bool operator!=(const raw_hash_set& a, const raw_hash_set& b) { - return !(a == b); - } - - friend void swap(raw_hash_set& a, - raw_hash_set& b) noexcept(noexcept(a.swap(b))) { - a.swap(b); - } - - private: - template - friend struct absl::container_internal::hashtable_debug_internal:: - HashtableDebugAccess; - - struct FindElement { - template - const_iterator operator()(const K& key, Args&&...) const { - return s.find(key); - } - const raw_hash_set& s; - }; - - struct HashElement { - template - size_t operator()(const K& key, Args&&...) const { - return h(key); - } - const hasher& h; - }; - - template - struct EqualElement { - template - bool operator()(const K2& lhs, Args&&...) const { - return eq(lhs, rhs); - } - const K1& rhs; - const key_equal& eq; - }; - - struct EmplaceDecomposable { - template - std::pair operator()(const K& key, Args&&... args) const { - auto res = s.find_or_prepare_insert(key); - if (res.second) { - s.emplace_at(res.first, std::forward(args)...); - } - return {s.iterator_at(res.first), res.second}; - } - raw_hash_set& s; - }; - - template - struct InsertSlot { - template - std::pair operator()(const K& key, Args&&...) && { - auto res = s.find_or_prepare_insert(key); - if (res.second) { - PolicyTraits::transfer(&s.alloc_ref(), s.slots_ + res.first, &slot); - } else if (do_destroy) { - PolicyTraits::destroy(&s.alloc_ref(), &slot); - } - return {s.iterator_at(res.first), res.second}; - } - raw_hash_set& s; - // Constructed slot. Either moved into place or destroyed. - slot_type&& slot; - }; - - // Computes std::ceil(n / kMaxLoadFactor). Faster than calling std::ceil. - static inline size_t NumSlotsFast(size_t n) { - return static_cast( - (n * kMaxLoadFactorDenominator + (kMaxLoadFactorNumerator - 1)) / - kMaxLoadFactorNumerator); - } - - // "erases" the object from the container, except that it doesn't actually - // destroy the object. It only updates all the metadata of the class. - // This can be used in conjunction with Policy::transfer to move the object to - // another place. - void erase_meta_only(const_iterator it) { - assert(IsFull(*it.inner_.ctrl_) && "erasing a dangling iterator"); - --size_; - const size_t index = it.inner_.ctrl_ - ctrl_; - const size_t index_before = (index - Group::kWidth) & capacity_; - const auto empty_after = Group(it.inner_.ctrl_).MatchEmpty(); - const auto empty_before = Group(ctrl_ + index_before).MatchEmpty(); - - // We count how many consecutive non empties we have to the right and to the - // left of `it`. If the sum is >= kWidth then there is at least one probe - // window that might have seen a full group. - bool was_never_full = - empty_before && empty_after && - static_cast(empty_after.TrailingZeros() + - empty_before.LeadingZeros()) < Group::kWidth; - - set_ctrl(index, was_never_full ? kEmpty : kDeleted); - growth_left() += was_never_full; - } - - void initialize_slots() { - assert(capacity_); - auto layout = MakeLayout(capacity_); - char* mem = static_cast( - Allocate(&alloc_ref(), layout.AllocSize())); - ctrl_ = reinterpret_cast(layout.template Pointer<0>(mem)); - slots_ = layout.template Pointer<1>(mem); - reset_ctrl(); - growth_left() = static_cast(capacity_ * kMaxLoadFactor) - size_; - } - - void destroy_slots() { - if (!capacity_) return; - for (size_t i = 0; i != capacity_; ++i) { - if (IsFull(ctrl_[i])) { - PolicyTraits::destroy(&alloc_ref(), slots_ + i); - } - } - auto layout = MakeLayout(capacity_); - // Unpoison before returning the memory to the allocator. - SanitizerUnpoisonMemoryRegion(slots_, sizeof(slot_type) * capacity_); - Deallocate(&alloc_ref(), ctrl_, layout.AllocSize()); - ctrl_ = EmptyGroup(); - slots_ = nullptr; - size_ = 0; - capacity_ = 0; - growth_left() = 0; - } - - void resize(size_t new_capacity) { - assert(IsValidCapacity(new_capacity)); - auto* old_ctrl = ctrl_; - auto* old_slots = slots_; - const size_t old_capacity = capacity_; - capacity_ = new_capacity; - initialize_slots(); - - for (size_t i = 0; i != old_capacity; ++i) { - if (IsFull(old_ctrl[i])) { - size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, - PolicyTraits::element(old_slots + i)); - size_t new_i = find_first_non_full(hash); - set_ctrl(new_i, H2(hash)); - PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, old_slots + i); - } - } - if (old_capacity) { - SanitizerUnpoisonMemoryRegion(old_slots, - sizeof(slot_type) * old_capacity); - auto layout = MakeLayout(old_capacity); - Deallocate(&alloc_ref(), old_ctrl, - layout.AllocSize()); - } - } - - void drop_deletes_without_resize() ABSL_ATTRIBUTE_NOINLINE { - assert(IsValidCapacity(capacity_)); - // Algorithm: - // - mark all DELETED slots as EMPTY - // - mark all FULL slots as DELETED - // - for each slot marked as DELETED - // hash = Hash(element) - // target = find_first_non_full(hash) - // if target is in the same group - // mark slot as FULL - // else if target is EMPTY - // transfer element to target - // mark slot as EMPTY - // mark target as FULL - // else if target is DELETED - // swap current element with target element - // mark target as FULL - // repeat procedure for current slot with moved from element (target) - ConvertDeletedToEmptyAndFullToDeleted(ctrl_, capacity_); - typename std::aligned_storage::type - raw; - slot_type* slot = reinterpret_cast(&raw); - for (size_t i = 0; i != capacity_; ++i) { - if (!IsDeleted(ctrl_[i])) continue; - size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, - PolicyTraits::element(slots_ + i)); - size_t new_i = find_first_non_full(hash); - - // Verify if the old and new i fall within the same group wrt the hash. - // If they do, we don't need to move the object as it falls already in the - // best probe we can. - const auto probe_index = [&](size_t pos) { - return ((pos - probe(hash).offset()) & capacity_) / Group::kWidth; - }; - - // Element doesn't move. - if (ABSL_PREDICT_TRUE(probe_index(new_i) == probe_index(i))) { - set_ctrl(i, H2(hash)); - continue; - } - if (IsEmpty(ctrl_[new_i])) { - // Transfer element to the empty spot. - // set_ctrl poisons/unpoisons the slots so we have to call it at the - // right time. - set_ctrl(new_i, H2(hash)); - PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, slots_ + i); - set_ctrl(i, kEmpty); - } else { - assert(IsDeleted(ctrl_[new_i])); - set_ctrl(new_i, H2(hash)); - // Until we are done rehashing, DELETED marks previously FULL slots. - // Swap i and new_i elements. - PolicyTraits::transfer(&alloc_ref(), slot, slots_ + i); - PolicyTraits::transfer(&alloc_ref(), slots_ + i, slots_ + new_i); - PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, slot); - --i; // repeat - } - } - growth_left() = static_cast(capacity_ * kMaxLoadFactor) - size_; - } - - void rehash_and_grow_if_necessary() { - if (capacity_ == 0) { - resize(Group::kWidth - 1); - } else if (size() <= kMaxLoadFactor / 2 * capacity_) { - // Squash DELETED without growing if there is enough capacity. - drop_deletes_without_resize(); - } else { - // Otherwise grow the container. - resize(capacity_ * 2 + 1); - } - } - - bool has_element(const value_type& elem) const { - size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, elem); - auto seq = probe(hash); - while (true) { - Group g{ctrl_ + seq.offset()}; - for (int i : g.Match(H2(hash))) { - if (ABSL_PREDICT_TRUE(PolicyTraits::element(slots_ + seq.offset(i)) == - elem)) - return true; - } - if (ABSL_PREDICT_TRUE(g.MatchEmpty())) return false; - seq.next(); - assert(seq.index() < capacity_ && "full table!"); - } - return false; - } - - // Probes the raw_hash_set with the probe sequence for hash and returns the - // pointer to the first empty or deleted slot. - // NOTE: this function must work with tables having both kEmpty and kDelete - // in one group. Such tables appears during drop_deletes_without_resize. - // - // This function is very useful when insertions happen and: - // - the input is already a set - // - there are enough slots - // - the element with the hash is not in the table - size_t find_first_non_full(size_t hash) { - auto seq = probe(hash); - while (true) { - Group g{ctrl_ + seq.offset()}; - auto mask = g.MatchEmptyOrDeleted(); - if (mask) { -#if !defined(NDEBUG) - // We want to force small tables to have random entries too, so - // in debug build we will randomly insert in either the front or back of - // the group. - // TODO(kfm,sbenza): revisit after we do unconditional mixing - if (ShouldInsertBackwards(hash, ctrl_)) - return seq.offset(mask.HighestBitSet()); - else - return seq.offset(mask.LowestBitSet()); -#else - return seq.offset(mask.LowestBitSet()); -#endif - } - assert(seq.index() < capacity_ && "full table!"); - seq.next(); - } - } - - // TODO(alkis): Optimize this assuming *this and that don't overlap. - raw_hash_set& move_assign(raw_hash_set&& that, std::true_type) { - raw_hash_set tmp(std::move(that)); - swap(tmp); - return *this; - } - raw_hash_set& move_assign(raw_hash_set&& that, std::false_type) { - raw_hash_set tmp(std::move(that), alloc_ref()); - swap(tmp); - return *this; - } - - protected: - template - std::pair find_or_prepare_insert(const K& key) { - auto hash = hash_ref()(key); - auto seq = probe(hash); - while (true) { - Group g{ctrl_ + seq.offset()}; - for (int i : g.Match(H2(hash))) { - if (ABSL_PREDICT_TRUE(PolicyTraits::apply( - EqualElement{key, eq_ref()}, - PolicyTraits::element(slots_ + seq.offset(i))))) - return {seq.offset(i), false}; - } - if (ABSL_PREDICT_TRUE(g.MatchEmpty())) break; - seq.next(); - } - return {prepare_insert(hash), true}; - } - - size_t prepare_insert(size_t hash) ABSL_ATTRIBUTE_NOINLINE { - size_t target = find_first_non_full(hash); - if (ABSL_PREDICT_FALSE(growth_left() == 0 && !IsDeleted(ctrl_[target]))) { - rehash_and_grow_if_necessary(); - target = find_first_non_full(hash); - } - ++size_; - growth_left() -= IsEmpty(ctrl_[target]); - set_ctrl(target, H2(hash)); - return target; - } - - // Constructs the value in the space pointed by the iterator. This only works - // after an unsuccessful find_or_prepare_insert() and before any other - // modifications happen in the raw_hash_set. - // - // PRECONDITION: i is an index returned from find_or_prepare_insert(k), where - // k is the key decomposed from `forward(args)...`, and the bool - // returned by find_or_prepare_insert(k) was true. - // POSTCONDITION: *m.iterator_at(i) == value_type(forward(args)...). - template - void emplace_at(size_t i, Args&&... args) { - PolicyTraits::construct(&alloc_ref(), slots_ + i, - std::forward(args)...); - - assert(PolicyTraits::apply(FindElement{*this}, *iterator_at(i)) == - iterator_at(i) && - "constructed value does not match the lookup key"); - } - - iterator iterator_at(size_t i) { return {ctrl_ + i, slots_ + i}; } - const_iterator iterator_at(size_t i) const { return {ctrl_ + i, slots_ + i}; } - - private: - friend struct RawHashSetTestOnlyAccess; - - probe_seq probe(size_t hash) const { - return probe_seq(H1(hash, ctrl_), capacity_); - } - - // Reset all ctrl bytes back to kEmpty, except the sentinel. - void reset_ctrl() { - std::memset(ctrl_, kEmpty, capacity_ + Group::kWidth); - ctrl_[capacity_] = kSentinel; - SanitizerPoisonMemoryRegion(slots_, sizeof(slot_type) * capacity_); - } - - // Sets the control byte, and if `i < Group::kWidth`, set the cloned byte at - // the end too. - void set_ctrl(size_t i, ctrl_t h) { - assert(i < capacity_); - - if (IsFull(h)) { - SanitizerUnpoisonObject(slots_ + i); - } else { - SanitizerPoisonObject(slots_ + i); - } - - ctrl_[i] = h; - ctrl_[((i - Group::kWidth) & capacity_) + Group::kWidth] = h; - } - - size_t& growth_left() { return settings_.template get<0>(); } - - hasher& hash_ref() { return settings_.template get<1>(); } - const hasher& hash_ref() const { return settings_.template get<1>(); } - key_equal& eq_ref() { return settings_.template get<2>(); } - const key_equal& eq_ref() const { return settings_.template get<2>(); } - allocator_type& alloc_ref() { return settings_.template get<3>(); } - const allocator_type& alloc_ref() const { - return settings_.template get<3>(); - } - - // On average each group has 2 empty slot (for the vectorized case). - static constexpr int64_t kMaxLoadFactorNumerator = 14; - static constexpr int64_t kMaxLoadFactorDenominator = 16; - static constexpr float kMaxLoadFactor = - 1.0 * kMaxLoadFactorNumerator / kMaxLoadFactorDenominator; - - // TODO(alkis): Investigate removing some of these fields: - // - ctrl/slots can be derived from each other - // - size can be moved into the slot array - ctrl_t* ctrl_ = EmptyGroup(); // [(capacity + 1) * ctrl_t] - slot_type* slots_ = nullptr; // [capacity * slot_type] - size_t size_ = 0; // number of full slots - size_t capacity_ = 0; // total number of slots - absl::container_internal::CompressedTuple - settings_{0, hasher{}, key_equal{}, allocator_type{}}; -}; - -namespace hashtable_debug_internal { -template -struct HashtableDebugAccess> { - using Traits = typename Set::PolicyTraits; - using Slot = typename Traits::slot_type; - - static size_t GetNumProbes(const Set& set, - const typename Set::key_type& key) { - size_t num_probes = 0; - size_t hash = set.hash_ref()(key); - auto seq = set.probe(hash); - while (true) { - container_internal::Group g{set.ctrl_ + seq.offset()}; - for (int i : g.Match(container_internal::H2(hash))) { - if (Traits::apply( - typename Set::template EqualElement{ - key, set.eq_ref()}, - Traits::element(set.slots_ + seq.offset(i)))) - return num_probes; - ++num_probes; - } - if (g.MatchEmpty()) return num_probes; - seq.next(); - ++num_probes; - } - } - - static size_t AllocatedByteSize(const Set& c) { - size_t capacity = c.capacity_; - if (capacity == 0) return 0; - auto layout = Set::MakeLayout(capacity); - size_t m = layout.AllocSize(); - - size_t per_slot = Traits::space_used(static_cast(nullptr)); - if (per_slot != ~size_t{}) { - m += per_slot * c.size(); - } else { - for (size_t i = 0; i != capacity; ++i) { - if (container_internal::IsFull(c.ctrl_[i])) { - m += Traits::space_used(c.slots_ + i); - } - } - } - return m; - } - - static size_t LowerBoundAllocatedByteSize(size_t size) { - size_t capacity = container_internal::NormalizeCapacity( - std::ceil(size / Set::kMaxLoadFactor)); - if (capacity == 0) return 0; - auto layout = Set::MakeLayout(capacity); - size_t m = layout.AllocSize(); - size_t per_slot = Traits::space_used(static_cast(nullptr)); - if (per_slot != ~size_t{}) { - m += per_slot * size; - } - return m; - } -}; - -} // namespace hashtable_debug_internal -} // namespace container_internal -} // namespace absl - -#endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_ diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc deleted file mode 100644 index 891fa45..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc +++ /dev/null @@ -1,428 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include -#include - -#include "gtest/gtest.h" -#include "absl/container/internal/raw_hash_set.h" -#include "absl/container/internal/tracked.h" - -namespace absl { -namespace container_internal { -namespace { - -enum AllocSpec { - kPropagateOnCopy = 1, - kPropagateOnMove = 2, - kPropagateOnSwap = 4, -}; - -struct AllocState { - size_t num_allocs = 0; - std::set owned; -}; - -template -class CheckedAlloc { - public: - template - friend class CheckedAlloc; - - using value_type = T; - - CheckedAlloc() {} - explicit CheckedAlloc(size_t id) : id_(id) {} - CheckedAlloc(const CheckedAlloc&) = default; - CheckedAlloc& operator=(const CheckedAlloc&) = default; - - template - CheckedAlloc(const CheckedAlloc& that) - : id_(that.id_), state_(that.state_) {} - - template - struct rebind { - using other = CheckedAlloc; - }; - - using propagate_on_container_copy_assignment = - std::integral_constant; - - using propagate_on_container_move_assignment = - std::integral_constant; - - using propagate_on_container_swap = - std::integral_constant; - - CheckedAlloc select_on_container_copy_construction() const { - if (Spec & kPropagateOnCopy) return *this; - return {}; - } - - T* allocate(size_t n) { - T* ptr = std::allocator().allocate(n); - track_alloc(ptr); - return ptr; - } - void deallocate(T* ptr, size_t n) { - memset(ptr, 0, n * sizeof(T)); // The freed memory must be unpoisoned. - track_dealloc(ptr); - return std::allocator().deallocate(ptr, n); - } - - friend bool operator==(const CheckedAlloc& a, const CheckedAlloc& b) { - return a.id_ == b.id_; - } - friend bool operator!=(const CheckedAlloc& a, const CheckedAlloc& b) { - return !(a == b); - } - - size_t num_allocs() const { return state_->num_allocs; } - - void swap(CheckedAlloc& that) { - using std::swap; - swap(id_, that.id_); - swap(state_, that.state_); - } - - friend void swap(CheckedAlloc& a, CheckedAlloc& b) { a.swap(b); } - - friend std::ostream& operator<<(std::ostream& o, const CheckedAlloc& a) { - return o << "alloc(" << a.id_ << ")"; - } - - private: - void track_alloc(void* ptr) { - AllocState* state = state_.get(); - ++state->num_allocs; - if (!state->owned.insert(ptr).second) - ADD_FAILURE() << *this << " got previously allocated memory: " << ptr; - } - void track_dealloc(void* ptr) { - if (state_->owned.erase(ptr) != 1) - ADD_FAILURE() << *this - << " deleting memory owned by another allocator: " << ptr; - } - - size_t id_ = std::numeric_limits::max(); - - std::shared_ptr state_ = std::make_shared(); -}; - -struct Identity { - int32_t operator()(int32_t v) const { return v; } -}; - -struct Policy { - using slot_type = Tracked; - using init_type = Tracked; - using key_type = int32_t; - - template - static void construct(allocator_type* alloc, slot_type* slot, - Args&&... args) { - std::allocator_traits::construct( - *alloc, slot, std::forward(args)...); - } - - template - static void destroy(allocator_type* alloc, slot_type* slot) { - std::allocator_traits::destroy(*alloc, slot); - } - - template - static void transfer(allocator_type* alloc, slot_type* new_slot, - slot_type* old_slot) { - construct(alloc, new_slot, std::move(*old_slot)); - destroy(alloc, old_slot); - } - - template - static auto apply(F&& f, int32_t v) -> decltype(std::forward(f)(v, v)) { - return std::forward(f)(v, v); - } - - template - static auto apply(F&& f, const slot_type& v) - -> decltype(std::forward(f)(v.val(), v)) { - return std::forward(f)(v.val(), v); - } - - template - static auto apply(F&& f, slot_type&& v) - -> decltype(std::forward(f)(v.val(), std::move(v))) { - return std::forward(f)(v.val(), std::move(v)); - } - - static slot_type& element(slot_type* slot) { return *slot; } -}; - -template -struct PropagateTest : public ::testing::Test { - using Alloc = CheckedAlloc, Spec>; - - using Table = raw_hash_set, Alloc>; - - PropagateTest() { - EXPECT_EQ(a1, t1.get_allocator()); - EXPECT_NE(a2, t1.get_allocator()); - } - - Alloc a1 = Alloc(1); - Table t1 = Table(0, a1); - Alloc a2 = Alloc(2); -}; - -using PropagateOnAll = - PropagateTest; -using NoPropagateOnCopy = PropagateTest; -using NoPropagateOnMove = PropagateTest; - -TEST_F(PropagateOnAll, Empty) { EXPECT_EQ(0, a1.num_allocs()); } - -TEST_F(PropagateOnAll, InsertAllocates) { - auto it = t1.insert(0).first; - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); -} - -TEST_F(PropagateOnAll, InsertDecomposes) { - auto it = t1.insert(0).first; - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); - - EXPECT_FALSE(t1.insert(0).second); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); -} - -TEST_F(PropagateOnAll, RehashMoves) { - auto it = t1.insert(0).first; - EXPECT_EQ(0, it->num_moves()); - t1.rehash(2 * t1.capacity()); - EXPECT_EQ(2, a1.num_allocs()); - it = t1.find(0); - EXPECT_EQ(1, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); -} - -TEST_F(PropagateOnAll, CopyConstructor) { - auto it = t1.insert(0).first; - Table u(t1); - EXPECT_EQ(2, a1.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(1, it->num_copies()); -} - -TEST_F(NoPropagateOnCopy, CopyConstructor) { - auto it = t1.insert(0).first; - Table u(t1); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(1, u.get_allocator().num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(1, it->num_copies()); -} - -TEST_F(PropagateOnAll, CopyConstructorWithSameAlloc) { - auto it = t1.insert(0).first; - Table u(t1, a1); - EXPECT_EQ(2, a1.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(1, it->num_copies()); -} - -TEST_F(NoPropagateOnCopy, CopyConstructorWithSameAlloc) { - auto it = t1.insert(0).first; - Table u(t1, a1); - EXPECT_EQ(2, a1.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(1, it->num_copies()); -} - -TEST_F(PropagateOnAll, CopyConstructorWithDifferentAlloc) { - auto it = t1.insert(0).first; - Table u(t1, a2); - EXPECT_EQ(a2, u.get_allocator()); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(1, a2.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(1, it->num_copies()); -} - -TEST_F(NoPropagateOnCopy, CopyConstructorWithDifferentAlloc) { - auto it = t1.insert(0).first; - Table u(t1, a2); - EXPECT_EQ(a2, u.get_allocator()); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(1, a2.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(1, it->num_copies()); -} - -TEST_F(PropagateOnAll, MoveConstructor) { - auto it = t1.insert(0).first; - Table u(std::move(t1)); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); -} - -TEST_F(NoPropagateOnMove, MoveConstructor) { - auto it = t1.insert(0).first; - Table u(std::move(t1)); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); -} - -TEST_F(PropagateOnAll, MoveConstructorWithSameAlloc) { - auto it = t1.insert(0).first; - Table u(std::move(t1), a1); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); -} - -TEST_F(NoPropagateOnMove, MoveConstructorWithSameAlloc) { - auto it = t1.insert(0).first; - Table u(std::move(t1), a1); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); -} - -TEST_F(PropagateOnAll, MoveConstructorWithDifferentAlloc) { - auto it = t1.insert(0).first; - Table u(std::move(t1), a2); - it = u.find(0); - EXPECT_EQ(a2, u.get_allocator()); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(1, a2.num_allocs()); - EXPECT_EQ(1, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); -} - -TEST_F(NoPropagateOnMove, MoveConstructorWithDifferentAlloc) { - auto it = t1.insert(0).first; - Table u(std::move(t1), a2); - it = u.find(0); - EXPECT_EQ(a2, u.get_allocator()); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(1, a2.num_allocs()); - EXPECT_EQ(1, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); -} - -TEST_F(PropagateOnAll, CopyAssignmentWithSameAlloc) { - auto it = t1.insert(0).first; - Table u(0, a1); - u = t1; - EXPECT_EQ(2, a1.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(1, it->num_copies()); -} - -TEST_F(NoPropagateOnCopy, CopyAssignmentWithSameAlloc) { - auto it = t1.insert(0).first; - Table u(0, a1); - u = t1; - EXPECT_EQ(2, a1.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(1, it->num_copies()); -} - -TEST_F(PropagateOnAll, CopyAssignmentWithDifferentAlloc) { - auto it = t1.insert(0).first; - Table u(0, a2); - u = t1; - EXPECT_EQ(a1, u.get_allocator()); - EXPECT_EQ(2, a1.num_allocs()); - EXPECT_EQ(0, a2.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(1, it->num_copies()); -} - -TEST_F(NoPropagateOnCopy, CopyAssignmentWithDifferentAlloc) { - auto it = t1.insert(0).first; - Table u(0, a2); - u = t1; - EXPECT_EQ(a2, u.get_allocator()); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(1, a2.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(1, it->num_copies()); -} - -TEST_F(PropagateOnAll, MoveAssignmentWithSameAlloc) { - auto it = t1.insert(0).first; - Table u(0, a1); - u = std::move(t1); - EXPECT_EQ(a1, u.get_allocator()); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); -} - -TEST_F(NoPropagateOnMove, MoveAssignmentWithSameAlloc) { - auto it = t1.insert(0).first; - Table u(0, a1); - u = std::move(t1); - EXPECT_EQ(a1, u.get_allocator()); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); -} - -TEST_F(PropagateOnAll, MoveAssignmentWithDifferentAlloc) { - auto it = t1.insert(0).first; - Table u(0, a2); - u = std::move(t1); - EXPECT_EQ(a1, u.get_allocator()); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(0, a2.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); -} - -TEST_F(NoPropagateOnMove, MoveAssignmentWithDifferentAlloc) { - auto it = t1.insert(0).first; - Table u(0, a2); - u = std::move(t1); - it = u.find(0); - EXPECT_EQ(a2, u.get_allocator()); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(1, a2.num_allocs()); - EXPECT_EQ(1, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); -} - -TEST_F(PropagateOnAll, Swap) { - auto it = t1.insert(0).first; - Table u(0, a2); - u.swap(t1); - EXPECT_EQ(a1, u.get_allocator()); - EXPECT_EQ(a2, t1.get_allocator()); - EXPECT_EQ(1, a1.num_allocs()); - EXPECT_EQ(0, a2.num_allocs()); - EXPECT_EQ(0, it->num_moves()); - EXPECT_EQ(0, it->num_copies()); -} - -} // namespace -} // namespace container_internal -} // namespace absl diff --git a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc b/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc deleted file mode 100644 index 9d92e15..0000000 --- a/Example/Pods/FirebaseFirestore/Firestore/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc +++ /dev/null @@ -1,1965 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// 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. - -#include "absl/container/internal/raw_hash_set.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/base/attributes.h" -#include "absl/base/internal/cycleclock.h" -#include "absl/base/internal/raw_logging.h" -#include "absl/container/internal/container_memory.h" -#include "absl/container/internal/hash_function_defaults.h" -#include "absl/container/internal/hash_policy_testing.h" -#include "absl/container/internal/hashtable_debug.h" -#include "absl/strings/string_view.h" - -namespace absl { -namespace container_internal { - -struct RawHashSetTestOnlyAccess { - template - static auto GetSlots(const C& c) -> decltype(c.slots_) { - return c.slots_; - } -}; - -namespace { - -using ::testing::DoubleNear; -using ::testing::ElementsAre; -using ::testing::Optional; -using ::testing::Pair; -using ::testing::UnorderedElementsAre; - -TEST(Util, NormalizeCapacity) { - constexpr size_t kMinCapacity = Group::kWidth - 1; - EXPECT_EQ(kMinCapacity, NormalizeCapacity(0)); - EXPECT_EQ(kMinCapacity, NormalizeCapacity(1)); - EXPECT_EQ(kMinCapacity, NormalizeCapacity(2)); - EXPECT_EQ(kMinCapacity, NormalizeCapacity(kMinCapacity)); - EXPECT_EQ(kMinCapacity * 2 + 1, NormalizeCapacity(kMinCapacity + 1)); - EXPECT_EQ(kMinCapacity * 2 + 1, NormalizeCapacity(kMinCapacity + 2)); -} - -TEST(Util, probe_seq) { - probe_seq<16> seq(0, 127); - auto gen = [&]() { - size_t res = seq.offset(); - seq.next(); - return res; - }; - std::vector offsets(8); - std::generate_n(offsets.begin(), 8, gen); - EXPECT_THAT(offsets, ElementsAre(0, 16, 48, 96, 32, 112, 80, 64)); - seq = probe_seq<16>(128, 127); - std::generate_n(offsets.begin(), 8, gen); - EXPECT_THAT(offsets, ElementsAre(0, 16, 48, 96, 32, 112, 80, 64)); -} - -TEST(BitMask, Smoke) { - EXPECT_FALSE((BitMask(0))); - EXPECT_TRUE((BitMask(5))); - - EXPECT_THAT((BitMask(0)), ElementsAre()); - EXPECT_THAT((BitMask(0x1)), ElementsAre(0)); - EXPECT_THAT((BitMask(0x2)), ElementsAre(1)); - EXPECT_THAT((BitMask(0x3)), ElementsAre(0, 1)); - EXPECT_THAT((BitMask(0x4)), ElementsAre(2)); - EXPECT_THAT((BitMask(0x5)), ElementsAre(0, 2)); - EXPECT_THAT((BitMask(0x55)), ElementsAre(0, 2, 4, 6)); - EXPECT_THAT((BitMask(0xAA)), ElementsAre(1, 3, 5, 7)); -} - -TEST(BitMask, WithShift) { - // See the non-SSE version of Group for details on what this math is for. - uint64_t ctrl = 0x1716151413121110; - uint64_t hash = 0x12; - constexpr uint64_t msbs = 0x8080808080808080ULL; - constexpr uint64_t lsbs = 0x0101010101010101ULL; - auto x = ctrl ^ (lsbs * hash); - uint64_t mask = (x - lsbs) & ~x & msbs; - EXPECT_EQ(0x0000000080800000, mask); - - BitMask b(mask); - EXPECT_EQ(*b, 2); -} - -TEST(BitMask, LeadingTrailing) { - EXPECT_EQ((BitMask(0b0001101001000000).LeadingZeros()), 3); - EXPECT_EQ((BitMask(0b0001101001000000).TrailingZeros()), 6); - - EXPECT_EQ((BitMask(0b0000000000000001).LeadingZeros()), 15); - EXPECT_EQ((BitMask(0b0000000000000001).TrailingZeros()), 0); - - EXPECT_EQ((BitMask(0b1000000000000000).LeadingZeros()), 0); - EXPECT_EQ((BitMask(0b1000000000000000).TrailingZeros()), 15); - - EXPECT_EQ((BitMask(0x0000008080808000).LeadingZeros()), 3); - EXPECT_EQ((BitMask(0x0000008080808000).TrailingZeros()), 1); - - EXPECT_EQ((BitMask(0x0000000000000080).LeadingZeros()), 7); - EXPECT_EQ((BitMask(0x0000000000000080).TrailingZeros()), 0); - - EXPECT_EQ((BitMask(0x8000000000000000).LeadingZeros()), 0); - EXPECT_EQ((BitMask(0x8000000000000000).TrailingZeros()), 7); -} - -TEST(Group, EmptyGroup) { - for (h2_t h = 0; h != 128; ++h) EXPECT_FALSE(Group{EmptyGroup()}.Match(h)); -} - -TEST(Group, Match) { - if (Group::kWidth == 16) { - ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, - 7, 5, 3, 1, 1, 1, 1, 1}; - EXPECT_THAT(Group{group}.Match(0), ElementsAre()); - EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15)); - EXPECT_THAT(Group{group}.Match(3), ElementsAre(3, 10)); - EXPECT_THAT(Group{group}.Match(5), ElementsAre(5, 9)); - EXPECT_THAT(Group{group}.Match(7), ElementsAre(7, 8)); - } else if (Group::kWidth == 8) { - ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; - EXPECT_THAT(Group{group}.Match(0), ElementsAre()); - EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 5, 7)); - EXPECT_THAT(Group{group}.Match(2), ElementsAre(2, 4)); - } else { - FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth; - } -} - -TEST(Group, MatchEmpty) { - if (Group::kWidth == 16) { - ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, - 7, 5, 3, 1, 1, 1, 1, 1}; - EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0, 4)); - } else if (Group::kWidth == 8) { - ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; - EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0)); - } else { - FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth; - } -} - -TEST(Group, MatchEmptyOrDeleted) { - if (Group::kWidth == 16) { - ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, - 7, 5, 3, 1, 1, 1, 1, 1}; - EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 2, 4)); - } else if (Group::kWidth == 8) { - ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; - EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 3)); - } else { - FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth; - } -} - -TEST(Batch, DropDeletes) { - constexpr size_t kCapacity = 63; - constexpr size_t kGroupWidth = container_internal::Group::kWidth; - std::vector ctrl(kCapacity + 1 + kGroupWidth); - ctrl[kCapacity] = kSentinel; - std::vector pattern = {kEmpty, 2, kDeleted, 2, kEmpty, 1, kDeleted}; - for (size_t i = 0; i != kCapacity; ++i) { - ctrl[i] = pattern[i % pattern.size()]; - if (i < kGroupWidth - 1) - ctrl[i + kCapacity + 1] = pattern[i % pattern.size()]; - } - ConvertDeletedToEmptyAndFullToDeleted(ctrl.data(), kCapacity); - ASSERT_EQ(ctrl[kCapacity], kSentinel); - for (size_t i = 0; i < kCapacity + 1 + kGroupWidth; ++i) { - ctrl_t expected = pattern[i % (kCapacity + 1) % pattern.size()]; - if (i == kCapacity) expected = kSentinel; - if (expected == kDeleted) expected = kEmpty; - if (IsFull(expected)) expected = kDeleted; - EXPECT_EQ(ctrl[i], expected) - << i << " " << int{pattern[i % pattern.size()]}; - } -} - -TEST(Group, CountLeadingEmptyOrDeleted) { - const std::vector empty_examples = {kEmpty, kDeleted}; - const std::vector full_examples = {0, 1, 2, 3, 5, 9, 127, kSentinel}; - - for (ctrl_t empty : empty_examples) { - std::vector e(Group::kWidth, empty); - EXPECT_EQ(Group::kWidth, Group{e.data()}.CountLeadingEmptyOrDeleted()); - for (ctrl_t full : full_examples) { - for (size_t i = 0; i != Group::kWidth; ++i) { - std::vector f(Group::kWidth, empty); - f[i] = full; - EXPECT_EQ(i, Group{f.data()}.CountLeadingEmptyOrDeleted()); - } - std::vector f(Group::kWidth, empty); - f[Group::kWidth * 2 / 3] = full; - f[Group::kWidth / 2] = full; - EXPECT_EQ( - Group::kWidth / 2, Group{f.data()}.CountLeadingEmptyOrDeleted()); - } - } -} - -struct IntPolicy { - using slot_type = int64_t; - using key_type = int64_t; - using init_type = int64_t; - - static void construct(void*, int64_t* slot, int64_t v) { *slot = v; } - static void destroy(void*, int64_t*) {} - static void transfer(void*, int64_t* new_slot, int64_t* old_slot) { - *new_slot = *old_slot; - } - - static int64_t& element(slot_type* slot) { return *slot; } - - template - static auto apply(F&& f, int64_t x) -> decltype(std::forward(f)(x, x)) { - return std::forward(f)(x, x); - } -}; - -class StringPolicy { - template ::value>::type> - decltype(std::declval()( - std::declval(), std::piecewise_construct, - std::declval>(), - std::declval())) static apply_impl(F&& f, - std::pair, V> p) { - const absl::string_view& key = std::get<0>(p.first); - return std::forward(f)(key, std::piecewise_construct, std::move(p.first), - std::move(p.second)); - } - - public: - struct slot_type { - struct ctor {}; - - template - slot_type(ctor, Ts&&... ts) : pair(std::forward(ts)...) {} - - std::pair pair; - }; - - using key_type = std::string; - using init_type = std::pair; - - template - static void construct(allocator_type* alloc, slot_type* slot, Args... args) { - std::allocator_traits::construct( - *alloc, slot, typename slot_type::ctor(), std::forward(args)...); - } - - template - static void destroy(allocator_type* alloc, slot_type* slot) { - std::allocator_traits::destroy(*alloc, slot); - } - - template - static void transfer(allocator_type* alloc, slot_type* new_slot, - slot_type* old_slot) { - construct(alloc, new_slot, std::move(old_slot->pair)); - destroy(alloc, old_slot); - } - - static std::pair& element(slot_type* slot) { - return slot->pair; - } - - template - static auto apply(F&& f, Args&&... args) - -> decltype(apply_impl(std::forward(f), - PairArgs(std::forward(args)...))) { - return apply_impl(std::forward(f), - PairArgs(std::forward(args)...)); - } -}; - -struct StringHash : absl::Hash { - using is_transparent = void; -}; -struct StringEq : std::equal_to { - using is_transparent = void; -}; - -struct StringTable - : raw_hash_set> { - using Base = typename StringTable::raw_hash_set; - StringTable() {} - using Base::Base; -}; - -struct IntTable - : raw_hash_set, - std::equal_to, std::allocator> { - using Base = typename IntTable::raw_hash_set; - IntTable() {} - using Base::Base; -}; - -struct BadFastHash { - template - size_t operator()(const T&) const { - return 0; - } -}; - -struct BadTable : raw_hash_set, - std::allocator> { - using Base = typename BadTable::raw_hash_set; - BadTable() {} - using Base::Base; -}; - -TEST(Table, EmptyFunctorOptimization) { - static_assert(std::is_empty>::value, ""); - static_assert(std::is_empty>::value, ""); - - struct MockTable { - void* ctrl; - void* slots; - size_t size; - size_t capacity; - size_t growth_left; - }; - struct StatelessHash { - size_t operator()(absl::string_view) const { return 0; } - }; - struct StatefulHash : StatelessHash { - size_t dummy; - }; - - EXPECT_EQ( - sizeof(MockTable), - sizeof( - raw_hash_set, std::allocator>)); - - EXPECT_EQ( - sizeof(MockTable) + sizeof(StatefulHash), - sizeof( - raw_hash_set, std::allocator>)); -} - -TEST(Table, Empty) { - IntTable t; - EXPECT_EQ(0, t.size()); - EXPECT_TRUE(t.empty()); -} - -#ifdef __GNUC__ -template -ABSL_ATTRIBUTE_ALWAYS_INLINE inline void DoNotOptimize(const T& v) { - asm volatile("" : : "r,m"(v) : "memory"); -} -#endif - -TEST(Table, Prefetch) { - IntTable t; - t.emplace(1); - // Works for both present and absent keys. - t.prefetch(1); - t.prefetch(2); - - // Do not run in debug mode, when prefetch is not implemented, or when - // sanitizers are enabled. -#if defined(NDEBUG) && defined(__GNUC__) && !defined(ADDRESS_SANITIZER) && \ - !defined(MEMORY_SANITIZER) && !defined(THREAD_SANITIZER) && \ - !defined(UNDEFINED_BEHAVIOR_SANITIZER) - const auto now = [] { return absl::base_internal::CycleClock::Now(); }; - - static constexpr int size = 1000000; - for (int i = 0; i < size; ++i) t.insert(i); - - int64_t no_prefetch = 0, prefetch = 0; - for (int iter = 0; iter < 10; ++iter) { - int64_t time = now(); - for (int i = 0; i < size; ++i) { - DoNotOptimize(t.find(i)); - } - no_prefetch += now() - time; - - time = now(); - for (int i = 0; i < size; ++i) { - t.prefetch(i + 20); - DoNotOptimize(t.find(i)); - } - prefetch += now() - time; - } - - // no_prefetch is at least 30% slower. - EXPECT_GE(1.0 * no_prefetch / prefetch, 1.3); -#endif -} - -TEST(Table, LookupEmpty) { - IntTable t; - auto it = t.find(0); - EXPECT_TRUE(it == t.end()); -} - -TEST(Table, Insert1) { - IntTable t; - EXPECT_TRUE(t.find(0) == t.end()); - auto res = t.emplace(0); - EXPECT_TRUE(res.second); - EXPECT_THAT(*res.first, 0); - EXPECT_EQ(1, t.size()); - EXPECT_THAT(*t.find(0), 0); -} - -TEST(Table, Insert2) { - IntTable t; - EXPECT_TRUE(t.find(0) == t.end()); - auto res = t.emplace(0); - EXPECT_TRUE(res.second); - EXPECT_THAT(*res.first, 0); - EXPECT_EQ(1, t.size()); - EXPECT_TRUE(t.find(1) == t.end()); - res = t.emplace(1); - EXPECT_TRUE(res.second); - EXPECT_THAT(*res.first, 1); - EXPECT_EQ(2, t.size()); - EXPECT_THAT(*t.find(0), 0); - EXPECT_THAT(*t.find(1), 1); -} - -TEST(Table, InsertCollision) { - BadTable t; - EXPECT_TRUE(t.find(1) == t.end()); - auto res = t.emplace(1); - EXPECT_TRUE(res.second); - EXPECT_THAT(*res.first, 1); - EXPECT_EQ(1, t.size()); - - EXPECT_TRUE(t.find(2) == t.end()); - res = t.emplace(2); - EXPECT_THAT(*res.first, 2); - EXPECT_TRUE(res.second); - EXPECT_EQ(2, t.size()); - - EXPECT_THAT(*t.find(1), 1); - EXPECT_THAT(*t.find(2), 2); -} - -// Test that we do not add existent element in case we need to search through -// many groups with deleted elements -TEST(Table, InsertCollisionAndFindAfterDelete) { - BadTable t; // all elements go to the same group. - // Have at least 2 groups with Group::kWidth collisions - // plus some extra collisions in the last group. - constexpr size_t kNumInserts = Group::kWidth * 2 + 5; - for (size_t i = 0; i < kNumInserts; ++i) { - auto res = t.emplace(i); - EXPECT_TRUE(res.second); - EXPECT_THAT(*res.first, i); - EXPECT_EQ(i + 1, t.size()); - } - - // Remove elements one by one and check - // that we still can find all other elements. - for (size_t i = 0; i < kNumInserts; ++i) { - EXPECT_EQ(1, t.erase(i)) << i; - for (size_t j = i + 1; j < kNumInserts; ++j) { - EXPECT_THAT(*t.find(j), j); - auto res = t.emplace(j); - EXPECT_FALSE(res.second) << i << " " << j; - EXPECT_THAT(*res.first, j); - EXPECT_EQ(kNumInserts - i - 1, t.size()); - } - } - EXPECT_TRUE(t.empty()); -} - -TEST(Table, LazyEmplace) { - StringTable t; - bool called = false; - auto it = t.lazy_emplace("abc", [&](const StringTable::constructor& f) { - called = true; - f("abc", "ABC"); - }); - EXPECT_TRUE(called); - EXPECT_THAT(*it, Pair("abc", "ABC")); - called = false; - it = t.lazy_emplace("abc", [&](const StringTable::constructor& f) { - called = true; - f("abc", "DEF"); - }); - EXPECT_FALSE(called); - EXPECT_THAT(*it, Pair("abc", "ABC")); -} - -TEST(Table, ContainsEmpty) { - IntTable t; - - EXPECT_FALSE(t.contains(0)); -} - -TEST(Table, Contains1) { - IntTable t; - - EXPECT_TRUE(t.insert(0).second); - EXPECT_TRUE(t.contains(0)); - EXPECT_FALSE(t.contains(1)); - - EXPECT_EQ(1, t.erase(0)); - EXPECT_FALSE(t.contains(0)); -} - -TEST(Table, Contains2) { - IntTable t; - - EXPECT_TRUE(t.insert(0).second); - EXPECT_TRUE(t.contains(0)); - EXPECT_FALSE(t.contains(1)); - - t.clear(); - EXPECT_FALSE(t.contains(0)); -} - -int decompose_constructed; -struct DecomposeType { - DecomposeType(int i) : i(i) { // NOLINT - ++decompose_constructed; - } - - explicit DecomposeType(const char* d) : DecomposeType(*d) {} - - int i; -}; - -struct DecomposeHash { - using is_transparent = void; - size_t operator()(DecomposeType a) const { return a.i; } - size_t operator()(int a) const { return a; } - size_t operator()(const char* a) const { return *a; } -}; - -struct DecomposeEq { - using is_transparent = void; - bool operator()(DecomposeType a, DecomposeType b) const { return a.i == b.i; } - bool operator()(DecomposeType a, int b) const { return a.i == b; } - bool operator()(DecomposeType a, const char* b) const { return a.i == *b; } -}; - -struct DecomposePolicy { - using slot_type = DecomposeType; - using key_type = DecomposeType; - using init_type = DecomposeType; - - template - static void construct(void*, DecomposeType* slot, T&& v) { - *slot = DecomposeType(std::forward(v)); - } - static void destroy(void*, DecomposeType*) {} - static DecomposeType& element(slot_type* slot) { return *slot; } - - template - static auto apply(F&& f, const T& x) -> decltype(std::forward(f)(x, x)) { - return std::forward(f)(x, x); - } -}; - -template -void TestDecompose(bool construct_three) { - DecomposeType elem{0}; - const int one = 1; - const char* three_p = "3"; - const auto& three = three_p; - - raw_hash_set> set1; - - decompose_constructed = 0; - int expected_constructed = 0; - EXPECT_EQ(expected_constructed, decompose_constructed); - set1.insert(elem); - EXPECT_EQ(expected_constructed, decompose_constructed); - set1.insert(1); - EXPECT_EQ(++expected_constructed, decompose_constructed); - set1.emplace("3"); - EXPECT_EQ(++expected_constructed, decompose_constructed); - EXPECT_EQ(expected_constructed, decompose_constructed); - - { // insert(T&&) - set1.insert(1); - EXPECT_EQ(expected_constructed, decompose_constructed); - } - - { // insert(const T&) - set1.insert(one); - EXPECT_EQ(expected_constructed, decompose_constructed); - } - - { // insert(hint, T&&) - set1.insert(set1.begin(), 1); - EXPECT_EQ(expected_constructed, decompose_constructed); - } - - { // insert(hint, const T&) - set1.insert(set1.begin(), one); - EXPECT_EQ(expected_constructed, decompose_constructed); - } - - { // emplace(...) - set1.emplace(1); - EXPECT_EQ(expected_constructed, decompose_constructed); - set1.emplace("3"); - expected_constructed += construct_three; - EXPECT_EQ(expected_constructed, decompose_constructed); - set1.emplace(one); - EXPECT_EQ(expected_constructed, decompose_constructed); - set1.emplace(three); - expected_constructed += construct_three; - EXPECT_EQ(expected_constructed, decompose_constructed); - } - - { // emplace_hint(...) - set1.emplace_hint(set1.begin(), 1); - EXPECT_EQ(expected_constructed, decompose_constructed); - set1.emplace_hint(set1.begin(), "3"); - expected_constructed += construct_three; - EXPECT_EQ(expected_constructed, decompose_constructed); - set1.emplace_hint(set1.begin(), one); - EXPECT_EQ(expected_constructed, decompose_constructed); - set1.emplace_hint(set1.begin(), three); - expected_constructed += construct_three; - EXPECT_EQ(expected_constructed, decompose_constructed); - } -} - -TEST(Table, Decompose) { - TestDecompose(false); - - struct TransparentHashIntOverload { - size_t operator()(DecomposeType a) const { return a.i; } - size_t operator()(int a) const { return a; } - }; - struct TransparentEqIntOverload { - bool operator()(DecomposeType a, DecomposeType b) const { - return a.i == b.i; - } - bool operator()(DecomposeType a, int b) const { return a.i == b; } - }; - TestDecompose(true); - TestDecompose(true); - TestDecompose(true); -} - -// Returns the largest m such that a table with m elements has the same number -// of buckets as a table with n elements. -size_t MaxDensitySize(size_t n) { - IntTable t; - t.reserve(n); - for (size_t i = 0; i != n; ++i) t.emplace(i); - const size_t c = t.bucket_count(); - while (c == t.bucket_count()) t.emplace(n++); - return t.size() - 1; -} - -struct Modulo1000Hash { - size_t operator()(int x) const { return x % 1000; } -}; - -struct Modulo1000HashTable - : public raw_hash_set, - std::allocator> {}; - -// Test that rehash with no resize happen in case of many deleted slots. -TEST(Table, RehashWithNoResize) { - Modulo1000HashTable t; - // Adding the same length (and the same hash) strings - // to have at least kMinFullGroups groups - // with Group::kWidth collisions. Then fill up to MaxDensitySize; - const size_t kMinFullGroups = 7; - std::vector keys; - for (size_t i = 0; i < MaxDensitySize(Group::kWidth * kMinFullGroups); ++i) { - int k = i * 1000; - t.emplace(k); - keys.push_back(k); - } - const size_t capacity = t.capacity(); - - // Remove elements from all groups except the first and the last one. - // All elements removed from full groups will be marked as kDeleted. - const size_t erase_begin = Group::kWidth / 2; - const size_t erase_end = (t.size() / Group::kWidth - 1) * Group::kWidth; - for (size_t i = erase_begin; i < erase_end; ++i) { - EXPECT_EQ(1, t.erase(keys[i])) << i; - } - keys.erase(keys.begin() + erase_begin, keys.begin() + erase_end); - - auto last_key = keys.back(); - size_t last_key_num_probes = GetHashtableDebugNumProbes(t, last_key); - - // Make sure that we have to make a lot of probes for last key. - ASSERT_GT(last_key_num_probes, kMinFullGroups); - - int x = 1; - // Insert and erase one element, before inplace rehash happen. - while (last_key_num_probes == GetHashtableDebugNumProbes(t, last_key)) { - t.emplace(x); - ASSERT_EQ(capacity, t.capacity()); - // All elements should be there. - ASSERT_TRUE(t.find(x) != t.end()) << x; - for (const auto& k : keys) { - ASSERT_TRUE(t.find(k) != t.end()) << k; - } - t.erase(x); - ++x; - } -} - -TEST(Table, InsertEraseStressTest) { - IntTable t; - const size_t kMinElementCount = 250; - std::deque keys; - size_t i = 0; - for (; i < MaxDensitySize(kMinElementCount); ++i) { - t.emplace(i); - keys.push_back(i); - } - const size_t kNumIterations = 1000000; - for (; i < kNumIterations; ++i) { - ASSERT_EQ(1, t.erase(keys.front())); - keys.pop_front(); - t.emplace(i); - keys.push_back(i); - } -} - -TEST(Table, InsertOverloads) { - StringTable t; - // These should all trigger the insert(init_type) overload. - t.insert({{}, {}}); - t.insert({"ABC", {}}); - t.insert({"DEF", "!!!"}); - - EXPECT_THAT(t, UnorderedElementsAre(Pair("", ""), Pair("ABC", ""), - Pair("DEF", "!!!"))); -} - -TEST(Table, LargeTable) { - IntTable t; - for (int64_t i = 0; i != 100000; ++i) t.emplace(i << 40); - for (int64_t i = 0; i != 100000; ++i) ASSERT_EQ(i << 40, *t.find(i << 40)); -} - -// Timeout if copy is quadratic as it was in Rust. -TEST(Table, EnsureNonQuadraticAsInRust) { - static const size_t kLargeSize = 1 << 15; - - IntTable t; - for (size_t i = 0; i != kLargeSize; ++i) { - t.insert(i); - } - - // If this is quadratic, the test will timeout. - IntTable t2; - for (const auto& entry : t) t2.insert(entry); -} - -TEST(Table, ClearBug) { - IntTable t; - constexpr size_t capacity = container_internal::Group::kWidth - 1; - constexpr size_t max_size = capacity / 2; - for (size_t i = 0; i < max_size; ++i) { - t.insert(i); - } - ASSERT_EQ(capacity, t.capacity()); - intptr_t original = reinterpret_cast(&*t.find(2)); - t.clear(); - ASSERT_EQ(capacity, t.capacity()); - for (size_t i = 0; i < max_size; ++i) { - t.insert(i); - } - ASSERT_EQ(capacity, t.capacity()); - intptr_t second = reinterpret_cast(&*t.find(2)); - // We are checking that original and second are close enough to each other - // that they are probably still in the same group. This is not strictly - // guaranteed. - EXPECT_LT(std::abs(original - second), - capacity * sizeof(IntTable::value_type)); -} - -TEST(Table, Erase) { - IntTable t; - EXPECT_TRUE(t.find(0) == t.end()); - auto res = t.emplace(0); - EXPECT_TRUE(res.second); - EXPECT_EQ(1, t.size()); - t.erase(res.first); - EXPECT_EQ(0, t.size()); - EXPECT_TRUE(t.find(0) == t.end()); -} - -// Collect N bad keys by following algorithm: -// 1. Create an empty table and reserve it to 2 * N. -// 2. Insert N random elements. -// 3. Take first Group::kWidth - 1 to bad_keys array. -// 4. Clear the table without resize. -// 5. Go to point 2 while N keys not collected -std::vector CollectBadMergeKeys(size_t N) { - static constexpr int kGroupSize = Group::kWidth - 1; - - auto topk_range = [](size_t b, size_t e, IntTable* t) -> std::vector { - for (size_t i = b; i != e; ++i) { - t->emplace(i); - } - std::vector res; - res.reserve(kGroupSize); - auto it = t->begin(); - for (size_t i = b; i != e && i != b + kGroupSize; ++i, ++it) { - res.push_back(*it); - } - return res; - }; - - std::vector bad_keys; - bad_keys.reserve(N); - IntTable t; - t.reserve(N * 2); - - for (size_t b = 0; bad_keys.size() < N; b += N) { - auto keys = topk_range(b, b + N, &t); - bad_keys.insert(bad_keys.end(), keys.begin(), keys.end()); - t.erase(t.begin(), t.end()); - EXPECT_TRUE(t.empty()); - } - return bad_keys; -} - -struct ProbeStats { - // Number of elements with specific probe length over all tested tables. - std::vector all_probes_histogram; - // Ratios total_probe_length/size for every tested table. - std::vector single_table_ratios; - - friend ProbeStats operator+(const ProbeStats& a, const ProbeStats& b) { - ProbeStats res = a; - res.all_probes_histogram.resize(std::max(res.all_probes_histogram.size(), - b.all_probes_histogram.size())); - std::transform(b.all_probes_histogram.begin(), b.all_probes_histogram.end(), - res.all_probes_histogram.begin(), - res.all_probes_histogram.begin(), std::plus()); - res.single_table_ratios.insert(res.single_table_ratios.end(), - b.single_table_ratios.begin(), - b.single_table_ratios.end()); - return res; - } - - // Average ratio total_probe_length/size over tables. - double AvgRatio() const { - return std::accumulate(single_table_ratios.begin(), - single_table_ratios.end(), 0.0) / - single_table_ratios.size(); - } - - // Maximum ratio total_probe_length/size over tables. - double MaxRatio() const { - return *std::max_element(single_table_ratios.begin(), - single_table_ratios.end()); - } - - // Percentile ratio total_probe_length/size over tables. - double PercentileRatio(double Percentile = 0.95) const { - auto r = single_table_ratios; - auto mid = r.begin() + static_cast(r.size() * Percentile); - if (mid != r.end()) { - std::nth_element(r.begin(), mid, r.end()); - return *mid; - } else { - return MaxRatio(); - } - } - - // Maximum probe length over all elements and all tables. - size_t MaxProbe() const { return all_probes_histogram.size(); } - - // Fraction of elements with specified probe length. - std::vector ProbeNormalizedHistogram() const { - double total_elements = std::accumulate(all_probes_histogram.begin(), - all_probes_histogram.end(), 0ull); - std::vector res; - for (size_t p : all_probes_histogram) { - res.push_back(p / total_elements); - } - return res; - } - - size_t PercentileProbe(double Percentile = 0.99) const { - size_t idx = 0; - for (double p : ProbeNormalizedHistogram()) { - if (Percentile > p) { - Percentile -= p; - ++idx; - } else { - return idx; - } - } - return idx; - } - - friend std::ostream& operator<<(std::ostream& out, const ProbeStats& s) { - out << "{AvgRatio:" << s.AvgRatio() << ", MaxRatio:" << s.MaxRatio() - << ", PercentileRatio:" << s.PercentileRatio() - << ", MaxProbe:" << s.MaxProbe() << ", Probes=["; - for (double p : s.ProbeNormalizedHistogram()) { - out << p << ","; - } - out << "]}"; - - return out; - } -}; - -struct ExpectedStats { - double avg_ratio; - double max_ratio; - std::vector> pecentile_ratios; - std::vector> pecentile_probes; - - friend std::ostream& operator<<(std::ostream& out, const ExpectedStats& s) { - out << "{AvgRatio:" << s.avg_ratio << ", MaxRatio:" << s.max_ratio - << ", PercentileRatios: ["; - for (auto el : s.pecentile_ratios) { - out << el.first << ":" << el.second << ", "; - } - out << "], PercentileProbes: ["; - for (auto el : s.pecentile_probes) { - out << el.first << ":" << el.second << ", "; - } - out << "]}"; - - return out; - } -}; - -void VerifyStats(size_t size, const ExpectedStats& exp, - const ProbeStats& stats) { - EXPECT_LT(stats.AvgRatio(), exp.avg_ratio) << size << " " << stats; - EXPECT_LT(stats.MaxRatio(), exp.max_ratio) << size << " " << stats; - for (auto pr : exp.pecentile_ratios) { - EXPECT_LE(stats.PercentileRatio(pr.first), pr.second) - << size << " " << pr.first << " " << stats; - } - - for (auto pr : exp.pecentile_probes) { - EXPECT_LE(stats.PercentileProbe(pr.first), pr.second) - << size << " " << pr.first << " " << stats; - } -} - -using ProbeStatsPerSize = std::map; - -// Collect total ProbeStats on num_iters iterations of the following algorithm: -// 1. Create new table and reserve it to keys.size() * 2 -// 2. Insert all keys xored with seed -// 3. Collect ProbeStats from final table. -ProbeStats CollectProbeStatsOnKeysXoredWithSeed(const std::vector& keys, - size_t num_iters) { - const size_t reserve_size = keys.size() * 2; - - ProbeStats stats; - - int64_t seed = 0x71b1a19b907d6e33; - while (num_iters--) { - seed = static_cast(static_cast(seed) * 17 + 13); - IntTable t1; - t1.reserve(reserve_size); - for (const auto& key : keys) { - t1.emplace(key ^ seed); - } - - auto probe_histogram = GetHashtableDebugNumProbesHistogram(t1); - stats.all_probes_histogram.resize( - std::max(stats.all_probes_histogram.size(), probe_histogram.size())); - std::transform(probe_histogram.begin(), probe_histogram.end(), - stats.all_probes_histogram.begin(), - stats.all_probes_histogram.begin(), std::plus()); - - size_t total_probe_seq_length = 0; - for (size_t i = 0; i < probe_histogram.size(); ++i) { - total_probe_seq_length += i * probe_histogram[i]; - } - stats.single_table_ratios.push_back(total_probe_seq_length * 1.0 / - keys.size()); - t1.erase(t1.begin(), t1.end()); - } - return stats; -} - -ExpectedStats XorSeedExpectedStats() { - constexpr bool kRandomizesInserts = -#if NDEBUG - false; -#else // NDEBUG - true; -#endif // NDEBUG - - // The effective load factor is larger in non-opt mode because we insert - // elements out of order. - switch (container_internal::Group::kWidth) { - case 8: - if (kRandomizesInserts) { - return {0.05, - 1.0, - {{0.95, 0.5}}, - {{0.95, 0}, {0.99, 2}, {0.999, 4}, {0.9999, 10}}}; - } else { - return {0.05, - 2.0, - {{0.95, 0.1}}, - {{0.95, 0}, {0.99, 2}, {0.999, 4}, {0.9999, 10}}}; - } - case 16: - if (kRandomizesInserts) { - return {0.1, - 1.0, - {{0.95, 0.1}}, - {{0.95, 0}, {0.99, 1}, {0.999, 8}, {0.9999, 15}}}; - } else { - return {0.05, - 1.0, - {{0.95, 0.05}}, - {{0.95, 0}, {0.99, 1}, {0.999, 4}, {0.9999, 10}}}; - } - } - ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width"); - return {}; -} -TEST(Table, DISABLED_EnsureNonQuadraticTopNXorSeedByProbeSeqLength) { - ProbeStatsPerSize stats; - std::vector sizes = {Group::kWidth << 5, Group::kWidth << 10}; - for (size_t size : sizes) { - stats[size] = - CollectProbeStatsOnKeysXoredWithSeed(CollectBadMergeKeys(size), 200); - } - auto expected = XorSeedExpectedStats(); - for (size_t size : sizes) { - auto& stat = stats[size]; - VerifyStats(size, expected, stat); - } -} - -// Collect total ProbeStats on num_iters iterations of the following algorithm: -// 1. Create new table -// 2. Select 10% of keys and insert 10 elements key * 17 + j * 13 -// 3. Collect ProbeStats from final table -ProbeStats CollectProbeStatsOnLinearlyTransformedKeys( - const std::vector& keys, size_t num_iters) { - ProbeStats stats; - - std::random_device rd; - std::mt19937 rng(rd()); - auto linear_transform = [](size_t x, size_t y) { return x * 17 + y * 13; }; - std::uniform_int_distribution dist(0, keys.size()-1); - while (num_iters--) { - IntTable t1; - size_t num_keys = keys.size() / 10; - size_t start = dist(rng); - for (size_t i = 0; i != num_keys; ++i) { - for (size_t j = 0; j != 10; ++j) { - t1.emplace(linear_transform(keys[(i + start) % keys.size()], j)); - } - } - - auto probe_histogram = GetHashtableDebugNumProbesHistogram(t1); - stats.all_probes_histogram.resize( - std::max(stats.all_probes_histogram.size(), probe_histogram.size())); - std::transform(probe_histogram.begin(), probe_histogram.end(), - stats.all_probes_histogram.begin(), - stats.all_probes_histogram.begin(), std::plus()); - - size_t total_probe_seq_length = 0; - for (size_t i = 0; i < probe_histogram.size(); ++i) { - total_probe_seq_length += i * probe_histogram[i]; - } - stats.single_table_ratios.push_back(total_probe_seq_length * 1.0 / - t1.size()); - t1.erase(t1.begin(), t1.end()); - } - return stats; -} - -ExpectedStats LinearTransformExpectedStats() { - constexpr bool kRandomizesInserts = -#if NDEBUG - false; -#else // NDEBUG - true; -#endif // NDEBUG - - // The effective load factor is larger in non-opt mode because we insert - // elements out of order. - switch (container_internal::Group::kWidth) { - case 8: - if (kRandomizesInserts) { - return {0.1, - 0.5, - {{0.95, 0.3}}, - {{0.95, 0}, {0.99, 1}, {0.999, 8}, {0.9999, 15}}}; - } else { - return {0.15, - 0.5, - {{0.95, 0.3}}, - {{0.95, 0}, {0.99, 3}, {0.999, 15}, {0.9999, 25}}}; - } - case 16: - if (kRandomizesInserts) { - return {0.1, - 0.4, - {{0.95, 0.3}}, - {{0.95, 0}, {0.99, 1}, {0.999, 8}, {0.9999, 15}}}; - } else { - return {0.05, - 0.2, - {{0.95, 0.1}}, - {{0.95, 0}, {0.99, 1}, {0.999, 6}, {0.9999, 10}}}; - } - } - ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width"); - return {}; -} -TEST(Table, DISABLED_EnsureNonQuadraticTopNLinearTransformByProbeSeqLength) { - ProbeStatsPerSize stats; - std::vector sizes = {Group::kWidth << 5, Group::kWidth << 10}; - for (size_t size : sizes) { - stats[size] = CollectProbeStatsOnLinearlyTransformedKeys( - CollectBadMergeKeys(size), 300); - } - auto expected = LinearTransformExpectedStats(); - for (size_t size : sizes) { - auto& stat = stats[size]; - VerifyStats(size, expected, stat); - } -} - -TEST(Table, EraseCollision) { - BadTable t; - - // 1 2 3 - t.emplace(1); - t.emplace(2); - t.emplace(3); - EXPECT_THAT(*t.find(1), 1); - EXPECT_THAT(*t.find(2), 2); - EXPECT_THAT(*t.find(3), 3); - EXPECT_EQ(3, t.size()); - - // 1 DELETED 3 - t.erase(t.find(2)); - EXPECT_THAT(*t.find(1), 1); - EXPECT_TRUE(t.find(2) == t.end()); - EXPECT_THAT(*t.find(3), 3); - EXPECT_EQ(2, t.size()); - - // DELETED DELETED 3 - t.erase(t.find(1)); - EXPECT_TRUE(t.find(1) == t.end()); - EXPECT_TRUE(t.find(2) == t.end()); - EXPECT_THAT(*t.find(3), 3); - EXPECT_EQ(1, t.size()); - - // DELETED DELETED DELETED - t.erase(t.find(3)); - EXPECT_TRUE(t.find(1) == t.end()); - EXPECT_TRUE(t.find(2) == t.end()); - EXPECT_TRUE(t.find(3) == t.end()); - EXPECT_EQ(0, t.size()); -} - -TEST(Table, EraseInsertProbing) { - BadTable t(100); - - // 1 2 3 4 - t.emplace(1); - t.emplace(2); - t.emplace(3); - t.emplace(4); - - // 1 DELETED 3 DELETED - t.erase(t.find(2)); - t.erase(t.find(4)); - - // 1 10 3 11 12 - t.emplace(10); - t.emplace(11); - t.emplace(12); - - EXPECT_EQ(5, t.size()); - EXPECT_THAT(t, UnorderedElementsAre(1, 10, 3, 11, 12)); -} - -TEST(Table, Clear) { - IntTable t; - EXPECT_TRUE(t.find(0) == t.end()); - t.clear(); - EXPECT_TRUE(t.find(0) == t.end()); - auto res = t.emplace(0); - EXPECT_TRUE(res.second); - EXPECT_EQ(1, t.size()); - t.clear(); - EXPECT_EQ(0, t.size()); - EXPECT_TRUE(t.find(0) == t.end()); -} - -TEST(Table, Swap) { - IntTable t; - EXPECT_TRUE(t.find(0) == t.end()); - auto res = t.emplace(0); - EXPECT_TRUE(res.second); - EXPECT_EQ(1, t.size()); - IntTable u; - t.swap(u); - EXPECT_EQ(0, t.size()); - EXPECT_EQ(1, u.size()); - EXPECT_TRUE(t.find(0) == t.end()); - EXPECT_THAT(*u.find(0), 0); -} - -TEST(Table, Rehash) { - IntTable t; - EXPECT_TRUE(t.find(0) == t.end()); - t.emplace(0); - t.emplace(1); - EXPECT_EQ(2, t.size()); - t.rehash(128); - EXPECT_EQ(2, t.size()); - EXPECT_THAT(*t.find(0), 0); - EXPECT_THAT(*t.find(1), 1); -} - -TEST(Table, RehashDoesNotRehashWhenNotNecessary) { - IntTable t; - t.emplace(0); - t.emplace(1); - auto* p = &*t.find(0); - t.rehash(1); - EXPECT_EQ(p, &*t.find(0)); -} - -TEST(Table, RehashZeroDoesNotAllocateOnEmptyTable) { - IntTable t; - t.rehash(0); - EXPECT_EQ(0, t.bucket_count()); -} - -TEST(Table, RehashZeroDeallocatesEmptyTable) { - IntTable t; - t.emplace(0); - t.clear(); - EXPECT_NE(0, t.bucket_count()); - t.rehash(0); - EXPECT_EQ(0, t.bucket_count()); -} - -TEST(Table, RehashZeroForcesRehash) { - IntTable t; - t.emplace(0); - t.emplace(1); - auto* p = &*t.find(0); - t.rehash(0); - EXPECT_NE(p, &*t.find(0)); -} - -TEST(Table, ConstructFromInitList) { - using P = std::pair; - struct Q { - operator P() const { return {}; } - }; - StringTable t = {P(), Q(), {}, {{}, {}}}; -} - -TEST(Table, CopyConstruct) { - IntTable t; - t.max_load_factor(.321f); - t.emplace(0); - EXPECT_EQ(1, t.size()); - { - IntTable u(t); - EXPECT_EQ(1, u.size()); - EXPECT_EQ(t.max_load_factor(), u.max_load_factor()); - EXPECT_THAT(*u.find(0), 0); - } - { - IntTable u{t}; - EXPECT_EQ(1, u.size()); - EXPECT_EQ(t.max_load_factor(), u.max_load_factor()); - EXPECT_THAT(*u.find(0), 0); - } - { - IntTable u = t; - EXPECT_EQ(1, u.size()); - EXPECT_EQ(t.max_load_factor(), u.max_load_factor()); - EXPECT_THAT(*u.find(0), 0); - } -} - -TEST(Table, CopyConstructWithAlloc) { - StringTable t; - t.max_load_factor(.321f); - t.emplace("a", "b"); - EXPECT_EQ(1, t.size()); - StringTable u(t, Alloc>()); - EXPECT_EQ(1, u.size()); - EXPECT_EQ(t.max_load_factor(), u.max_load_factor()); - EXPECT_THAT(*u.find("a"), Pair("a", "b")); -} - -struct ExplicitAllocIntTable - : raw_hash_set, - std::equal_to, Alloc> { - ExplicitAllocIntTable() {} -}; - -TEST(Table, AllocWithExplicitCtor) { - ExplicitAllocIntTable t; - EXPECT_EQ(0, t.size()); -} - -TEST(Table, MoveConstruct) { - { - StringTable t; - t.max_load_factor(.321f); - const float lf = t.max_load_factor(); - t.emplace("a", "b"); - EXPECT_EQ(1, t.size()); - - StringTable u(std::move(t)); - EXPECT_EQ(1, u.size()); - EXPECT_EQ(lf, u.max_load_factor()); - EXPECT_THAT(*u.find("a"), Pair("a", "b")); - } - { - StringTable t; - t.max_load_factor(.321f); - const float lf = t.max_load_factor(); - t.emplace("a", "b"); - EXPECT_EQ(1, t.size()); - - StringTable u{std::move(t)}; - EXPECT_EQ(1, u.size()); - EXPECT_EQ(lf, u.max_load_factor()); - EXPECT_THAT(*u.find("a"), Pair("a", "b")); - } - { - StringTable t; - t.max_load_factor(.321f); - const float lf = t.max_load_factor(); - t.emplace("a", "b"); - EXPECT_EQ(1, t.size()); - - StringTable u = std::move(t); - EXPECT_EQ(1, u.size()); - EXPECT_EQ(lf, u.max_load_factor()); - EXPECT_THAT(*u.find("a"), Pair("a", "b")); - } -} - -TEST(Table, MoveConstructWithAlloc) { - StringTable t; - t.max_load_factor(.321f); - const float lf = t.max_load_factor(); - t.emplace("a", "b"); - EXPECT_EQ(1, t.size()); - StringTable u(std::move(t), Alloc>()); - EXPECT_EQ(1, u.size()); - EXPECT_EQ(lf, u.max_load_factor()); - EXPECT_THAT(*u.find("a"), Pair("a", "b")); -} - -TEST(Table, CopyAssign) { - StringTable t; - t.max_load_factor(.321f); - t.emplace("a", "b"); - EXPECT_EQ(1, t.size()); - StringTable u; - u = t; - EXPECT_EQ(1, u.size()); - EXPECT_EQ(t.max_load_factor(), u.max_load_factor()); - EXPECT_THAT(*u.find("a"), Pair("a", "b")); -} - -TEST(Table, CopySelfAssign) { - StringTable t; - t.max_load_factor(.321f); - const float lf = t.max_load_factor(); - t.emplace("a", "b"); - EXPECT_EQ(1, t.size()); - t = *&t; - EXPECT_EQ(1, t.size()); - EXPECT_EQ(lf, t.max_load_factor()); - EXPECT_THAT(*t.find("a"), Pair("a", "b")); -} - -TEST(Table, MoveAssign) { - StringTable t; - t.max_load_factor(.321f); - const float lf = t.max_load_factor(); - t.emplace("a", "b"); - EXPECT_EQ(1, t.size()); - StringTable u; - u = std::move(t); - EXPECT_EQ(1, u.size()); - EXPECT_EQ(lf, u.max_load_factor()); - EXPECT_THAT(*u.find("a"), Pair("a", "b")); -} - -TEST(Table, Equality) { - StringTable t; - std::vector> v = {{"a", "b"}, {"aa", "bb"}}; - t.insert(std::begin(v), std::end(v)); - StringTable u = t; - EXPECT_EQ(u, t); -} - -TEST(Table, Equality2) { - StringTable t; - std::vector> v1 = {{"a", "b"}, {"aa", "bb"}}; - t.insert(std::begin(v1), std::end(v1)); - StringTable u; - std::vector> v2 = {{"a", "a"}, {"aa", "aa"}}; - u.insert(std::begin(v2), std::end(v2)); - EXPECT_NE(u, t); -} - -TEST(Table, Equality3) { - StringTable t; - std::vector> v1 = {{"b", "b"}, {"bb", "bb"}}; - t.insert(std::begin(v1), std::end(v1)); - StringTable u; - std::vector> v2 = {{"a", "a"}, {"aa", "aa"}}; - u.insert(std::begin(v2), std::end(v2)); - EXPECT_NE(u, t); -} - -TEST(Table, NumDeletedRegression) { - IntTable t; - t.emplace(0); - t.erase(t.find(0)); - // construct over a deleted slot. - t.emplace(0); - t.clear(); -} - -TEST(Table, FindFullDeletedRegression) { - IntTable t; - for (int i = 0; i < 1000; ++i) { - t.emplace(i); - t.erase(t.find(i)); - } - EXPECT_EQ(0, t.size()); -} - -TEST(Table, ReplacingDeletedSlotDoesNotRehash) { - size_t n; - { - // Compute n such that n is the maximum number of elements before rehash. - IntTable t; - t.emplace(0); - size_t c = t.bucket_count(); - for (n = 1; c == t.bucket_count(); ++n) t.emplace(n); - --n; - } - IntTable t; - t.rehash(n); - const size_t c = t.bucket_count(); - for (size_t i = 0; i != n; ++i) t.emplace(i); - EXPECT_EQ(c, t.bucket_count()) << "rehashing threshold = " << n; - t.erase(0); - t.emplace(0); - EXPECT_EQ(c, t.bucket_count()) << "rehashing threshold = " << n; -} - -TEST(Table, NoThrowMoveConstruct) { - ASSERT_TRUE( - std::is_nothrow_copy_constructible>::value); - ASSERT_TRUE(std::is_nothrow_copy_constructible< - std::equal_to>::value); - ASSERT_TRUE(std::is_nothrow_copy_constructible>::value); - EXPECT_TRUE(std::is_nothrow_move_constructible::value); -} - -TEST(Table, NoThrowMoveAssign) { - ASSERT_TRUE( - std::is_nothrow_move_assignable>::value); - ASSERT_TRUE( - std::is_nothrow_move_assignable>::value); - ASSERT_TRUE(std::is_nothrow_move_assignable>::value); - ASSERT_TRUE( - absl::allocator_traits>::is_always_equal::value); - EXPECT_TRUE(std::is_nothrow_move_assignable::value); -} - -TEST(Table, NoThrowSwappable) { - ASSERT_TRUE( - container_internal::IsNoThrowSwappable>()); - ASSERT_TRUE(container_internal::IsNoThrowSwappable< - std::equal_to>()); - ASSERT_TRUE(container_internal::IsNoThrowSwappable>()); - EXPECT_TRUE(container_internal::IsNoThrowSwappable()); -} - -TEST(Table, HeterogeneousLookup) { - struct Hash { - size_t operator()(int64_t i) const { return i; } - size_t operator()(double i) const { - ADD_FAILURE(); - return i; - } - }; - struct Eq { - bool operator()(int64_t a, int64_t b) const { return a == b; } - bool operator()(double a, int64_t b) const { - ADD_FAILURE(); - return a == b; - } - bool operator()(int64_t a, double b) const { - ADD_FAILURE(); - return a == b; - } - bool operator()(double a, double b) const { - ADD_FAILURE(); - return a == b; - } - }; - - struct THash { - using is_transparent = void; - size_t operator()(int64_t i) const { return i; } - size_t operator()(double i) const { return i; } - }; - struct TEq { - using is_transparent = void; - bool operator()(int64_t a, int64_t b) const { return a == b; } - bool operator()(double a, int64_t b) const { return a == b; } - bool operator()(int64_t a, double b) const { return a == b; } - bool operator()(double a, double b) const { return a == b; } - }; - - raw_hash_set> s{0, 1, 2}; - // It will convert to int64_t before the query. - EXPECT_EQ(1, *s.find(double{1.1})); - - raw_hash_set> ts{0, 1, 2}; - // It will try to use the double, and fail to find the object. - EXPECT_TRUE(ts.find(1.1) == ts.end()); -} - -template -using CallFind = decltype(std::declval().find(17)); - -template -using CallErase = decltype(std::declval().erase(17)); - -template -using CallExtract = decltype(std::declval().extract(17)); - -template -using CallPrefetch = decltype(std::declval().prefetch(17)); - -template -using CallCount = decltype(std::declval().count(17)); - -template